mirror of
https://github.com/php/php-src.git
synced 2024-10-21 00:12:34 +00:00
334 lines
9.2 KiB
C
334 lines
9.2 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 4 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2003 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.02 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available at through the world-wide-web at |
|
|
| http://www.php.net/license/2_02.txt. |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: |
|
|
| Wez Furlong (wez@thebrainroom.com) |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#include "php.h"
|
|
#include "php_globals.h"
|
|
#include "php_network.h"
|
|
#include "php_open_temporary_file.h"
|
|
#include "ext/standard/file.h"
|
|
#include <stddef.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "php_streams_int.h"
|
|
|
|
static HashTable stream_filters_hash;
|
|
|
|
PHPAPI HashTable *php_get_stream_filters_hash()
|
|
{
|
|
return &stream_filters_hash;
|
|
}
|
|
|
|
PHPAPI int php_stream_filter_register_factory(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC)
|
|
{
|
|
return zend_hash_add(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern), factory, sizeof(*factory), NULL);
|
|
}
|
|
|
|
PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern TSRMLS_DC)
|
|
{
|
|
return zend_hash_del(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern));
|
|
}
|
|
|
|
/* Buckets */
|
|
|
|
PHPAPI php_stream_bucket *php_stream_bucket_new(php_stream *stream, char *buf, size_t buflen, int own_buf, int buf_persistent TSRMLS_DC)
|
|
{
|
|
int is_persistent = php_stream_is_persistent(stream);
|
|
php_stream_bucket *bucket;
|
|
|
|
bucket = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), is_persistent);
|
|
|
|
if (bucket == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
bucket->next = bucket->prev = NULL;
|
|
|
|
if (is_persistent && !buf_persistent) {
|
|
/* all data in a persistent bucket must also be persistent */
|
|
bucket->buf = pemalloc(buflen, 1);
|
|
|
|
if (bucket->buf == NULL) {
|
|
pefree(bucket, 1);
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(bucket->buf, buf, buflen);
|
|
bucket->buflen = buflen;
|
|
bucket->own_buf = 1;
|
|
} else {
|
|
bucket->buf = buf;
|
|
bucket->buflen = buflen;
|
|
bucket->own_buf = own_buf;
|
|
}
|
|
bucket->is_persistent = is_persistent;
|
|
bucket->refcount = 1;
|
|
|
|
return bucket;
|
|
}
|
|
|
|
/* Given a bucket, returns a version of that bucket with a writeable buffer.
|
|
* If the original bucket has a refcount of 1 and owns its buffer, then it
|
|
* is returned unchanged.
|
|
* Otherwise, a copy of the buffer is made.
|
|
* In both cases, the original bucket is unlinked from its brigade.
|
|
* If a copy is made, the original bucket is delref'd.
|
|
* */
|
|
PHPAPI php_stream_bucket *php_stream_bucket_make_writeable(php_stream_bucket *bucket TSRMLS_DC)
|
|
{
|
|
php_stream_bucket *retval;
|
|
|
|
php_stream_bucket_unlink(bucket TSRMLS_CC);
|
|
|
|
if (bucket->refcount == 1 && bucket->own_buf) {
|
|
return bucket;
|
|
}
|
|
|
|
retval = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), bucket->is_persistent);
|
|
memcpy(retval, bucket, sizeof(*retval));
|
|
|
|
retval->buf = pemalloc(retval->buflen, retval->is_persistent);
|
|
memcpy(retval->buf, bucket->buf, retval->buflen);
|
|
|
|
retval->refcount = 1;
|
|
retval->own_buf = 1;
|
|
|
|
php_stream_bucket_delref(bucket TSRMLS_CC);
|
|
|
|
return retval;
|
|
}
|
|
|
|
PHPAPI int php_stream_bucket_split(php_stream_bucket *in, php_stream_bucket **left, php_stream_bucket **right, size_t length TSRMLS_DC)
|
|
{
|
|
*left = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
|
|
*right = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
|
|
|
|
if (*left == NULL || *right == NULL) {
|
|
goto exit_fail;
|
|
}
|
|
|
|
(*left)->buf = pemalloc(length, in->is_persistent);
|
|
(*left)->buflen = length;
|
|
memcpy((*left)->buf, in->buf, length);
|
|
(*left)->refcount = 1;
|
|
(*left)->own_buf = 1;
|
|
(*left)->is_persistent = in->is_persistent;
|
|
|
|
(*right)->buflen = in->buflen - length;
|
|
(*right)->buf = pemalloc((*right)->buflen, in->is_persistent);
|
|
memcpy((*right)->buf, in->buf + length, (*right)->buflen);
|
|
(*right)->refcount = 1;
|
|
(*right)->own_buf = 1;
|
|
(*right)->is_persistent = in->is_persistent;
|
|
|
|
return SUCCESS;
|
|
|
|
exit_fail:
|
|
if (*right) {
|
|
if ((*right)->buf) {
|
|
pefree((*right)->buf, in->is_persistent);
|
|
}
|
|
pefree(*right, in->is_persistent);
|
|
}
|
|
if (*left) {
|
|
if ((*left)->buf) {
|
|
pefree((*left)->buf, in->is_persistent);
|
|
}
|
|
pefree(*left, in->is_persistent);
|
|
}
|
|
return FAILURE;
|
|
}
|
|
|
|
PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket TSRMLS_DC)
|
|
{
|
|
if (--bucket->refcount == 0) {
|
|
if (bucket->own_buf) {
|
|
pefree(bucket->buf, bucket->is_persistent);
|
|
}
|
|
pefree(bucket, bucket->is_persistent);
|
|
}
|
|
}
|
|
|
|
PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC)
|
|
{
|
|
bucket->next = brigade->head;
|
|
bucket->prev = NULL;
|
|
|
|
if (brigade->head) {
|
|
brigade->head->prev = bucket;
|
|
} else {
|
|
brigade->tail = bucket;
|
|
}
|
|
brigade->head = bucket;
|
|
bucket->brigade = brigade;
|
|
}
|
|
|
|
PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC)
|
|
{
|
|
bucket->prev = brigade->tail;
|
|
bucket->next = NULL;
|
|
|
|
if (brigade->tail) {
|
|
brigade->tail->next = bucket;
|
|
} else {
|
|
brigade->head = bucket;
|
|
}
|
|
brigade->tail = bucket;
|
|
bucket->brigade = brigade;
|
|
}
|
|
|
|
PHPAPI void php_stream_bucket_unlink(php_stream_bucket *bucket TSRMLS_DC)
|
|
{
|
|
if (bucket->prev) {
|
|
bucket->prev->next = bucket->next;
|
|
} else {
|
|
bucket->brigade->head = bucket->next;
|
|
}
|
|
if (bucket->next) {
|
|
bucket->next->prev = bucket->prev;
|
|
} else {
|
|
bucket->brigade->tail = bucket->prev;
|
|
}
|
|
bucket->brigade = NULL;
|
|
bucket->next = bucket->prev = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* We allow very simple pattern matching for filter factories:
|
|
* if "charset.utf-8/sjis" is requested, we search first for an exact
|
|
* match. If that fails, we try "charset.*".
|
|
* This means that we don't need to clog up the hashtable with a zillion
|
|
* charsets (for example) but still be able to provide them all as filters */
|
|
PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, const char *filterparams, int filterparamslen, int persistent TSRMLS_DC)
|
|
{
|
|
php_stream_filter_factory *factory;
|
|
php_stream_filter *filter = NULL;
|
|
int n;
|
|
char *period;
|
|
|
|
n = strlen(filtername);
|
|
|
|
if (SUCCESS == zend_hash_find(&stream_filters_hash, (char*)filtername, n, (void**)&factory)) {
|
|
filter = factory->create_filter(filtername, filterparams, filterparamslen, persistent TSRMLS_CC);
|
|
} else if ((period = strchr(filtername, '.'))) {
|
|
/* try a wildcard */
|
|
char wildname[128];
|
|
|
|
PHP_STRLCPY(wildname, filtername, sizeof(wildname) - 1, period-filtername + 1);
|
|
strcat(wildname, "*");
|
|
|
|
if (SUCCESS == zend_hash_find(&stream_filters_hash, wildname, strlen(wildname), (void**)&factory)) {
|
|
filter = factory->create_filter(filtername, filterparams, filterparamslen, persistent TSRMLS_CC);
|
|
}
|
|
}
|
|
|
|
if (filter == NULL) {
|
|
/* TODO: these need correct docrefs */
|
|
if (factory == NULL)
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to locate filter \"%s\"", filtername);
|
|
else
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create or locate filter \"%s\"", filtername);
|
|
}
|
|
|
|
return filter;
|
|
}
|
|
|
|
PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC)
|
|
{
|
|
php_stream_filter *filter;
|
|
|
|
filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent);
|
|
memset(filter, 0, sizeof(php_stream_filter));
|
|
|
|
filter->fops = fops;
|
|
filter->abstract = abstract;
|
|
filter->is_persistent = persistent;
|
|
|
|
return filter;
|
|
}
|
|
|
|
PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC)
|
|
{
|
|
if (filter->fops->dtor)
|
|
filter->fops->dtor(filter TSRMLS_CC);
|
|
pefree(filter, filter->is_persistent);
|
|
}
|
|
|
|
PHPAPI void php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter)
|
|
{
|
|
filter->next = chain->head;
|
|
filter->prev = NULL;
|
|
|
|
if (chain->head) {
|
|
chain->head->prev = filter;
|
|
} else {
|
|
chain->tail = filter;
|
|
}
|
|
chain->head = filter;
|
|
filter->chain = chain;
|
|
}
|
|
|
|
PHPAPI void php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter)
|
|
{
|
|
filter->prev = chain->tail;
|
|
filter->next = NULL;
|
|
if (chain->tail) {
|
|
chain->tail->next = filter;
|
|
} else {
|
|
chain->head = filter;
|
|
}
|
|
chain->tail = filter;
|
|
filter->chain = chain;
|
|
}
|
|
|
|
PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor TSRMLS_DC)
|
|
{
|
|
if (filter->prev) {
|
|
filter->prev->next = filter->next;
|
|
} else {
|
|
filter->chain->head = filter->next;
|
|
}
|
|
if (filter->next) {
|
|
filter->next->prev = filter->prev;
|
|
} else {
|
|
filter->chain->tail = filter->prev;
|
|
}
|
|
if (call_dtor) {
|
|
php_stream_filter_free(filter TSRMLS_CC);
|
|
return NULL;
|
|
}
|
|
return filter;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
* vim<600: noet sw=4 ts=4
|
|
*/
|