1 /* 2 * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> 3 * 4 * Jansson is free software; you can redistribute it and/or modify 5 * it under the terms of the MIT license. See LICENSE for details. 6 */ 7 /** 8 * License: MIT 9 */ 10 module jansson_d.strbuffer; 11 12 13 package: 14 15 private static import core.stdc.string; 16 private static import jansson_d.jansson; 17 private static import jansson_d.jansson_private; 18 19 struct strbuffer_t 20 { 21 char* value; 22 23 /* bytes used */ 24 size_t length_; 25 26 @disable 27 alias length = length_; 28 29 /* bytes allocated */ 30 size_t size; 31 } 32 33 private enum STRBUFFER_MIN_SIZE = 16; 34 private enum STRBUFFER_FACTOR = 2; 35 private enum size_t STRBUFFER_SIZE_MAX = size_t.max; 36 37 nothrow @trusted @nogc //ToDo: @nodiscard 38 int strbuffer_init(scope strbuffer_t* strbuff) 39 40 in 41 { 42 assert(strbuff != null); 43 } 44 45 do 46 { 47 strbuff.size = STRBUFFER_MIN_SIZE; 48 strbuff.length_ = 0; 49 50 strbuff.value = cast(char*)(jansson_d.jansson_private.jsonp_malloc(strbuff.size)); 51 52 if (strbuff.value == null) { 53 return -1; 54 } 55 56 /* initialize to empty */ 57 strbuff.value[0] = '\0'; 58 59 return 0; 60 } 61 62 nothrow @trusted @nogc 63 void strbuffer_close(scope strbuffer_t* strbuff) 64 65 in 66 { 67 assert(strbuff != null); 68 } 69 70 do 71 { 72 jansson_d.jansson_private.jsonp_free(strbuff.value); 73 strbuff.size = 0; 74 strbuff.length_ = 0; 75 strbuff.value = null; 76 } 77 78 pure nothrow @trusted @nogc @live 79 void strbuffer_clear(scope strbuffer_t* strbuff) 80 81 in 82 { 83 assert(strbuff != null); 84 } 85 86 do 87 { 88 strbuff.length_ = 0; 89 strbuff.value[0] = '\0'; 90 } 91 92 pure nothrow @trusted @nogc @live 93 const (char)* strbuffer_value(return scope const strbuffer_t* strbuff) 94 95 in 96 { 97 assert(strbuff != null); 98 } 99 100 do 101 { 102 return strbuff.value; 103 } 104 105 /* Steal the value and close the strbuffer */ 106 pure nothrow @trusted @nogc @live 107 char* strbuffer_steal_value(scope strbuffer_t* strbuff) 108 109 in 110 { 111 assert(strbuff != null); 112 } 113 114 do 115 { 116 char* result = strbuff.value; 117 strbuff.value = null; 118 119 return result; 120 } 121 122 nothrow @trusted @nogc 123 int strbuffer_append_byte(scope strbuffer_t* strbuff, char byte_) 124 125 do 126 { 127 return .strbuffer_append_bytes(strbuff, &byte_, 1); 128 } 129 130 nothrow @trusted @nogc 131 int strbuffer_append_bytes(scope strbuffer_t* strbuff, scope const char* data, size_t size) 132 133 in 134 { 135 assert(strbuff != null); 136 } 137 138 do 139 { 140 if (size >= (strbuff.size - strbuff.length_)) { 141 /* avoid integer overflow */ 142 if ((strbuff.size > (STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR)) || (size > (STRBUFFER_SIZE_MAX - 1)) || (strbuff.length_ > (STRBUFFER_SIZE_MAX - 1 - size))) { 143 return -1; 144 } 145 146 size_t new_size = mixin (jansson_d.jansson_private.max!("strbuff.size * STRBUFFER_FACTOR", "strbuff.length_ + size + 1")); 147 148 char* new_value = cast(char*)(jansson_d.jansson_private.jsonp_malloc(new_size)); 149 150 if (new_value == null) { 151 return -1; 152 } 153 154 core.stdc..string.memcpy(new_value, strbuff.value, strbuff.length_); 155 156 jansson_d.jansson_private.jsonp_free(strbuff.value); 157 strbuff.value = new_value; 158 strbuff.size = new_size; 159 } 160 161 core.stdc..string.memcpy(strbuff.value + strbuff.length_, data, size); 162 strbuff.length_ += size; 163 strbuff.value[strbuff.length_] = '\0'; 164 165 return 0; 166 } 167 168 pure nothrow @trusted @nogc @live 169 char strbuffer_pop(scope strbuffer_t* strbuff) 170 171 in 172 { 173 assert(strbuff != null); 174 } 175 176 do 177 { 178 if (strbuff.length_ > 0) { 179 char c = strbuff.value[--strbuff.length_]; 180 strbuff.value[strbuff.length_] = '\0'; 181 182 return c; 183 } else { 184 return '\0'; 185 } 186 }