http\Env::parseParams()
[m6w6/ext-http] / php_http_buffer.c
1
2 /* $Id: php_http_buffer_t.c 211942 2006-04-24 17:17:09Z mike $ */
3
4 #include "php.h"
5 #include "php_http_buffer.h"
6
7 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex(php_http_buffer_t *buf, size_t chunk_size, int flags)
8 {
9 if (!buf) {
10 buf = pemalloc(sizeof(*buf), flags & PHP_HTTP_BUFFER_INIT_PERSISTENT);
11 }
12
13 if (buf) {
14 buf->size = (chunk_size) ? chunk_size : PHP_HTTP_BUFFER_DEFAULT_SIZE;
15 buf->pmem = (flags & PHP_HTTP_BUFFER_INIT_PERSISTENT) ? 1 : 0;
16 buf->data = (flags & PHP_HTTP_BUFFER_INIT_PREALLOC) ? pemalloc(buf->size, buf->pmem) : NULL;
17 buf->free = (flags & PHP_HTTP_BUFFER_INIT_PREALLOC) ? buf->size : 0;
18 buf->used = 0;
19 }
20
21 return buf;
22 }
23
24 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_from_string_ex(php_http_buffer_t *buf, const char *string, size_t length)
25 {
26 if ((buf = php_http_buffer_init(buf))) {
27 if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(buf, string, length)) {
28 pefree(buf, buf->pmem);
29 buf = NULL;
30 }
31 }
32 return buf;
33 }
34
35 PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer_t *buf, size_t len, size_t override_size, int allow_error)
36 {
37 char *ptr = NULL;
38 #if 0
39 fprintf(stderr, "RESIZE: len=%lu, size=%lu, used=%lu, free=%lu\n", len, buf->size, buf->used, buf->free);
40 #endif
41 if (buf->free < len) {
42 size_t size = override_size ? override_size : buf->size;
43
44 while ((size + buf->free) < len) {
45 size <<= 1;
46 }
47
48 if (allow_error) {
49 ptr = perealloc_recoverable(buf->data, buf->used + buf->free + size, buf->pmem);
50 } else {
51 ptr = perealloc(buf->data, buf->used + buf->free + size, buf->pmem);
52 }
53
54 if (ptr) {
55 buf->data = ptr;
56 } else {
57 return PHP_HTTP_BUFFER_NOMEM;
58 }
59
60 buf->free += size;
61 return size;
62 }
63 return 0;
64 }
65
66 PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *buf)
67 {
68 /* avoid another realloc on fixation */
69 if (buf->free > 1) {
70 char *ptr = perealloc(buf->data, buf->used + 1, buf->pmem);
71
72 if (ptr) {
73 buf->data = ptr;
74 } else {
75 return PHP_HTTP_BUFFER_NOMEM;
76 }
77 buf->free = 1;
78 }
79 return buf->used;
80 }
81
82 PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf, const char *append, size_t append_len)
83 {
84 if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len)) {
85 return PHP_HTTP_BUFFER_NOMEM;
86 }
87 memcpy(buf->data + buf->used, append, append_len);
88 buf->used += append_len;
89 buf->free -= append_len;
90 return append_len;
91 }
92
93 PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer_t *buf, const char *format, ...)
94 {
95 va_list argv;
96 char *append;
97 size_t append_len, alloc;
98
99 va_start(argv, format);
100 append_len = vspprintf(&append, 0, format, argv);
101 va_end(argv);
102
103 alloc = php_http_buffer_append(buf, append, append_len);
104 efree(append);
105
106 if (PHP_HTTP_BUFFER_NOMEM == alloc) {
107 return PHP_HTTP_BUFFER_NOMEM;
108 }
109 return append_len;
110 }
111
112 PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer_t *buf, const char *insert, size_t insert_len, size_t offset)
113 {
114 if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, insert_len)) {
115 return PHP_HTTP_BUFFER_NOMEM;
116 }
117 memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
118 memcpy(buf->data + offset, insert, insert_len);
119 buf->used += insert_len;
120 buf->free -= insert_len;
121 return insert_len;
122 }
123
124 PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer_t *buf, size_t offset, const char *format, ...)
125 {
126 va_list argv;
127 char *insert;
128 size_t insert_len, alloc;
129
130 va_start(argv, format);
131 insert_len = vspprintf(&insert, 0, format, argv);
132 va_end(argv);
133
134 alloc = php_http_buffer_insert(buf, insert, insert_len, offset);
135 efree(insert);
136
137 if (PHP_HTTP_BUFFER_NOMEM == alloc) {
138 return PHP_HTTP_BUFFER_NOMEM;
139 }
140 return insert_len;
141 }
142
143 PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer_t *buf, const char *prepend, size_t prepend_len)
144 {
145 if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, prepend_len)) {
146 return PHP_HTTP_BUFFER_NOMEM;
147 }
148 memmove(buf->data + prepend_len, buf->data, buf->used);
149 memcpy(buf->data, prepend, prepend_len);
150 buf->used += prepend_len;
151 buf->free -= prepend_len;
152 return prepend_len;
153 }
154
155 PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer_t *buf, const char *format, ...)
156 {
157 va_list argv;
158 char *prepend;
159 size_t prepend_len, alloc;
160
161 va_start(argv, format);
162 prepend_len = vspprintf(&prepend, 0, format, argv);
163 va_end(argv);
164
165 alloc = php_http_buffer_prepend(buf, prepend, prepend_len);
166 efree(prepend);
167
168 if (PHP_HTTP_BUFFER_NOMEM == alloc) {
169 return PHP_HTTP_BUFFER_NOMEM;
170 }
171 return prepend_len;
172 }
173
174 PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer_t *buf, char **into, size_t *len)
175 {
176 char *copy = ecalloc(1, buf->used + 1);
177 memcpy(copy, buf->data, buf->used);
178 if (into) {
179 *into = copy;
180 }
181 if (len) {
182 *len = buf->used;
183 }
184 return copy;
185 }
186
187 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_copy(const php_http_buffer_t *from, php_http_buffer_t *to)
188 {
189 int free_to = !to;
190
191 to = php_http_buffer_clone(from, to);
192
193 if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(to, from->data, from->used)) {
194 if (free_to) {
195 php_http_buffer_free(&to);
196 } else {
197 php_http_buffer_dtor(to);
198 }
199 }
200 return to;
201 }
202
203 PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *buf, size_t offset, size_t length)
204 {
205 if (offset > buf->used) {
206 return 0;
207 }
208 if (offset + length > buf->used) {
209 length = buf->used - offset;
210 }
211 memmove(buf->data + offset, buf->data + offset + length, buf->used - length - offset);
212 buf->used -= length;
213 buf->free += length;
214 return length;
215 }
216
217 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_sub(const php_http_buffer_t *buf, size_t offset, size_t length)
218 {
219 if (offset >= buf->used) {
220 return NULL;
221 } else {
222 size_t need = 1 + ((length + offset) > buf->used ? (buf->used - offset) : (length - offset));
223 php_http_buffer_t *sub = php_http_buffer_init_ex(NULL, need, PHP_HTTP_BUFFER_INIT_PREALLOC | (buf->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT:0));
224 if (sub) {
225 if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(sub, buf->data + offset, need)) {
226 php_http_buffer_free(&sub);
227 } else {
228 sub->size = buf->size;
229 }
230 }
231 return sub;
232 }
233 }
234
235 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_right(const php_http_buffer_t *buf, size_t length)
236 {
237 if (length < buf->used) {
238 return php_http_buffer_sub(buf, buf->used - length, length);
239 } else {
240 return php_http_buffer_sub(buf, 0, buf->used);
241 }
242 }
243
244
245 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_va(php_http_buffer_t *buf, unsigned argc, va_list argv)
246 {
247 unsigned i = 0;
248 buf = php_http_buffer_init(buf);
249
250 if (buf) {
251 while (argc > i++) {
252 php_http_buffer_free_t f = va_arg(argv, php_http_buffer_free_t);
253 php_http_buffer_t *current = va_arg(argv, php_http_buffer_t *);
254 php_http_buffer_append(buf, current->data, current->used);
255 FREE_PHP_HTTP_BUFFER(f, current);
256 }
257 }
258
259 return buf;
260 }
261
262 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_ex(php_http_buffer_t *buf, unsigned argc, ...)
263 {
264 va_list argv;
265 php_http_buffer_t *ret;
266
267 va_start(argv, argc);
268 ret = php_http_buffer_merge_va(buf, argc, argv);
269 va_end(argv);
270 return ret;
271 }
272
273 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge(unsigned argc, ...)
274 {
275 va_list argv;
276 php_http_buffer_t *ret;
277
278 va_start(argv, argc);
279 ret = php_http_buffer_merge_va(NULL, argc, argv);
280 va_end(argv);
281 return ret;
282 }
283
284 PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_fix(php_http_buffer_t *buf)
285 {
286 if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(buf, 1, 1, 0)) {
287 return NULL;
288 }
289 buf->data[buf->used] = '\0';
290 return buf;
291 }
292
293 PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer_t *left, php_http_buffer_t *right)
294 {
295 if (left->used > right->used) {
296 return -1;
297 } else if (right->used > left->used) {
298 return 1;
299 } else {
300 return memcmp(left->data, right->data, left->used);
301 }
302 }
303
304 PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer_t *buf)
305 {
306 buf->free += buf->used;
307 buf->used = 0;
308 }
309
310 PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer_t *buf)
311 {
312 if (buf->data) {
313 pefree(buf->data, buf->pmem);
314 buf->data = NULL;
315 }
316 buf->used = 0;
317 buf->free = 0;
318 }
319
320 PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer_t **buf)
321 {
322 if (*buf) {
323 php_http_buffer_dtor(*buf);
324 pefree(*buf, (*buf)->pmem);
325 *buf = NULL;
326 }
327 }
328
329 PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer_t **s, const char *data, size_t data_len, char **chunk, size_t chunk_size)
330 {
331 php_http_buffer_t *storage;
332
333 *chunk = NULL;
334
335 if (!*s) {
336 *s = php_http_buffer_init_ex(NULL, chunk_size << 1, chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0);
337 }
338 storage = *s;
339
340 if (data_len) {
341 php_http_buffer_append(storage, data, data_len);
342 }
343
344 if (!chunk_size) {
345 php_http_buffer_data(storage, chunk, &chunk_size);
346 php_http_buffer_free(s);
347 return chunk_size;
348 }
349
350 if (storage->used >= (chunk_size = storage->size >> 1)) {
351 *chunk = estrndup(storage->data, chunk_size);
352 php_http_buffer_cut(storage, 0, chunk_size);
353 return chunk_size;
354 }
355
356 return 0;
357 }
358
359 PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_len, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC)
360 {
361 char *chunk = NULL;
362 size_t got = 0;
363
364 while ((got = php_http_buffer_chunk_buffer(s, data, data_len, &chunk, chunk_len))) {
365 passout(opaque, chunk, got TSRMLS_CC);
366 if (!chunk_len) {
367 /* we already got the last chunk,
368 and freed all resources */
369 break;
370 }
371 data = NULL;
372 data_len = 0;
373 STR_SET(chunk, NULL);
374 }
375 STR_FREE(chunk);
376 }
377
378 PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t *s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg TSRMLS_DC)
379 {
380 size_t passed_on = 0, passed_in = php_http_buffer_chunked_input(&s, chunk_size, passin, passin_arg TSRMLS_CC);
381
382 if (passed_in == PHP_HTTP_BUFFER_PASS0) {
383 return passed_in;
384 }
385 if (passed_in) {
386 passed_on = passon(passon_arg, s->data, passed_in TSRMLS_CC);
387
388 if (passed_on == PHP_HTTP_BUFFER_PASS0) {
389 return passed_on;
390 }
391
392 if (passed_on) {
393 php_http_buffer_cut(s, 0, passed_on);
394 }
395 }
396
397 return passed_on - passed_in;
398 }
399
400 PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque TSRMLS_DC)
401 {
402 php_http_buffer_t *str;
403 size_t passed;
404
405 if (!*s) {
406 *s = php_http_buffer_init_ex(NULL, chunk_size, chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0);
407 }
408 str = *s;
409
410 php_http_buffer_resize(str, chunk_size);
411 passed = passin(opaque, str->data + str->used, chunk_size TSRMLS_CC);
412
413 if (passed != PHP_HTTP_BUFFER_PASS0) {
414 str->used += passed;
415 str->free -= passed;
416 }
417
418 php_http_buffer_fix(str);
419
420 return passed;
421 }
422
423 /*
424 * Local variables:
425 * tab-width: 4
426 * c-basic-offset: 4
427 * End:
428 * vim600: sw=4 ts=4 fdm=marker
429 * vim<600: sw=4 ts=4
430 */
431