Annotation of embedaddon/php/main/streams/filter.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 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 321634 2012-01-01 13:15:04Z felipe $ */
        !            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: {
        !            37:        return &stream_filters_hash;
        !            38: }
        !            39: 
        !            40: /* Normal hash selection/retrieval call */
        !            41: PHPAPI HashTable *_php_get_stream_filters_hash(TSRMLS_D)
        !            42: {
        !            43:        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: {
        !            49:        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: {
        !            54:        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: {
        !            60:        if (!FG(stream_filters)) {
        !            61:                php_stream_filter_factory tmpfactory;
        !            62: 
        !            63:                ALLOC_HASHTABLE(FG(stream_filters));
        !            64:                zend_hash_init(FG(stream_filters), zend_hash_num_elements(&stream_filters_hash), NULL, NULL, 1);
        !            65:                zend_hash_copy(FG(stream_filters), &stream_filters_hash, NULL, &tmpfactory, sizeof(php_stream_filter_factory));
        !            66:        }
        !            67: 
        !            68:        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: {
        !            75:        int is_persistent = php_stream_is_persistent(stream);
        !            76:        php_stream_bucket *bucket;
        !            77: 
        !            78:        bucket = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), is_persistent);
        !            79: 
        !            80:        if (bucket == NULL) {
        !            81:                return NULL;
        !            82:        }
        !            83:        
        !            84:        bucket->next = bucket->prev = NULL;
        !            85: 
        !            86:        if (is_persistent && !buf_persistent) {
        !            87:                /* all data in a persistent bucket must also be persistent */
        !            88:                bucket->buf = pemalloc(buflen, 1);
        !            89:                
        !            90:                if (bucket->buf == NULL) {
        !            91:                        pefree(bucket, 1);
        !            92:                        return NULL;
        !            93:                }
        !            94:                
        !            95:                memcpy(bucket->buf, buf, buflen);
        !            96:                bucket->buflen = buflen;
        !            97:                bucket->own_buf = 1;
        !            98:        } else {
        !            99:                bucket->buf = buf;
        !           100:                bucket->buflen = buflen;
        !           101:                bucket->own_buf = own_buf;
        !           102:        }
        !           103:        bucket->is_persistent = is_persistent;
        !           104:        bucket->refcount = 1;
        !           105:        bucket->brigade = NULL;
        !           106: 
        !           107:        return bucket;
        !           108: }
        !           109: 
        !           110: /* Given a bucket, returns a version of that bucket with a writeable buffer.
        !           111:  * If the original bucket has a refcount of 1 and owns its buffer, then it
        !           112:  * is returned unchanged.
        !           113:  * Otherwise, a copy of the buffer is made.
        !           114:  * In both cases, the original bucket is unlinked from its brigade.
        !           115:  * If a copy is made, the original bucket is delref'd.
        !           116:  * */
        !           117: PHPAPI php_stream_bucket *php_stream_bucket_make_writeable(php_stream_bucket *bucket TSRMLS_DC)
        !           118: {
        !           119:        php_stream_bucket *retval;
        !           120: 
        !           121:        php_stream_bucket_unlink(bucket TSRMLS_CC);
        !           122:        
        !           123:        if (bucket->refcount == 1 && bucket->own_buf) {
        !           124:                return bucket;
        !           125:        }
        !           126: 
        !           127:        retval = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), bucket->is_persistent);
        !           128:        memcpy(retval, bucket, sizeof(*retval));
        !           129: 
        !           130:        retval->buf = pemalloc(retval->buflen, retval->is_persistent);
        !           131:        memcpy(retval->buf, bucket->buf, retval->buflen);
        !           132: 
        !           133:        retval->refcount = 1;
        !           134:        retval->own_buf = 1;
        !           135: 
        !           136:        php_stream_bucket_delref(bucket TSRMLS_CC);
        !           137:        
        !           138:        return retval;
        !           139: }
        !           140: 
        !           141: PHPAPI int php_stream_bucket_split(php_stream_bucket *in, php_stream_bucket **left, php_stream_bucket **right, size_t length TSRMLS_DC)
        !           142: {
        !           143:        *left = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
        !           144:        *right = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
        !           145: 
        !           146:        if (*left == NULL || *right == NULL) {
        !           147:                goto exit_fail;
        !           148:        }
        !           149: 
        !           150:        (*left)->buf = pemalloc(length, in->is_persistent);
        !           151:        (*left)->buflen = length;
        !           152:        memcpy((*left)->buf, in->buf, length);
        !           153:        (*left)->refcount = 1;
        !           154:        (*left)->own_buf = 1;
        !           155:        (*left)->is_persistent = in->is_persistent;
        !           156:        
        !           157:        (*right)->buflen = in->buflen - length;
        !           158:        (*right)->buf = pemalloc((*right)->buflen, in->is_persistent);
        !           159:        memcpy((*right)->buf, in->buf + length, (*right)->buflen);
        !           160:        (*right)->refcount = 1;
        !           161:        (*right)->own_buf = 1;
        !           162:        (*right)->is_persistent = in->is_persistent;
        !           163:        
        !           164:        return SUCCESS;
        !           165:        
        !           166: exit_fail:
        !           167:        if (*right) {
        !           168:                if ((*right)->buf) {
        !           169:                        pefree((*right)->buf, in->is_persistent);
        !           170:                }
        !           171:                pefree(*right, in->is_persistent);
        !           172:        }
        !           173:        if (*left) {
        !           174:                if ((*left)->buf) {
        !           175:                        pefree((*left)->buf, in->is_persistent);
        !           176:                }
        !           177:                pefree(*left, in->is_persistent);
        !           178:        }
        !           179:        return FAILURE;
        !           180: }
        !           181: 
        !           182: PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket TSRMLS_DC)
        !           183: {
        !           184:        if (--bucket->refcount == 0) {
        !           185:                if (bucket->own_buf) {
        !           186:                        pefree(bucket->buf, bucket->is_persistent);
        !           187:                }
        !           188:                pefree(bucket, bucket->is_persistent);
        !           189:        }
        !           190: }
        !           191: 
        !           192: PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC)
        !           193: {
        !           194:        bucket->next = brigade->head;
        !           195:        bucket->prev = NULL;
        !           196: 
        !           197:        if (brigade->head) {
        !           198:                brigade->head->prev = bucket;
        !           199:        } else {
        !           200:                brigade->tail = bucket;
        !           201:        }
        !           202:        brigade->head = bucket;
        !           203:        bucket->brigade = brigade;
        !           204: }
        !           205: 
        !           206: PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC)
        !           207: {
        !           208:        if (brigade->tail == bucket) {
        !           209:                return;
        !           210:        }
        !           211: 
        !           212:        bucket->prev = brigade->tail;
        !           213:        bucket->next = NULL;
        !           214: 
        !           215:        if (brigade->tail) {
        !           216:                brigade->tail->next = bucket;
        !           217:        } else {
        !           218:                brigade->head = bucket;
        !           219:        }
        !           220:        brigade->tail = bucket;
        !           221:        bucket->brigade = brigade;
        !           222: }
        !           223: 
        !           224: PHPAPI void php_stream_bucket_unlink(php_stream_bucket *bucket TSRMLS_DC)
        !           225: {
        !           226:        if (bucket->prev) {
        !           227:                bucket->prev->next = bucket->next;
        !           228:        } else if (bucket->brigade) {
        !           229:                bucket->brigade->head = bucket->next;
        !           230:        }
        !           231:        if (bucket->next) {
        !           232:                bucket->next->prev = bucket->prev;
        !           233:        } else if (bucket->brigade) {
        !           234:                bucket->brigade->tail = bucket->prev;
        !           235:        }
        !           236:        bucket->brigade = NULL;
        !           237:        bucket->next = bucket->prev = NULL;
        !           238: }
        !           239:        
        !           240: 
        !           241: 
        !           242: 
        !           243: 
        !           244: 
        !           245: 
        !           246: 
        !           247: /* We allow very simple pattern matching for filter factories:
        !           248:  * if "convert.charset.utf-8/sjis" is requested, we search first for an exact
        !           249:  * match. If that fails, we try "convert.charset.*", then "convert.*"
        !           250:  * This means that we don't need to clog up the hashtable with a zillion
        !           251:  * charsets (for example) but still be able to provide them all as filters */
        !           252: PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
        !           253: {
        !           254:        HashTable *filter_hash = (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
        !           255:        php_stream_filter_factory *factory = NULL;
        !           256:        php_stream_filter *filter = NULL;
        !           257:        int n;
        !           258:        char *period;
        !           259: 
        !           260:        n = strlen(filtername);
        !           261:        
        !           262:        if (SUCCESS == zend_hash_find(filter_hash, (char*)filtername, n + 1, (void**)&factory)) {
        !           263:                filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
        !           264:        } else if ((period = strrchr(filtername, '.'))) {
        !           265:                /* try a wildcard */
        !           266:                char *wildname;
        !           267: 
        !           268:                wildname = emalloc(n+3);
        !           269:                memcpy(wildname, filtername, n+1);
        !           270:                period = wildname + (period - filtername);
        !           271:                while (period && !filter) {
        !           272:                        *period = '\0';
        !           273:                        strncat(wildname, ".*", 2);
        !           274:                        if (SUCCESS == zend_hash_find(filter_hash, wildname, strlen(wildname) + 1, (void**)&factory)) {
        !           275:                                filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
        !           276:                        }
        !           277: 
        !           278:                        *period = '\0';
        !           279:                        period = strrchr(wildname, '.');
        !           280:                }
        !           281:                efree(wildname);
        !           282:        }
        !           283: 
        !           284:        if (filter == NULL) {
        !           285:                /* TODO: these need correct docrefs */
        !           286:                if (factory == NULL)
        !           287:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to locate filter \"%s\"", filtername);
        !           288:                else
        !           289:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create or locate filter \"%s\"", filtername);
        !           290:        }
        !           291:        
        !           292:        return filter;
        !           293: }
        !           294: 
        !           295: PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC)
        !           296: {
        !           297:        php_stream_filter *filter;
        !           298: 
        !           299:        filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent);
        !           300:        memset(filter, 0, sizeof(php_stream_filter));
        !           301: 
        !           302:        filter->fops = fops;
        !           303:        filter->abstract = abstract;
        !           304:        filter->is_persistent = persistent;
        !           305:        
        !           306:        return filter;
        !           307: }
        !           308: 
        !           309: PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC)
        !           310: {
        !           311:        if (filter->fops->dtor)
        !           312:                filter->fops->dtor(filter TSRMLS_CC);
        !           313:        pefree(filter, filter->is_persistent);
        !           314: }
        !           315: 
        !           316: PHPAPI int php_stream_filter_prepend_ex(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
        !           317: {
        !           318:        filter->next = chain->head;
        !           319:        filter->prev = NULL;
        !           320: 
        !           321:        if (chain->head) {
        !           322:                chain->head->prev = filter;
        !           323:        } else {
        !           324:                chain->tail = filter;
        !           325:        }
        !           326:        chain->head = filter;
        !           327:        filter->chain = chain;
        !           328: 
        !           329:        return SUCCESS;
        !           330: }
        !           331: 
        !           332: PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
        !           333: {
        !           334:        php_stream_filter_prepend_ex(chain, filter TSRMLS_CC);
        !           335: }
        !           336: 
        !           337: PHPAPI int php_stream_filter_append_ex(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
        !           338: {
        !           339:        php_stream *stream = chain->stream;
        !           340: 
        !           341:        filter->prev = chain->tail;
        !           342:        filter->next = NULL;
        !           343:        if (chain->tail) {
        !           344:                chain->tail->next = filter;
        !           345:        } else {
        !           346:                chain->head = filter;
        !           347:        }
        !           348:        chain->tail = filter;
        !           349:        filter->chain = chain;
        !           350: 
        !           351:        if (&(stream->readfilters) == chain && (stream->writepos - stream->readpos) > 0) {
        !           352:                /* Let's going ahead and wind anything in the buffer through this filter */
        !           353:                php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
        !           354:                php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out;
        !           355:                php_stream_filter_status_t status;
        !           356:                php_stream_bucket *bucket;
        !           357:                size_t consumed = 0;
        !           358: 
        !           359:                bucket = php_stream_bucket_new(stream, (char*) stream->readbuf + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC);
        !           360:                php_stream_bucket_append(brig_inp, bucket TSRMLS_CC);
        !           361:                status = filter->fops->filter(stream, filter, brig_inp, brig_outp, &consumed, PSFS_FLAG_NORMAL TSRMLS_CC);
        !           362: 
        !           363:                if (stream->readpos + consumed > (uint)stream->writepos) {
        !           364:                        /* No behaving filter should cause this. */
        !           365:                        status = PSFS_ERR_FATAL;
        !           366:                }
        !           367: 
        !           368:                switch (status) {
        !           369:                        case PSFS_ERR_FATAL:
        !           370:                                while (brig_in.head) {
        !           371:                                        bucket = brig_in.head;
        !           372:                                        php_stream_bucket_unlink(bucket TSRMLS_CC);
        !           373:                                        php_stream_bucket_delref(bucket TSRMLS_CC);
        !           374:                                }
        !           375:                                while (brig_out.head) {
        !           376:                                        bucket = brig_out.head;
        !           377:                                        php_stream_bucket_unlink(bucket TSRMLS_CC);
        !           378:                                        php_stream_bucket_delref(bucket TSRMLS_CC);
        !           379:                                }
        !           380:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter failed to process pre-buffered data");
        !           381:                                return FAILURE;
        !           382:                        case PSFS_FEED_ME:
        !           383:                                /* We don't actually need data yet,
        !           384:                                   leave this filter in a feed me state until data is needed. 
        !           385:                                   Reset stream's internal read buffer since the filter is "holding" it. */
        !           386:                                stream->readpos = 0;
        !           387:                                stream->writepos = 0;
        !           388:                                break;
        !           389:                        case PSFS_PASS_ON:
        !           390:                                /* If any data is consumed, we cannot rely upon the existing read buffer,
        !           391:                                   as the filtered data must replace the existing data, so invalidate the cache */
        !           392:                                /* note that changes here should be reflected in
        !           393:                                   main/streams/streams.c::php_stream_fill_read_buffer */
        !           394:                                stream->writepos = 0;
        !           395:                                stream->readpos = 0;
        !           396: 
        !           397:                                while (brig_outp->head) {
        !           398:                                        bucket = brig_outp->head;
        !           399:                                        /* Grow buffer to hold this bucket if need be.
        !           400:                                           TODO: See warning in main/stream/streams.c::php_stream_fill_read_buffer */
        !           401:                                        if (stream->readbuflen - stream->writepos < bucket->buflen) {
        !           402:                                                stream->readbuflen += bucket->buflen;
        !           403:                                                stream->readbuf = perealloc(stream->readbuf, stream->readbuflen, stream->is_persistent);
        !           404:                                        }
        !           405:                                        memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen);
        !           406:                                        stream->writepos += bucket->buflen;
        !           407: 
        !           408:                                        php_stream_bucket_unlink(bucket TSRMLS_CC);
        !           409:                                        php_stream_bucket_delref(bucket TSRMLS_CC);
        !           410:                                }
        !           411:                                break;
        !           412:                }
        !           413:        }
        !           414: 
        !           415:        return SUCCESS;
        !           416: }
        !           417: 
        !           418: PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
        !           419: {
        !           420:        if (php_stream_filter_append_ex(chain, filter TSRMLS_CC) != SUCCESS) {
        !           421:                if (chain->head == filter) {
        !           422:                        chain->head = NULL;
        !           423:                        chain->tail = NULL;
        !           424:                } else {
        !           425:                        filter->prev->next = NULL;
        !           426:                        chain->tail = filter->prev;
        !           427:                }
        !           428:        }
        !           429: }
        !           430: 
        !           431: PHPAPI int _php_stream_filter_flush(php_stream_filter *filter, int finish TSRMLS_DC)
        !           432: {
        !           433:        php_stream_bucket_brigade brig_a = { NULL, NULL }, brig_b = { NULL, NULL }, *inp = &brig_a, *outp = &brig_b, *brig_temp;
        !           434:        php_stream_bucket *bucket;
        !           435:        php_stream_filter_chain *chain;
        !           436:        php_stream_filter *current;
        !           437:        php_stream *stream;
        !           438:        size_t flushed_size = 0;
        !           439:        long flags = (finish ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC);
        !           440: 
        !           441:        if (!filter->chain || !filter->chain->stream) {
        !           442:                /* Filter is not attached to a chain, or chain is somehow not part of a stream */
        !           443:                return FAILURE;
        !           444:        }
        !           445: 
        !           446:        chain = filter->chain;
        !           447:        stream = chain->stream;
        !           448: 
        !           449:        for(current = filter; current; current = current->next) {
        !           450:                php_stream_filter_status_t status;
        !           451: 
        !           452:                status = filter->fops->filter(stream, filter, inp, outp, NULL, flags TSRMLS_CC);
        !           453:                if (status == PSFS_FEED_ME) {
        !           454:                        /* We've flushed the data far enough */
        !           455:                        return SUCCESS;
        !           456:                }
        !           457:                if (status == PSFS_ERR_FATAL) {
        !           458:                        return FAILURE;
        !           459:                }
        !           460:                /* Otherwise we have data available to PASS_ON
        !           461:                        Swap the brigades and continue */
        !           462:                brig_temp = inp;
        !           463:                inp = outp;
        !           464:                outp = brig_temp;
        !           465:                outp->head = NULL;
        !           466:                outp->tail = NULL;
        !           467: 
        !           468:                flags = PSFS_FLAG_NORMAL;
        !           469:        }
        !           470: 
        !           471:        /* Last filter returned data via PSFS_PASS_ON
        !           472:                Do something with it */
        !           473: 
        !           474:        for(bucket = inp->head; bucket; bucket = bucket->next) {
        !           475:                flushed_size += bucket->buflen;
        !           476:        }
        !           477: 
        !           478:        if (flushed_size == 0) {
        !           479:                /* Unlikely, but possible */
        !           480:                return SUCCESS;
        !           481:        }
        !           482: 
        !           483:        if (chain == &(stream->readfilters)) {
        !           484:                /* Dump any newly flushed data to the read buffer */
        !           485:                if (stream->readpos > 0) {
        !           486:                        /* Back the buffer up */
        !           487:                        memcpy(stream->readbuf, stream->readbuf + stream->readpos, stream->writepos - stream->readpos);
        !           488:                        stream->readpos = 0;
        !           489:                        stream->writepos -= stream->readpos;
        !           490:                }
        !           491:                if (flushed_size > (stream->readbuflen - stream->writepos)) {
        !           492:                        /* Grow the buffer */
        !           493:                        stream->readbuf = perealloc(stream->readbuf, stream->writepos + flushed_size + stream->chunk_size, stream->is_persistent);
        !           494:                }
        !           495:                while ((bucket = inp->head)) {
        !           496:                        memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen);
        !           497:                        stream->writepos += bucket->buflen;
        !           498:                        php_stream_bucket_unlink(bucket TSRMLS_CC);
        !           499:                        php_stream_bucket_delref(bucket TSRMLS_CC);
        !           500:                }
        !           501:        } else if (chain == &(stream->writefilters)) {
        !           502:                /* Send flushed data to the stream */
        !           503:                while ((bucket = inp->head)) {
        !           504:                        stream->ops->write(stream, bucket->buf, bucket->buflen TSRMLS_CC);
        !           505:                        php_stream_bucket_unlink(bucket TSRMLS_CC);
        !           506:                        php_stream_bucket_delref(bucket TSRMLS_CC);
        !           507:                }
        !           508:        }
        !           509: 
        !           510:        return SUCCESS;
        !           511: }
        !           512: 
        !           513: PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor TSRMLS_DC)
        !           514: {
        !           515:        if (filter->prev) {
        !           516:                filter->prev->next = filter->next;
        !           517:        } else {
        !           518:                filter->chain->head = filter->next;
        !           519:        }
        !           520:        if (filter->next) {
        !           521:                filter->next->prev = filter->prev;
        !           522:        } else {
        !           523:                filter->chain->tail = filter->prev;
        !           524:        }
        !           525: 
        !           526:        if (filter->rsrc_id > 0) {
        !           527:                zend_list_delete(filter->rsrc_id);
        !           528:        }
        !           529: 
        !           530:        if (call_dtor) {
        !           531:                php_stream_filter_free(filter TSRMLS_CC);
        !           532:                return NULL;
        !           533:        }
        !           534:        return filter;
        !           535: }
        !           536: 
        !           537: /*
        !           538:  * Local variables:
        !           539:  * tab-width: 4
        !           540:  * c-basic-offset: 4
        !           541:  * End:
        !           542:  * vim600: noet sw=4 ts=4 fdm=marker
        !           543:  * vim<600: noet sw=4 ts=4
        !           544:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>