2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
14 #include "php_http_buffer.h"
16 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_init_ex(
17 php_http_buffer_t
*buf
, size_t chunk_size
, unsigned flags
)
20 buf
= pemalloc(sizeof(*buf
), flags
& PHP_HTTP_BUFFER_INIT_PERSISTENT
);
24 buf
->size
= (chunk_size
) ? chunk_size
: PHP_HTTP_BUFFER_DEFAULT_SIZE
;
25 buf
->pmem
= (flags
& PHP_HTTP_BUFFER_INIT_PERSISTENT
) ? 1 : 0;
26 buf
->data
= (flags
& PHP_HTTP_BUFFER_INIT_PREALLOC
) ?
27 pemalloc(buf
->size
, buf
->pmem
) : NULL
;
28 buf
->free
= (flags
& PHP_HTTP_BUFFER_INIT_PREALLOC
) ? buf
->size
: 0;
35 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_from_string_ex(
36 php_http_buffer_t
*buf
, const char *str
, size_t len
)
40 if (EXPECTED(buf
= php_http_buffer_init(buf
))) {
41 if (PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_append(buf
, str
, len
)) {
43 pefree(buf
, buf
->pmem
);
51 PHP_HTTP_BUFFER_API
size_t php_http_buffer_resize_ex(
52 php_http_buffer_t
*buf
, size_t len
, size_t override_size
,
53 zend_bool allow_error
)
57 fprintf(stderr
, "RESIZE: len=%lu, size=%lu, used=%lu, free=%lu, total=%lu\n", len
, buf
->size
, buf
->used
, buf
->free
, buf
->free
+buf
->used
);
59 if (buf
->free
< len
) {
60 size_t size
= override_size
? override_size
: buf
->size
;
62 while (UNEXPECTED((size
+ buf
->free
) < len
)) {
67 ptr
= perealloc_recoverable(buf
->data
,
68 buf
->used
+ buf
->free
+ size
, buf
->pmem
);
70 ptr
= perealloc(buf
->data
, buf
->used
+ buf
->free
+ size
, buf
->pmem
);
76 return PHP_HTTP_BUFFER_NOMEM
;
85 PHP_HTTP_BUFFER_API
char *php_http_buffer_account(
86 php_http_buffer_t
*buf
, size_t to_account
)
88 assert(to_account
<= buf
->free
);
90 buf
->free
-= to_account
;
91 buf
->used
+= to_account
;
93 return buf
->data
+ buf
->used
;
96 PHP_HTTP_BUFFER_API
size_t php_http_buffer_shrink(php_http_buffer_t
*buf
)
98 /* avoid another realloc on fixation */
100 char *ptr
= perealloc(buf
->data
, buf
->used
+ 1, buf
->pmem
);
105 return PHP_HTTP_BUFFER_NOMEM
;
112 PHP_HTTP_BUFFER_API
size_t php_http_buffer_append(php_http_buffer_t
*buf
,
113 const char *append
, size_t append_len
)
115 if ( buf
->free
< append_len
&&
116 PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_resize(buf
, append_len
)
118 return PHP_HTTP_BUFFER_NOMEM
;
121 memcpy(buf
->data
+ buf
->used
, append
, append_len
);
122 buf
->used
+= append_len
;
123 buf
->free
-= append_len
;
128 PHP_HTTP_BUFFER_API
size_t php_http_buffer_appendf(php_http_buffer_t
*buf
,
129 const char *format
, ...)
133 size_t append_len
, alloc
;
135 va_start(argv
, format
);
136 append_len
= vspprintf(&append
, 0, format
, argv
);
139 alloc
= php_http_buffer_append(buf
, append
, append_len
);
142 if (PHP_HTTP_BUFFER_NOMEM
== alloc
) {
143 return PHP_HTTP_BUFFER_NOMEM
;
148 PHP_HTTP_BUFFER_API
char *php_http_buffer_data(const php_http_buffer_t
*buf
,
149 char **into
, size_t *len
)
151 char *copy
= ecalloc(1, buf
->used
+ 1);
153 memcpy(copy
, buf
->data
, buf
->used
);
164 PHP_HTTP_BUFFER_API
size_t php_http_buffer_cut(php_http_buffer_t
*buf
,
165 size_t offset
, size_t length
)
167 if (offset
> buf
->used
) {
170 if (offset
+ length
> buf
->used
) {
171 length
= buf
->used
- offset
;
173 memmove(buf
->data
+ offset
, buf
->data
+ offset
+ length
,
174 buf
->used
- length
- offset
);
180 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_fix(
181 php_http_buffer_t
*buf
)
183 if ( buf
->free
< 1 &&
184 PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_resize_ex(buf
, 1, 1, 0)
188 buf
->data
[buf
->used
] = '\0';
192 PHP_HTTP_BUFFER_API
void php_http_buffer_reset(php_http_buffer_t
*buf
)
194 buf
->free
+= buf
->used
;
198 PHP_HTTP_BUFFER_API
void php_http_buffer_dtor(php_http_buffer_t
*buf
)
201 pefree(buf
->data
, buf
->pmem
);
208 PHP_HTTP_BUFFER_API
void php_http_buffer_free(php_http_buffer_t
**buf
)
211 php_http_buffer_dtor(*buf
);
212 pefree(*buf
, (*buf
)->pmem
);
217 PHP_HTTP_BUFFER_API
size_t php_http_buffer_chunk_buffer(php_http_buffer_t
**s
,
218 const char *data
, size_t data_len
, char **chunk
, size_t chunk_size
)
220 php_http_buffer_t
*storage
;
225 *s
= php_http_buffer_init_ex(NULL
, chunk_size
<< 1,
226 chunk_size
? PHP_HTTP_BUFFER_INIT_PREALLOC
: 0);
231 php_http_buffer_append(storage
, data
, data_len
);
235 php_http_buffer_data(storage
, chunk
, &chunk_size
);
236 php_http_buffer_free(s
);
240 if (storage
->used
>= chunk_size
) {
241 *chunk
= estrndup(storage
->data
, chunk_size
);
242 php_http_buffer_cut(storage
, 0, chunk_size
);
249 PHP_HTTP_BUFFER_API
size_t php_http_buffer_chunked_output(php_http_buffer_t
**s
,
250 const char *data
, size_t data_len
, size_t chunk_len
,
251 php_http_buffer_pass_func_t passout
, void *opaque
)
254 size_t passed
= 0, got
= 0;
256 while ((got
= php_http_buffer_chunk_buffer(s
, data
, data_len
, &chunk
, chunk_len
))) {
257 if (PHP_HTTP_BUFFER_PASS0
== passout(opaque
, chunk
, got
)) {
258 PTR_SET(chunk
, NULL
);
259 return PHP_HTTP_BUFFER_PASS0
;
263 /* we already got the last chunk,
264 and freed all resources */
269 PTR_SET(chunk
, NULL
);
275 PHP_HTTP_BUFFER_API ssize_t
php_http_buffer_passthru(php_http_buffer_t
**s
, size_t chunk_size
,
276 php_http_buffer_pass_func_t passin
, void *passin_arg
,
277 php_http_buffer_pass_func_t passon
, void *passon_arg
)
279 size_t passed_on
= 0, passed_in
;
281 passed_in
= php_http_buffer_chunked_input(s
, chunk_size
, passin
, passin_arg
);
283 if (passed_in
== PHP_HTTP_BUFFER_PASS0
) {
286 if (passed_in
|| (*s
)->used
) {
287 passed_on
= passon(passon_arg
, (*s
)->data
, (*s
)->used
);
289 if (passed_on
== PHP_HTTP_BUFFER_PASS0
) {
294 php_http_buffer_cut(*s
, 0, passed_on
);
298 return passed_on
- passed_in
;
301 PHP_HTTP_BUFFER_API
size_t php_http_buffer_chunked_input(php_http_buffer_t
**s
,
302 size_t chunk_size
, php_http_buffer_pass_func_t passin
, void *opaque
)
304 php_http_buffer_t
*str
;
307 if (UNEXPECTED(!*s
)) {
308 *s
= php_http_buffer_init_ex(NULL
, chunk_size
,
309 chunk_size
? PHP_HTTP_BUFFER_INIT_PREALLOC
: 0);
313 php_http_buffer_resize(str
, chunk_size
);
314 passed
= passin(opaque
, str
->data
+ str
->used
, chunk_size
);
316 if (passed
!= PHP_HTTP_BUFFER_PASS0
) {
321 php_http_buffer_fix(str
);
326 #ifdef PHP_HTTP_BUFFER_EXTENDED
328 PHP_HTTP_BUFFER_API
int php_http_buffer_cmp(php_http_buffer_t
*left
,
329 php_http_buffer_t
*right
)
331 if (left
->used
> right
->used
) {
333 } else if (right
->used
> left
->used
) {
336 return memcmp(left
->data
, right
->data
, left
->used
);
340 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_copy(
341 const php_http_buffer_t
*from
, php_http_buffer_t
*to
)
345 to
= php_http_buffer_clone(from
, to
);
347 if (PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_append(to
, from
->data
, from
->used
)) {
349 php_http_buffer_free(&to
);
351 php_http_buffer_dtor(to
);
357 PHP_HTTP_BUFFER_API
size_t php_http_buffer_insert(php_http_buffer_t
*buf
,
358 const char *insert
, size_t insert_len
, size_t offset
)
360 if (PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_resize(buf
, insert_len
)) {
361 return PHP_HTTP_BUFFER_NOMEM
;
363 memmove(buf
->data
+ offset
+ insert_len
, buf
->data
+ offset
, insert_len
);
364 memcpy(buf
->data
+ offset
, insert
, insert_len
);
365 buf
->used
+= insert_len
;
366 buf
->free
-= insert_len
;
370 PHP_HTTP_BUFFER_API
size_t php_http_buffer_insertf(php_http_buffer_t
*buf
,
371 size_t offset
, const char *format
, ...)
375 size_t insert_len
, alloc
;
377 va_start(argv
, format
);
378 insert_len
= vspprintf(&insert
, 0, format
, argv
);
381 alloc
= php_http_buffer_insert(buf
, insert
, insert_len
, offset
);
384 if (PHP_HTTP_BUFFER_NOMEM
== alloc
) {
385 return PHP_HTTP_BUFFER_NOMEM
;
390 PHP_HTTP_BUFFER_API
size_t php_http_buffer_prepend(php_http_buffer_t
*buf
,
391 const char *prepend
, size_t prepend_len
)
393 if (PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_resize(buf
, prepend_len
)) {
394 return PHP_HTTP_BUFFER_NOMEM
;
396 memmove(buf
->data
+ prepend_len
, buf
->data
, buf
->used
);
397 memcpy(buf
->data
, prepend
, prepend_len
);
398 buf
->used
+= prepend_len
;
399 buf
->free
-= prepend_len
;
403 PHP_HTTP_BUFFER_API
size_t php_http_buffer_prependf(php_http_buffer_t
*buf
,
404 const char *format
, ...)
408 size_t prepend_len
, alloc
;
410 va_start(argv
, format
);
411 prepend_len
= vspprintf(&prepend
, 0, format
, argv
);
414 alloc
= php_http_buffer_prepend(buf
, prepend
, prepend_len
);
417 if (PHP_HTTP_BUFFER_NOMEM
== alloc
) {
418 return PHP_HTTP_BUFFER_NOMEM
;
423 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_sub(
424 const php_http_buffer_t
*buf
, size_t offset
, size_t length
)
426 if (offset
>= buf
->used
) {
429 php_http_buffer_t
*sub
;
430 size_t need
= 1 + ((length
+ offset
) > buf
->used
?
431 (buf
->used
- offset
) : (length
- offset
));
432 unsigned flags
= buf
->pmem
? PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0;
434 sub
= php_http_buffer_init_ex(NULL
, need
,
435 PHP_HTTP_BUFFER_INIT_PREALLOC
| flags
);
438 if (PHP_HTTP_BUFFER_NOMEM
== php_http_buffer_append(sub
, buf
->data
+ offset
, need
)) {
439 php_http_buffer_free(&sub
);
441 sub
->size
= buf
->size
;
448 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_right(
449 const php_http_buffer_t
*buf
, size_t length
)
451 if (length
< buf
->used
) {
452 return php_http_buffer_sub(buf
, buf
->used
- length
, length
);
454 return php_http_buffer_sub(buf
, 0, buf
->used
);
459 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_merge_va(
460 php_http_buffer_t
*buf
, unsigned argc
, va_list argv
)
463 buf
= php_http_buffer_init(buf
);
467 php_http_buffer_free_t f
= va_arg(argv
, php_http_buffer_free_t
);
468 php_http_buffer_t
*current
= va_arg(argv
, php_http_buffer_t
*);
469 php_http_buffer_append(buf
, current
->data
, current
->used
);
470 FREE_PHP_HTTP_BUFFER(f
, current
);
477 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_merge_ex(
478 php_http_buffer_t
*buf
, unsigned argc
, ...)
481 php_http_buffer_t
*ret
;
483 va_start(argv
, argc
);
484 ret
= php_http_buffer_merge_va(buf
, argc
, argv
);
489 PHP_HTTP_BUFFER_API php_http_buffer_t
*php_http_buffer_merge(unsigned argc
, ...)
492 php_http_buffer_t
*ret
;
494 va_start(argv
, argc
);
495 ret
= php_http_buffer_merge_va(NULL
, argc
, argv
);
507 * vim600: sw=4 ts=4 fdm=marker