LCOV - code coverage report
Current view: top level - ext/http - php_http_buffer.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 139 152 91.4 %
Date: 2015-02-17 20:30:22 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11