From: Sara Golemon Date: Tue, 20 Jul 2004 05:26:33 +0000 (+0000) Subject: Add bz2 stream filter support X-Git-Tag: PRE_ZEND_VM_DISPATCH_PATCH~435 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f92797f4e0b6a9bed77504a99c2658d567e078c6;p=php Add bz2 stream filter support --- diff --git a/NEWS b/NEWS index 2b1153f856..171bd70df3 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ PHP NEWS - Fixed bug #29109 (SoapFault exception: [WSDL] Out of memory). (Dmitry) - Fixed bug #29061 (soap extension segfaults). (Dmitry) - Added zlib stream filter suport. (Sara) +- Added bz2 stream filter support. (Sara) - Changed the implementation of TRUE, FALSE, and NULL from constants to keywords. (Marcus) - Fixed ZTS destruction. (Marcus) diff --git a/ext/bz2/bz2.c b/ext/bz2/bz2.c index 515197f9d3..e51c993b5a 100644 --- a/ext/bz2/bz2.c +++ b/ext/bz2/bz2.c @@ -243,13 +243,14 @@ static void php_bz2_error(INTERNAL_FUNCTION_PARAMETERS, int); PHP_MINIT_FUNCTION(bz2) { php_register_url_stream_wrapper("compress.bzip2", &php_stream_bzip2_wrapper TSRMLS_CC); - + php_stream_filter_register_factory("bzip2.*", &php_bz2_filter_factory TSRMLS_CC); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(bz2) { php_unregister_url_stream_wrapper("compress.bzip2" TSRMLS_CC); + php_stream_filter_unregister_factory("bzip2.*" TSRMLS_CC); return SUCCESS; } @@ -258,6 +259,8 @@ PHP_MINFO_FUNCTION(bz2) { php_info_print_table_start(); php_info_print_table_row(2, "BZip2 Support", "Enabled"); + php_info_print_table_row(2, "Stream Wrapper support", "compress.bz2://"); + php_info_print_table_row(2, "Stream Filter support", "bzip2.decompress, bzip2.compress"); php_info_print_table_row(2, "BZip2 Version", (char *) BZ2_bzlibVersion()); php_info_print_table_end(); } diff --git a/ext/bz2/bz2.dsp b/ext/bz2/bz2.dsp index ebe183cca8..0e78ee7845 100644 --- a/ext/bz2/bz2.dsp +++ b/ext/bz2/bz2.dsp @@ -1,108 +1,112 @@ -# Microsoft Developer Studio Project File - Name="bz2" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=bz2 - Win32 Debug_TS -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "bz2.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "bz2.mak" CFG="bz2 - Win32 Debug_TS" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "bz2 - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "bz2 - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "bz2 - Win32 Release_TS" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release_TS" -# PROP BASE Intermediate_Dir "Release_TS" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release_TS" -# PROP Intermediate_Dir "Release_TS" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZ2_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\..\php_build\includes" /D ZEND_DEBUG=0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "COMPILE_DL_BZ2" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_BZ2=1 /D "PHP_BZ2_EXPORTS" /FR /YX /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x407 /d "NDEBUG" -# ADD RSC /l 0x407 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 libbz2.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php5ts.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_bz2.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline" /libpath:"..\..\..\php_build\release" - -!ELSEIF "$(CFG)" == "bz2 - Win32 Debug_TS" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug_TS" -# PROP BASE Intermediate_Dir "Debug_TS" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug_TS" -# PROP Intermediate_Dir "Debug_TS" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZ2_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\..\php_build\includes" /D ZEND_DEBUG=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "COMPILE_DL_BZ2" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_BZ2=1 /D "PHP_BZ2_EXPORTS" /YX /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x407 /d "_DEBUG" -# ADD RSC /l 0x407 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 php5ts_debug.lib libbz2.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_bz2.dll" /pdbtype:sept /libpath:"..\..\Debug_TS" /libpath:"..\..\..\php_build\release" - -!ENDIF - -# Begin Target - -# Name "bz2 - Win32 Release_TS" -# Name "bz2 - Win32 Debug_TS" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\bz2.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\php_bz2.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="bz2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=bz2 - Win32 Debug_TS +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bz2.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bz2.mak" CFG="bz2 - Win32 Debug_TS" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bz2 - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "bz2 - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bz2 - Win32 Release_TS" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_TS" +# PROP BASE Intermediate_Dir "Release_TS" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_TS" +# PROP Intermediate_Dir "Release_TS" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZ2_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\..\php_build\includes" /D ZEND_DEBUG=0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "COMPILE_DL_BZ2" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_BZ2=1 /D "PHP_BZ2_EXPORTS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 libbz2.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php5ts.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_bz2.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline" /libpath:"..\..\..\php_build\release" + +!ELSEIF "$(CFG)" == "bz2 - Win32 Debug_TS" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_TS" +# PROP BASE Intermediate_Dir "Debug_TS" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_TS" +# PROP Intermediate_Dir "Debug_TS" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZ2_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\..\php_build\includes" /D ZEND_DEBUG=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "COMPILE_DL_BZ2" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_BZ2=1 /D "PHP_BZ2_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 php5ts_debug.lib libbz2.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_bz2.dll" /pdbtype:sept /libpath:"..\..\Debug_TS" /libpath:"..\..\..\php_build\release" + +!ENDIF + +# Begin Target + +# Name "bz2 - Win32 Release_TS" +# Name "bz2 - Win32 Debug_TS" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\bz2.c +# End Source File +# Begin Source File + +SOURCE=.\bz2_filter.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\php_bz2.h +# End Source File +# End Group +# End Target +# End Project diff --git a/ext/bz2/bz2_filter.c b/ext/bz2/bz2_filter.c new file mode 100644 index 0000000000..87990c78a1 --- /dev/null +++ b/ext/bz2/bz2_filter.c @@ -0,0 +1,369 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.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: Sara Golemon (pollita@php.net) | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "php.h" +#include "php_bz2.h" + +/* {{{ data structure */ + +typedef struct _php_bz2_filter_data { + int persistent; + bz_stream strm; + char *inbuf; + size_t inbuf_len; + char *outbuf; + size_t outbuf_len; +} php_bz2_filter_data; + +/* }}} */ + +/* {{{ Memory management wrappers */ + +static void *php_bz2_alloc(void *opaque, int items, int size) +{ + return (void *)pemalloc(items * size, ((php_bz2_filter_data*)opaque)->persistent); +} + +static void php_bz2_free(void *opaque, void *address) +{ + pefree((void *)address, ((php_bz2_filter_data*)opaque)->persistent); +} +/* }}} */ + +/* {{{ bzip2.decompress filter implementation */ + +static php_stream_filter_status_t php_bz2_decompress_filter( + php_stream *stream, + php_stream_filter *thisfilter, + php_stream_bucket_brigade *buckets_in, + php_stream_bucket_brigade *buckets_out, + size_t *bytes_consumed, + int flags + TSRMLS_DC) +{ + php_bz2_filter_data *data; + php_stream_bucket *bucket; + size_t consumed = 0; + int status; + php_stream_filter_status_t exit_status = PSFS_FEED_ME; + bz_stream *streamp; + + if (!thisfilter || !thisfilter->abstract) { + /* Should never happen */ + return PSFS_ERR_FATAL; + } + + data = (php_bz2_filter_data *)(thisfilter->abstract); + streamp = &(data->strm); + + while (buckets_in->head) { + size_t bin = 0, desired; + + bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); + while (bin < bucket->buflen) { + desired = bucket->buflen - bin; + if (desired > data->inbuf_len) { + desired = data->inbuf_len; + } + memcpy(data->strm.next_in, bucket->buf + bin, desired); + data->strm.avail_in = desired; + + status = BZ2_bzDecompress(&(data->strm)); + if (status != BZ_OK && status != BZ_STREAM_END) { + /* Something bad happened */ + php_stream_bucket_delref(bucket TSRMLS_CC); + return PSFS_ERR_FATAL; + } + desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */ + data->strm.next_in = data->inbuf; + data->strm.avail_in = 0; + consumed += desired; + bin += desired; + + if (data->strm.avail_out < data->outbuf_len) { + php_stream_bucket *out_bucket; + size_t bucketlen = data->outbuf_len - data->strm.avail_out; + out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC); + php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC); + data->strm.avail_out = data->outbuf_len; + data->strm.next_out = data->outbuf; + exit_status = PSFS_PASS_ON; + } + } + php_stream_bucket_delref(bucket TSRMLS_CC); + } + + if (flags & PSFS_FLAG_FLUSH_CLOSE) { + /* Spit it out! */ + status = BZ_OK; + while (status == BZ_OK) { + status = BZ2_bzDecompress(&(data->strm)); + if (data->strm.avail_out < data->outbuf_len) { + size_t bucketlen = data->outbuf_len - data->strm.avail_out; + + bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC); + php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); + data->strm.avail_out = data->outbuf_len; + data->strm.next_out = data->outbuf; + exit_status = PSFS_PASS_ON; + } + } + } + + if (bytes_consumed) { + *bytes_consumed = consumed; + } + + return exit_status; +} + +static void php_bz2_decompress_dtor(php_stream_filter *thisfilter TSRMLS_DC) +{ + if (thisfilter && thisfilter->abstract) { + php_bz2_filter_data *data = thisfilter->abstract; + BZ2_bzDecompressEnd(&(data->strm)); + pefree(data->inbuf, data->persistent); + pefree(data->outbuf, data->persistent); + pefree(data, data->persistent); + } +} + +static php_stream_filter_ops php_bz2_decompress_ops = { + php_bz2_decompress_filter, + php_bz2_decompress_dtor, + "bzip2.decompress" +}; +/* }}} */ + +/* {{{ bzip2.compress filter implementation */ + +static php_stream_filter_status_t php_bz2_compress_filter( + php_stream *stream, + php_stream_filter *thisfilter, + php_stream_bucket_brigade *buckets_in, + php_stream_bucket_brigade *buckets_out, + size_t *bytes_consumed, + int flags + TSRMLS_DC) +{ + php_bz2_filter_data *data; + php_stream_bucket *bucket; + size_t consumed = 0; + int status; + php_stream_filter_status_t exit_status = PSFS_FEED_ME; + bz_stream *streamp; + + if (!thisfilter || !thisfilter->abstract) { + /* Should never happen */ + return PSFS_ERR_FATAL; + } + + data = (php_bz2_filter_data *)(thisfilter->abstract); + streamp = &(data->strm); + + while (buckets_in->head) { + size_t bin = 0, desired; + + bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC); + + while (bin < bucket->buflen) { + desired = bucket->buflen - bin; + if (desired > data->inbuf_len) { + desired = data->inbuf_len; + } + memcpy(data->strm.next_in, bucket->buf + bin, desired); + data->strm.avail_in = desired; + + status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN)); + if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) { + /* Something bad happened */ + php_stream_bucket_delref(bucket TSRMLS_CC); + return PSFS_ERR_FATAL; + } + desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */ + data->strm.next_in = data->inbuf; + data->strm.avail_in = 0; + consumed += desired; + bin += desired; + + if (data->strm.avail_out < data->outbuf_len) { + php_stream_bucket *out_bucket; + size_t bucketlen = data->outbuf_len - data->strm.avail_out; + + out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC); + php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC); + data->strm.avail_out = data->outbuf_len; + data->strm.next_out = data->outbuf; + exit_status = PSFS_PASS_ON; + } + } + php_stream_bucket_delref(bucket TSRMLS_CC); + } + + if (flags & PSFS_FLAG_FLUSH_CLOSE) { + /* Spit it out! */ + status = BZ_OUTBUFF_FULL; + while (status == BZ_OUTBUFF_FULL) { + status = BZ2_bzCompress(&(data->strm), BZ_FINISH); + if (data->strm.avail_out < data->outbuf_len) { + size_t bucketlen = data->outbuf_len - data->strm.avail_out; + + bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC); + php_stream_bucket_append(buckets_out, bucket TSRMLS_CC); + data->strm.avail_out = data->outbuf_len; + data->strm.next_out = data->outbuf; + exit_status = PSFS_PASS_ON; + } + } + } + + if (bytes_consumed) { + *bytes_consumed = consumed; + } + return exit_status; +} + +static void php_bz2_compress_dtor(php_stream_filter *thisfilter TSRMLS_DC) +{ + if (thisfilter && thisfilter->abstract) { + php_bz2_filter_data *data = thisfilter->abstract; + BZ2_bzCompressEnd(&(data->strm)); + pefree(data->inbuf, data->persistent); + pefree(data->outbuf, data->persistent); + pefree(data, data->persistent); + } +} + +static php_stream_filter_ops php_bz2_compress_ops = { + php_bz2_compress_filter, + php_bz2_compress_dtor, + "bzip2.compress" +}; + +/* }}} */ + +/* {{{ bzip2.* common factory */ + +static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC) +{ + php_stream_filter_ops *fops = NULL; + php_bz2_filter_data *data; + int status; + + /* Create this filter */ + data = pecalloc(1, sizeof(php_bz2_filter_data), persistent); + + /* Circular reference */ + data->strm.opaque = (void *) data; + + data->strm.bzalloc = php_bz2_alloc; + data->strm.bzfree = php_bz2_free; + data->persistent = persistent; + data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048; + data->strm.next_in = data->inbuf = (char *) pemalloc(data->inbuf_len, persistent); + data->strm.avail_in = 0; + data->strm.next_out = data->outbuf = (char *) pemalloc(data->outbuf_len, persistent); + + if (strcasecmp(filtername, "bzip2.decompress") == 0) { + int smallFootprint = 0; + + if (filterparams) { + zval **tmpzval = NULL; + + if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) { + zend_hash_find(HASH_OF(filterparams), "small", sizeof("small"), (void **) &tmpzval); + } else { + tmpzval = &filterparams; + } + + if (tmpzval) { + SEPARATE_ZVAL(tmpzval); + convert_to_boolean_ex(tmpzval); + smallFootprint = Z_LVAL_PP(tmpzval); + zval_ptr_dtor(tmpzval); + } + } + + status = BZ2_bzDecompressInit(&(data->strm), 0, smallFootprint); + fops = &php_bz2_decompress_ops; + } else if (strcasecmp(filtername, "bzip2.compress") == 0) { + int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE; + int workFactor = PHP_BZ2_FILTER_DEFAULT_WORKFACTOR; + + if (filterparams) { + zval **tmpzval; + + if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) { + if (zend_hash_find(HASH_OF(filterparams), "blocks", sizeof("blocks"), (void**) &tmpzval) == SUCCESS) { + /* How much memory to allocate (1 - 9) x 100kb */ + SEPARATE_ZVAL(tmpzval); + convert_to_long_ex(tmpzval); + if (Z_LVAL_PP(tmpzval) < 1 || Z_LVAL_PP(tmpzval) > 9) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for number of blocks to allocate. (%ld)", Z_LVAL_PP(tmpzval)); + } else { + blockSize100k = Z_LVAL_PP(tmpzval); + } + zval_ptr_dtor(tmpzval); + } + + if (zend_hash_find(HASH_OF(filterparams), "work", sizeof("work"), (void**) &tmpzval) == SUCCESS) { + /* Work Factor (0 - 250) */ + SEPARATE_ZVAL(tmpzval); + convert_to_long_ex(tmpzval); + if (Z_LVAL_PP(tmpzval) < 0 || Z_LVAL_PP(tmpzval) > 250) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for work factor. (%ld)", Z_LVAL_PP(tmpzval)); + } else { + workFactor = Z_LVAL_PP(tmpzval); + } + zval_ptr_dtor(tmpzval); + } + } + } + + status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor); + fops = &php_bz2_compress_ops; + } else { + status = BZ_DATA_ERROR; + } + + if (status != BZ_OK) { + /* Unspecified (probably strm) error, let stream-filter error do its own whining */ + pefree(data->strm.next_in, persistent); + pefree(data->strm.next_out, persistent); + pefree(data, persistent); + return NULL; + } + + return php_stream_filter_alloc(fops, data, persistent); +} + +php_stream_filter_factory php_bz2_filter_factory = { + php_bz2_filter_create +}; +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/ext/bz2/config.m4 b/ext/bz2/config.m4 index 6977ff8ac4..bd6e8a6ab9 100644 --- a/ext/bz2/config.m4 +++ b/ext/bz2/config.m4 @@ -35,6 +35,6 @@ if test "$PHP_BZ2" != "no"; then -L$BZIP_DIR/lib ]) - PHP_NEW_EXTENSION(bz2, bz2.c, $ext_shared) + PHP_NEW_EXTENSION(bz2, bz2.c bz2_filter.c, $ext_shared) PHP_SUBST(BZ2_SHARED_LIBADD) fi diff --git a/ext/bz2/config.w32 b/ext/bz2/config.w32 index 7fe9c555bf..af57f8bc30 100644 --- a/ext/bz2/config.w32 +++ b/ext/bz2/config.w32 @@ -6,7 +6,7 @@ ARG_WITH("bz2", "BZip2", "no"); if (PHP_BZ2 != "no") { if (CHECK_LIB("libbz2.lib", "bz2", PHP_BZ2) && CHECK_HEADER_ADD_INCLUDE("bzlib.h", "CFLAGS_BZ2")) { - EXTENSION("bz2", "bz2.c"); + EXTENSION("bz2", "bz2.c bz2_filter.c"); AC_DEFINE('HAVE_BZ2', 1, 'Have BZ2 library'); // BZ2 extension does this slightly differently from others if (PHP_BZ2_SHARED) { diff --git a/ext/bz2/php_bz2.h b/ext/bz2/php_bz2.h index d7f1138629..886308d3c0 100644 --- a/ext/bz2/php_bz2.h +++ b/ext/bz2/php_bz2.h @@ -62,9 +62,16 @@ PHP_BZ2_API php_stream *_php_stream_bz2open_from_BZFILE(BZFILE *bz, char *mode, #define php_stream_bz2open_from_BZFILE(bz, mode, innerstream) _php_stream_bz2open_from_BZFILE((bz), (mode), (innerstream) STREAMS_CC TSRMLS_CC) #define php_stream_bz2open(wrapper, path, mode, options, opened_path) _php_stream_bz2open((wrapper), (path), (mode), (options), (opened_path), NULL STREAMS_CC TSRMLS_CC) +php_stream_filter_factory php_bz2_filter_factory; extern php_stream_ops php_stream_bz2io_ops; #define PHP_STREAM_IS_BZIP2 &php_stream_bz2io_ops +/* 400kb */ +#define PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE 4 + +/* BZ2 Internal Default */ +#define PHP_BZ2_FILTER_DEFAULT_WORKFACTOR 0 + #endif diff --git a/ext/bz2/tests/bz2_filter_compress.phpt b/ext/bz2/tests/bz2_filter_compress.phpt new file mode 100644 index 0000000000..3de9a9d3ec --- /dev/null +++ b/ext/bz2/tests/bz2_filter_compress.phpt @@ -0,0 +1,17 @@ +--TEST-- +bzip2.compress (with convert.base64-encode) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +QlpoNDFBWSZTWRN6QG0AAAoVgECFACA395UgIABIintI1N6mpowIQ0E1MTTAQGYTNcRyMZm5kgW3ib7hVboE7Tmqj3ToGZ5G3q1ZauD2G58hibSck8KS95EEAbx1Cn+LuSKcKEgJvSA2gA== diff --git a/ext/bz2/tests/bz2_filter_decompress.phpt b/ext/bz2/tests/bz2_filter_decompress.phpt new file mode 100644 index 0000000000..951d572cb2 --- /dev/null +++ b/ext/bz2/tests/bz2_filter_decompress.phpt @@ -0,0 +1,17 @@ +--TEST-- +bzip2.decompress (with convert.base64-decode) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +I am the very model of a modern major general, I've information vegetable, animal, and mineral.