bz2.c 18 KB

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