~ubuntu-branches/ubuntu/hardy/php5/hardy-updates

« back to all changes in this revision

Viewing changes to ext/bz2/bz2.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-10-09 03:14:32 UTC
  • Revision ID: james.westby@ubuntu.com-20051009031432-kspik3lobxstafv9
Tags: upstream-5.0.5
ImportĀ upstreamĀ versionĀ 5.0.5

Show diffs side-by-side

added added

removed removed

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