193 linhas
5.8 KiB
C++
193 linhas
5.8 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
| Copyright (c) 1997-2010 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "hphp/runtime/ext/ext_bzip2.h"
|
|
#include "hphp/runtime/base/file/bzip2_file.h"
|
|
#include "hphp/util/alloc.h"
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
Variant f_bzclose(CObjRef bz) {
|
|
return f_fclose(bz);
|
|
}
|
|
|
|
Variant f_bzread(CObjRef bz, int length /* = 1024 */) {
|
|
return f_fread(bz, length);
|
|
}
|
|
|
|
Variant f_bzwrite(CObjRef bz, CStrRef data, int length /* = 0 */) {
|
|
return f_fwrite(bz, data, length);
|
|
}
|
|
|
|
Variant f_bzopen(CVarRef filename, CStrRef mode) {
|
|
if (mode != "r" && mode != "w") {
|
|
raise_warning(
|
|
"'%s' is not a valid mode for bzopen(). "
|
|
"Only 'w' and 'r' are supported.",
|
|
mode.data()
|
|
);
|
|
return false;
|
|
}
|
|
|
|
BZ2File *bz;
|
|
if (filename.isString()) {
|
|
if (filename.asCStrRef().empty()) {
|
|
raise_warning("filename cannot be empty");
|
|
return false;
|
|
}
|
|
bz = NEWOBJ(BZ2File)();
|
|
bool ret = bz->open(File::TranslatePath(filename.toString()), mode);
|
|
if (!ret) {
|
|
raise_warning("%s", Util::safe_strerror(errno).c_str());
|
|
return false;
|
|
}
|
|
} else {
|
|
if (!filename.isResource()) {
|
|
raise_warning("first parameter has to be string or file-resource");
|
|
return false;
|
|
}
|
|
PlainFile* f = filename.cast<PlainFile>();
|
|
if (!f) {
|
|
return false;
|
|
}
|
|
|
|
std::string stream_mode = f->getMode();
|
|
int stream_mode_len = stream_mode.length();
|
|
|
|
if (stream_mode_len != 1 &&
|
|
!(stream_mode_len == 2 && stream_mode.find('b') != string::npos)) {
|
|
raise_warning("cannot use stream opened in mode '%s'", stream_mode.c_str());
|
|
return false;
|
|
} else if (stream_mode_len == 1 &&
|
|
stream_mode[0] != 'r' && stream_mode[0] != 'w' &&
|
|
stream_mode[0] != 'a' && stream_mode[0] != 'x') {
|
|
raise_warning("cannot use stream opened in mode '%s'", stream_mode.c_str());
|
|
return false;
|
|
}
|
|
|
|
const char rw_mode = stream_mode[0];
|
|
if (mode == "r" && rw_mode != 'r') {
|
|
raise_warning("cannot write to a stream opened in read only mode");
|
|
return false;
|
|
} else if (mode == "w" && rw_mode != 'w' && rw_mode != 'a' && rw_mode != 'x') {
|
|
raise_warning("cannot read from a stream opened in write only mode");
|
|
return false;
|
|
}
|
|
|
|
bz = NEWOBJ(BZ2File)(f);
|
|
}
|
|
Object handle(bz);
|
|
return handle;
|
|
}
|
|
|
|
Variant f_bzflush(CObjRef bz) {
|
|
BZ2File *f = bz.getTyped<BZ2File>();
|
|
return f->flush();
|
|
}
|
|
|
|
String f_bzerrstr(CObjRef bz) {
|
|
BZ2File *f = bz.getTyped<BZ2File>();
|
|
return f->errstr();
|
|
}
|
|
|
|
Variant f_bzerror(CObjRef bz) {
|
|
BZ2File *f = bz.getTyped<BZ2File>();
|
|
return f->error();
|
|
}
|
|
|
|
int64_t f_bzerrno(CObjRef bz) {
|
|
BZ2File *f = bz.getTyped<BZ2File>();
|
|
return f->errnu();
|
|
}
|
|
|
|
Variant f_bzcompress(CStrRef source, int blocksize /* = 4 */,
|
|
int workfactor /* = 0 */) {
|
|
char *dest = NULL;
|
|
int error;
|
|
unsigned int source_len, dest_len;
|
|
|
|
source_len = source.length();
|
|
dest_len = source.length() + (0.01*source.length()) + 600;
|
|
|
|
if (!(dest = (char *)malloc(dest_len + 1))) {
|
|
return BZ_MEM_ERROR;
|
|
}
|
|
|
|
error = BZ2_bzBuffToBuffCompress(dest, &dest_len, (char *) source.c_str(),
|
|
source_len, blocksize, 0, workfactor);
|
|
if (error != BZ_OK) {
|
|
free(dest);
|
|
return error;
|
|
} else {
|
|
// this is to shrink the allocation, since we probably over allocated
|
|
dest = (char *)realloc(dest, dest_len + 1);
|
|
dest[dest_len] = '\0';
|
|
String ret = String(dest, dest_len, AttachString);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
Variant f_bzdecompress(CStrRef source, int small /* = 0 */) {
|
|
char *dest;
|
|
int source_len = source.length();
|
|
int error;
|
|
uint64_t size = 0;
|
|
bz_stream bzs;
|
|
|
|
bzs.bzalloc = NULL;
|
|
bzs.bzfree = NULL;
|
|
|
|
if (BZ2_bzDecompressInit(&bzs, 0, small) != BZ_OK) {
|
|
return false;
|
|
}
|
|
|
|
bzs.next_in = (char *) source.c_str();
|
|
bzs.avail_in = source_len;
|
|
|
|
/* in most cases bz2 offers at least 2:1 compression, so we use that as our base */
|
|
bzs.avail_out = source_len * 2;
|
|
bzs.next_out = dest = (char *) malloc(bzs.avail_out + 1);
|
|
if (!dest) {
|
|
return BZ_MEM_ERROR;
|
|
}
|
|
|
|
while ((error = BZ2_bzDecompress(&bzs)) == BZ_OK && bzs.avail_in > 0) {
|
|
/* compression is better then 2:1, need to allocate more memory */
|
|
bzs.avail_out = source_len;
|
|
size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32;
|
|
dest = (char *) Util::safe_realloc(dest, size + bzs.avail_out + 1);
|
|
bzs.next_out = dest + size;
|
|
}
|
|
|
|
if (error == BZ_STREAM_END || error == BZ_OK) {
|
|
size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32;
|
|
dest = (char *)Util::safe_realloc(dest, size + 1);
|
|
dest[size] = '\0';
|
|
String ret = String(dest, size, AttachString);
|
|
BZ2_bzDecompressEnd(&bzs);
|
|
return ret;
|
|
} else {
|
|
free(dest);
|
|
BZ2_bzDecompressEnd(&bzs);
|
|
return error;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|