xref: /PHP-5.3/ext/bz2/bz2.c (revision a2045ff3)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2013 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: Sterling Hughes <sterling@php.net>                           |
16   +----------------------------------------------------------------------+
17 */
18 
19 /* $Id$ */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "php.h"
26 #include "php_bz2.h"
27 
28 #if HAVE_BZ2
29 
30 /* PHP Includes */
31 #include "ext/standard/file.h"
32 #include "ext/standard/info.h"
33 #include "ext/standard/php_string.h"
34 
35 /* for fileno() */
36 #include <stdio.h>
37 
38 /* Internal error constants */
39 #define PHP_BZ_ERRNO   0
40 #define PHP_BZ_ERRSTR  1
41 #define PHP_BZ_ERRBOTH 2
42 
43 static PHP_MINIT_FUNCTION(bz2);
44 static PHP_MSHUTDOWN_FUNCTION(bz2);
45 static PHP_MINFO_FUNCTION(bz2);
46 static PHP_FUNCTION(bzopen);
47 static PHP_FUNCTION(bzread);
48 static PHP_FUNCTION(bzerrno);
49 static PHP_FUNCTION(bzerrstr);
50 static PHP_FUNCTION(bzerror);
51 static PHP_FUNCTION(bzcompress);
52 static PHP_FUNCTION(bzdecompress);
53 
54 /* {{{ arginfo */
55 ZEND_BEGIN_ARG_INFO_EX(arginfo_bzread, 0, 0, 1)
56 	ZEND_ARG_INFO(0, bz)
57 	ZEND_ARG_INFO(0, length)
58 ZEND_END_ARG_INFO()
59 
60 ZEND_BEGIN_ARG_INFO(arginfo_bzopen, 0)
61 	ZEND_ARG_INFO(0, file)
62 	ZEND_ARG_INFO(0, mode)
63 ZEND_END_ARG_INFO()
64 
65 ZEND_BEGIN_ARG_INFO(arginfo_bzerrno, 0)
66 	ZEND_ARG_INFO(0, bz)
67 ZEND_END_ARG_INFO()
68 
69 ZEND_BEGIN_ARG_INFO(arginfo_bzerrstr, 0)
70 	ZEND_ARG_INFO(0, bz)
71 ZEND_END_ARG_INFO()
72 
73 ZEND_BEGIN_ARG_INFO(arginfo_bzerror, 0)
74 	ZEND_ARG_INFO(0, bz)
75 ZEND_END_ARG_INFO()
76 
77 ZEND_BEGIN_ARG_INFO_EX(arginfo_bzcompress, 0, 0, 2)
78 	ZEND_ARG_INFO(0, source)
79 	ZEND_ARG_INFO(0, blocksize)
80 	ZEND_ARG_INFO(0, workfactor)
81 ZEND_END_ARG_INFO()
82 
83 ZEND_BEGIN_ARG_INFO_EX(arginfo_bzdecompress, 0, 0, 1)
84 	ZEND_ARG_INFO(0, source)
85 	ZEND_ARG_INFO(0, small)
86 ZEND_END_ARG_INFO()
87 
88 ZEND_BEGIN_ARG_INFO_EX(arginfo_bzwrite, 0, 0, 2)
89 	ZEND_ARG_INFO(0, fp)
90 	ZEND_ARG_INFO(0, str)
91 	ZEND_ARG_INFO(0, length)
92 ZEND_END_ARG_INFO()
93 
94 ZEND_BEGIN_ARG_INFO(arginfo_bzflush, 0)
95 	ZEND_ARG_INFO(0, fp)
96 ZEND_END_ARG_INFO()
97 /* }}} */
98 
99 static const zend_function_entry bz2_functions[] = {
100 	PHP_FE(bzopen,       arginfo_bzopen)
101 	PHP_FE(bzread,       arginfo_bzread)
102 	PHP_FALIAS(bzwrite,   fwrite,		arginfo_bzwrite)
103 	PHP_FALIAS(bzflush,   fflush,		arginfo_bzflush)
104 	PHP_FALIAS(bzclose,   fclose,		arginfo_bzflush)
105 	PHP_FE(bzerrno,      arginfo_bzerrno)
106 	PHP_FE(bzerrstr,     arginfo_bzerrstr)
107 	PHP_FE(bzerror,      arginfo_bzerror)
108 	PHP_FE(bzcompress,   arginfo_bzcompress)
109 	PHP_FE(bzdecompress, arginfo_bzdecompress)
110 	PHP_FE_END
111 };
112 
113 zend_module_entry bz2_module_entry = {
114 	STANDARD_MODULE_HEADER,
115 	"bz2",
116 	bz2_functions,
117 	PHP_MINIT(bz2),
118 	PHP_MSHUTDOWN(bz2),
119 	NULL,
120 	NULL,
121 	PHP_MINFO(bz2),
122 	NO_VERSION_YET,
123 	STANDARD_MODULE_PROPERTIES
124 };
125 
126 #ifdef COMPILE_DL_BZ2
127 ZEND_GET_MODULE(bz2)
128 #endif
129 
130 struct php_bz2_stream_data_t {
131 	BZFILE *bz_file;
132 	php_stream *stream;
133 };
134 
135 /* {{{ BZip2 stream implementation */
136 
php_bz2iop_read(php_stream * stream,char * buf,size_t count TSRMLS_DC)137 static size_t php_bz2iop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
138 {
139 	struct php_bz2_stream_data_t *self = (struct php_bz2_stream_data_t *) stream->abstract;
140 	size_t ret;
141 
142 	ret = BZ2_bzread(self->bz_file, buf, count);
143 
144 	if (ret == 0) {
145 		stream->eof = 1;
146 	}
147 
148 	return ret;
149 }
150 
php_bz2iop_write(php_stream * stream,const char * buf,size_t count TSRMLS_DC)151 static size_t php_bz2iop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
152 {
153 	struct php_bz2_stream_data_t *self = (struct php_bz2_stream_data_t *) stream->abstract;
154 
155 	return BZ2_bzwrite(self->bz_file, (char*)buf, count);
156 }
157 
php_bz2iop_close(php_stream * stream,int close_handle TSRMLS_DC)158 static int php_bz2iop_close(php_stream *stream, int close_handle TSRMLS_DC)
159 {
160 	struct php_bz2_stream_data_t *self = (struct php_bz2_stream_data_t *)stream->abstract;
161 	int ret = EOF;
162 
163 	if (close_handle) {
164 		BZ2_bzclose(self->bz_file);
165 	}
166 
167 	if (self->stream) {
168 		php_stream_free(self->stream, PHP_STREAM_FREE_CLOSE | (close_handle == 0 ? PHP_STREAM_FREE_PRESERVE_HANDLE : 0));
169 	}
170 
171 	efree(self);
172 
173 	return ret;
174 }
175 
php_bz2iop_flush(php_stream * stream TSRMLS_DC)176 static int php_bz2iop_flush(php_stream *stream TSRMLS_DC)
177 {
178 	struct php_bz2_stream_data_t *self = (struct php_bz2_stream_data_t *)stream->abstract;
179 	return BZ2_bzflush(self->bz_file);
180 }
181 /* }}} */
182 
183 php_stream_ops php_stream_bz2io_ops = {
184 	php_bz2iop_write, php_bz2iop_read,
185 	php_bz2iop_close, php_bz2iop_flush,
186 	"BZip2",
187 	NULL, /* seek */
188 	NULL, /* cast */
189 	NULL, /* stat */
190 	NULL  /* set_option */
191 };
192 
193 /* {{{ Bzip2 stream openers */
_php_stream_bz2open_from_BZFILE(BZFILE * bz,char * mode,php_stream * innerstream STREAMS_DC TSRMLS_DC)194 PHP_BZ2_API php_stream *_php_stream_bz2open_from_BZFILE(BZFILE *bz,
195 														char *mode, php_stream *innerstream STREAMS_DC TSRMLS_DC)
196 {
197 	struct php_bz2_stream_data_t *self;
198 
199 	self = emalloc(sizeof(*self));
200 
201 	self->stream = innerstream;
202 	self->bz_file = bz;
203 
204 	return php_stream_alloc_rel(&php_stream_bz2io_ops, self, 0, mode);
205 }
206 
_php_stream_bz2open(php_stream_wrapper * wrapper,char * path,char * mode,int options,char ** opened_path,php_stream_context * context STREAMS_DC TSRMLS_DC)207 PHP_BZ2_API php_stream *_php_stream_bz2open(php_stream_wrapper *wrapper,
208 											char *path,
209 											char *mode,
210 											int options,
211 											char **opened_path,
212 											php_stream_context *context STREAMS_DC TSRMLS_DC)
213 {
214 	php_stream *retstream = NULL, *stream = NULL;
215 	char *path_copy = NULL;
216 	BZFILE *bz_file = NULL;
217 
218 	if (strncasecmp("compress.bzip2://", path, 17) == 0) {
219 		path += 17;
220 	}
221 	if (mode[0] == '\0' || (mode[0] != 'w' && mode[0] != 'r' && mode[1] != '\0')) {
222 		return NULL;
223 	}
224 
225 #ifdef VIRTUAL_DIR
226 	virtual_filepath_ex(path, &path_copy, NULL TSRMLS_CC);
227 #else
228 	path_copy = path;
229 #endif
230 
231 	if ((PG(safe_mode) && (!php_checkuid(path_copy, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(path_copy TSRMLS_CC)) {
232 		return NULL;
233 	}
234 
235 	/* try and open it directly first */
236 	bz_file = BZ2_bzopen(path_copy, mode);
237 
238 	if (opened_path && bz_file) {
239 		*opened_path = estrdup(path_copy);
240 	}
241 	path_copy = NULL;
242 
243 	if (bz_file == NULL) {
244 		/* that didn't work, so try and get something from the network/wrapper */
245 		stream = php_stream_open_wrapper(path, mode, options | STREAM_WILL_CAST | ENFORCE_SAFE_MODE, opened_path);
246 
247 		if (stream) {
248 			int fd;
249 			if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **) &fd, REPORT_ERRORS)) {
250 				bz_file = BZ2_bzdopen(fd, mode);
251 			}
252 		}
253 
254 		/* remove the file created by php_stream_open_wrapper(), it is not needed since BZ2 functions
255 		 * failed.
256 		 */
257 		if (opened_path && !bz_file && mode[0] == 'w') {
258 			VCWD_UNLINK(*opened_path);
259 		}
260 	}
261 
262 	if (bz_file) {
263 		retstream = _php_stream_bz2open_from_BZFILE(bz_file, mode, stream STREAMS_REL_CC TSRMLS_CC);
264 		if (retstream) {
265 			return retstream;
266 		}
267 
268 		BZ2_bzclose(bz_file);
269 	}
270 
271 	if (stream) {
272 		php_stream_close(stream);
273 	}
274 
275 	return NULL;
276 }
277 
278 /* }}} */
279 
280 static php_stream_wrapper_ops bzip2_stream_wops = {
281 	_php_stream_bz2open,
282 	NULL, /* close */
283 	NULL, /* fstat */
284 	NULL, /* stat */
285 	NULL, /* opendir */
286 	"BZip2",
287 	NULL, /* unlink */
288 	NULL, /* rename */
289 	NULL, /* mkdir */
290 	NULL  /* rmdir */
291 };
292 
293 static php_stream_wrapper php_stream_bzip2_wrapper = {
294 	&bzip2_stream_wops,
295 	NULL,
296 	0 /* is_url */
297 };
298 
299 static void php_bz2_error(INTERNAL_FUNCTION_PARAMETERS, int);
300 
PHP_MINIT_FUNCTION(bz2)301 static PHP_MINIT_FUNCTION(bz2)
302 {
303 	php_register_url_stream_wrapper("compress.bzip2", &php_stream_bzip2_wrapper TSRMLS_CC);
304 	php_stream_filter_register_factory("bzip2.*", &php_bz2_filter_factory TSRMLS_CC);
305 	return SUCCESS;
306 }
307 
PHP_MSHUTDOWN_FUNCTION(bz2)308 static PHP_MSHUTDOWN_FUNCTION(bz2)
309 {
310 	php_unregister_url_stream_wrapper("compress.bzip2" TSRMLS_CC);
311 	php_stream_filter_unregister_factory("bzip2.*" TSRMLS_CC);
312 
313 	return SUCCESS;
314 }
315 
PHP_MINFO_FUNCTION(bz2)316 static PHP_MINFO_FUNCTION(bz2)
317 {
318 	php_info_print_table_start();
319 	php_info_print_table_row(2, "BZip2 Support", "Enabled");
320 	php_info_print_table_row(2, "Stream Wrapper support", "compress.bzip2://");
321 	php_info_print_table_row(2, "Stream Filter support", "bzip2.decompress, bzip2.compress");
322 	php_info_print_table_row(2, "BZip2 Version", (char *) BZ2_bzlibVersion());
323 	php_info_print_table_end();
324 }
325 
326 /* {{{ proto string bzread(resource bz[, int length])
327    Reads up to length bytes from a BZip2 stream, or 1024 bytes if length is not specified */
PHP_FUNCTION(bzread)328 static PHP_FUNCTION(bzread)
329 {
330 	zval *bz;
331 	long len = 1024;
332 	php_stream *stream;
333 
334 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &bz, &len)) {
335 		RETURN_FALSE;
336 	}
337 
338 	php_stream_from_zval(stream, &bz);
339 
340 	if ((len + 1) < 1) {
341 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "length may not be negative");
342 		RETURN_FALSE;
343 	}
344 
345 	Z_STRVAL_P(return_value) = emalloc(len + 1);
346 	Z_STRLEN_P(return_value) = php_stream_read(stream, Z_STRVAL_P(return_value), len);
347 
348 	if (Z_STRLEN_P(return_value) < 0) {
349 		efree(Z_STRVAL_P(return_value));
350 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not read valid bz2 data from stream");
351 		RETURN_FALSE;
352 	}
353 
354 	Z_STRVAL_P(return_value)[Z_STRLEN_P(return_value)] = 0;
355 
356 	if (PG(magic_quotes_runtime)) {
357 		Z_STRVAL_P(return_value) = php_addslashes(	Z_STRVAL_P(return_value),
358 													Z_STRLEN_P(return_value),
359 													&Z_STRLEN_P(return_value), 1 TSRMLS_CC);
360 	}
361 
362 	Z_TYPE_P(return_value) = IS_STRING;
363 }
364 /* }}} */
365 
366 /* {{{ proto resource bzopen(string|int file|fp, string mode)
367    Opens a new BZip2 stream */
PHP_FUNCTION(bzopen)368 static PHP_FUNCTION(bzopen)
369 {
370 	zval    **file;   /* The file to open */
371 	char     *mode;   /* The mode to open the stream with */
372 	int      mode_len;
373 
374 	BZFILE   *bz;     /* The compressed file stream */
375 	php_stream *stream = NULL;
376 
377 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs", &file, &mode, &mode_len) == FAILURE) {
378 		return;
379 	}
380 
381 	if (mode_len != 1 || (mode[0] != 'r' && mode[0] != 'w')) {
382 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' is not a valid mode for bzopen(). Only 'w' and 'r' are supported.", mode);
383 		RETURN_FALSE;
384 	}
385 
386 	/* If it's not a resource its a string containing the filename to open */
387 	if (Z_TYPE_PP(file) == IS_STRING) {
388 		convert_to_string_ex(file);
389 
390 		if (strlen(Z_STRVAL_PP(file)) != Z_STRLEN_PP(file)) {
391 			RETURN_FALSE;
392 		}
393 		if (Z_STRLEN_PP(file) == 0) {
394 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "filename cannot be empty");
395 			RETURN_FALSE;
396 		}
397 
398 		stream = php_stream_bz2open(NULL,
399 									Z_STRVAL_PP(file),
400 									mode,
401 									ENFORCE_SAFE_MODE | REPORT_ERRORS,
402 									NULL);
403 	} else if (Z_TYPE_PP(file) == IS_RESOURCE) {
404 		/* If it is a resource, than its a stream resource */
405 		int fd;
406 		int stream_mode_len;
407 
408 		php_stream_from_zval(stream, file);
409 		stream_mode_len = strlen(stream->mode);
410 
411 		if (stream_mode_len != 1 && !(stream_mode_len == 2 && memchr(stream->mode, 'b', 2))) {
412 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot use stream opened in mode '%s'", stream->mode);
413 			RETURN_FALSE;
414 		} else if (stream_mode_len == 1 && stream->mode[0] != 'r' && stream->mode[0] != 'w' && stream->mode[0] != 'a' && stream->mode[0] != 'x') {
415 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot use stream opened in mode '%s'", stream->mode);
416 			RETURN_FALSE;
417 		}
418 
419 		switch(mode[0]) {
420 			case 'r':
421 				/* only "r" and "rb" are supported */
422 				if (stream->mode[0] != mode[0] && !(stream_mode_len == 2 && stream->mode[1] != mode[0])) {
423 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot read from a stream opened in write only mode");
424 					RETURN_FALSE;
425 				}
426 				break;
427 			case 'w':
428 				/* support only "w"(b), "a"(b), "x"(b) */
429 				if (stream->mode[0] != mode[0] && !(stream_mode_len == 2 && stream->mode[1] != mode[0])
430 					&& stream->mode[0] != 'a' && !(stream_mode_len == 2 && stream->mode[1] != 'a')
431 					&& stream->mode[0] != 'x' && !(stream_mode_len == 2 && stream->mode[1] != 'x')) {
432 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot write to a stream opened in read only mode");
433 					RETURN_FALSE;
434 				}
435 				break;
436 			default:
437 				/* not reachable */
438 				break;
439 		}
440 
441 		if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_FD, (void *) &fd, REPORT_ERRORS)) {
442 			RETURN_FALSE;
443 		}
444 
445 		bz = BZ2_bzdopen(fd, mode);
446 
447 		stream = php_stream_bz2open_from_BZFILE(bz, mode, stream);
448 	} else {
449 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "first parameter has to be string or file-resource");
450 		RETURN_FALSE;
451 	}
452 
453 	if (stream) {
454 		php_stream_to_zval(stream, return_value);
455 	} else {
456 		RETURN_FALSE;
457 	}
458 }
459 /* }}} */
460 
461 /* {{{ proto int bzerrno(resource bz)
462    Returns the error number */
PHP_FUNCTION(bzerrno)463 static PHP_FUNCTION(bzerrno)
464 {
465 	php_bz2_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_BZ_ERRNO);
466 }
467 /* }}} */
468 
469 /* {{{ proto string bzerrstr(resource bz)
470    Returns the error string */
PHP_FUNCTION(bzerrstr)471 static PHP_FUNCTION(bzerrstr)
472 {
473 	php_bz2_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_BZ_ERRSTR);
474 }
475 /* }}} */
476 
477 /* {{{ proto array bzerror(resource bz)
478    Returns the error number and error string in an associative array */
PHP_FUNCTION(bzerror)479 static PHP_FUNCTION(bzerror)
480 {
481 	php_bz2_error(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_BZ_ERRBOTH);
482 }
483 /* }}} */
484 
485 /* {{{ proto string bzcompress(string source [, int blocksize100k [, int workfactor]])
486    Compresses a string into BZip2 encoded data */
PHP_FUNCTION(bzcompress)487 static PHP_FUNCTION(bzcompress)
488 {
489 	char             *source;          /* Source data to compress */
490 	long              zblock_size = 0; /* Optional block size to use */
491 	long              zwork_factor = 0;/* Optional work factor to use */
492 	char             *dest = NULL;     /* Destination to place the compressed data into */
493 	int               error,           /* Error Container */
494 					  block_size  = 4, /* Block size for compression algorithm */
495 					  work_factor = 0, /* Work factor for compression algorithm */
496 					  argc;            /* Argument count */
497 	int               source_len;      /* Length of the source data */
498 	unsigned int      dest_len;        /* Length of the destination buffer */
499 
500 	argc = ZEND_NUM_ARGS();
501 
502 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &source, &source_len, &zblock_size, &zwork_factor) == FAILURE) {
503 		return;
504 	}
505 
506 	/* Assign them to easy to use variables, dest_len is initially the length of the data
507 	   + .01 x length of data + 600 which is the largest size the results of the compression
508 	   could possibly be, at least that's what the libbz2 docs say (thanks to jeremy@nirvani.net
509 	   for pointing this out).  */
510 	dest_len   = (unsigned int) (source_len + (0.01 * source_len) + 600);
511 
512 	/* Allocate the destination buffer */
513 	dest = emalloc(dest_len + 1);
514 
515 	/* Handle the optional arguments */
516 	if (argc > 1) {
517 		block_size = zblock_size;
518 	}
519 
520 	if (argc > 2) {
521 		work_factor = zwork_factor;
522 	}
523 
524 	error = BZ2_bzBuffToBuffCompress(dest, &dest_len, source, source_len, block_size, 0, work_factor);
525 	if (error != BZ_OK) {
526 		efree(dest);
527 		RETURN_LONG(error);
528 	} else {
529 		/* Copy the buffer, we have perhaps allocate alot more than we need,
530 		   so we erealloc() the buffer to the proper size */
531 		dest = erealloc(dest, dest_len + 1);
532 		dest[dest_len] = 0;
533 		RETURN_STRINGL(dest, dest_len, 0);
534 	}
535 }
536 /* }}} */
537 
538 /* {{{ proto string bzdecompress(string source [, int small])
539    Decompresses BZip2 compressed data */
PHP_FUNCTION(bzdecompress)540 static PHP_FUNCTION(bzdecompress)
541 {
542 	char *source, *dest;
543 	int source_len, error;
544 	long small = 0;
545 #if defined(PHP_WIN32)
546 	unsigned __int64 size = 0;
547 #else
548 	unsigned long long size = 0;
549 #endif
550 	bz_stream bzs;
551 
552 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &source, &source_len, &small)) {
553 		RETURN_FALSE;
554 	}
555 
556 	bzs.bzalloc = NULL;
557 	bzs.bzfree = NULL;
558 
559 	if (BZ2_bzDecompressInit(&bzs, 0, small) != BZ_OK) {
560 		RETURN_FALSE;
561 	}
562 
563 	bzs.next_in = source;
564 	bzs.avail_in = source_len;
565 
566 	/* in most cases bz2 offers at least 2:1 compression, so we use that as our base */
567 	bzs.avail_out = source_len * 2;
568 	bzs.next_out = dest = emalloc(bzs.avail_out + 1);
569 
570 	while ((error = BZ2_bzDecompress(&bzs)) == BZ_OK && bzs.avail_in > 0) {
571 		/* compression is better then 2:1, need to allocate more memory */
572 		bzs.avail_out = source_len;
573 		size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32;
574 		dest = safe_erealloc(dest, 1, bzs.avail_out+1, (size_t) size );
575 		bzs.next_out = dest + size;
576 	}
577 
578 	if (error == BZ_STREAM_END || error == BZ_OK) {
579 		size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32;
580 		dest = safe_erealloc(dest, 1, (size_t) size, 1);
581 		dest[size] = '\0';
582 		RETVAL_STRINGL(dest, (int) size, 0);
583 	} else { /* real error */
584 		efree(dest);
585 		RETVAL_LONG(error);
586 	}
587 
588 	BZ2_bzDecompressEnd(&bzs);
589 }
590 /* }}} */
591 
592 /* {{{ php_bz2_error()
593    The central error handling interface, does the work for bzerrno, bzerrstr and bzerror */
php_bz2_error(INTERNAL_FUNCTION_PARAMETERS,int opt)594 static void php_bz2_error(INTERNAL_FUNCTION_PARAMETERS, int opt)
595 {
596 	zval         *bzp;     /* BZip2 Resource Pointer */
597 	php_stream   *stream;
598 	const char   *errstr;  /* Error string */
599 	int           errnum;  /* Error number */
600 	struct php_bz2_stream_data_t *self;
601 
602 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &bzp) == FAILURE) {
603 		return;
604 	}
605 
606 	php_stream_from_zval(stream, &bzp);
607 
608 	if (!php_stream_is(stream, PHP_STREAM_IS_BZIP2)) {
609 		RETURN_FALSE;
610 	}
611 
612 	self = (struct php_bz2_stream_data_t *) stream->abstract;
613 
614 	/* Fetch the error information */
615 	errstr = BZ2_bzerror(self->bz_file, &errnum);
616 
617 	/* Determine what to return */
618 	switch (opt) {
619 		case PHP_BZ_ERRNO:
620 			RETURN_LONG(errnum);
621 			break;
622 		case PHP_BZ_ERRSTR:
623 			RETURN_STRING((char*)errstr, 1);
624 			break;
625 		case PHP_BZ_ERRBOTH:
626 			array_init(return_value);
627 
628 			add_assoc_long  (return_value, "errno",  errnum);
629 			add_assoc_string(return_value, "errstr", (char*)errstr, 1);
630 			break;
631 	}
632 }
633 /* }}} */
634 
635 #endif
636 
637 /*
638  * Local variables:
639  * tab-width: 4
640  * c-basic-offset: 4
641  * End:
642  * vim600: fdm=marker
643  * vim: noet sw=4 ts=4
644  */
645