back to dev
[m6w6/ext-http] / php_http_buffer.c
index e65a8f8795541af5abc0aa4669c2a809b904192c..8ccee0847584b0e4f678596105ccfee8a5915251 100644 (file)
@@ -1,13 +1,22 @@
-
-/* $Id: php_http_buffer.c 211942 2006-04-24 17:17:09Z mike $ */
-
-#include "php.h"
+/*
+    +--------------------------------------------------------------------+
+    | PECL :: http                                                       |
+    +--------------------------------------------------------------------+
+    | Redistribution and use in source and binary forms, with or without |
+    | modification, are permitted provided that the conditions mentioned |
+    | in the accompanying LICENSE file are met.                          |
+    +--------------------------------------------------------------------+
+    | Copyright (c) 2004-2014, Michael Wallner <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+#include <php.h>
 #include "php_http_buffer.h"
 
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_init_ex(php_http_buffer *buf, size_t chunk_size, int flags)
+PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex(php_http_buffer_t *buf, size_t chunk_size, int flags)
 {
        if (!buf) {
-               buf = pemalloc(sizeof(php_http_buffer), flags & PHP_HTTP_BUFFER_INIT_PERSISTENT);
+               buf = pemalloc(sizeof(*buf), flags & PHP_HTTP_BUFFER_INIT_PERSISTENT);
        }
 
        if (buf) {
@@ -21,7 +30,7 @@ PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_init_ex(php_http_buffer *bu
        return buf;
 }
 
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_from_string_ex(php_http_buffer *buf, const char *string, size_t length)
+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)
 {
        if ((buf = php_http_buffer_init(buf))) {
                if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(buf, string, length)) {
@@ -32,11 +41,11 @@ PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_from_string_ex(php_http_buf
        return buf;
 }
 
-PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer *buf, size_t len, size_t override_size, int allow_error)
+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)
 {
        char *ptr = NULL;
 #if 0
-       fprintf(stderr, "RESIZE: size=%lu, used=%lu, free=%lu\n", buf->size, buf->used, buf->free);
+       fprintf(stderr, "RESIZE: len=%lu, size=%lu, used=%lu, free=%lu\n", len, buf->size, buf->used, buf->free);
 #endif
        if (buf->free < len) {
                size_t size = override_size ? override_size : buf->size;
@@ -63,7 +72,20 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer *buf, size_
        return 0;
 }
 
-PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer *buf)
+PHP_HTTP_BUFFER_API char *php_http_buffer_account(php_http_buffer_t *buf, size_t to_account)
+{
+       /* it's probably already too late but check anyway */
+       if (to_account > buf->free) {
+               return NULL;
+       }
+
+       buf->free -= to_account;
+       buf->used += to_account;
+
+       return buf->data + buf->used;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *buf)
 {
        /* avoid another realloc on fixation */
        if (buf->free > 1) {
@@ -79,9 +101,9 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer *buf)
        return buf->used;
 }
 
-PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer *buf, const char *append, size_t append_len)
+PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf, const char *append, size_t append_len)
 {
-       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len)) {
+       if (buf->free < append_len && PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len)) {
                return PHP_HTTP_BUFFER_NOMEM;
        }
        memcpy(buf->data + buf->used, append, append_len);
@@ -90,7 +112,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer *buf, const ch
        return append_len;
 }
 
-PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer *buf, const char *format, ...)
+PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer_t *buf, const char *format, ...)
 {
        va_list argv;
        char *append;
@@ -109,69 +131,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer *buf, const c
        return append_len;
 }
 
-PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer *buf, const char *insert, size_t insert_len, size_t offset)
-{
-       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, insert_len)) {
-               return PHP_HTTP_BUFFER_NOMEM;
-       }
-       memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
-       memcpy(buf->data + offset, insert, insert_len);
-       buf->used += insert_len;
-       buf->free -= insert_len;
-       return insert_len;
-}
-
-PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer *buf, size_t offset, const char *format, ...)
-{
-       va_list argv;
-       char *insert;
-       size_t insert_len, alloc;
-
-       va_start(argv, format);
-       insert_len = vspprintf(&insert, 0, format, argv);
-       va_end(argv);
-
-       alloc = php_http_buffer_insert(buf, insert, insert_len, offset);
-       efree(insert);
-
-       if (PHP_HTTP_BUFFER_NOMEM == alloc) {
-               return PHP_HTTP_BUFFER_NOMEM;
-       }
-       return insert_len;
-}
-
-PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer *buf, const char *prepend, size_t prepend_len)
-{
-       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, prepend_len)) {
-               return PHP_HTTP_BUFFER_NOMEM;
-       }
-       memmove(buf->data + prepend_len, buf->data, buf->used);
-       memcpy(buf->data, prepend, prepend_len);
-       buf->used += prepend_len;
-       buf->free -= prepend_len;
-       return prepend_len;
-}
-
-PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer *buf, const char *format, ...)
-{
-       va_list argv;
-       char *prepend;
-       size_t prepend_len, alloc;
-
-       va_start(argv, format);
-       prepend_len = vspprintf(&prepend, 0, format, argv);
-       va_end(argv);
-
-       alloc = php_http_buffer_prepend(buf, prepend, prepend_len);
-       efree(prepend);
-
-       if (PHP_HTTP_BUFFER_NOMEM == alloc) {
-               return PHP_HTTP_BUFFER_NOMEM;
-       }
-       return prepend_len;
-}
-
-PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer *buf, char **into, size_t *len)
+PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer_t *buf, char **into, size_t *len)
 {
        char *copy = ecalloc(1, buf->used + 1);
        memcpy(copy, buf->data, buf->used);
@@ -184,16 +144,7 @@ PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer *buf, char
        return copy;
 }
 
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_dup(const php_http_buffer *buf)
-{
-       php_http_buffer *dup = php_http_buffer_clone(buf);
-       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(dup, buf->data, buf->used)) {
-               php_http_buffer_free(&dup);
-       }
-       return dup;
-}
-
-PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer *buf, size_t offset, size_t length)
+PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *buf, size_t offset, size_t length)
 {
        if (offset > buf->used) {
                return 0;
@@ -207,100 +158,22 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer *buf, size_t offs
        return length;
 }
 
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_sub(const php_http_buffer *buf, size_t offset, size_t length)
-{
-       if (offset >= buf->used) {
-               return NULL;
-       } else {
-               size_t need = 1 + ((length + offset) > buf->used ? (buf->used - offset) : (length - offset));
-               php_http_buffer *sub = php_http_buffer_init_ex(NULL, need, PHP_HTTP_BUFFER_INIT_PREALLOC | (buf->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT:0));
-               if (sub) {
-                       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(sub, buf->data + offset, need)) {
-                               php_http_buffer_free(&sub);
-                       } else {
-                               sub->size = buf->size;
-                       }
-               }
-               return sub;
-       }
-}
-
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_right(const php_http_buffer *buf, size_t length)
-{
-       if (length < buf->used) {
-               return php_http_buffer_sub(buf, buf->used - length, length);
-       } else {
-               return php_http_buffer_sub(buf, 0, buf->used);
-       }
-}
-
-
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge_va(php_http_buffer *buf, unsigned argc, va_list argv)
-{
-       unsigned i = 0;
-       buf = php_http_buffer_init(buf);
-
-       if (buf) {
-               while (argc > i++) {
-                       php_http_buffer_free_t f = va_arg(argv, php_http_buffer_free_t);
-                       php_http_buffer *current = va_arg(argv, php_http_buffer *);
-                       php_http_buffer_append(buf, current->data, current->used);
-                       FREE_PHP_HTTP_BUFFER(f, current);
-               }
-       }
-
-       return buf;
-}
-
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge_ex(php_http_buffer *buf, unsigned argc, ...)
-{
-       va_list argv;
-       php_http_buffer *ret;
-
-       va_start(argv, argc);
-       ret = php_http_buffer_merge_va(buf, argc, argv);
-       va_end(argv);
-       return ret;
-}
-
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_merge(unsigned argc, ...)
+PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_fix(php_http_buffer_t *buf)
 {
-       va_list argv;
-       php_http_buffer *ret;
-
-       va_start(argv, argc);
-       ret = php_http_buffer_merge_va(NULL, argc, argv);
-       va_end(argv);
-       return ret;
-}
-
-PHP_HTTP_BUFFER_API php_http_buffer *php_http_buffer_fix(php_http_buffer *buf)
-{
-       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(buf, 1, 1, 0)) {
+       if (buf->free < 1 && PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(buf, 1, 1, 0)) {
                return NULL;
        }
        buf->data[buf->used] = '\0';
        return buf;
 }
 
-PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer *left, php_http_buffer *right)
-{
-       if (left->used > right->used) {
-               return -1;
-       } else if (right->used > left->used) {
-               return 1;
-       } else {
-               return memcmp(left->data, right->data, left->used);
-       }
-}
-
-PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer *buf)
+PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer_t *buf)
 {
        buf->free += buf->used;
        buf->used = 0;
 }
 
-PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer *buf)
+PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer_t *buf)
 {
        if (buf->data) {
                pefree(buf->data, buf->pmem);
@@ -310,7 +183,7 @@ PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer *buf)
        buf->free = 0;
 }
 
-PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer **buf)
+PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer_t **buf)
 {
        if (*buf) {
                php_http_buffer_dtor(*buf);
@@ -319,9 +192,9 @@ PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer **buf)
        }
 }
 
-PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer **s, const char *data, size_t data_len, char **chunk, size_t chunk_size)
+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)
 {
-       php_http_buffer *storage;
+       php_http_buffer_t *storage;
        
        *chunk = NULL;
        
@@ -340,7 +213,7 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer **s, con
                return chunk_size;
        }
        
-       if (storage->used >= (chunk_size = storage->size >> 1)) {
+       if (storage->used >= chunk_size) {
                *chunk = estrndup(storage->data, chunk_size);
                php_http_buffer_cut(storage, 0, chunk_size);
                return chunk_size;
@@ -349,13 +222,17 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer **s, con
        return 0;
 }
 
-PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer **s, const char *data, size_t data_len, size_t chunk_len, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC)
+PHP_HTTP_BUFFER_API size_t 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)
 {
        char *chunk = NULL;
-       size_t got = 0;
-       
+       size_t passed = 0, got = 0;
+
        while ((got = php_http_buffer_chunk_buffer(s, data, data_len, &chunk, chunk_len))) {
-               passout(opaque, chunk, got TSRMLS_CC);
+               if (PHP_HTTP_BUFFER_PASS0 == passout(opaque, chunk, got TSRMLS_CC)) {
+                       STR_SET(chunk, NULL);
+                       return PHP_HTTP_BUFFER_PASS0;
+               }
+               ++passed;
                if (!chunk_len) {
                        /*      we already got the last chunk,
                                and freed all resources */
@@ -366,33 +243,34 @@ PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer **s, con
                STR_SET(chunk, NULL);
        }
        STR_FREE(chunk);
+       return passed;
 }
 
-PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer *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)
+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)
 {
-       size_t passed_on = 0, passed_in = php_http_buffer_chunked_input(&s, chunk_size, passin, passin_arg TSRMLS_CC);
+       size_t passed_on = 0, passed_in = php_http_buffer_chunked_input(s, chunk_size, passin, passin_arg TSRMLS_CC);
 
        if (passed_in == PHP_HTTP_BUFFER_PASS0) {
                return passed_in;
        }
-       if (passed_in) {
-               passed_on = passon(passon_arg, s->data, passed_in TSRMLS_CC);
+       if (passed_in || (*s)->used) {
+               passed_on = passon(passon_arg, (*s)->data, (*s)->used TSRMLS_CC);
 
                if (passed_on == PHP_HTTP_BUFFER_PASS0) {
                        return passed_on;
                }
 
                if (passed_on) {
-                       php_http_buffer_cut(s, 0, passed_on);
+                       php_http_buffer_cut(*s, 0, passed_on);
                }
        }
 
        return passed_on - passed_in;
 }
 
-PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque TSRMLS_DC)
+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)
 {
-       php_http_buffer *str;
+       php_http_buffer_t *str;
        size_t passed;
 
        if (!*s) {
@@ -413,6 +291,166 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer **s, si
        return passed;
 }
 
+#ifdef PHP_HTTP_BUFFER_EXTENDED
+
+PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer_t *left, php_http_buffer_t *right)
+{
+       if (left->used > right->used) {
+               return -1;
+       } else if (right->used > left->used) {
+               return 1;
+       } else {
+               return memcmp(left->data, right->data, left->used);
+       }
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_copy(const php_http_buffer_t *from, php_http_buffer_t *to)
+{
+       int free_to = !to;
+
+       to = php_http_buffer_clone(from, to);
+
+       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(to, from->data, from->used)) {
+               if (free_to) {
+                       php_http_buffer_free(&to);
+               } else {
+                       php_http_buffer_dtor(to);
+               }
+       }
+       return to;
+}
+
+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)
+{
+       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, insert_len)) {
+               return PHP_HTTP_BUFFER_NOMEM;
+       }
+       memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
+       memcpy(buf->data + offset, insert, insert_len);
+       buf->used += insert_len;
+       buf->free -= insert_len;
+       return insert_len;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer_t *buf, size_t offset, const char *format, ...)
+{
+       va_list argv;
+       char *insert;
+       size_t insert_len, alloc;
+
+       va_start(argv, format);
+       insert_len = vspprintf(&insert, 0, format, argv);
+       va_end(argv);
+
+       alloc = php_http_buffer_insert(buf, insert, insert_len, offset);
+       efree(insert);
+
+       if (PHP_HTTP_BUFFER_NOMEM == alloc) {
+               return PHP_HTTP_BUFFER_NOMEM;
+       }
+       return insert_len;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer_t *buf, const char *prepend, size_t prepend_len)
+{
+       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, prepend_len)) {
+               return PHP_HTTP_BUFFER_NOMEM;
+       }
+       memmove(buf->data + prepend_len, buf->data, buf->used);
+       memcpy(buf->data, prepend, prepend_len);
+       buf->used += prepend_len;
+       buf->free -= prepend_len;
+       return prepend_len;
+}
+
+PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer_t *buf, const char *format, ...)
+{
+       va_list argv;
+       char *prepend;
+       size_t prepend_len, alloc;
+
+       va_start(argv, format);
+       prepend_len = vspprintf(&prepend, 0, format, argv);
+       va_end(argv);
+
+       alloc = php_http_buffer_prepend(buf, prepend, prepend_len);
+       efree(prepend);
+
+       if (PHP_HTTP_BUFFER_NOMEM == alloc) {
+               return PHP_HTTP_BUFFER_NOMEM;
+       }
+       return prepend_len;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_sub(const php_http_buffer_t *buf, size_t offset, size_t length)
+{
+       if (offset >= buf->used) {
+               return NULL;
+       } else {
+               size_t need = 1 + ((length + offset) > buf->used ? (buf->used - offset) : (length - offset));
+               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));
+               if (sub) {
+                       if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(sub, buf->data + offset, need)) {
+                               php_http_buffer_free(&sub);
+                       } else {
+                               sub->size = buf->size;
+                       }
+               }
+               return sub;
+       }
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_right(const php_http_buffer_t *buf, size_t length)
+{
+       if (length < buf->used) {
+               return php_http_buffer_sub(buf, buf->used - length, length);
+       } else {
+               return php_http_buffer_sub(buf, 0, buf->used);
+       }
+}
+
+
+PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_va(php_http_buffer_t *buf, unsigned argc, va_list argv)
+{
+       unsigned i = 0;
+       buf = php_http_buffer_init(buf);
+
+       if (buf) {
+               while (argc > i++) {
+                       php_http_buffer_free_t f = va_arg(argv, php_http_buffer_free_t);
+                       php_http_buffer_t *current = va_arg(argv, php_http_buffer_t *);
+                       php_http_buffer_append(buf, current->data, current->used);
+                       FREE_PHP_HTTP_BUFFER(f, current);
+               }
+       }
+
+       return buf;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_ex(php_http_buffer_t *buf, unsigned argc, ...)
+{
+       va_list argv;
+       php_http_buffer_t *ret;
+
+       va_start(argv, argc);
+       ret = php_http_buffer_merge_va(buf, argc, argv);
+       va_end(argv);
+       return ret;
+}
+
+PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge(unsigned argc, ...)
+{
+       va_list argv;
+       php_http_buffer_t *ret;
+
+       va_start(argv, argc);
+       ret = php_http_buffer_merge_va(NULL, argc, argv);
+       va_end(argv);
+       return ret;
+}
+
+#endif
+
 /*
  * Local variables:
  * tab-width: 4