/src/samba/source3/lib/cbuf.c
Line | Count | Source |
1 | | /* |
2 | | * Samba Unix/Linux SMB client library |
3 | | * |
4 | | * Copyright (C) Gregor Beck 2010 |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | /** |
21 | | * @file cbuf.c |
22 | | * @author Gregor Beck <gb@sernet.de> |
23 | | * @date Aug 2010 |
24 | | * |
25 | | * @brief A talloced character buffer. |
26 | | * |
27 | | */ |
28 | | |
29 | | |
30 | | #include "replace.h" |
31 | | #include "system/locale.h" |
32 | | #include "cbuf.h" |
33 | | #include <talloc.h> |
34 | | #include <assert.h> |
35 | | #include "lib/util/byteorder.h" |
36 | | |
37 | | |
38 | | struct cbuf { |
39 | | char* buf; |
40 | | size_t pos; |
41 | | size_t size; |
42 | | }; |
43 | | |
44 | | |
45 | | cbuf* cbuf_clear(cbuf* b) |
46 | 5.79M | { |
47 | 5.79M | cbuf_setpos(b, 0); |
48 | 5.79M | return b; |
49 | 5.79M | } |
50 | | |
51 | | cbuf* cbuf_new(const void* ctx) |
52 | 7.97k | { |
53 | 7.97k | cbuf* s = talloc(ctx, cbuf); |
54 | 7.97k | if (s == NULL) |
55 | 0 | return NULL; |
56 | 7.97k | s->size = 32; |
57 | 7.97k | s->buf = (char *)talloc_size(s, s->size); |
58 | 7.97k | if (s->size && (s->buf == NULL)) { |
59 | 0 | talloc_free(s); |
60 | 0 | return NULL; |
61 | 0 | } |
62 | 7.97k | return cbuf_clear(s); |
63 | 7.97k | } |
64 | | |
65 | | cbuf* cbuf_copy(const cbuf* b) |
66 | 0 | { |
67 | 0 | cbuf* s = talloc(talloc_parent(b), cbuf); |
68 | 0 | if (s == NULL) { |
69 | 0 | return NULL; |
70 | 0 | } |
71 | | |
72 | 0 | s->buf = (char *)talloc_memdup(s, b->buf, b->size); /* only up to pos? */ |
73 | | |
74 | | /* XXX shallow did not work, because realloc */ |
75 | | /* fails with multiple references */ |
76 | | /* s->buf = talloc_reference(s, b->buf); */ |
77 | |
|
78 | 0 | if (s->buf == NULL) { |
79 | 0 | cbuf_delete(s); |
80 | 0 | return NULL; |
81 | 0 | } |
82 | 0 | s->size = b->size; |
83 | 0 | s->pos = b->pos; |
84 | 0 | return s; |
85 | 0 | } |
86 | | |
87 | | void cbuf_delete(cbuf* b) |
88 | 0 | { |
89 | 0 | talloc_free(b); |
90 | 0 | } |
91 | | |
92 | 167k | #define SWAP(A,B,T) do { \ |
93 | 167k | T tmp = A; A = B; B = tmp; \ |
94 | 167k | } while(0) |
95 | | |
96 | | |
97 | | void cbuf_swap(cbuf* b1, cbuf* b2) |
98 | 1.16M | { |
99 | 1.16M | if (b1 == b2) { |
100 | 1.11M | return; |
101 | 1.11M | } |
102 | 48.8k | talloc_reparent(b1, b2, b1->buf); |
103 | 48.8k | talloc_reparent(b2, b1, b2->buf); |
104 | 48.8k | SWAP(b1->buf, b2->buf, char*); |
105 | 48.8k | SWAP(b1->pos, b2->pos, size_t); |
106 | 48.8k | SWAP(b1->size, b2->size, size_t); |
107 | 48.8k | } |
108 | | |
109 | | |
110 | | |
111 | | cbuf* cbuf_takeover(cbuf* b1, cbuf* b2) |
112 | 0 | { |
113 | 0 | talloc_reparent(b2, b1, b2->buf); |
114 | 0 | b1->buf = b2->buf; |
115 | 0 | b1->pos = b2->pos; |
116 | 0 | b1->size = b2->size; |
117 | 0 | cbuf_delete(b2); |
118 | 0 | return b1; |
119 | 0 | } |
120 | | |
121 | | cbuf* cbuf_swapptr(cbuf* b, char** ptr, size_t len) |
122 | 21.4k | { |
123 | 21.4k | void* p = talloc_parent(*ptr); |
124 | 21.4k | SWAP(b->buf, *ptr, char*); |
125 | 21.4k | talloc_steal(b, b->buf); |
126 | 21.4k | talloc_steal(p, *ptr); |
127 | 21.4k | b->size = talloc_get_size(b->buf); |
128 | 21.4k | b->pos = (len == -1) ? strlen(b->buf) : len; |
129 | | |
130 | 21.4k | assert(b->pos <= b->size); |
131 | 21.4k | return b; |
132 | 21.4k | } |
133 | | |
134 | | cbuf* cbuf_resize(cbuf* b, size_t size) |
135 | 6.56k | { |
136 | 6.56k | char* save_buf = b->buf; |
137 | 6.56k | b->buf = talloc_realloc(b, b->buf, char, size); |
138 | 6.56k | if (b->buf == NULL) { |
139 | 0 | talloc_free(save_buf); |
140 | 0 | b->size = 0; |
141 | 6.56k | } else { |
142 | 6.56k | b->size = size; |
143 | 6.56k | } |
144 | 6.56k | b->pos = MIN(b->pos, b->size); |
145 | 6.56k | return b->buf ? b : NULL; |
146 | 6.56k | } |
147 | | |
148 | | char* cbuf_reserve(cbuf* b, size_t len) |
149 | 71.0M | { |
150 | 71.0M | if(b->size < b->pos + len) |
151 | 6.56k | cbuf_resize(b, MAX(2*b->size, b->pos + len)); |
152 | 71.0M | return b->buf ? b->buf + b->pos : NULL; |
153 | 71.0M | } |
154 | | |
155 | | int cbuf_puts(cbuf* b, const char* str, size_t len) |
156 | 27.0k | { |
157 | 27.0k | char* dst; |
158 | | |
159 | 27.0k | if (b == NULL) |
160 | 273 | return 0; |
161 | | |
162 | 26.7k | if (len == -1) { |
163 | 23.0k | len=strlen(str); |
164 | 23.0k | } |
165 | | |
166 | 26.7k | dst = cbuf_reserve(b, len+1); |
167 | 26.7k | if (dst == NULL) |
168 | 0 | return -1; |
169 | | |
170 | 26.7k | memcpy(dst, str, len); |
171 | 26.7k | dst[len] = '\0'; /* just to ease debugging */ |
172 | | |
173 | 26.7k | b->pos += len; |
174 | 26.7k | assert(b->pos < b->size); |
175 | | |
176 | 26.7k | return len; |
177 | 26.7k | } |
178 | | |
179 | 68.1M | int cbuf_putc(cbuf* b, char c) { |
180 | 68.1M | char* dst; |
181 | | |
182 | 68.1M | if (b == NULL) |
183 | 55.1k | return 0; |
184 | | |
185 | 68.0M | dst = cbuf_reserve(b, 2); |
186 | 68.0M | if (dst == NULL) { |
187 | 0 | return -1; |
188 | 0 | } |
189 | | |
190 | 68.0M | dst[0] = c; |
191 | 68.0M | dst[1] = '\0'; /* just to ease debugging */ |
192 | | |
193 | 68.0M | b->pos++; |
194 | 68.0M | assert(b->pos < b->size); |
195 | | |
196 | 68.0M | return 1; |
197 | 68.0M | } |
198 | | |
199 | 445 | int cbuf_putdw(cbuf* b, uint32_t u) { |
200 | 445 | char* dst; |
201 | 445 | static const size_t LEN = sizeof(uint32_t); |
202 | | |
203 | 445 | if (b == NULL) |
204 | 0 | return 0; |
205 | | |
206 | 445 | dst = cbuf_reserve(b, LEN); |
207 | 445 | if (dst == NULL) { |
208 | 0 | return -1; |
209 | 0 | } |
210 | | |
211 | 445 | SIVAL(dst, 0, u); |
212 | | |
213 | 445 | b->pos += LEN; |
214 | 445 | assert(b->pos <= b->size); /* no NULL termination*/ |
215 | | |
216 | 445 | return LEN; |
217 | 445 | } |
218 | | |
219 | 4.10M | size_t cbuf_getpos(const cbuf* b) { |
220 | 4.10M | assert(b->pos <= b->size); |
221 | 4.10M | return b->pos; |
222 | 4.10M | } |
223 | | |
224 | 5.84M | void cbuf_setpos(cbuf* b, size_t pos) { |
225 | 5.84M | assert(pos <= b->size); |
226 | 5.84M | b->pos = pos; |
227 | 5.84M | if (pos < b->size) |
228 | 5.84M | b->buf[pos] = '\0'; /* just to ease debugging */ |
229 | 5.84M | } |
230 | | |
231 | 2.95M | char* cbuf_gets(cbuf* b, size_t idx) { |
232 | 2.95M | assert(idx <= b->pos); |
233 | | |
234 | 2.95M | if (cbuf_reserve(b, 1) == NULL) |
235 | 0 | return NULL; |
236 | | |
237 | 2.95M | b->buf[b->pos] = '\0'; |
238 | 2.95M | return b->buf + idx; |
239 | 2.95M | } |
240 | | |
241 | | int cbuf_printf(cbuf* b, const char* fmt, ...) |
242 | 0 | { |
243 | 0 | va_list args, args2; |
244 | 0 | int len; |
245 | 0 | char* dst = b->buf + b->pos; |
246 | 0 | const int avail = b->size - b->pos; |
247 | 0 | assert(avail >= 0); |
248 | |
|
249 | 0 | va_start(args, fmt); |
250 | 0 | va_copy(args2, args); |
251 | |
|
252 | 0 | len = vsnprintf(dst, avail, fmt, args); |
253 | |
|
254 | 0 | if (len >= avail) { |
255 | 0 | dst = cbuf_reserve(b, len+1); |
256 | 0 | len = (dst != NULL) ? vsnprintf(dst, len+1, fmt, args2) : -1; |
257 | 0 | } |
258 | |
|
259 | 0 | if (len > 0) { |
260 | 0 | b->pos += len; |
261 | 0 | } |
262 | |
|
263 | 0 | va_end(args); |
264 | 0 | va_end(args2); |
265 | 0 | assert(b->pos <= b->size); |
266 | |
|
267 | 0 | return len; |
268 | 0 | } |
269 | | |
270 | | int cbuf_print_quoted_string(cbuf* ost, const char* s) |
271 | 0 | { |
272 | 0 | int n = 1; |
273 | 0 | cbuf_putc(ost,'"'); |
274 | |
|
275 | 0 | while(true) { |
276 | 0 | switch (*s) { |
277 | 0 | case '\0': |
278 | 0 | cbuf_putc(ost, '"'); |
279 | 0 | return n+1; |
280 | | |
281 | 0 | case '"': |
282 | 0 | case '\\': |
283 | 0 | cbuf_putc(ost, '\\'); |
284 | 0 | n++; |
285 | |
|
286 | 0 | FALL_THROUGH; |
287 | 0 | default: |
288 | 0 | cbuf_putc(ost, *s); |
289 | 0 | n++; |
290 | 0 | } |
291 | 0 | s++; |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | | |
296 | | int cbuf_print_quoted(cbuf* ost, const char* s, size_t len) |
297 | 0 | { |
298 | 0 | int n = 1; |
299 | 0 | int ret; |
300 | 0 | cbuf_reserve(ost, len+2); |
301 | |
|
302 | 0 | cbuf_putc(ost,'"'); |
303 | |
|
304 | 0 | while(len--) { |
305 | 0 | switch (*s) { |
306 | 0 | case '"': |
307 | 0 | case '\\': |
308 | 0 | ret = cbuf_printf(ost, "\\%c", *s); |
309 | 0 | break; |
310 | 0 | default: |
311 | 0 | if (isprint(*s) && ((*s == ' ') || !isspace(*s))) { |
312 | 0 | ret = cbuf_putc(ost, *s); |
313 | 0 | } else { |
314 | 0 | ret = cbuf_printf(ost, |
315 | 0 | "\\%02x", |
316 | 0 | (unsigned char)*s); |
317 | 0 | } |
318 | 0 | } |
319 | 0 | s++; |
320 | 0 | if (ret == -1) { |
321 | 0 | return -1; |
322 | 0 | } |
323 | 0 | n += ret; |
324 | 0 | } |
325 | 0 | ret = cbuf_putc(ost,'"'); |
326 | |
|
327 | 0 | return (ret == -1) ? -1 : (n + ret); |
328 | 0 | } |