2003-02-16 22:19:28 +00:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
2004-01-08 08:18:22 +00:00
|
|
|
| PHP Version 5 |
|
2003-02-16 22:19:28 +00:00
|
|
|
+----------------------------------------------------------------------+
|
2006-01-01 13:10:10 +00:00
|
|
|
| Copyright (c) 1997-2006 The PHP Group |
|
2003-02-16 22:19:28 +00:00
|
|
|
+----------------------------------------------------------------------+
|
2006-01-01 13:10:10 +00:00
|
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
2003-02-16 22:19:28 +00:00
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
2003-06-10 20:04:29 +00:00
|
|
|
| available through the world-wide-web at the following url: |
|
2006-01-01 13:10:10 +00:00
|
|
|
| http://www.php.net/license/3_01.txt |
|
2003-02-16 22:19:28 +00:00
|
|
|
| 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. |
|
|
|
|
+----------------------------------------------------------------------+
|
2003-02-19 08:40:19 +00:00
|
|
|
| Authors: Wez Furlong <wez@thebrainroom.com> |
|
2003-02-16 22:19:28 +00:00
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* $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"
|
|
|
|
|
2004-06-21 21:08:05 +00:00
|
|
|
/* Global filter hash, copied to FG(stream_filters) on registration of volatile filter */
|
2003-02-16 22:19:28 +00:00
|
|
|
static HashTable stream_filters_hash;
|
|
|
|
|
2004-06-21 21:08:05 +00:00
|
|
|
/* Should only be used during core initialization */
|
|
|
|
PHPAPI HashTable *php_get_stream_filters_hash_global()
|
2003-02-16 22:19:28 +00:00
|
|
|
{
|
|
|
|
return &stream_filters_hash;
|
|
|
|
}
|
|
|
|
|
2004-06-21 21:08:05 +00:00
|
|
|
/* Normal hash selection/retrieval call */
|
|
|
|
PHPAPI HashTable *_php_get_stream_filters_hash(TSRMLS_D)
|
|
|
|
{
|
|
|
|
return (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* API for registering GLOBAL filters */
|
2003-02-16 22:19:28 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2004-06-21 21:08:05 +00:00
|
|
|
/* API for registering VOLATILE wrappers */
|
|
|
|
PHPAPI int php_stream_filter_register_factory_volatile(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC)
|
|
|
|
{
|
|
|
|
if (!FG(stream_filters)) {
|
|
|
|
php_stream_filter_factory tmpfactory;
|
|
|
|
|
2004-09-13 21:07:22 +00:00
|
|
|
ALLOC_HASHTABLE(FG(stream_filters));
|
2004-06-21 21:08:05 +00:00
|
|
|
zend_hash_init(FG(stream_filters), 0, NULL, NULL, 1);
|
|
|
|
zend_hash_copy(FG(stream_filters), &stream_filters_hash, NULL, &tmpfactory, sizeof(php_stream_filter_factory));
|
|
|
|
}
|
|
|
|
|
|
|
|
return zend_hash_add(FG(stream_filters), (char*)filterpattern, strlen(filterpattern), factory, sizeof(*factory), NULL);
|
|
|
|
}
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
/* 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 */
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->buf.s = pemalloc(buflen, 1);
|
2003-02-18 01:22:21 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
if (bucket->buf.s == NULL) {
|
2003-02-18 01:22:21 +00:00
|
|
|
pefree(bucket, 1);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
memcpy(bucket->buf.s, buf, buflen);
|
|
|
|
bucket->buflen = buflen;
|
2003-02-18 01:22:21 +00:00
|
|
|
bucket->own_buf = 1;
|
|
|
|
} else {
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->buf.s = buf;
|
|
|
|
bucket->buflen = buflen;
|
2003-02-18 01:22:21 +00:00
|
|
|
bucket->own_buf = own_buf;
|
|
|
|
}
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->buf_type = IS_STRING;
|
2005-08-11 23:36:07 +00:00
|
|
|
bucket->is_persistent = is_persistent;
|
|
|
|
bucket->refcount = 1;
|
|
|
|
|
|
|
|
return bucket;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
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 */
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->buf.u = safe_pemalloc(sizeof(UChar), buflen, 0, 1);
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
if (bucket->buf.u == NULL) {
|
2005-08-11 23:36:07 +00:00
|
|
|
pefree(bucket, 1);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
memcpy(bucket->buf.u, buf, buflen);
|
|
|
|
bucket->buflen = buflen;
|
2005-08-11 23:36:07 +00:00
|
|
|
bucket->own_buf = 1;
|
|
|
|
} else {
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->buf.u = buf;
|
|
|
|
bucket->buflen = buflen;
|
2005-08-11 23:36:07 +00:00
|
|
|
bucket->own_buf = own_buf;
|
|
|
|
}
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->buf_type = IS_UNICODE;
|
2003-02-18 01:22:21 +00:00
|
|
|
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));
|
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
if (bucket->buf_type == IS_UNICODE) {
|
|
|
|
retval->buf.u = safe_pemalloc(sizeof(UChar), retval->buflen, 0, retval->is_persistent);
|
|
|
|
memcpy(retval->buf.u, bucket->buf.u, UBYTES(retval->buflen));
|
2005-08-11 23:36:07 +00:00
|
|
|
} else {
|
2006-03-13 04:40:11 +00:00
|
|
|
retval->buf.s = pemalloc(retval->buflen, retval->is_persistent);
|
|
|
|
memcpy(retval->buf.s, bucket->buf.s, retval->buflen);
|
2005-08-11 23:36:07 +00:00
|
|
|
}
|
2003-02-18 01:22:21 +00:00
|
|
|
|
|
|
|
retval->refcount = 1;
|
|
|
|
retval->own_buf = 1;
|
|
|
|
|
2003-02-18 01:39:26 +00:00
|
|
|
php_stream_bucket_delref(bucket TSRMLS_CC);
|
2003-02-18 01:22:21 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
if (in->buf_type == IS_UNICODE) {
|
|
|
|
(*left)->buf.u = safe_pemalloc(sizeof(UChar), length, 0, in->is_persistent);
|
|
|
|
(*left)->buflen = length;
|
|
|
|
memcpy((*left)->buf.u, in->buf.u, UBYTES(length));
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
(*right)->buflen = in->buflen - length;
|
|
|
|
(*right)->buf.u = pemalloc(UBYTES((*right)->buflen), in->is_persistent);
|
|
|
|
memcpy((*right)->buf.u, in->buf.u + length, UBYTES((*right)->buflen));
|
2005-08-11 23:36:07 +00:00
|
|
|
} else {
|
2006-03-13 04:40:11 +00:00
|
|
|
(*left)->buf.s = pemalloc(length, in->is_persistent);
|
|
|
|
(*left)->buflen = length;
|
|
|
|
memcpy((*left)->buf.s, in->buf.s, length);
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
(*right)->buflen = in->buflen - length;
|
|
|
|
(*right)->buf.s = pemalloc((*right)->buflen, in->is_persistent);
|
|
|
|
memcpy((*right)->buf.s, in->buf.s + length, (*right)->buflen);
|
2005-08-11 23:36:07 +00:00
|
|
|
}
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
(*left)->refcount = 1;
|
|
|
|
(*left)->own_buf = 1;
|
|
|
|
(*left)->is_persistent = in->is_persistent;
|
2006-03-13 04:40:11 +00:00
|
|
|
(*left)->buf_type = in->buf_type;
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
(*right)->refcount = 1;
|
|
|
|
(*right)->own_buf = 1;
|
|
|
|
(*right)->is_persistent = in->is_persistent;
|
2006-03-13 04:40:11 +00:00
|
|
|
(*right)->buf_type = in->buf_type;
|
2003-02-18 01:22:21 +00:00
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
|
|
exit_fail:
|
|
|
|
if (*right) {
|
2006-03-13 04:40:11 +00:00
|
|
|
if ((*right)->buf.v) {
|
|
|
|
pefree((*right)->buf.v, in->is_persistent);
|
2003-02-18 01:22:21 +00:00
|
|
|
}
|
|
|
|
pefree(*right, in->is_persistent);
|
|
|
|
}
|
|
|
|
if (*left) {
|
2006-03-13 04:40:11 +00:00
|
|
|
if ((*left)->buf.v) {
|
|
|
|
pefree((*left)->buf.v, in->is_persistent);
|
2003-02-18 01:22:21 +00:00
|
|
|
}
|
|
|
|
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) {
|
2006-03-13 04:40:11 +00:00
|
|
|
pefree(bucket->buf.v, bucket->is_persistent);
|
2003-02-18 01:22:21 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2006-01-10 16:14:45 +00:00
|
|
|
if (brigade->tail == bucket) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-02-16 22:19:28 +00:00
|
|
|
/* We allow very simple pattern matching for filter factories:
|
2003-10-28 21:52:59 +00:00
|
|
|
* if "convert.charset.utf-8/sjis" is requested, we search first for an exact
|
|
|
|
* match. If that fails, we try "convert.charset.*", then "convert.*"
|
2003-02-16 22:19:28 +00:00
|
|
|
* 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 */
|
2003-04-16 14:30:25 +00:00
|
|
|
PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
|
2003-02-16 22:19:28 +00:00
|
|
|
{
|
2004-06-21 21:08:05 +00:00
|
|
|
HashTable *filter_hash = (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
|
2006-05-19 10:23:43 +00:00
|
|
|
php_stream_filter_factory *factory = NULL;
|
2003-02-16 22:19:28 +00:00
|
|
|
php_stream_filter *filter = NULL;
|
|
|
|
int n;
|
|
|
|
char *period;
|
|
|
|
|
|
|
|
n = strlen(filtername);
|
|
|
|
|
2004-06-21 21:08:05 +00:00
|
|
|
if (SUCCESS == zend_hash_find(filter_hash, (char*)filtername, n, (void**)&factory)) {
|
2003-04-16 14:30:25 +00:00
|
|
|
filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
|
2003-10-28 21:52:59 +00:00
|
|
|
} else if ((period = strrchr(filtername, '.'))) {
|
2003-02-16 22:19:28 +00:00
|
|
|
/* try a wildcard */
|
2003-10-28 21:52:59 +00:00
|
|
|
char *wildname;
|
|
|
|
|
|
|
|
wildname = estrdup(filtername);
|
|
|
|
period = wildname + (period - filtername);
|
2003-10-28 23:29:16 +00:00
|
|
|
while (period && !filter) {
|
2003-10-28 21:52:59 +00:00
|
|
|
*period = '\0';
|
|
|
|
strcat(wildname, ".*");
|
2004-06-21 21:08:05 +00:00
|
|
|
if (SUCCESS == zend_hash_find(filter_hash, wildname, strlen(wildname), (void**)&factory)) {
|
2003-10-28 21:52:59 +00:00
|
|
|
filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
|
|
|
|
}
|
|
|
|
|
|
|
|
*period = '\0';
|
|
|
|
period = strrchr(wildname, '.');
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
2003-10-28 21:52:59 +00:00
|
|
|
efree(wildname);
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (filter == NULL) {
|
|
|
|
/* TODO: these need correct docrefs */
|
2006-04-13 18:14:14 +00:00
|
|
|
if (factory == NULL) {
|
2003-02-16 22:19:28 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to locate filter \"%s\"", filtername);
|
2006-04-13 18:14:14 +00:00
|
|
|
} else {
|
2003-02-16 22:19:28 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create or locate filter \"%s\"", filtername);
|
2006-04-13 18:14:14 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
2006-04-13 04:41:08 +00:00
|
|
|
|
|
|
|
filter->name = pestrdup(filtername, filter->is_persistent);
|
2003-02-16 22:19:28 +00:00
|
|
|
|
|
|
|
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);
|
2006-04-13 04:41:08 +00:00
|
|
|
pefree(filter->name, filter->is_persistent);
|
2003-02-16 22:19:28 +00:00
|
|
|
pefree(filter, filter->is_persistent);
|
|
|
|
}
|
|
|
|
|
2004-05-26 21:19:21 +00:00
|
|
|
PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
|
2003-02-16 22:19:28 +00:00
|
|
|
{
|
2003-02-18 01:22:21 +00:00
|
|
|
filter->next = chain->head;
|
2003-02-16 22:19:28 +00:00
|
|
|
filter->prev = NULL;
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
if (chain->head) {
|
|
|
|
chain->head->prev = filter;
|
2003-02-16 22:19:28 +00:00
|
|
|
} else {
|
2003-02-18 01:22:21 +00:00
|
|
|
chain->tail = filter;
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
2003-02-18 01:22:21 +00:00
|
|
|
chain->head = filter;
|
|
|
|
filter->chain = chain;
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
|
|
|
|
2004-05-26 21:19:21 +00:00
|
|
|
PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
|
2003-02-16 22:19:28 +00:00
|
|
|
{
|
2004-03-31 23:48:59 +00:00
|
|
|
php_stream *stream = chain->stream;
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
filter->prev = chain->tail;
|
2003-02-16 22:19:28 +00:00
|
|
|
filter->next = NULL;
|
2003-02-18 01:22:21 +00:00
|
|
|
if (chain->tail) {
|
|
|
|
chain->tail->next = filter;
|
2003-02-16 22:19:28 +00:00
|
|
|
} else {
|
2003-02-18 01:22:21 +00:00
|
|
|
chain->head = filter;
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
2003-02-18 01:22:21 +00:00
|
|
|
chain->tail = filter;
|
|
|
|
filter->chain = chain;
|
2004-03-31 23:48:59 +00:00
|
|
|
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if (&(stream->readfilters) == chain) {
|
2004-03-31 23:48:59 +00:00
|
|
|
/* Let's going ahead and wind anything in the buffer through this filter */
|
2006-03-13 04:40:11 +00:00
|
|
|
php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
|
|
|
|
php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out;
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
php_stream_filter_status_t status = PSFS_FEED_ME;
|
2004-03-31 23:48:59 +00:00
|
|
|
php_stream_bucket *bucket;
|
2006-03-13 04:40:11 +00:00
|
|
|
size_t consumed = 0;
|
2004-03-31 23:48:59 +00:00
|
|
|
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if ((stream->writepos - stream->readpos) > 0) {
|
|
|
|
if (stream->readbuf_type == IS_UNICODE) {
|
|
|
|
bucket = php_stream_bucket_new_unicode(stream, stream->readbuf.u + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC);
|
|
|
|
} else {
|
|
|
|
bucket = php_stream_bucket_new(stream, stream->readbuf.s + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC);
|
|
|
|
}
|
|
|
|
php_stream_bucket_append(brig_inp, bucket TSRMLS_CC);
|
|
|
|
status = filter->fops->filter(stream, filter, brig_inp, brig_outp, &consumed, PSFS_FLAG_NORMAL TSRMLS_CC);
|
2004-03-31 23:48:59 +00:00
|
|
|
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if (stream->readpos + consumed > stream->writepos || consumed < 0) {
|
|
|
|
/* No behaving filter should cause this. */
|
|
|
|
status = PSFS_ERR_FATAL;
|
|
|
|
}
|
2006-03-13 04:40:11 +00:00
|
|
|
}
|
2005-08-11 23:36:07 +00:00
|
|
|
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if (status == PSFS_ERR_FATAL) {
|
|
|
|
/* If this first cycle simply fails then there's something wrong with the filter.
|
|
|
|
Pull the filter off the chain and leave the read buffer alone. */
|
|
|
|
if (chain->head == filter) {
|
|
|
|
chain->head = NULL;
|
|
|
|
chain->tail = NULL;
|
|
|
|
} else {
|
|
|
|
filter->prev->next = NULL;
|
|
|
|
chain->tail = filter->prev;
|
|
|
|
}
|
|
|
|
php_stream_bucket_unlink(bucket TSRMLS_CC);
|
|
|
|
php_stream_bucket_delref(bucket TSRMLS_CC);
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter failed to process pre-buffered data. Not adding to filterchain.");
|
|
|
|
} else {
|
|
|
|
/* This filter addition may change the readbuffer type.
|
|
|
|
Since all the previously held data is in the bucket brigade,
|
|
|
|
we can reappropriate the buffer that already exists (if one does) */
|
|
|
|
if (stream->readbuf_type == IS_UNICODE && (filter->fops->flags & PSFO_FLAG_OUTPUTS_UNICODE) == 0) {
|
|
|
|
/* Buffer is currently based on unicode characters, but filter only outputs STRING adjust counting */
|
|
|
|
stream->readbuf_type = IS_STRING;
|
|
|
|
stream->readbuflen *= UBYTES(1);
|
|
|
|
} else if (stream->readbuf_type == IS_STRING && (filter->fops->flags & PSFO_FLAG_OUTPUTS_STRING) == 0) {
|
|
|
|
/* Buffer is currently based on binary characters, but filter only outputs UNICODE adjust counting */
|
|
|
|
stream->readbuf_type = IS_UNICODE;
|
|
|
|
stream->readbuflen /= UBYTES(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status == PSFS_FEED_ME) {
|
2004-03-31 23:48:59 +00:00
|
|
|
/* We don't actually need data yet,
|
|
|
|
leave this filter in a feed me state until data is needed.
|
|
|
|
Reset stream's internal read buffer since the filter is "holding" it. */
|
2006-03-13 04:40:11 +00:00
|
|
|
stream->readpos = 0;
|
|
|
|
stream->writepos = 0;
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
} else if (status == PSFS_PASS_ON) {
|
2006-03-13 04:40:11 +00:00
|
|
|
/* Put any filtered data onto the readbuffer stack.
|
|
|
|
Previously read data has been at least partially consumed. */
|
|
|
|
stream->readpos += consumed;
|
|
|
|
|
|
|
|
if (stream->writepos == stream->readpos) {
|
|
|
|
/* Entirely consumed */
|
|
|
|
stream->writepos = 0;
|
|
|
|
stream->readpos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (brig_outp->head) {
|
|
|
|
bucket = brig_outp->head;
|
|
|
|
|
|
|
|
/* Convert for stream type */
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if (bucket->buf_type != stream->readbuf_type) {
|
|
|
|
/* Stream expects different type than bucket contains, convert slopily */
|
|
|
|
php_stream_bucket_convert_notranscode(bucket, stream->readbuf_type);
|
2006-03-13 04:40:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Grow buffer to hold this bucket if need be.
|
|
|
|
TODO: See warning in main/stream/streams.c::php_stream_fill_read_buffer */
|
|
|
|
if (stream->readbuflen - stream->writepos < bucket->buflen) {
|
|
|
|
stream->readbuflen += bucket->buflen;
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
stream->readbuf.v = perealloc(stream->readbuf.v, PS_ULEN(stream->readbuf_type == IS_UNICODE, stream->readbuflen), stream->is_persistent);
|
2006-03-13 04:40:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Append to readbuf */
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if (stream->readbuf_type == IS_UNICODE) {
|
2006-03-13 04:40:11 +00:00
|
|
|
memcpy(stream->readbuf.u + stream->writepos, bucket->buf.u, UBYTES(bucket->buflen));
|
|
|
|
} else {
|
|
|
|
memcpy(stream->readbuf.s + stream->writepos, bucket->buf.s, bucket->buflen);
|
|
|
|
}
|
|
|
|
stream->writepos += bucket->buflen;
|
|
|
|
|
|
|
|
php_stream_bucket_unlink(bucket TSRMLS_CC);
|
|
|
|
php_stream_bucket_delref(bucket TSRMLS_CC);
|
|
|
|
}
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
}
|
2005-08-11 23:36:07 +00:00
|
|
|
}
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
} /* end of readfilters specific code */
|
2005-08-11 23:36:07 +00:00
|
|
|
}
|
2004-03-31 23:48:59 +00:00
|
|
|
|
2005-08-11 23:36:07 +00:00
|
|
|
PHPAPI int _php_stream_filter_check_chain(php_stream_filter_chain *chain TSRMLS_DC)
|
|
|
|
{
|
|
|
|
php_stream_filter *filter;
|
|
|
|
long last_output = PSFO_FLAG_OUTPUTS_ANY;
|
2004-03-31 23:48:59 +00:00
|
|
|
|
2005-08-11 23:36:07 +00:00
|
|
|
for(filter = chain->head; filter; filter = filter->next) {
|
|
|
|
if ((((filter->fops->flags & PSFO_FLAG_ACCEPT_MASK) << PSFO_FLAG_ACCEPT_SHIFT) & last_output) == 0) {
|
|
|
|
/* Nothing which the last filter outputs is accepted by this filter */
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
if (filter->fops->flags & PSFO_FLAG_OUTPUTS_SAME) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (filter->fops->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) {
|
|
|
|
last_output = ((last_output & PSFO_FLAG_OUTPUTS_STRING) ? PSFO_FLAG_OUTPUTS_UNICODE : 0) |
|
|
|
|
((last_output & PSFO_FLAG_OUTPUTS_UNICODE) ? PSFO_FLAG_OUTPUTS_STRING : 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
last_output = filter->fops->flags & PSFO_FLAG_OUTPUTS_ANY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
PHPAPI int _php_stream_filter_output_prefer_unicode(php_stream_filter *filter TSRMLS_DC)
|
|
|
|
{
|
|
|
|
php_stream_filter_chain *chain = filter->chain;
|
|
|
|
php_stream_filter *f;
|
|
|
|
int inverted = 0;
|
2006-01-12 19:21:36 +00:00
|
|
|
int preferred = (chain == &chain->stream->readfilters ? 1 : 0);
|
2005-08-11 23:36:07 +00:00
|
|
|
|
|
|
|
for (f = filter->next; f ; f = f->next) {
|
|
|
|
if ((f->fops->flags & PSFO_FLAG_ACCEPTS_STRING) == 0) {
|
|
|
|
return inverted ^= 1;
|
|
|
|
}
|
|
|
|
if ((f->fops->flags & PSFO_FLAG_ACCEPTS_UNICODE) == 0) {
|
|
|
|
return inverted;
|
|
|
|
}
|
|
|
|
if (((f->fops->flags & PSFO_FLAG_OUTPUTS_SAME) == 0) &&
|
|
|
|
((f->fops->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) == 0)) {
|
|
|
|
/* Input type for next filter won't effect output -- Might as well go for unicode */
|
|
|
|
return inverted ^ 1;
|
|
|
|
}
|
|
|
|
if (f->fops->flags & PSFO_FLAG_OUTPUTS_SAME) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (f->fops->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) {
|
|
|
|
inverted ^= 1;
|
|
|
|
continue;
|
2004-03-31 23:48:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-11 23:36:07 +00:00
|
|
|
return preferred ^ inverted;
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
|
|
|
|
2006-04-12 22:40:56 +00:00
|
|
|
PHPAPI int _php_stream_filter_product(php_stream_filter_chain *chain, int type TSRMLS_DC)
|
|
|
|
{
|
|
|
|
php_stream_filter *f;
|
|
|
|
|
|
|
|
for (f = chain->head; f; f = f->next) {
|
|
|
|
if ((type == IS_STRING && (f->fops->flags & PSFO_FLAG_ACCEPTS_STRING) == 0) ||
|
|
|
|
(type == IS_UNICODE && (f->fops->flags & PSFO_FLAG_ACCEPTS_UNICODE) == 0)) {
|
|
|
|
/* At some point, the type produced conflicts with the type accepted */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f->fops->flags & PSFO_FLAG_OUTPUTS_OPPOSITE) {
|
|
|
|
type = (type == IS_STRING) ? IS_UNICODE : IS_STRING;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((f->fops->flags & PSFO_FLAG_OUTPUTS_SAME) ||
|
|
|
|
(f->fops->flags & PSFO_FLAG_OUTPUTS_ANY)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (f->fops->flags & PSFO_FLAG_OUTPUTS_UNICODE) {
|
|
|
|
type = IS_UNICODE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
type = IS_STRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2004-09-14 03:48:17 +00:00
|
|
|
PHPAPI int _php_stream_filter_flush(php_stream_filter *filter, int finish TSRMLS_DC)
|
|
|
|
{
|
|
|
|
php_stream_bucket_brigade brig_a = { NULL, NULL }, brig_b = { NULL, NULL }, *inp = &brig_a, *outp = &brig_b, *brig_temp;
|
|
|
|
php_stream_bucket *bucket;
|
|
|
|
php_stream_filter_chain *chain;
|
|
|
|
php_stream_filter *current;
|
|
|
|
php_stream *stream;
|
|
|
|
size_t flushed_size = 0;
|
|
|
|
long flags = (finish ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC);
|
|
|
|
|
|
|
|
if (!filter->chain || !filter->chain->stream) {
|
|
|
|
/* Filter is not attached to a chain, or chain is somehow not part of a stream */
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
chain = filter->chain;
|
|
|
|
stream = chain->stream;
|
|
|
|
|
|
|
|
for(current = filter; current; current = current->next) {
|
|
|
|
php_stream_filter_status_t status;
|
|
|
|
|
|
|
|
status = filter->fops->filter(stream, filter, inp, outp, NULL, flags TSRMLS_CC);
|
|
|
|
if (status == PSFS_FEED_ME) {
|
|
|
|
/* We've flushed the data far enough */
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
if (status == PSFS_ERR_FATAL) {
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
/* Otherwise we have data available to PASS_ON
|
|
|
|
Swap the brigades and continue */
|
|
|
|
brig_temp = inp;
|
|
|
|
inp = outp;
|
|
|
|
outp = brig_temp;
|
|
|
|
outp->head = NULL;
|
|
|
|
outp->tail = NULL;
|
|
|
|
|
|
|
|
flags = PSFS_FLAG_NORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Last filter returned data via PSFS_PASS_ON
|
|
|
|
Do something with it */
|
|
|
|
|
|
|
|
for(bucket = inp->head; bucket; bucket = bucket->next) {
|
2006-03-13 04:40:11 +00:00
|
|
|
flushed_size += bucket->buflen;
|
2004-09-14 03:48:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flushed_size == 0) {
|
|
|
|
/* Unlikely, but possible */
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chain == &(stream->readfilters)) {
|
2006-03-13 04:40:11 +00:00
|
|
|
/* Dump any newly flushed data to the read buffer */
|
|
|
|
if (stream->readpos > stream->chunk_size) {
|
|
|
|
/* Back the buffer up */
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
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));
|
2006-03-13 04:40:11 +00:00
|
|
|
stream->writepos -= stream->readpos;
|
|
|
|
stream->readpos = 0;
|
|
|
|
}
|
|
|
|
if (flushed_size > (stream->readbuflen - stream->writepos)) {
|
|
|
|
/* Grow the buffer */
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
stream->readbuf.v = perealloc(stream->readbuf.v, PS_ULEN(stream->readbuf_type == IS_UNICODE, stream->writepos + flushed_size + stream->chunk_size), stream->is_persistent);
|
2006-03-13 04:40:11 +00:00
|
|
|
}
|
|
|
|
while ((bucket = inp->head)) {
|
|
|
|
/* Convert if necessary */
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if (bucket->buf_type != stream->readbuf_type) {
|
|
|
|
/* Stream expects different type than what's in bucket, convert slopily */
|
|
|
|
php_stream_bucket_convert_notranscode(bucket, stream->readbuf_type);
|
2005-08-11 23:36:07 +00:00
|
|
|
}
|
2006-03-13 04:40:11 +00:00
|
|
|
|
|
|
|
/* Append to readbuf */
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if (stream->readbuf_type == IS_UNICODE) {
|
2006-03-13 04:40:11 +00:00
|
|
|
memcpy(stream->readbuf.u + stream->writepos, bucket->buf.u, UBYTES(bucket->buflen));
|
|
|
|
} else {
|
|
|
|
memcpy(stream->readbuf.s + stream->writepos, bucket->buf.s, bucket->buflen);
|
|
|
|
}
|
|
|
|
stream->writepos += bucket->buflen;
|
|
|
|
php_stream_bucket_unlink(bucket TSRMLS_CC);
|
|
|
|
php_stream_bucket_delref(bucket TSRMLS_CC);
|
2004-09-14 03:48:17 +00:00
|
|
|
}
|
2006-03-13 04:40:11 +00:00
|
|
|
|
|
|
|
|
2004-09-14 03:48:17 +00:00
|
|
|
} else if (chain == &(stream->writefilters)) {
|
|
|
|
/* Send flushed data to the stream */
|
|
|
|
while ((bucket = inp->head)) {
|
2006-03-13 04:40:11 +00:00
|
|
|
/* Convert if necessary */
|
|
|
|
if (bucket->buf_type == IS_UNICODE) {
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
/* Force data to binary, adjusting buflen */
|
|
|
|
php_stream_bucket_convert_notranscode(bucket, IS_STRING);
|
2005-08-11 23:36:07 +00:00
|
|
|
}
|
2006-03-13 04:40:11 +00:00
|
|
|
|
|
|
|
/* Must be binary by this point */
|
|
|
|
stream->ops->write(stream, bucket->buf.s, bucket->buflen TSRMLS_CC);
|
|
|
|
|
2004-09-14 03:48:17 +00:00
|
|
|
php_stream_bucket_unlink(bucket TSRMLS_CC);
|
|
|
|
php_stream_bucket_delref(bucket TSRMLS_CC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor TSRMLS_DC)
|
2003-02-16 22:19:28 +00:00
|
|
|
{
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
/* UTODO: Figure out a sane way to "defilter" so that unicode converters can be swapped around
|
|
|
|
For now, at least fopen(,'b') + stream_encoding($fp, 'charset') works since there's nothing to remove */
|
|
|
|
|
2003-02-16 22:19:28 +00:00
|
|
|
if (filter->prev) {
|
|
|
|
filter->prev->next = filter->next;
|
|
|
|
} else {
|
2003-02-18 01:22:21 +00:00
|
|
|
filter->chain->head = filter->next;
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
|
|
|
if (filter->next) {
|
|
|
|
filter->next->prev = filter->prev;
|
|
|
|
} else {
|
2003-02-18 01:22:21 +00:00
|
|
|
filter->chain->tail = filter->prev;
|
2003-02-16 22:19:28 +00:00
|
|
|
}
|
2005-03-29 04:02:03 +00:00
|
|
|
|
|
|
|
if (filter->rsrc_id > 0) {
|
|
|
|
zend_list_delete(filter->rsrc_id);
|
|
|
|
}
|
|
|
|
|
2003-02-16 22:19:28 +00:00
|
|
|
if (call_dtor) {
|
|
|
|
php_stream_filter_free(filter TSRMLS_CC);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
PHPAPI int _php_stream_bucket_convert(php_stream_bucket *bucket, unsigned char type, UConverter *conv TSRMLS_DC)
|
2005-08-11 23:36:07 +00:00
|
|
|
{
|
2006-03-13 04:40:11 +00:00
|
|
|
if (bucket->buf_type == type) {
|
2005-08-11 23:36:07 +00:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
if (conv) {
|
|
|
|
/* transcode current type using provided converter */
|
|
|
|
if (type == IS_UNICODE) {
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
UChar *dest;
|
|
|
|
int destlen;
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-08-08 16:59:11 +00:00
|
|
|
zend_string_to_unicode_ex(conv, &dest, &destlen, bucket->buf.s, bucket->buflen, &status);
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
if (bucket->own_buf) {
|
|
|
|
pefree(bucket->buf.s, bucket->is_persistent);
|
|
|
|
}
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-08-08 16:59:11 +00:00
|
|
|
/* Might be dangerous, double check this (or, better, get a persistent version of zend_string_to_unicode_ex() */
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->is_persistent = 0;
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->buf_type = IS_UNICODE;
|
|
|
|
bucket->buf.u = dest;
|
|
|
|
bucket->buflen = destlen;
|
|
|
|
bucket->own_buf = 1;
|
|
|
|
return SUCCESS;
|
|
|
|
} else {
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
char *dest;
|
2006-03-24 20:21:48 +00:00
|
|
|
int destlen, num_conv;
|
|
|
|
|
2006-08-08 16:59:11 +00:00
|
|
|
num_conv = zend_unicode_to_string_ex(conv, &dest, &destlen, bucket->buf.u, bucket->buflen, &status);
|
2006-03-24 20:21:48 +00:00
|
|
|
if (U_FAILURE(status)) {
|
2006-03-26 06:19:24 +00:00
|
|
|
int32_t offset = u_countChar32(bucket->buf.u, num_conv);
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-06-21 20:17:21 +00:00
|
|
|
zend_raise_conversion_error_ex("Could not convert Unicode string to binary string", conv, ZEND_FROM_UNICODE, offset TSRMLS_CC);
|
2006-03-24 20:21:48 +00:00
|
|
|
}
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
if (bucket->own_buf) {
|
|
|
|
pefree(bucket->buf.u, bucket->is_persistent);
|
|
|
|
}
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
/* See above */
|
|
|
|
bucket->is_persistent = 0;
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->buf_type = IS_STRING;
|
|
|
|
bucket->buf.s = dest;
|
|
|
|
bucket->buflen = destlen;
|
|
|
|
bucket->own_buf = 1;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Convert without transcode, usually a bad idea as it creates ugly data,
|
|
|
|
When binary streams receive unicode data (because of filters or writing unicode strings)
|
|
|
|
this is the only option */
|
|
|
|
if (type == IS_UNICODE) {
|
|
|
|
if (bucket->buflen == 0) {
|
|
|
|
/* Shortcut conversion for empty buckets */
|
|
|
|
if (bucket->own_buf) {
|
|
|
|
pefree(bucket->buf.s, bucket->is_persistent);
|
|
|
|
}
|
2006-03-24 21:25:44 +00:00
|
|
|
bucket->buf_type = IS_UNICODE;
|
|
|
|
bucket->buf.u = EMPTY_STR;
|
2006-03-13 04:40:11 +00:00
|
|
|
bucket->own_buf = 0;
|
|
|
|
bucket->buflen = 0;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
2005-08-11 23:36:07 +00:00
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
if (bucket->own_buf) {
|
|
|
|
/* one UChar padding for partial units, one more for terminating NULL */
|
|
|
|
bucket->buf.s = perealloc(bucket->buf.s, bucket->buflen + UBYTES(2), bucket->is_persistent);
|
|
|
|
} else {
|
|
|
|
int destlen = ceil(bucket->buflen / sizeof(UChar));
|
|
|
|
UChar *dest = pemalloc(UBYTES(destlen + 2), bucket->is_persistent);
|
|
|
|
memcpy(dest, bucket->buf.s, bucket->buflen);
|
|
|
|
bucket->buf.u = dest;
|
|
|
|
bucket->own_buf = 1;
|
|
|
|
}
|
|
|
|
memset(bucket->buf.s + bucket->buflen, 0, UBYTES(2));
|
|
|
|
bucket->buf_type = IS_UNICODE;
|
|
|
|
bucket->buflen = ceil(bucket->buflen / sizeof(UChar));
|
|
|
|
return SUCCESS;
|
|
|
|
} else { /* IS_STRING */
|
|
|
|
bucket->buf_type = IS_STRING;
|
|
|
|
bucket->buflen *= 2;
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
2005-08-11 23:36:07 +00:00
|
|
|
}
|
|
|
|
|
2006-03-13 04:40:11 +00:00
|
|
|
/* Never reached */
|
|
|
|
return FAILURE;
|
2005-08-11 23:36:07 +00:00
|
|
|
}
|
|
|
|
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
PHPAPI int _php_stream_encoding_apply(php_stream *stream, int writechain, const char *encoding, uint16_t error_mode, UChar *subst TSRMLS_DC)
|
|
|
|
{
|
|
|
|
int encoding_len = strlen(encoding);
|
|
|
|
int buflen = sizeof("unicode.from.") + encoding_len - 1; /* might be "to", but "from" is long enough for both */
|
|
|
|
char *buf = emalloc(buflen + 1);
|
|
|
|
php_stream_filter *filter;
|
|
|
|
zval *filterparams;
|
|
|
|
|
|
|
|
if (writechain) {
|
|
|
|
memcpy(buf, "unicode.to.", sizeof("unicode.to.") - 1);
|
|
|
|
memcpy(buf + sizeof("unicode.to.") - 1, encoding, encoding_len + 1);
|
|
|
|
} else {
|
|
|
|
memcpy(buf, "unicode.from.", sizeof("unicode.from.") - 1);
|
|
|
|
memcpy(buf + sizeof("unicode.from.") - 1, encoding, encoding_len + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ALLOC_INIT_ZVAL(filterparams);
|
|
|
|
array_init(filterparams);
|
2006-09-19 10:38:31 +00:00
|
|
|
add_ascii_assoc_long(filterparams, "error_mode", error_mode);
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
if (subst) {
|
2006-09-19 10:38:31 +00:00
|
|
|
add_ascii_assoc_unicode(filterparams, "subst_char", subst, 1);
|
Another (and hopefully last) major streams commit.
This moves unicode conversion to the filter layer
(rather than at the lower streams layer)
unicode_filter.c has been moved from ext/unicode to main/streams
as it's an integral part of the streams unicode conversion process.
There are now three ways to set encoding on a stream:
(1) By context
$ctx = stream_context_create(NULL,array('encoding'=>'latin1'));
$fp = fopen('somefile', 'r+t', false, $ctx);
(2) By stream_encoding()
$fp = fopen('somefile', 'r+');
stream_encoding($fp, 'latin1');
(3) By filter
$fp = fopen('somefile', 'r+');
stream_filter_append($fp, 'unicode.from.latin1', STREAM_FILTER_READ);
stream_filter_append($fp, 'unicode.to.latin1', STREAM_FILTER_WRITE);
Note: Methods 1 and 2 are convenience wrappers around method 3.
2006-03-29 01:20:43 +00:00
|
|
|
}
|
|
|
|
filter = php_stream_filter_create(buf, filterparams, php_stream_is_persistent(stream) TSRMLS_CC);
|
|
|
|
efree(buf);
|
|
|
|
zval_ptr_dtor(&filterparams);
|
|
|
|
|
|
|
|
if (!filter) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to apply encoding for charset: %s\n", encoding);
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
php_stream_filter_append(writechain ? &stream->writefilters : &stream->readfilters, filter);
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-02-16 22:19:28 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|