Line data Source code
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/. */
6 :
7 : #ifndef vm_Compression_h
8 : #define vm_Compression_h
9 :
10 : #include <zlib.h>
11 :
12 : #include "jsalloc.h"
13 : #include "jstypes.h"
14 :
15 : #include "js/Vector.h"
16 :
17 : namespace js {
18 :
19 : struct CompressedDataHeader
20 : {
21 : uint32_t compressedBytes;
22 : };
23 :
24 : class Compressor
25 : {
26 : public:
27 : // After compressing CHUNK_SIZE bytes, we will do a full flush so we can
28 : // start decompression at that point.
29 : static const size_t CHUNK_SIZE = 64 * 1024;
30 :
31 : private:
32 : // Number of bytes we should hand to zlib each compressMore() call.
33 : static const size_t MAX_INPUT_SIZE = 2 * 1024;
34 :
35 : z_stream zs;
36 : const unsigned char* inp;
37 : size_t inplen;
38 : size_t outbytes;
39 : bool initialized;
40 : bool finished;
41 :
42 : // The number of uncompressed bytes written for the current chunk. When this
43 : // reaches CHUNK_SIZE, we finish the current chunk and start a new chunk.
44 : uint32_t currentChunkSize;
45 :
46 : // At the end of each chunk (and the end of the uncompressed data if it's
47 : // not a chunk boundary), we record the offset in the compressed data.
48 : js::Vector<uint32_t, 8, SystemAllocPolicy> chunkOffsets;
49 :
50 : public:
51 : enum Status {
52 : MOREOUTPUT,
53 : DONE,
54 : CONTINUE,
55 : OOM
56 : };
57 :
58 : Compressor(const unsigned char* inp, size_t inplen);
59 : ~Compressor();
60 : bool init();
61 : void setOutput(unsigned char* out, size_t outlen);
62 : /* Compress some of the input. Return true if it should be called again. */
63 : Status compressMore();
64 0 : size_t sizeOfChunkOffsets() const { return chunkOffsets.length() * sizeof(chunkOffsets[0]); }
65 :
66 : // Returns the number of bytes needed to store the data currently written +
67 : // the chunk offsets.
68 : size_t totalBytesNeeded() const;
69 :
70 : // Append the chunk offsets to |dest|.
71 : void finish(char* dest, size_t destBytes);
72 :
73 0 : static void toChunkOffset(size_t uncompressedOffset, size_t* chunk, size_t* chunkOffset) {
74 0 : *chunk = uncompressedOffset / CHUNK_SIZE;
75 0 : *chunkOffset = uncompressedOffset % CHUNK_SIZE;
76 0 : }
77 0 : static size_t chunkSize(size_t uncompressedBytes, size_t chunk) {
78 0 : MOZ_ASSERT(uncompressedBytes > 0);
79 0 : size_t lastChunk = (uncompressedBytes - 1) / CHUNK_SIZE;
80 0 : MOZ_ASSERT(chunk <= lastChunk);
81 0 : if (chunk < lastChunk || uncompressedBytes % CHUNK_SIZE == 0)
82 0 : return CHUNK_SIZE;
83 0 : return uncompressedBytes % CHUNK_SIZE;
84 : }
85 : };
86 :
87 : /*
88 : * Decompress a string. The caller must know the length of the output and
89 : * allocate |out| to a string of that length.
90 : */
91 : bool DecompressString(const unsigned char* inp, size_t inplen,
92 : unsigned char* out, size_t outlen);
93 :
94 : /*
95 : * Decompress a single chunk of at most Compressor::CHUNK_SIZE bytes.
96 : * |chunk| is the chunk index. The caller must know the length of the output
97 : * (the uncompressed chunk) and allocate |out| to a string of that length.
98 : */
99 : bool DecompressStringChunk(const unsigned char* inp, size_t chunk,
100 : unsigned char* out, size_t outlen);
101 :
102 : } /* namespace js */
103 :
104 : #endif /* vm_Compression_h */
|