]> granicus.if.org Git - php/commitdiff
Add bz2 stream filter support
authorSara Golemon <pollita@php.net>
Tue, 20 Jul 2004 05:26:33 +0000 (05:26 +0000)
committerSara Golemon <pollita@php.net>
Tue, 20 Jul 2004 05:26:33 +0000 (05:26 +0000)
NEWS
ext/bz2/bz2.c
ext/bz2/bz2.dsp
ext/bz2/bz2_filter.c [new file with mode: 0644]
ext/bz2/config.m4
ext/bz2/config.w32
ext/bz2/php_bz2.h
ext/bz2/tests/bz2_filter_compress.phpt [new file with mode: 0644]
ext/bz2/tests/bz2_filter_decompress.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 2b1153f856dbadaf2fc6df61ae23f43eaabd0aa6..171bd70df392beade2edb9c820e25c27d4b8cf03 100644 (file)
--- 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)
index 515197f9d34c1b0d754b1e0c2850f3554653a525..e51c993b5ab8713050e023c71706bf67b08c2e8e 100644 (file)
@@ -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();
 }
index ebe183cca8f07367488c0f760ee0c4459a635179..0e78ee784558ff2519c94399775d3f86f6945c3c 100644 (file)
-# Microsoft Developer Studio Project File - Name="bz2" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
-\r
-CFG=bz2 - Win32 Debug_TS\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "bz2.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "bz2.mak" CFG="bz2 - Win32 Debug_TS"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "bz2 - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
-!MESSAGE "bz2 - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-MTL=midl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "bz2 - Win32 Release_TS"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release_TS"\r
-# PROP BASE Intermediate_Dir "Release_TS"\r
-# PROP BASE Ignore_Export_Lib 0\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir "Release_TS"\r
-# PROP Intermediate_Dir "Release_TS"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BZ2_EXPORTS" /YX /FD /c\r
-# 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\r
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
-# ADD BASE RSC /l 0x407 /d "NDEBUG"\r
-# ADD RSC /l 0x407 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# 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\r
-# 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"\r
-\r
-!ELSEIF  "$(CFG)" == "bz2 - Win32 Debug_TS"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug_TS"\r
-# PROP BASE Intermediate_Dir "Debug_TS"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir "Debug_TS"\r
-# PROP Intermediate_Dir "Debug_TS"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# 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\r
-# 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\r
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
-# ADD BASE RSC /l 0x407 /d "_DEBUG"\r
-# ADD RSC /l 0x407 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# 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\r
-# 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"\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "bz2 - Win32 Release_TS"\r
-# Name "bz2 - Win32 Debug_TS"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\bz2.c\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=.\php_bz2.h\r
-# End Source File\r
-# End Group\r
-# End Target\r
-# End Project\r
+# 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 (file)
index 0000000..87990c7
--- /dev/null
@@ -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
+ */
index 6977ff8ac4dee578248a3c38117e56bc255be151..bd6e8a6ab94e4fb81077691b679112f241c0064a 100644 (file)
@@ -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
index 7fe9c555bf9476a4acf20e8aa81eb5a917e230d6..af57f8bc30a4c2738daf6cfff3e5c8d95cda1162 100644 (file)
@@ -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) {
index d7f11386293adbb66be20a2b5f0d8a98896e7806..886308d3c0cf704d38d9be2a4ac23be7f77d8891 100644 (file)
@@ -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 (file)
index 0000000..3de9a9d
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+bzip2.compress (with convert.base64-encode)
+--SKIPIF--
+<?php if (!extension_loaded("bz2")) print "skip"; ?>
+--FILE--
+<?php /* $Id$ */
+$text = 'I am the very model of a modern major general, I\'ve information vegetable, animal, and mineral.';
+
+$fp = fopen('php://stdout', 'w');
+stream_filter_append($fp, 'bzip2.compress', STREAM_FILTER_WRITE);
+stream_filter_append($fp, 'convert.base64-encode', STREAM_FILTER_WRITE);
+fwrite($fp, $text);
+fclose($fp);
+
+?> 
+--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 (file)
index 0000000..951d572
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+bzip2.decompress (with convert.base64-decode)
+--SKIPIF--
+<?php if (!extension_loaded("bz2")) print "skip"; ?>
+--FILE--
+<?php /* $Id$ */
+$text = 'QlpoNDFBWSZTWRN6QG0AAAoVgECFACA395UgIABIintI1N6mpowIQ0E1MTTAQGYTNcRyMZm5kgW3ib7hVboE7Tmqj3ToGZ5G3q1ZauD2G58hibSck8KS95EEAbx1Cn+LuSKcKEgJvSA2gA==';
+
+$fp = fopen('php://stdout', 'w');
+stream_filter_append($fp, 'convert.base64-decode', STREAM_FILTER_WRITE);
+stream_filter_append($fp, 'bzip2.decompress', STREAM_FILTER_WRITE);
+fwrite($fp, $text);
+fclose($fp);
+
+?> 
+--EXPECT-- 
+I am the very model of a modern major general, I've information vegetable, animal, and mineral.