25#ifndef OF_INFLATE64_STREAM_M
26# import "OFInflateStream.h"
28# import "OFInflate64Stream.h"
29# define OFInflateStream OFInflate64Stream
31#import "OFHuffmanTree.h"
33#import "OFInitializationFailedException.h"
34#import "OFInvalidFormatException.h"
35#import "OFNotOpenException.h"
36#import "OFOutOfMemoryException.h"
38#ifndef OF_INFLATE64_STREAM_M
39# define bufferSize OFInflateStreamBufferSize
41# define bufferSize OFInflate64StreamBufferSize
46 stateUncompressedBlockHeader,
47 stateUncompressedBlock,
53 huffmanStateWriteValue,
54 huffmanStateAwaitCode,
55 huffmanStateAwaitLengthExtraBits,
56 huffmanStateAwaitDistance,
57 huffmanStateAwaitDistanceExtraBits,
58 huffmanStateProcessPair
61#ifndef OF_INFLATE64_STREAM_M
62static const uint8_t numDistanceCodes = 30;
63static const uint8_t lengthCodes[29] = {
65 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
66 64, 80, 96, 112, 128, 160, 192, 224, 255
68static const uint8_t lengthExtraBits[29] = {
69 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
72static const uint16_t distanceCodes[30] = {
73 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
74 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
76static const uint8_t distanceExtraBits[30] = {
77 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
78 10, 11, 11, 12, 12, 13, 13
81static const uint8_t numDistanceCodes = 32;
82static const uint8_t lengthCodes[29] = {
84 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
85 64, 80, 96, 112, 128, 160, 192, 224, 0
87static const uint8_t lengthExtraBits[29] = {
88 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
91static const uint16_t distanceCodes[32] = {
92 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
93 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577,
96static const uint8_t distanceExtraBits[32] = {
97 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
98 10, 11, 11, 12, 12, 13, 13, 14, 14
101static const uint8_t codeLengthsOrder[19] = {
102 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
104static OFHuffmanTree fixedLitLenTree, fixedDistTree;
112 uint16_t ret = stream->_savedBits;
114 OFAssert(stream->_savedBitsLength < count);
116 for (uint_fast8_t i = stream->_savedBitsLength; i < count; i++) {
117 if OF_UNLIKELY (stream->_bitIndex == 8) {
118 if OF_LIKELY (stream->_bufferIndex <
119 stream->_bufferLength)
121 stream->_buffer[stream->_bufferIndex++];
123 size_t length = [stream->_stream
127 if OF_UNLIKELY (length < 1) {
128 stream->_savedBits = ret;
129 stream->_savedBitsLength = i;
133 stream->_byte = stream->_buffer[0];
134 stream->_bufferIndex = 1;
135 stream->_bufferLength = (uint16_t)length;
138 stream->_bitIndex = 0;
141 ret |= ((stream->_byte >> stream->_bitIndex++) & 1) << i;
144 stream->_savedBits = 0;
145 stream->_savedBitsLength = 0;
153 uint8_t lengths[288];
155 if (
self != [OFInflateStream
class])
158 for (uint16_t i = 0; i <= 143; i++)
160 for (uint16_t i = 144; i <= 255; i++)
162 for (uint16_t i = 256; i <= 279; i++)
164 for (uint16_t i = 280; i <= 287; i++)
167 fixedLitLenTree = _OFHuffmanTreeNew(lengths, 288);
169 for (uint16_t i = 0; i <= 31; i++)
172 fixedDistTree = _OFHuffmanTreeNew(lengths, 32);
175+ (instancetype)streamWithStream: (
OFStream *)stream
177 return objc_autoreleaseReturnValue(
178 [[
self alloc] initWithStream: stream]);
183 OF_INVALID_INIT_METHOD
191 _stream = objc_retain(stream);
196#ifdef OF_INFLATE64_STREAM_M
197 _slidingWindowMask = 0xFFFF;
199 _slidingWindowMask = 0x7FFF;
217 if (_state == stateHuffmanTree) {
220 if (_context.huffmanTree.codeLenTree != NULL)
221 _OFHuffmanTreeFree(_context.huffmanTree.codeLenTree);
224 if (_state == stateHuffmanTree || _state == stateHuffmanBlock) {
225 if (_context.huffman.litLenTree != fixedLitLenTree)
226 _OFHuffmanTreeFree(_context.huffman.litLenTree);
227 if (_context.huffman.distTree != fixedDistTree)
228 _OFHuffmanTreeFree(_context.huffman.distTree);
234- (size_t)lowlevelReadIntoBuffer: (
void *)buffer_
235 length: (
size_t)length
237 unsigned char *buffer = buffer_;
238 uint16_t bits = 0, tmp, value = 0;
239 size_t bytesWritten = 0;
240 unsigned char *slidingWindow;
241 uint16_t slidingWindowIndex;
244 @throw [OFNotOpenException exceptionWithObject:
self];
250 switch ((
enum State)_state) {
251 case stateBlockHeader:
252 if OF_UNLIKELY (_inLastBlock) {
253 [_stream unreadFromBuffer: _buffer + _bufferIndex
254 length: _bufferLength -
256 _bufferIndex = _bufferLength = 0;
258 _atEndOfStream =
true;
262 if OF_UNLIKELY (!tryReadBits(
self, &bits, 3))
265 _inLastBlock = (bits & 1);
269 _state = stateUncompressedBlockHeader;
271 _context.uncompressedHeader.position = 0;
272 memset(_context.uncompressedHeader.length, 0, 4);
275 _state = stateHuffmanBlock;
276 _context.huffman.state = huffmanStateAwaitCode;
277 _context.huffman.litLenTree = fixedLitLenTree;
278 _context.huffman.distTree = fixedDistTree;
279 _context.huffman.treeIter = fixedLitLenTree;
282 _state = stateHuffmanTree;
283 _context.huffmanTree.lengths = NULL;
284 _context.huffmanTree.receivedCount = 0;
285 _context.huffmanTree.value = 0xFE;
286 _context.huffmanTree.litLenCodesCount = 0xFF;
287 _context.huffmanTree.distCodesCount = 0xFF;
288 _context.huffmanTree.codeLenCodesCount = 0xFF;
295 case stateUncompressedBlockHeader:
296#define CTX _context.uncompressedHeader
298 [_stream unreadFromBuffer: _buffer + _bufferIndex
299 length: _bufferLength - _bufferIndex];
300 _bufferIndex = _bufferLength = 0;
302 CTX.position += [_stream
303 readIntoBuffer: CTX.length + CTX.position
304 length: 4 - CTX.position];
306 if OF_UNLIKELY (CTX.position < 4)
309 if OF_UNLIKELY ((CTX.length[0] | (CTX.length[1] << 8)) !=
310 (uint16_t)~(CTX.length[2] | (CTX.length[3] << 8)))
311 @throw [OFInvalidFormatException exception];
313 _state = stateUncompressedBlock;
319 _context.uncompressed.length =
320 CTX.length[0] | (CTX.length[1] << 8);
321 _context.uncompressed.position = 0;
325 case stateUncompressedBlock:
326#define CTX _context.uncompressed
327 if OF_UNLIKELY (length == 0)
330 tmp = (length < (
size_t)CTX.length - CTX.position
331 ? (uint16_t)length : CTX.length - CTX.position);
333 tmp = (uint16_t)[_stream readIntoBuffer: buffer + bytesWritten
336 if OF_UNLIKELY (tmp == 0)
339 slidingWindow = _slidingWindow;
340 slidingWindowIndex = _slidingWindowIndex;
341 for (uint_fast16_t i = 0; i < tmp; i++) {
342 slidingWindow[slidingWindowIndex] =
343 buffer[bytesWritten + i];
344 slidingWindowIndex = (slidingWindowIndex + 1) &
347 _slidingWindowIndex = slidingWindowIndex;
353 if OF_UNLIKELY (CTX.position == CTX.length)
354 _state = stateBlockHeader;
358 case stateHuffmanTree:
359#define CTX _context.huffmanTree
360 if OF_LIKELY (CTX.value == 0xFE) {
361 if OF_LIKELY (CTX.litLenCodesCount == 0xFF) {
362 if OF_UNLIKELY (!tryReadBits(
self, &bits, 5))
365 if OF_UNLIKELY (bits > 29)
366 @throw [OFInvalidFormatException
369 CTX.litLenCodesCount = bits;
372 if OF_LIKELY (CTX.distCodesCount == 0xFF) {
373 if OF_UNLIKELY (!tryReadBits(
self, &bits, 5))
376 CTX.distCodesCount = bits;
379 if OF_LIKELY (CTX.codeLenCodesCount == 0xFF) {
380 if OF_UNLIKELY (!tryReadBits(
self, &bits, 4))
383 CTX.codeLenCodesCount = bits;
386 if OF_LIKELY (CTX.lengths == NULL)
389 for (uint16_t i = CTX.receivedCount;
390 i < CTX.codeLenCodesCount + 4; i++) {
391 if OF_UNLIKELY (!tryReadBits(
self, &bits, 3)) {
392 CTX.receivedCount = i;
396 CTX.lengths[codeLengthsOrder[i]] = bits;
399 CTX.codeLenTree = _OFHuffmanTreeNew(CTX.lengths, 19);
400 CTX.treeIter = CTX.codeLenTree;
404 CTX.receivedCount = 0;
408 if OF_LIKELY (CTX.lengths == NULL)
410 CTX.litLenCodesCount + CTX.distCodesCount + 258, 1);
412 for (uint16_t i = CTX.receivedCount;
413 i < CTX.litLenCodesCount + CTX.distCodesCount + 258;) {
416 if OF_LIKELY (CTX.value == 0xFF) {
417 if OF_UNLIKELY (!_OFHuffmanTreeWalk(
self,
418 tryReadBits, &CTX.treeIter, &value)) {
419 CTX.receivedCount = i;
423 CTX.treeIter = CTX.codeLenTree;
426 CTX.lengths[i++] = value;
434 if OF_UNLIKELY (i < 1)
438 if OF_UNLIKELY (!tryReadBits(
self, &bits, 2)) {
439 CTX.receivedCount = i;
444 value = CTX.lengths[i - 1];
449 if OF_UNLIKELY (!tryReadBits(
self, &bits, 3)) {
450 CTX.receivedCount = i;
460 if OF_UNLIKELY (!tryReadBits(
self, &bits, 7)) {
461 CTX.receivedCount = i;
474 if OF_UNLIKELY (i + count >
475 CTX.litLenCodesCount + CTX.distCodesCount + 258)
478 for (j = 0; j < count; j++)
479 CTX.lengths[i++] = value;
484 _OFHuffmanTreeFree(CTX.codeLenTree);
485 CTX.codeLenTree = NULL;
487 CTX.litLenTree = _OFHuffmanTreeNew(CTX.lengths,
488 CTX.litLenCodesCount + 257);
489 CTX.distTree = _OFHuffmanTreeNew(
490 CTX.lengths + CTX.litLenCodesCount + 257,
491 CTX.distCodesCount + 1);
500 _state = stateHuffmanBlock;
501 _context.huffman.state = huffmanStateAwaitCode;
502 _context.huffman.treeIter = CTX.litLenTree;
506 case stateHuffmanBlock:
507#define CTX _context.huffman
509 uint8_t extraBits, lengthCodeIndex;
511 if OF_UNLIKELY (CTX.state == huffmanStateWriteValue) {
512 if OF_UNLIKELY (length == 0)
515 buffer[bytesWritten++] = CTX.value;
518 _slidingWindow[_slidingWindowIndex] = CTX.value;
519 _slidingWindowIndex =
520 (_slidingWindowIndex + 1) &
523 CTX.state = huffmanStateAwaitCode;
524 CTX.treeIter = CTX.litLenTree;
527 if OF_UNLIKELY (CTX.state ==
528 huffmanStateAwaitLengthExtraBits) {
529 if OF_UNLIKELY (!tryReadBits(
self, &bits,
535 CTX.state = huffmanStateAwaitDistance;
536 CTX.treeIter = CTX.distTree;
540 if (CTX.state == huffmanStateAwaitDistance) {
541 if OF_UNLIKELY (!_OFHuffmanTreeWalk(
self,
542 tryReadBits, &CTX.treeIter, &value))
545 if OF_UNLIKELY (value >= numDistanceCodes)
549 CTX.distance = distanceCodes[value];
550 extraBits = distanceExtraBits[value];
553 if OF_UNLIKELY (!tryReadBits(
self,
555#define HSADEB huffmanStateAwaitDistanceExtraBits
558 CTX.extraBits = extraBits;
562 CTX.distance += bits;
565 CTX.state = huffmanStateProcessPair;
566 }
else if (CTX.state ==
567 huffmanStateAwaitDistanceExtraBits) {
568 if OF_UNLIKELY (!tryReadBits(
self, &bits,
572 CTX.distance += bits;
574 CTX.state = huffmanStateProcessPair;
578 if (CTX.state == huffmanStateProcessPair) {
579 for (uint_fast16_t j = 0; j < CTX.length; j++) {
582 if OF_UNLIKELY (length == 0) {
587 idx = (_slidingWindowIndex -
588 CTX.distance) & _slidingWindowMask;
589 value = _slidingWindow[idx];
591 buffer[bytesWritten++] = value;
594 _slidingWindow[_slidingWindowIndex] =
596 _slidingWindowIndex =
597 (_slidingWindowIndex + 1) &
601 CTX.state = huffmanStateAwaitCode;
602 CTX.treeIter = CTX.litLenTree;
605 if OF_UNLIKELY (!_OFHuffmanTreeWalk(
self, tryReadBits,
606 &CTX.treeIter, &value))
610 if OF_UNLIKELY (value == 256) {
611 if (CTX.litLenTree != fixedLitLenTree)
612 _OFHuffmanTreeFree(CTX.litLenTree);
613 if (CTX.distTree != fixedDistTree)
614 _OFHuffmanTreeFree(CTX.distTree);
616 _state = stateBlockHeader;
621 if OF_LIKELY (value < 256) {
622 if OF_UNLIKELY (length == 0) {
623 CTX.state = huffmanStateWriteValue;
628 buffer[bytesWritten++] = value;
631 _slidingWindow[_slidingWindowIndex] = value;
632 _slidingWindowIndex =
633 (_slidingWindowIndex + 1) &
636 CTX.treeIter = CTX.litLenTree;
640 if OF_UNLIKELY (value > 285)
644 lengthCodeIndex = value - 257;
645 CTX.length = lengthCodes[lengthCodeIndex] + 3;
646 extraBits = lengthExtraBits[lengthCodeIndex];
649 if OF_UNLIKELY (!tryReadBits(
self, &bits,
651 CTX.extraBits = extraBits;
653 huffmanStateAwaitLengthExtraBits;
660 CTX.treeIter = CTX.distTree;
661 CTX.state = huffmanStateAwaitDistance;
676 return _atEndOfStream;
681 return ((id <OFReadyForReadingObserving>)_stream)
682 .fileDescriptorForReading;
687 return (_stream.hasDataInReadBuffer ||
688 _bufferLength - _bufferIndex > 0);
697 [_stream unreadFromBuffer: _buffer + _bufferIndex
698 length: _bufferLength - _bufferIndex];
699 _bufferIndex = _bufferLength = 0;
701 objc_release(_stream);
void * OFAllocZeroedMemory(size_t count, size_t size) OF_MALLOC_FUNC
Allocates memory for the specified number of items of the specified size and initializes it with zero...
Definition OFObject.m:119
void OFFreeMemory(void *pointer)
Frees memory allocated by OFAllocMemory, OFAllocZeroedMemory or OFResizeMemory.
Definition OFObject.m:156
void * OFAllocMemory(size_t count, size_t size) OF_MALLOC_FUNC
Allocates memory for the specified number of items of the specified size.
Definition OFObject.m:101
#define nil
A value representing no object.
Definition ObjFWRT.h:68
instancetype exception()
Creates a new, autoreleased exception.
Definition OFException.m:283
A class that handles Deflate decompression transparently for an underlying stream.
Definition OFInflateStream.h:39
OFStream * underlyingStream
The underlying stream of the inflate stream.
Definition OFInflateStream.h:84
An exception indicating an object is not open, connected or bound.
Definition OFNotOpenException.h:30
instancetype exceptionWithObject:(id object)
Creates a new, autoreleased not open exception.
Definition OFNotOpenException.m:33
instancetype init()
Initializes an already allocated object.
Definition OFObject.m:671
void dealloc()
Deallocates the object.
Definition OFObject.m:1321
instancetype alloc()
Allocates memory for an instance of the class and sets up the memory pool for the object.
Definition OFObject.m:515
void initialize()
A method which is called the moment before the first call to the class is being made.
Definition OFObject.m:511
A base class for different types of streams.
Definition OFStream.h:280
size_t readIntoBuffer:length:(void *buffer,[length] size_t length)
Reads at most length bytes from the stream into a buffer.
Definition OFStream.m:135
bool lowlevelIsAtEndOfStream()
Returns whether the lowlevel is at the end of the stream.
Definition OFStream.m:112
void close()
Closes the stream.
Definition OFStream.m:1772
bool lowlevelHasDataInReadBuffer()
Returns whether the lowlevel has data in the read buffer.
Definition OFStream.m:117
int fileDescriptorForReading
The file descriptor for reading that should be checked by the OFKernelEventObserver.
Definition OFKernelEventObserver.h:89