Arquivos
hhvm/hphp/runtime/ext/ext_bzip2.cpp
T
2013-06-25 13:19:07 -07:00

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;
}
}
///////////////////////////////////////////////////////////////////////////////
}