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 	}