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