Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "vm/Compression.h"
9 #include "js/Utility.h"
11 using namespace js;
13 #if USE_ZLIB
14 static void *
15 zlib_alloc(void *cx, uInt items, uInt size)
16 {
17 return js_calloc(items, size);
18 }
20 static void
21 zlib_free(void *cx, void *addr)
22 {
23 js_free(addr);
24 }
26 Compressor::Compressor(const unsigned char *inp, size_t inplen)
27 : inp(inp),
28 inplen(inplen),
29 outbytes(0),
30 initialized(false)
31 {
32 JS_ASSERT(inplen > 0);
33 zs.opaque = nullptr;
34 zs.next_in = (Bytef *)inp;
35 zs.avail_in = 0;
36 zs.next_out = nullptr;
37 zs.avail_out = 0;
38 zs.zalloc = zlib_alloc;
39 zs.zfree = zlib_free;
40 }
43 Compressor::~Compressor()
44 {
45 if (initialized) {
46 int ret = deflateEnd(&zs);
47 if (ret != Z_OK) {
48 // If we finished early, we can get a Z_DATA_ERROR.
49 JS_ASSERT(ret == Z_DATA_ERROR);
50 JS_ASSERT(uInt(zs.next_in - inp) < inplen || !zs.avail_out);
51 }
52 }
53 }
55 bool
56 Compressor::init()
57 {
58 if (inplen >= UINT32_MAX)
59 return false;
60 // zlib is slow and we'd rather be done compression sooner
61 // even if it means decompression is slower which penalizes
62 // Function.toString()
63 int ret = deflateInit(&zs, Z_BEST_SPEED);
64 if (ret != Z_OK) {
65 JS_ASSERT(ret == Z_MEM_ERROR);
66 return false;
67 }
68 initialized = true;
69 return true;
70 }
72 void
73 Compressor::setOutput(unsigned char *out, size_t outlen)
74 {
75 JS_ASSERT(outlen > outbytes);
76 zs.next_out = out + outbytes;
77 zs.avail_out = outlen - outbytes;
78 }
80 Compressor::Status
81 Compressor::compressMore()
82 {
83 JS_ASSERT(zs.next_out);
84 uInt left = inplen - (zs.next_in - inp);
85 bool done = left <= CHUNKSIZE;
86 if (done)
87 zs.avail_in = left;
88 else if (zs.avail_in == 0)
89 zs.avail_in = CHUNKSIZE;
90 Bytef *oldout = zs.next_out;
91 int ret = deflate(&zs, done ? Z_FINISH : Z_NO_FLUSH);
92 outbytes += zs.next_out - oldout;
93 if (ret == Z_MEM_ERROR) {
94 zs.avail_out = 0;
95 return OOM;
96 }
97 if (ret == Z_BUF_ERROR || (done && ret == Z_OK)) {
98 JS_ASSERT(zs.avail_out == 0);
99 return MOREOUTPUT;
100 }
101 JS_ASSERT_IF(!done, ret == Z_OK);
102 JS_ASSERT_IF(done, ret == Z_STREAM_END);
103 return done ? DONE : CONTINUE;
104 }
106 bool
107 js::DecompressString(const unsigned char *inp, size_t inplen, unsigned char *out, size_t outlen)
108 {
109 JS_ASSERT(inplen <= UINT32_MAX);
110 z_stream zs;
111 zs.zalloc = zlib_alloc;
112 zs.zfree = zlib_free;
113 zs.opaque = nullptr;
114 zs.next_in = (Bytef *)inp;
115 zs.avail_in = inplen;
116 zs.next_out = out;
117 JS_ASSERT(outlen);
118 zs.avail_out = outlen;
119 int ret = inflateInit(&zs);
120 if (ret != Z_OK) {
121 JS_ASSERT(ret == Z_MEM_ERROR);
122 return false;
123 }
124 ret = inflate(&zs, Z_FINISH);
125 JS_ASSERT(ret == Z_STREAM_END);
126 ret = inflateEnd(&zs);
127 JS_ASSERT(ret == Z_OK);
128 return true;
129 }
130 #endif /* USE_ZLIB */