PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_HEAD/main/streams - filter.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 440
Code covered: 59.8 % Executed lines: 263
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 6                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Wez Furlong <wez@thebrainroom.com>                          |
      16                 :    +----------------------------------------------------------------------+
      17                 :  */
      18                 : 
      19                 : /* $Id: filter.c 286624 2009-08-01 14:45:42Z kalle $ */
      20                 : 
      21                 : #include "php.h"
      22                 : #include "php_globals.h"
      23                 : #include "php_network.h"
      24                 : #include "php_open_temporary_file.h"
      25                 : #include "ext/standard/file.h"
      26                 : #include <stddef.h>
      27                 : #include <fcntl.h>
      28                 : 
      29                 : #include "php_streams_int.h"
      30                 : 
      31                 : /* Global filter hash, copied to FG(stream_filters) on registration of volatile filter */
      32                 : static HashTable stream_filters_hash;
      33                 : 
      34                 : /* Should only be used during core initialization */
      35                 : PHPAPI HashTable *php_get_stream_filters_hash_global(void)
      36           34046 : {
      37           34046 :         return &stream_filters_hash;
      38                 : }
      39                 : 
      40                 : /* Normal hash selection/retrieval call */
      41                 : PHPAPI HashTable *_php_get_stream_filters_hash(TSRMLS_D)
      42              32 : {
      43              32 :         return (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
      44                 : }
      45                 : 
      46                 : /* API for registering GLOBAL filters */
      47                 : PHPAPI int php_stream_filter_register_factory(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC)
      48          170070 : {
      49          170070 :         return zend_hash_add(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern) + 1, factory, sizeof(*factory), NULL);
      50                 : }
      51                 : 
      52                 : PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern TSRMLS_DC)
      53          153351 : {
      54          153351 :         return zend_hash_del(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern) + 1);
      55                 : }
      56                 : 
      57                 : /* API for registering VOLATILE wrappers */
      58                 : PHPAPI int php_stream_filter_register_factory_volatile(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC)
      59              12 : {
      60              12 :         if (!FG(stream_filters)) {
      61                 :                 php_stream_filter_factory tmpfactory;
      62                 : 
      63               8 :                 ALLOC_HASHTABLE(FG(stream_filters));
      64               8 :                 zend_hash_init(FG(stream_filters), zend_hash_num_elements(&stream_filters_hash), NULL, NULL, 1);
      65               8 :                 zend_hash_copy(FG(stream_filters), &stream_filters_hash, NULL, &tmpfactory, sizeof(php_stream_filter_factory));
      66                 :         }
      67                 : 
      68              12 :         return zend_hash_add(FG(stream_filters), (char*)filterpattern, strlen(filterpattern) + 1, factory, sizeof(*factory), NULL);
      69                 : }
      70                 : 
      71                 : /* Buckets */
      72                 : 
      73                 : PHPAPI php_stream_bucket *php_stream_bucket_new(php_stream *stream, char *buf, size_t buflen, int own_buf, int buf_persistent TSRMLS_DC)
      74           16181 : {
      75           16181 :         int is_persistent = php_stream_is_persistent(stream);
      76                 :         php_stream_bucket *bucket;
      77                 : 
      78           16181 :         bucket = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), is_persistent);
      79                 : 
      80           16181 :         if (bucket == NULL) {
      81               0 :                 return NULL;
      82                 :         }
      83                 :         
      84           16181 :         bucket->next = bucket->prev = NULL;
      85                 : 
      86           16181 :         if (is_persistent && !buf_persistent) {
      87                 :                 /* all data in a persistent bucket must also be persistent */
      88               0 :                 bucket->buf.s = pemalloc(buflen, 1);
      89                 :                 
      90               0 :                 if (bucket->buf.s == NULL) {
      91               0 :                         pefree(bucket, 1);
      92               0 :                         return NULL;
      93                 :                 }
      94                 :                 
      95               0 :                 memcpy(bucket->buf.s, buf, buflen);
      96               0 :                 bucket->buflen = buflen;
      97               0 :                 bucket->own_buf = 1;
      98                 :         } else {
      99           16181 :                 bucket->buf.s = buf;
     100           16181 :                 bucket->buflen = buflen;
     101           16181 :                 bucket->own_buf = own_buf;
     102                 :         }
     103           16181 :         bucket->buf_type = IS_STRING;
     104           16181 :         bucket->is_persistent = is_persistent;
     105           16181 :         bucket->refcount = 1;
     106           16181 :         bucket->brigade = NULL;
     107                 : 
     108           16181 :         return bucket;
     109                 : }
     110                 : 
     111                 : PHPAPI php_stream_bucket *php_stream_bucket_new_unicode(php_stream *stream, UChar *buf, int32_t buflen, int own_buf, int buf_persistent TSRMLS_DC)
     112           14935 : {
     113           14935 :         int is_persistent = php_stream_is_persistent(stream);
     114                 :         php_stream_bucket *bucket;
     115                 : 
     116           14935 :         bucket = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), is_persistent);
     117                 : 
     118           14935 :         if (bucket == NULL) {
     119               0 :                 return NULL;
     120                 :         }
     121                 :         
     122           14935 :         bucket->next = bucket->prev = NULL;
     123                 : 
     124           14935 :         if (is_persistent && !buf_persistent) {
     125                 :                 /* all data in a persistent bucket must also be persistent */
     126               0 :                 bucket->buf.u = safe_pemalloc(sizeof(UChar), buflen, 0, 1);
     127                 :                 
     128               0 :                 if (bucket->buf.u == NULL) {
     129               0 :                         pefree(bucket, 1);
     130               0 :                         return NULL;
     131                 :                 }
     132                 :                 
     133               0 :                 memcpy(bucket->buf.u, buf, buflen);
     134               0 :                 bucket->buflen = buflen;
     135               0 :                 bucket->own_buf = 1;
     136                 :         } else {
     137           14935 :                 bucket->buf.u = buf;
     138           14935 :                 bucket->buflen = buflen;
     139           14935 :                 bucket->own_buf = own_buf;
     140                 :         }
     141           14935 :         bucket->buf_type = IS_UNICODE;
     142           14935 :         bucket->is_persistent = is_persistent;
     143           14935 :         bucket->refcount = 1;
     144           14935 :         bucket->brigade = NULL;
     145                 : 
     146           14935 :         return bucket;
     147                 : }
     148                 : 
     149                 : /* Given a bucket, returns a version of that bucket with a writeable buffer.
     150                 :  * If the original bucket has a refcount of 1 and owns its buffer, then it
     151                 :  * is returned unchanged.
     152                 :  * Otherwise, a copy of the buffer is made.
     153                 :  * In both cases, the original bucket is unlinked from its brigade.
     154                 :  * If a copy is made, the original bucket is delref'd.
     155                 :  * */
     156                 : PHPAPI php_stream_bucket *php_stream_bucket_make_writeable(php_stream_bucket *bucket TSRMLS_DC)
     157             191 : {
     158                 :         php_stream_bucket *retval;
     159                 : 
     160             191 :         php_stream_bucket_unlink(bucket TSRMLS_CC);
     161                 :         
     162             191 :         if (bucket->refcount == 1 && bucket->own_buf) {
     163               8 :                 return bucket;
     164                 :         }
     165                 : 
     166             183 :         retval = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), bucket->is_persistent);
     167             183 :         memcpy(retval, bucket, sizeof(*retval));
     168                 : 
     169             183 :         if (bucket->buf_type == IS_UNICODE) {
     170               0 :                 retval->buf.u = safe_pemalloc(sizeof(UChar), retval->buflen, 0, retval->is_persistent);
     171               0 :                 memcpy(retval->buf.u, bucket->buf.u, UBYTES(retval->buflen));
     172                 :         } else {
     173             183 :                 retval->buf.s = pemalloc(retval->buflen, retval->is_persistent);
     174             183 :                 memcpy(retval->buf.s, bucket->buf.s, retval->buflen);
     175                 :         }
     176                 : 
     177             183 :         retval->refcount = 1;
     178             183 :         retval->own_buf = 1;
     179                 : 
     180             183 :         php_stream_bucket_delref(bucket TSRMLS_CC);
     181                 :         
     182             183 :         return retval;
     183                 : }
     184                 : 
     185                 : PHPAPI int php_stream_bucket_split(php_stream_bucket *in, php_stream_bucket **left, php_stream_bucket **right, size_t length TSRMLS_DC)
     186               0 : {
     187               0 :         *left = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
     188               0 :         *right = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
     189                 : 
     190               0 :         if (*left == NULL || *right == NULL) {
     191                 :                 goto exit_fail;
     192                 :         }
     193                 : 
     194               0 :         if (in->buf_type == IS_UNICODE) {
     195               0 :                 (*left)->buf.u = safe_pemalloc(sizeof(UChar), length, 0, in->is_persistent);
     196               0 :                 (*left)->buflen = length;
     197               0 :                 memcpy((*left)->buf.u, in->buf.u, UBYTES(length));
     198                 :         
     199               0 :                 (*right)->buflen = in->buflen - length;
     200               0 :                 (*right)->buf.u = pemalloc(UBYTES((*right)->buflen), in->is_persistent);
     201               0 :                 memcpy((*right)->buf.u, in->buf.u + length, UBYTES((*right)->buflen));
     202                 :         } else {
     203               0 :                 (*left)->buf.s = pemalloc(length, in->is_persistent);
     204               0 :                 (*left)->buflen = length;
     205               0 :                 memcpy((*left)->buf.s, in->buf.s, length);
     206                 :         
     207               0 :                 (*right)->buflen = in->buflen - length;
     208               0 :                 (*right)->buf.s = pemalloc((*right)->buflen, in->is_persistent);
     209               0 :                 memcpy((*right)->buf.s, in->buf.s + length, (*right)->buflen);
     210                 :         }
     211                 : 
     212               0 :         (*left)->refcount = 1;
     213               0 :         (*left)->own_buf = 1;
     214               0 :         (*left)->is_persistent = in->is_persistent;
     215               0 :         (*left)->buf_type = in->buf_type;
     216                 : 
     217               0 :         (*right)->refcount = 1;
     218               0 :         (*right)->own_buf = 1;
     219               0 :         (*right)->is_persistent = in->is_persistent;
     220               0 :         (*right)->buf_type = in->buf_type;
     221                 :         
     222               0 :         return SUCCESS;
     223                 :         
     224               0 : exit_fail:
     225               0 :         if (*right) {
     226               0 :                 if ((*right)->buf.v) {
     227               0 :                         pefree((*right)->buf.v, in->is_persistent);
     228                 :                 }
     229               0 :                 pefree(*right, in->is_persistent);
     230                 :         }
     231               0 :         if (*left) {
     232               0 :                 if ((*left)->buf.v) {
     233               0 :                         pefree((*left)->buf.v, in->is_persistent);
     234                 :                 }
     235               0 :                 pefree(*left, in->is_persistent);
     236                 :         }
     237               0 :         return FAILURE;
     238                 : }
     239                 : 
     240                 : PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket TSRMLS_DC)
     241           31313 : {
     242           31313 :         if (--bucket->refcount == 0) {
     243           31299 :                 if (bucket->own_buf) {
     244           15442 :                         pefree(bucket->buf.v, bucket->is_persistent);
     245                 :                 }
     246           31299 :                 pefree(bucket, bucket->is_persistent);
     247                 :         }
     248           31313 : }
     249                 : 
     250                 : PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC)
     251               0 : {
     252               0 :         bucket->next = brigade->head;
     253               0 :         bucket->prev = NULL;
     254                 : 
     255               0 :         if (brigade->head) {
     256               0 :                 brigade->head->prev = bucket;
     257                 :         } else {
     258               0 :                 brigade->tail = bucket;
     259                 :         }
     260               0 :         brigade->head = bucket;
     261               0 :         bucket->brigade = brigade;
     262               0 : }
     263                 : 
     264                 : PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC)
     265           31778 : {
     266           31778 :         if (brigade->tail == bucket) {
     267               1 :                 return;
     268                 :         }
     269                 : 
     270           31777 :         bucket->prev = brigade->tail;
     271           31777 :         bucket->next = NULL;
     272                 : 
     273           31777 :         if (brigade->tail) {
     274             166 :                 brigade->tail->next = bucket;
     275                 :         } else {
     276           31611 :                 brigade->head = bucket;
     277                 :         }
     278           31777 :         brigade->tail = bucket;
     279           31777 :         bucket->brigade = brigade;
     280                 : }
     281                 : 
     282                 : PHPAPI void php_stream_bucket_unlink(php_stream_bucket *bucket TSRMLS_DC)
     283           31777 : {
     284           31777 :         if (bucket->prev) {
     285               0 :                 bucket->prev->next = bucket->next;
     286           31777 :         } else if (bucket->brigade) {
     287           31777 :                 bucket->brigade->head = bucket->next;
     288                 :         }
     289           31777 :         if (bucket->next) {
     290             166 :                 bucket->next->prev = bucket->prev;
     291           31611 :         } else if (bucket->brigade) {
     292           31611 :                 bucket->brigade->tail = bucket->prev;
     293                 :         }
     294           31777 :         bucket->brigade = NULL;
     295           31777 :         bucket->next = bucket->prev = NULL;
     296           31777 : }
     297                 :         
     298                 : 
     299                 : 
     300                 : 
     301                 : 
     302                 : 
     303                 : 
     304                 : 
     305                 : /* We allow very simple pattern matching for filter factories:
     306                 :  * if "convert.charset.utf-8/sjis" is requested, we search first for an exact
     307                 :  * match. If that fails, we try "convert.charset.*", then "convert.*"
     308                 :  * This means that we don't need to clog up the hashtable with a zillion
     309                 :  * charsets (for example) but still be able to provide them all as filters */
     310                 : PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
     311           18962 : {
     312           18962 :         HashTable *filter_hash = (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
     313           18962 :         php_stream_filter_factory *factory = NULL;
     314           18962 :         php_stream_filter *filter = NULL;
     315                 :         int n;
     316                 :         char *period;
     317                 : 
     318           18962 :         n = strlen(filtername);
     319                 :         
     320           18962 :         if (SUCCESS == zend_hash_find(filter_hash, (char*)filtername, n + 1, (void**)&factory)) {
     321              86 :                 filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
     322           18876 :         } else if ((period = strrchr(filtername, '.'))) {
     323                 :                 /* try a wildcard */
     324                 :                 char *wildname;
     325                 : 
     326           18876 :                 wildname = emalloc(n+3);
     327           18876 :                 memcpy(wildname, filtername, n+1);
     328           18876 :                 period = wildname + (period - filtername);
     329           75355 :                 while (period && !filter) {
     330           37603 :                         *period = '\0';
     331           37603 :                         strcat(wildname, ".*");
     332           37603 :                         if (SUCCESS == zend_hash_find(filter_hash, wildname, strlen(wildname) + 1, (void**)&factory)) {
     333           18876 :                                 filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
     334                 :                         }
     335                 : 
     336           37603 :                         *period = '\0';
     337           37603 :                         period = strrchr(wildname, '.');
     338                 :                 }
     339           18876 :                 efree(wildname);
     340                 :         }
     341                 : 
     342           18962 :         if (filter == NULL) {
     343                 :                 /* TODO: these need correct docrefs */
     344               4 :                 if (factory == NULL) {
     345               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to locate filter \"%s\"", filtername);
     346                 :                 } else {
     347               4 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create or locate filter \"%s\"", filtername);
     348                 :                 }
     349               4 :                 return NULL;
     350                 :         }
     351                 : 
     352           18958 :         filter->name = pestrdup(filtername, filter->is_persistent);
     353                 :         
     354           18958 :         return filter;
     355                 : }
     356                 : 
     357                 : PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC)
     358           18958 : {
     359                 :         php_stream_filter *filter;
     360                 : 
     361           18958 :         filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent);
     362           18958 :         memset(filter, 0, sizeof(php_stream_filter));
     363                 : 
     364           18958 :         filter->fops = fops;
     365           18958 :         filter->abstract = abstract;
     366           18958 :         filter->is_persistent = persistent;
     367                 :         
     368           18958 :         return filter;
     369                 : }
     370                 : 
     371                 : PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC)
     372           18958 : {
     373           18958 :         if (filter->fops->dtor)
     374           18933 :                 filter->fops->dtor(filter TSRMLS_CC);
     375           18958 :         pefree(filter->name, filter->is_persistent);
     376           18958 :         pefree(filter, filter->is_persistent);
     377           18958 : }
     378                 : 
     379                 : PHPAPI int php_stream_filter_prepend_ex(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
     380              10 : {
     381              10 :         filter->next = chain->head;
     382              10 :         filter->prev = NULL;
     383                 : 
     384              10 :         if (chain->head) {
     385               2 :                 chain->head->prev = filter;
     386                 :         } else {
     387               8 :                 chain->tail = filter;
     388                 :         }
     389              10 :         chain->head = filter;
     390              10 :         filter->chain = chain;
     391                 : 
     392              10 :         return SUCCESS;
     393                 : }
     394                 : 
     395                 : PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
     396               0 : {
     397               0 :         php_stream_filter_prepend_ex(chain, filter TSRMLS_CC);
     398               0 : }
     399                 : 
     400                 : PHPAPI int php_stream_filter_append_ex(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
     401           18948 : {
     402           18948 :         php_stream *stream = chain->stream;
     403                 : 
     404           18948 :         filter->prev = chain->tail;
     405           18948 :         filter->next = NULL;
     406           18948 :         if (chain->tail) {
     407              33 :                 chain->tail->next = filter;
     408                 :         } else {
     409           18915 :                 chain->head = filter;
     410                 :         }
     411           18948 :         chain->tail = filter;
     412           18948 :         filter->chain = chain;
     413                 : 
     414           18948 :         if (&(stream->readfilters) == chain) {
     415                 :                 /* Let's going ahead and wind anything in the buffer through this filter */
     416           12801 :                 php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
     417           12801 :                 php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out;
     418           12801 :                 php_stream_filter_status_t status = PSFS_FEED_ME;
     419                 :                 php_stream_bucket *bucket;
     420           12801 :                 size_t consumed = 0;
     421                 : 
     422           12801 :                 if ((stream->writepos - stream->readpos) > 0) {
     423               8 :                         if (stream->readbuf_type == IS_UNICODE) {
     424               0 :                                 bucket = php_stream_bucket_new_unicode(stream, stream->readbuf.u + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC);
     425                 :                         } else {
     426               8 :                                 bucket = php_stream_bucket_new(stream, stream->readbuf.s + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC);
     427                 :                         }
     428               8 :                         php_stream_bucket_append(brig_inp, bucket TSRMLS_CC);
     429               8 :                         status = filter->fops->filter(stream, filter, brig_inp, brig_outp, &consumed, PSFS_FLAG_NORMAL TSRMLS_CC);
     430                 : 
     431               8 :                         if ((int) (stream->readpos + consumed) > stream->writepos || consumed < 0) {
     432                 :                                 /* No behaving filter should cause this. */
     433               0 :                                 status = PSFS_ERR_FATAL;
     434                 :                         }
     435                 :                 }
     436                 : 
     437           12801 :                 if (status == PSFS_ERR_FATAL) {
     438              14 :                         while (brig_in.head) {
     439               0 :                                 bucket = brig_in.head;
     440               0 :                                 php_stream_bucket_unlink(bucket TSRMLS_CC);
     441               0 :                                 php_stream_bucket_delref(bucket TSRMLS_CC);
     442                 :                         }
     443              14 :                         while (brig_out.head) {
     444               0 :                                 bucket = brig_out.head;
     445               0 :                                 php_stream_bucket_unlink(bucket TSRMLS_CC);
     446               0 :                                 php_stream_bucket_delref(bucket TSRMLS_CC);
     447                 :                         }
     448               7 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter failed to process pre-buffered data");
     449               7 :                         return FAILURE;
     450                 :                 } else {
     451                 :                         /* This filter addition may change the readbuffer type.
     452                 :                            Since all the previously held data is in the bucket brigade,
     453                 :                            we can reappropriate the buffer that already exists (if one does) */
     454           12802 :                         if (stream->readbuf_type == IS_UNICODE && (filter->fops->flags & PSFO_FLAG_OUTPUTS_UNICODE) == 0) {
     455                 :                                 /* Buffer is currently based on unicode characters, but filter only outputs STRING adjust counting */
     456               8 :                                 stream->readbuf_type = IS_STRING;
     457               8 :                                 stream->readbuflen *= UBYTES(1);
     458           12786 :                         } else if (stream->readbuf_type == IS_STRING && (filter->fops->flags & PSFO_FLAG_OUTPUTS_STRING) == 0) {
     459                 :                                 /* Buffer is currently based on binary characters, but filter only outputs UNICODE adjust counting */
     460           12734 :                                 stream->readbuf_type = IS_UNICODE;
     461           12734 :                                 stream->readbuflen /= UBYTES(1);
     462                 :                         }
     463                 : 
     464           12794 :                         if (status == PSFS_FEED_ME) {
     465                 :                                 /* We don't actually need data yet,
     466                 :                                    leave this filter in a feed me state until data is needed. 
     467                 :                                    Reset stream's internal read buffer since the filter is "holding" it. */
     468           12793 :                                 stream->readpos = 0;
     469           12793 :                                 stream->writepos = 0;
     470               1 :                         } else if (status == PSFS_PASS_ON) {
     471                 :                                 /* If any data is consumed, we cannot rely upon the existing read buffer,
     472                 :                                    as the filtered data must replace the existing data, so invalidate the cache */
     473                 :                                 /* note that changes here should be reflected in
     474                 :                                    main/streams/streams.c::php_stream_fill_read_buffer */
     475               1 :                                 stream->writepos = 0;
     476               1 :                                 stream->readpos = 0;
     477                 : 
     478               3 :                                 while (brig_outp->head) {
     479               1 :                                         bucket = brig_outp->head;
     480                 : 
     481                 :                                         /* Convert for stream type */
     482               1 :                                         if (bucket->buf_type != stream->readbuf_type) {
     483                 :                                                 /* Stream expects different type than bucket contains, convert slopily */
     484               0 :                                                 php_stream_bucket_convert_notranscode(bucket, stream->readbuf_type);
     485                 :                                         }
     486                 : 
     487                 :                                         /* Grow buffer to hold this bucket if need be */
     488               1 :                                         if (stream->readbuflen - stream->writepos < (unsigned int)bucket->buflen) {
     489               0 :                                                 stream->readbuflen += bucket->buflen;
     490               0 :                                                 stream->readbuf.v = perealloc(stream->readbuf.v, PS_ULEN(stream->readbuf_type == IS_UNICODE, stream->readbuflen), stream->is_persistent);
     491                 :                                         }
     492                 : 
     493                 :                                         /* Append to readbuf */
     494               1 :                                         if (stream->readbuf_type == IS_UNICODE) {
     495               0 :                                                 memcpy(stream->readbuf.u + stream->writepos, bucket->buf.u, UBYTES(bucket->buflen));
     496                 :                                         } else {
     497               1 :                                                 memcpy(stream->readbuf.s + stream->writepos, bucket->buf.s, bucket->buflen);
     498                 :                                         }
     499               1 :                                         stream->writepos += bucket->buflen;
     500                 : 
     501               1 :                                         php_stream_bucket_unlink(bucket TSRMLS_CC);
     502               1 :                                         php_stream_bucket_delref(bucket TSRMLS_CC);
     503                 :                                 }
     504                 :                         }
     505                 :                 }
     506                 :         } /* end of readfilters specific code */
     507                 : 
     508           18941 :         return SUCCESS;
     509                 : }
     510                 : 
     511                 : PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
     512           18856 : {
     513           18856 :         if (php_stream_filter_append_ex(chain, filter TSRMLS_CC) != SUCCESS) {
     514               0 :                 if (chain->head == filter) {
     515               0 :                         chain->head = NULL;
     516               0 :                         chain->tail = NULL;
     517                 :                 } else {
     518               0 :                         filter->prev->next = NULL;
     519               0 :                         chain->tail = filter->prev;
     520                 :                 }
     521                 :         }
     522           18856 : }
     523                 : 
     524                 : PHPAPI int _php_stream_filter_check_chain(php_stream_filter_chain *chain TSRMLS_DC)
     525              98 : {
     526                 :         php_stream_filter *filter;
     527              98 :         long last_output = PSFO_FLAG_OUTPUTS_ANY;
     528                 : 
     529             248 :         for(filter = chain->head; filter; filter = filter->next) {
     530             150 :                 if ((((filter->fops->flags & PSFO_FLAG_ACCEPT_MASK) << PSFO_FLAG_ACCEPT_SHIFT) & last_output) == 0) {
     531                 :                         /* Nothing which the last filter outputs is accepted by this filter */
     532               0 :                         return FAILURE;
     533                 :                 }
     534             150 :                 if (filter->fops->flags & PSFO_FLAG_OUTPUTS_SAME) {
     535             150 :                         continue;
     536                 :                 }
     537               0 :                 if (filter->fops->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) {
     538               0 :                         last_output = ((last_output & PSFO_FLAG_OUTPUTS_STRING)  ? PSFO_FLAG_OUTPUTS_UNICODE : 0) |
     539                 :                                                   ((last_output & PSFO_FLAG_OUTPUTS_UNICODE) ? PSFO_FLAG_OUTPUTS_STRING  : 0);
     540               0 :                         continue;
     541                 :                 }
     542               0 :                 last_output = filter->fops->flags & PSFO_FLAG_OUTPUTS_ANY;
     543                 :         }
     544                 : 
     545              98 :         return SUCCESS;
     546                 : }
     547                 : 
     548                 : PHPAPI int _php_stream_filter_output_prefer_unicode(php_stream_filter *filter TSRMLS_DC)
     549               0 : {
     550               0 :         php_stream_filter_chain *chain = filter->chain;
     551                 :         php_stream_filter *f;
     552               0 :         int inverted = 0;
     553               0 :         int preferred = (chain == &chain->stream->readfilters ? 1 : 0);
     554                 : 
     555               0 :         for (f = filter->next; f ; f = f->next) {
     556               0 :                 if ((f->fops->flags & PSFO_FLAG_ACCEPTS_STRING) == 0) {
     557               0 :                         return inverted ^= 1;
     558                 :                 }
     559               0 :                 if ((f->fops->flags & PSFO_FLAG_ACCEPTS_UNICODE) == 0) {
     560               0 :                         return inverted;
     561                 :                 }
     562               0 :                 if (((f->fops->flags & PSFO_FLAG_OUTPUTS_SAME) == 0) &&
     563                 :                         ((f->fops->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) == 0)) {
     564                 :                         /* Input type for next filter won't effect output -- Might as well go for unicode */
     565               0 :                         return inverted ^ 1;
     566                 :                 }
     567               0 :                 if (f->fops->flags & PSFO_FLAG_OUTPUTS_SAME) {
     568               0 :                         continue;
     569                 :                 }
     570               0 :                 if (f->fops->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) {
     571               0 :                         inverted ^= 1;
     572               0 :                         continue;
     573                 :                 }
     574                 :         }
     575                 : 
     576               0 :         return preferred ^ inverted;
     577                 : }
     578                 : 
     579                 : PHPAPI int _php_stream_filter_product(php_stream_filter_chain *chain, int type TSRMLS_DC)
     580           34831 : {
     581                 :         php_stream_filter *f;   
     582                 : 
     583           40769 :         for (f = chain->head; f; f = f->next) {
     584            5938 :                 if ((type == IS_STRING && (f->fops->flags & PSFO_FLAG_ACCEPTS_STRING) == 0) ||
     585                 :                         (type == IS_UNICODE && (f->fops->flags & PSFO_FLAG_ACCEPTS_UNICODE) == 0)) {
     586                 :                         /* At some point, the type produced conflicts with the type accepted */
     587               0 :                         return 0;
     588                 :                 }
     589                 : 
     590            5938 :                 if (f->fops->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) {
     591            5938 :                         type = (type == IS_STRING) ? IS_UNICODE : IS_STRING;
     592            5938 :                         continue;
     593                 :                 }
     594               0 :                 if ((f->fops->flags & PSFO_FLAG_OUTPUTS_SAME) ||
     595                 :                         (f->fops->flags & PSFO_FLAG_OUTPUTS_ANY)) {
     596                 :                         continue;
     597                 :                 }
     598               0 :                 if (f->fops->flags & PSFO_FLAG_OUTPUTS_UNICODE) {
     599               0 :                         type = IS_UNICODE;
     600               0 :                         continue;
     601                 :                 }
     602               0 :                 type = IS_STRING;
     603                 :         }
     604                 : 
     605           34831 :         return type;
     606                 : }
     607                 : 
     608                 : PHPAPI int _php_stream_filter_flush(php_stream_filter *filter, int finish TSRMLS_DC)
     609             144 : {
     610             144 :         php_stream_bucket_brigade brig_a = { NULL, NULL }, brig_b = { NULL, NULL }, *inp = &brig_a, *outp = &brig_b, *brig_temp;
     611                 :         php_stream_bucket *bucket;
     612                 :         php_stream_filter_chain *chain;
     613                 :         php_stream_filter *current;
     614                 :         php_stream *stream;
     615             144 :         size_t flushed_size = 0;
     616             144 :         long flags = (finish ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC);
     617                 : 
     618             144 :         if (!filter->chain || !filter->chain->stream) {
     619                 :                 /* Filter is not attached to a chain, or chain is somehow not part of a stream */
     620               0 :                 return FAILURE;
     621                 :         }
     622                 : 
     623             144 :         chain = filter->chain;
     624             144 :         stream = chain->stream;
     625                 : 
     626             212 :         for(current = filter; current; current = current->next) {
     627                 :                 php_stream_filter_status_t status;
     628                 : 
     629             144 :                 status = filter->fops->filter(stream, filter, inp, outp, NULL, flags TSRMLS_CC);
     630             144 :                 if (status == PSFS_FEED_ME) {
     631                 :                         /* We've flushed the data far enough */
     632              66 :                         return SUCCESS;
     633                 :                 }
     634              78 :                 if (status == PSFS_ERR_FATAL) {
     635              10 :                         return FAILURE;
     636                 :                 }
     637                 :                 /* Otherwise we have data available to PASS_ON
     638                 :                         Swap the brigades and continue */
     639              68 :                 brig_temp = inp;
     640              68 :                 inp = outp;
     641              68 :                 outp = brig_temp;
     642              68 :                 outp->head = NULL;
     643              68 :                 outp->tail = NULL;
     644                 : 
     645              68 :                 flags = PSFS_FLAG_NORMAL;
     646                 :         }
     647                 : 
     648                 :         /* Last filter returned data via PSFS_PASS_ON
     649                 :                 Do something with it */
     650                 : 
     651             137 :         for(bucket = inp->head; bucket; bucket = bucket->next) {
     652              69 :                 flushed_size += bucket->buflen;
     653                 :         }
     654                 : 
     655              68 :         if (flushed_size == 0) {
     656                 :                 /* Unlikely, but possible */
     657               3 :                 return SUCCESS;
     658                 :         }
     659                 : 
     660              65 :         if (chain == &(stream->readfilters)) {
     661                 :                 /* Dump any newly flushed data to the read buffer */
     662               0 :                 if ((unsigned int)stream->readpos > stream->chunk_size) {
     663                 :                         /* Back the buffer up */
     664               0 :                         memcpy(stream->readbuf.s, stream->readbuf.s + PS_ULEN(stream->readbuf_type == IS_UNICODE, stream->readpos), PS_ULEN(stream->readbuf_type == IS_UNICODE, stream->writepos - stream->readpos));
     665               0 :                         stream->writepos -= stream->readpos;
     666               0 :                         stream->readpos = 0;
     667                 :                 }
     668               0 :                 if (flushed_size > (stream->readbuflen - stream->writepos)) {
     669                 :                         /* Grow the buffer */
     670               0 :                         stream->readbuf.v = perealloc(stream->readbuf.v, PS_ULEN(stream->readbuf_type == IS_UNICODE, stream->writepos + flushed_size + stream->chunk_size), stream->is_persistent);
     671                 :                 }
     672               0 :                 while ((bucket = inp->head)) {
     673                 :                         /* Convert if necessary */
     674               0 :                         if (bucket->buf_type != stream->readbuf_type) {
     675                 :                                 /* Stream expects different type than what's in bucket, convert slopily */
     676               0 :                                 php_stream_bucket_convert_notranscode(bucket, stream->readbuf_type);
     677                 :                         }
     678                 : 
     679                 :                         /* Append to readbuf */
     680               0 :                         if (stream->readbuf_type == IS_UNICODE) {
     681               0 :                                  memcpy(stream->readbuf.u + stream->writepos, bucket->buf.u, UBYTES(bucket->buflen));
     682                 :                         } else {
     683               0 :                                  memcpy(stream->readbuf.s + stream->writepos, bucket->buf.s, bucket->buflen);
     684                 :                         }
     685               0 :                         stream->writepos += bucket->buflen;
     686               0 :                         php_stream_bucket_unlink(bucket TSRMLS_CC);
     687               0 :                         php_stream_bucket_delref(bucket TSRMLS_CC);
     688                 :                 }
     689                 : 
     690                 : 
     691              65 :         } else if (chain == &(stream->writefilters)) {
     692                 :                 /* Send flushed data to the stream */
     693             199 :                 while ((bucket = inp->head)) {
     694                 :                         /* Convert if necessary */
     695              69 :                         if (bucket->buf_type == IS_UNICODE) {
     696                 :                                 /* Force data to binary, adjusting buflen */
     697               0 :                                 php_stream_bucket_convert_notranscode(bucket, IS_STRING);
     698                 :                         }
     699                 : 
     700                 :                         /* Must be binary by this point */
     701              69 :                         stream->ops->write(stream, bucket->buf.s, bucket->buflen TSRMLS_CC);
     702                 : 
     703              69 :                         php_stream_bucket_unlink(bucket TSRMLS_CC);
     704              69 :                         php_stream_bucket_delref(bucket TSRMLS_CC);
     705                 :                 }
     706                 :         }
     707                 : 
     708              65 :         return SUCCESS;
     709                 : }
     710                 : 
     711                 : PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor TSRMLS_DC)
     712           18958 : {
     713                 :         /* UTODO: Figure out a sane way to "defilter" so that unicode converters can be swapped around
     714                 :            For now, at least fopen(,'b') + stream_encoding($fp, 'charset') works since there's nothing to remove */
     715                 : 
     716           18958 :         if (filter->prev) {
     717               1 :                 filter->prev->next = filter->next;
     718                 :         } else {
     719           18957 :                 filter->chain->head = filter->next;
     720                 :         }
     721           18958 :         if (filter->next) {
     722              34 :                 filter->next->prev = filter->prev;
     723                 :         } else {
     724           18924 :                 filter->chain->tail = filter->prev;
     725                 :         }
     726                 : 
     727           18958 :         if (filter->rsrc_id > 0) {
     728              65 :                 zend_list_delete(filter->rsrc_id);
     729                 :         }
     730                 : 
     731           18958 :         if (call_dtor) {
     732           18958 :                 php_stream_filter_free(filter TSRMLS_CC);
     733           18958 :                 return NULL;
     734                 :         }
     735               0 :         return filter;
     736                 : }
     737                 : 
     738                 : PHPAPI int _php_stream_bucket_convert(php_stream_bucket *bucket, unsigned char type, UConverter *conv TSRMLS_DC)
     739               1 : {
     740               1 :         if (bucket->buf_type == type) {
     741               0 :                 return SUCCESS;
     742                 :         }
     743                 : 
     744               1 :         if (conv) {
     745                 :                 /* transcode current type using provided converter */
     746               0 :                 if (type == IS_UNICODE) {
     747               0 :                         UErrorCode status = U_ZERO_ERROR;
     748                 :                         UChar *dest;
     749                 :                         int destlen;
     750                 : 
     751               0 :                         zend_string_to_unicode_ex(conv, &dest, &destlen, bucket->buf.s, bucket->buflen, &status);
     752                 : 
     753               0 :                         if (bucket->own_buf) {
     754               0 :                                 pefree(bucket->buf.s, bucket->is_persistent);
     755                 :                         }
     756                 : 
     757                 :                         /* Might be dangerous, double check this (or, better, get a persistent version of zend_string_to_unicode_ex() */
     758               0 :                         bucket->is_persistent = 0;
     759                 : 
     760               0 :                         bucket->buf_type = IS_UNICODE;
     761               0 :                         bucket->buf.u = dest;
     762               0 :                         bucket->buflen = destlen;
     763               0 :                         bucket->own_buf = 1;
     764               0 :                         return SUCCESS;
     765                 :                 } else {
     766               0 :                         UErrorCode status = U_ZERO_ERROR;
     767                 :                         char *dest;
     768                 :                         int destlen, num_conv;
     769                 : 
     770               0 :                         num_conv = zend_unicode_to_string_ex(conv, &dest, &destlen, bucket->buf.u, bucket->buflen, &status);
     771               0 :                         if (U_FAILURE(status)) {
     772               0 :                                 int32_t offset = u_countChar32(bucket->buf.u, num_conv);
     773                 : 
     774               0 :                                 zend_raise_conversion_error_ex("Could not convert Unicode string to binary string", conv, ZEND_FROM_UNICODE, offset TSRMLS_CC);
     775                 :                         }
     776                 : 
     777               0 :                         if (bucket->own_buf) {
     778               0 :                                 pefree(bucket->buf.u, bucket->is_persistent);
     779                 :                         }
     780                 : 
     781                 :                         /* See above */
     782               0 :                         bucket->is_persistent = 0;
     783                 : 
     784               0 :                         bucket->buf_type = IS_STRING;
     785               0 :                         bucket->buf.s = dest;
     786               0 :                         bucket->buflen = destlen;
     787               0 :                         bucket->own_buf = 1;
     788               0 :                         return SUCCESS;
     789                 :                 }
     790                 :         } else {
     791                 :                 /* Convert without transcode, usually a bad idea as it creates ugly data,
     792                 :                    When binary streams receive unicode data (because of filters or writing unicode strings)
     793                 :                    this is the only option */
     794               1 :                 if (type == IS_UNICODE) {
     795               0 :                         if (bucket->buflen == 0) {
     796                 :                                 /* Shortcut conversion for empty buckets */
     797               0 :                                 if (bucket->own_buf) {
     798               0 :                                         pefree(bucket->buf.s, bucket->is_persistent);
     799                 :                                 }
     800               0 :                                 bucket->buf_type = IS_UNICODE;
     801               0 :                                 bucket->buf.u = EMPTY_STR;
     802               0 :                                 bucket->own_buf = 0;
     803               0 :                                 bucket->buflen = 0;
     804               0 :                                 return SUCCESS;
     805                 :                         }
     806                 : 
     807               0 :                         if (bucket->own_buf) {
     808                 :                                 /* one UChar padding for partial units, one more for terminating NULL */
     809               0 :                                 bucket->buf.s = perealloc(bucket->buf.s, bucket->buflen + UBYTES(2), bucket->is_persistent);
     810                 :                         } else {
     811               0 :                                 int destlen = ceil(bucket->buflen / sizeof(UChar));
     812               0 :                                 UChar *dest = pemalloc(UBYTES(destlen + 2), bucket->is_persistent);
     813               0 :                                 memcpy(dest, bucket->buf.s, bucket->buflen);
     814               0 :                                 bucket->buf.u = dest;
     815               0 :                                 bucket->own_buf = 1;
     816                 :                         }
     817               0 :                         memset(bucket->buf.s + bucket->buflen, 0, UBYTES(2));
     818               0 :                         bucket->buf_type = IS_UNICODE;
     819               0 :                         bucket->buflen = ceil(bucket->buflen / sizeof(UChar));
     820               0 :                         return SUCCESS;
     821                 :                 } else { /* IS_STRING */
     822               1 :                         bucket->buf_type = IS_STRING;
     823               1 :                         bucket->buflen *= 2;
     824               1 :                         return SUCCESS;
     825                 :                 }
     826                 :         }
     827                 : 
     828                 :         /* Never reached */
     829                 :         return FAILURE;
     830                 : }
     831                 : 
     832                 : PHPAPI int _php_stream_encoding_apply(php_stream *stream, int writechain, const char *encoding, uint16_t error_mode, UChar *subst TSRMLS_DC)
     833           18715 : {
     834           18715 :         int encoding_len = strlen(encoding);
     835           18715 :         int buflen = sizeof("unicode.from.") + encoding_len - 1; /* might be "to", but "from" is long enough for both */
     836           18715 :         char *buf = emalloc(buflen + 1);
     837                 :         php_stream_filter *filter;
     838                 :         zval *filterparams;
     839                 : 
     840           18715 :         if (writechain) {
     841            5981 :                 memcpy(buf, "unicode.to.", sizeof("unicode.to.") - 1);
     842            5981 :                 memcpy(buf + sizeof("unicode.to.") - 1, encoding, encoding_len + 1);
     843                 :         } else {
     844           12734 :                 memcpy(buf, "unicode.from.", sizeof("unicode.from.") - 1);
     845           12734 :                 memcpy(buf + sizeof("unicode.from.") - 1, encoding, encoding_len + 1);
     846                 :         }
     847                 : 
     848           18715 :         ALLOC_INIT_ZVAL(filterparams);
     849           18715 :         array_init(filterparams);
     850           18715 :         add_ascii_assoc_long(filterparams, "error_mode", error_mode);
     851           18715 :         if (subst) {
     852            5981 :                 add_ascii_assoc_unicode(filterparams, "subst_char", subst, 1);
     853                 :         }
     854           18715 :         filter = php_stream_filter_create(buf, filterparams, php_stream_is_persistent(stream) TSRMLS_CC);
     855           18715 :         efree(buf);
     856           18715 :         zval_ptr_dtor(&filterparams);
     857                 : 
     858           18715 :         if (!filter) {
     859               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to apply encoding for charset: %s\n", encoding);
     860               0 :                 return FAILURE;
     861                 :         }
     862                 : 
     863           18715 :         php_stream_filter_append(writechain ? &stream->writefilters : &stream->readfilters, filter);
     864                 : 
     865           18715 :         return SUCCESS;
     866                 : }
     867                 : 
     868                 : /*
     869                 :  * Local variables:
     870                 :  * tab-width: 4
     871                 :  * c-basic-offset: 4
     872                 :  * End:
     873                 :  * vim600: noet sw=4 ts=4 fdm=marker
     874                 :  * vim<600: noet sw=4 ts=4
     875                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:47 +0000 (35 hours ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.