summaryrefslogtreecommitdiffstats
path: root/mozglue/linker/SeekableZStream.h
blob: 3505c681e830cc008053094b391c881a8255c0e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef SeekableZStream_h
#define SeekableZStream_h

#include "Zip.h"

/**
 * Seekable compressed stream are created by splitting the original
 * decompressed data in small chunks and compress these chunks
 * individually.
 *
 * The seekable compressed file format consists in a header defined below,
 * followed by a table of 32-bits words containing the offsets for each
 * individual compressed chunk, then followed by the compressed chunks.
 */

#pragma pack(1)
struct SeekableZStreamHeader: public Zip::SignedEntity<SeekableZStreamHeader>
{
  SeekableZStreamHeader()
  : Zip::SignedEntity<SeekableZStreamHeader>(magic)
  , totalSize(0), chunkSize(0), dictSize(0), nChunks(0), lastChunkSize(0)
  , windowBits(0), filter(0) { }

  /* Reuse Zip::SignedEntity to handle the magic number used in the Seekable
   * ZStream file format. The magic number is "SeZz". */
  static const uint32_t magic = 0x7a5a6553;

  /* Total size of the stream, including the 4 magic bytes. */
  le_uint32 totalSize;

  /* Chunk size */
  le_uint16 chunkSize;

  /* Size of the dictionary */
  le_uint16 dictSize;

  /* Number of chunks */
  le_uint32 nChunks;

  /* Size of last chunk (> 0, <= Chunk size) */
  le_uint16 lastChunkSize;

  /* windowBits value used when deflating */
  signed char windowBits;

  /* Filter Id */
  unsigned char filter;
};
#pragma pack()

static_assert(sizeof(SeekableZStreamHeader) == 5 * 4,
              "SeekableZStreamHeader should be 5 32-bits words");

/**
 * Helper class used to decompress Seekable ZStreams.
 */
class SeekableZStream {
public:
  /* Initialize from the given buffer. Returns whether initialization
   * succeeded (true) or failed (false). */
  bool Init(const void *buf, size_t length);

  /* Decompresses starting from the given chunk. The decompressed data is
   * stored at the given location. The given length, in bytes, indicates
   * how much data to decompress. If length is 0, then exactly one chunk
   * is decompressed.
   * Returns whether decompression succeeded (true) or failed (false). */
  bool Decompress(void *where, size_t chunk, size_t length = 0);

  /* Decompresses the given chunk at the given address. If a length is given,
   * only decompresses that amount of data instead of the entire chunk.
   * Returns whether decompression succeeded (true) or failed (false). */
  bool DecompressChunk(void *where, size_t chunk, size_t length = 0);
 
  /* Returns the uncompressed size of the complete zstream */
  size_t GetUncompressedSize() const
  {
    return (offsetTable.numElements() - 1) * chunkSize + lastChunkSize;
  }

  /* Returns the chunk size of the given chunk */
  size_t GetChunkSize(size_t chunk = 0) const {
    return (chunk == offsetTable.numElements() - 1) ? lastChunkSize : chunkSize;
  }

  /* Returns the number of chunks */
  size_t GetChunksNum() const {
    return offsetTable.numElements();
  }

  /**
   * Filters used to improve compression rate.
   */
  enum FilterDirection {
    FILTER,
    UNFILTER
  };
  typedef void (*ZStreamFilter)(off_t, FilterDirection,
                                  unsigned char *, size_t);

  enum FilterId {
    NONE,
    BCJ_THUMB,
    BCJ_ARM,
    BCJ_X86,
    FILTER_MAX
  };
  static ZStreamFilter GetFilter(FilterId id);

  static ZStreamFilter GetFilter(uint16_t id) {
    return GetFilter(static_cast<FilterId>(id));
  }

private:
  /* RAW Seekable SZtream buffer */
  const unsigned char *buffer;

  /* Total size of the stream, including the 4 magic bytes. */
  uint32_t totalSize;

  /* Chunk size */
  uint32_t chunkSize;

  /* Size of last chunk (> 0, <= Chunk size) */
  uint32_t lastChunkSize;

  /* windowBits value used when deflating */
  int windowBits;

  /* Offsets table */
  Array<le_uint32> offsetTable;

  /* Filter */
  ZStreamFilter filter;

  /* Deflate dictionary */
  Array<unsigned char> dictionary;

  /* Special allocator for inflate to use the same buffers for every chunk */
  zxx_stream::StaticAllocator allocator;
};

inline void
operator++(SeekableZStream::FilterId &other)
{
  const int orig = static_cast<int>(other);
  other = static_cast<SeekableZStream::FilterId>(orig + 1);
}

#endif /* SeekableZStream_h */