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