@@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2023 Jonathan Schleifer + * Copyright (c) 2008-2024 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -79,11 +79,17 @@ for (;;) { uint8_t byte; uint32_t CRC32, uncompressedSize; - if (_stream.atEndOfStream) { + /* + * The inflate stream might have overread, causing _stream to + * be at the end, but the inflate stream will unread it once it + * has reached the end. Hence only check it if the state is not + * OFGZIPStreamStateData. + */ + if (_state != OFGZIPStreamStateData && _stream.atEndOfStream) { if (_state != OFGZIPStreamStateID1) @throw [OFTruncatedDataException exception]; return 0; } @@ -248,12 +254,13 @@ _inflateStream = nil; _state++; break; case OFGZIPStreamStateCRC32: - _bytesRead += [_stream readIntoBuffer: _buffer - length: 4 - _bytesRead]; + _bytesRead += [_stream + readIntoBuffer: _buffer + _bytesRead + length: 4 - _bytesRead]; if (_bytesRead < 4) return 0; CRC32 = ((uint32_t)_buffer[3] << 24) | @@ -272,14 +279,18 @@ _bytesRead = 0; _CRC32 = ~0; _state++; break; case OFGZIPStreamStateUncompressedSize: - _bytesRead += [_stream readIntoBuffer: _buffer - length: 4 - _bytesRead]; + _bytesRead += [_stream + readIntoBuffer: _buffer + _bytesRead + length: 4 - _bytesRead]; + + if (_bytesRead < 4) + return 0; - uncompressedSize = ((uint32_t)_buffer[3] << 24) | + uncompressedSize = (_buffer[3] << 24) | (_buffer[2] << 16) | (_buffer[1] << 8) | _buffer[0]; if (_uncompressedSize != uncompressedSize) { OFString *actual = [OFString stringWithFormat: @"%" PRIu32, _uncompressedSize]; OFString *expected = [OFString stringWithFormat: @@ -301,10 +312,18 @@ - (bool)lowlevelIsAtEndOfStream { if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; + /* + * The inflate stream might have overread, causing _stream to be at the + * end, but the inflate stream will unread it once it has reached the + * end. + */ + if (_state == OFGZIPStreamStateData && !_inflateStream.atEndOfStream) + return false; + return _stream.atEndOfStream; } - (bool)hasDataInReadBuffer {