1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/Compression.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,131 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "vm/Compression.h" 1.11 + 1.12 +#include "js/Utility.h" 1.13 + 1.14 +using namespace js; 1.15 + 1.16 +#if USE_ZLIB 1.17 +static void * 1.18 +zlib_alloc(void *cx, uInt items, uInt size) 1.19 +{ 1.20 + return js_calloc(items, size); 1.21 +} 1.22 + 1.23 +static void 1.24 +zlib_free(void *cx, void *addr) 1.25 +{ 1.26 + js_free(addr); 1.27 +} 1.28 + 1.29 +Compressor::Compressor(const unsigned char *inp, size_t inplen) 1.30 + : inp(inp), 1.31 + inplen(inplen), 1.32 + outbytes(0), 1.33 + initialized(false) 1.34 +{ 1.35 + JS_ASSERT(inplen > 0); 1.36 + zs.opaque = nullptr; 1.37 + zs.next_in = (Bytef *)inp; 1.38 + zs.avail_in = 0; 1.39 + zs.next_out = nullptr; 1.40 + zs.avail_out = 0; 1.41 + zs.zalloc = zlib_alloc; 1.42 + zs.zfree = zlib_free; 1.43 +} 1.44 + 1.45 + 1.46 +Compressor::~Compressor() 1.47 +{ 1.48 + if (initialized) { 1.49 + int ret = deflateEnd(&zs); 1.50 + if (ret != Z_OK) { 1.51 + // If we finished early, we can get a Z_DATA_ERROR. 1.52 + JS_ASSERT(ret == Z_DATA_ERROR); 1.53 + JS_ASSERT(uInt(zs.next_in - inp) < inplen || !zs.avail_out); 1.54 + } 1.55 + } 1.56 +} 1.57 + 1.58 +bool 1.59 +Compressor::init() 1.60 +{ 1.61 + if (inplen >= UINT32_MAX) 1.62 + return false; 1.63 + // zlib is slow and we'd rather be done compression sooner 1.64 + // even if it means decompression is slower which penalizes 1.65 + // Function.toString() 1.66 + int ret = deflateInit(&zs, Z_BEST_SPEED); 1.67 + if (ret != Z_OK) { 1.68 + JS_ASSERT(ret == Z_MEM_ERROR); 1.69 + return false; 1.70 + } 1.71 + initialized = true; 1.72 + return true; 1.73 +} 1.74 + 1.75 +void 1.76 +Compressor::setOutput(unsigned char *out, size_t outlen) 1.77 +{ 1.78 + JS_ASSERT(outlen > outbytes); 1.79 + zs.next_out = out + outbytes; 1.80 + zs.avail_out = outlen - outbytes; 1.81 +} 1.82 + 1.83 +Compressor::Status 1.84 +Compressor::compressMore() 1.85 +{ 1.86 + JS_ASSERT(zs.next_out); 1.87 + uInt left = inplen - (zs.next_in - inp); 1.88 + bool done = left <= CHUNKSIZE; 1.89 + if (done) 1.90 + zs.avail_in = left; 1.91 + else if (zs.avail_in == 0) 1.92 + zs.avail_in = CHUNKSIZE; 1.93 + Bytef *oldout = zs.next_out; 1.94 + int ret = deflate(&zs, done ? Z_FINISH : Z_NO_FLUSH); 1.95 + outbytes += zs.next_out - oldout; 1.96 + if (ret == Z_MEM_ERROR) { 1.97 + zs.avail_out = 0; 1.98 + return OOM; 1.99 + } 1.100 + if (ret == Z_BUF_ERROR || (done && ret == Z_OK)) { 1.101 + JS_ASSERT(zs.avail_out == 0); 1.102 + return MOREOUTPUT; 1.103 + } 1.104 + JS_ASSERT_IF(!done, ret == Z_OK); 1.105 + JS_ASSERT_IF(done, ret == Z_STREAM_END); 1.106 + return done ? DONE : CONTINUE; 1.107 +} 1.108 + 1.109 +bool 1.110 +js::DecompressString(const unsigned char *inp, size_t inplen, unsigned char *out, size_t outlen) 1.111 +{ 1.112 + JS_ASSERT(inplen <= UINT32_MAX); 1.113 + z_stream zs; 1.114 + zs.zalloc = zlib_alloc; 1.115 + zs.zfree = zlib_free; 1.116 + zs.opaque = nullptr; 1.117 + zs.next_in = (Bytef *)inp; 1.118 + zs.avail_in = inplen; 1.119 + zs.next_out = out; 1.120 + JS_ASSERT(outlen); 1.121 + zs.avail_out = outlen; 1.122 + int ret = inflateInit(&zs); 1.123 + if (ret != Z_OK) { 1.124 + JS_ASSERT(ret == Z_MEM_ERROR); 1.125 + return false; 1.126 + } 1.127 + ret = inflate(&zs, Z_FINISH); 1.128 + JS_ASSERT(ret == Z_STREAM_END); 1.129 + ret = inflateEnd(&zs); 1.130 + JS_ASSERT(ret == Z_OK); 1.131 + return true; 1.132 +} 1.133 +#endif /* USE_ZLIB */ 1.134 +