|
7 | 7 | GzipDecoder::GzipDecoder() |
8 | 8 | : _state(State::kError), _headerStage(HeaderStage::kFixed10), _error("Gzip decode disabled"), _fixedLen(0), |
9 | 9 | _flags(0), _extraLenRead(0), _extraRemaining(0), _needName(false), _needComment(false), _needHcrc(false), |
10 | | - _trailerLen(0), _dict(nullptr), _dictOfs(0), _decomp(nullptr) { |
| 10 | + _trailerLen(0), _crc32(0), _outSize(0), _dict(nullptr), _dictOfs(0), _decomp(nullptr) { |
11 | 11 | memset(_fixed, 0, sizeof(_fixed)); |
12 | 12 | memset(_extraLenBytes, 0, sizeof(_extraLenBytes)); |
13 | 13 | memset(_trailer, 0, sizeof(_trailer)); |
@@ -73,10 +73,42 @@ static constexpr uint8_t kGzipFlagExtra = 0x04; |
73 | 73 | static constexpr uint8_t kGzipFlagName = 0x08; |
74 | 74 | static constexpr uint8_t kGzipFlagComment = 0x10; |
75 | 75 |
|
| 76 | +static uint32_t readLe32(const uint8_t* p) { |
| 77 | + return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); |
| 78 | +} |
| 79 | + |
| 80 | +static uint32_t* crc32Table() { |
| 81 | + static bool inited = false; |
| 82 | + static uint32_t table[256]; |
| 83 | + if (inited) |
| 84 | + return table; |
| 85 | + for (uint32_t i = 0; i < 256; ++i) { |
| 86 | + uint32_t c = i; |
| 87 | + for (uint32_t k = 0; k < 8; ++k) { |
| 88 | + if (c & 1U) |
| 89 | + c = 0xEDB88320U ^ (c >> 1); |
| 90 | + else |
| 91 | + c >>= 1; |
| 92 | + } |
| 93 | + table[i] = c; |
| 94 | + } |
| 95 | + inited = true; |
| 96 | + return table; |
| 97 | +} |
| 98 | + |
| 99 | +static uint32_t crc32Update(uint32_t crc, const uint8_t* data, size_t len) { |
| 100 | + uint32_t c = crc; |
| 101 | + uint32_t* t = crc32Table(); |
| 102 | + for (size_t i = 0; i < len; ++i) { |
| 103 | + c = t[(c ^ data[i]) & 0xFFU] ^ (c >> 8); |
| 104 | + } |
| 105 | + return c; |
| 106 | +} |
| 107 | + |
76 | 108 | GzipDecoder::GzipDecoder() |
77 | 109 | : _state(State::kHeader), _headerStage(HeaderStage::kFixed10), _error(nullptr), _fixedLen(0), _flags(0), |
78 | 110 | _extraLenRead(0), _extraRemaining(0), _needName(false), _needComment(false), _needHcrc(false), _trailerLen(0), |
79 | | - _dict(nullptr), _dictOfs(0), _decomp(nullptr) { |
| 111 | + _crc32(0), _outSize(0), _dict(nullptr), _dictOfs(0), _decomp(nullptr) { |
80 | 112 | memset(_fixed, 0, sizeof(_fixed)); |
81 | 113 | memset(_extraLenBytes, 0, sizeof(_extraLenBytes)); |
82 | 114 | memset(_trailer, 0, sizeof(_trailer)); |
@@ -110,6 +142,8 @@ void GzipDecoder::reset() { |
110 | 142 |
|
111 | 143 | _trailerLen = 0; |
112 | 144 | _dictOfs = 0; |
| 145 | + _crc32 = 0xFFFFFFFFU; |
| 146 | + _outSize = 0; |
113 | 147 | } |
114 | 148 |
|
115 | 149 | bool GzipDecoder::begin() { |
@@ -288,6 +322,20 @@ GzipDecoder::Result GzipDecoder::consumeTrailer(const uint8_t* in, size_t inLen, |
288 | 322 | } |
289 | 323 | if (_trailerLen < kGzipTrailerSize) |
290 | 324 | return Result::kNeedMoreInput; |
| 325 | + uint32_t expectedCrc = readLe32(_trailer); |
| 326 | + uint32_t expectedISize = readLe32(_trailer + 4); |
| 327 | + uint32_t gotCrc = _crc32 ^ 0xFFFFFFFFU; |
| 328 | + uint32_t gotISize = _outSize; |
| 329 | + |
| 330 | + if (expectedCrc != gotCrc) { |
| 331 | + setError("Gzip CRC32 mismatch"); |
| 332 | + return Result::kError; |
| 333 | + } |
| 334 | + if (expectedISize != gotISize) { |
| 335 | + setError("Gzip ISIZE mismatch"); |
| 336 | + return Result::kError; |
| 337 | + } |
| 338 | + |
291 | 339 | _state = State::kDone; |
292 | 340 | return Result::kDone; |
293 | 341 | } |
@@ -354,8 +402,11 @@ GzipDecoder::Result GzipDecoder::write(const uint8_t* in, size_t inLen, size_t* |
354 | 402 | totalConsumed += srcBufSize; |
355 | 403 | *inConsumed = totalConsumed; |
356 | 404 | if (dstBufSize > 0) { |
357 | | - *outPtr = reinterpret_cast<const uint8_t*>(dict + _dictOfs); |
| 405 | + const uint8_t* produced = reinterpret_cast<const uint8_t*>(dict + _dictOfs); |
| 406 | + *outPtr = produced; |
358 | 407 | *outLen = dstBufSize; |
| 408 | + _crc32 = crc32Update(_crc32, produced, dstBufSize); |
| 409 | + _outSize += (uint32_t)dstBufSize; |
359 | 410 | _dictOfs = (_dictOfs + dstBufSize) & (kTinflDictSize - 1); |
360 | 411 | } |
361 | 412 |
|
|
0 commit comments