Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -350,10 +350,12 @@ 4B8385181951BF9500D5358A /* OFSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B8385141951BF9500D5358A /* OFSettings.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B8385191951BF9500D5358A /* OFSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8385151951BF9500D5358A /* OFSettings.m */; }; 4B879A8C177231F000EBCEA4 /* OFDataArray+MessagePackValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B879A89177231F000EBCEA4 /* OFDataArray+MessagePackValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B879A8D177231F000EBCEA4 /* OFDataArray+MessagePackValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B879A8A177231F000EBCEA4 /* OFDataArray+MessagePackValue.m */; }; 4B879A8E177231F000EBCEA4 /* OFMessagePackRepresentation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B879A8B177231F000EBCEA4 /* OFMessagePackRepresentation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B881D3C1CCBFE2600E2F7D8 /* crc32.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B881D391CCBFE0700E2F7D8 /* crc32.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B881D3D1CCBFE2A00E2F7D8 /* crc32.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B881D3A1CCBFE0700E2F7D8 /* crc32.m */; }; 4B8B025917BBA7C7009ED983 /* OFZIPArchiveEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B8B025717BBA7C7009ED983 /* OFZIPArchiveEntry.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B8B025A17BBA7C7009ED983 /* OFZIPArchiveEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8B025817BBA7C7009ED983 /* OFZIPArchiveEntry.m */; }; 4B8B16FE133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B8B16FC133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B8B16FF133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8B16FD133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.m */; }; 4B8B170D133A3C11007CD8B3 /* OFConditionBroadcastFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8B1702133A3B8E007CD8B3 /* OFConditionBroadcastFailedException.m */; }; @@ -421,10 +423,12 @@ 4BC090441584F6760040640F /* OFInvalidJSONException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC090421584F6760040640F /* OFInvalidJSONException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BC090451584F6760040640F /* OFInvalidJSONException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC090431584F6760040640F /* OFInvalidJSONException.m */; }; 4BC1C3EB184B5EB200BBF50F /* OFMapTable+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC1C3EA184B5EB200BBF50F /* OFMapTable+Private.h */; }; 4BCAA9AF1772432F003EF859 /* OFMessagePackExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCAA9AD1772432E003EF859 /* OFMessagePackExtension.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BCAA9B01772432F003EF859 /* OFMessagePackExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BCAA9AE1772432E003EF859 /* OFMessagePackExtension.m */; }; + 4BD112611CCB73A60076FDB9 /* OFGZIPStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD1125F1CCB739A0076FDB9 /* OFGZIPStream.m */; }; + 4BD112621CCB73A90076FDB9 /* OFGZIPStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD1125E1CCB739A0076FDB9 /* OFGZIPStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BD653C5143B8489006182F0 /* OFTCPSocket+SOCKS5.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD653C3143B8489006182F0 /* OFTCPSocket+SOCKS5.h */; settings = {ATTRIBUTES = (); }; }; 4BD653C6143B8489006182F0 /* OFTCPSocket+SOCKS5.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD653C4143B8489006182F0 /* OFTCPSocket+SOCKS5.m */; }; 4BD77FDE176E4BC40031C497 /* OFUnboundPrefixException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD77FDC176E4BC40031C497 /* OFUnboundPrefixException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BD77FDF176E4BC40031C497 /* OFUnboundPrefixException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD77FDD176E4BC40031C497 /* OFUnboundPrefixException.m */; }; 4BD98C03133814220048DD5B /* objfw-defs.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD98C011338140B0048DD5B /* objfw-defs.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -852,10 +856,12 @@ 4B8385141951BF9500D5358A /* OFSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSettings.h; path = src/OFSettings.h; sourceTree = ""; }; 4B8385151951BF9500D5358A /* OFSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSettings.m; path = src/OFSettings.m; sourceTree = ""; }; 4B879A89177231F000EBCEA4 /* OFDataArray+MessagePackValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFDataArray+MessagePackValue.h"; path = "src/OFDataArray+MessagePackValue.h"; sourceTree = ""; }; 4B879A8A177231F000EBCEA4 /* OFDataArray+MessagePackValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFDataArray+MessagePackValue.m"; path = "src/OFDataArray+MessagePackValue.m"; sourceTree = ""; }; 4B879A8B177231F000EBCEA4 /* OFMessagePackRepresentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMessagePackRepresentation.h; path = src/OFMessagePackRepresentation.h; sourceTree = ""; }; + 4B881D391CCBFE0700E2F7D8 /* crc32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crc32.h; path = src/crc32.h; sourceTree = ""; }; + 4B881D3A1CCBFE0700E2F7D8 /* crc32.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = crc32.m; path = src/crc32.m; sourceTree = ""; }; 4B8B025717BBA7C7009ED983 /* OFZIPArchiveEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFZIPArchiveEntry.h; path = src/OFZIPArchiveEntry.h; sourceTree = ""; }; 4B8B025817BBA7C7009ED983 /* OFZIPArchiveEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFZIPArchiveEntry.m; path = src/OFZIPArchiveEntry.m; sourceTree = ""; }; 4B8B16FC133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFHashAlreadyCalculatedException.h; path = src/exceptions/OFHashAlreadyCalculatedException.h; sourceTree = ""; }; 4B8B16FD133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFHashAlreadyCalculatedException.m; path = src/exceptions/OFHashAlreadyCalculatedException.m; sourceTree = ""; }; 4B8B1701133A3B8E007CD8B3 /* OFConditionBroadcastFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFConditionBroadcastFailedException.h; path = src/exceptions/OFConditionBroadcastFailedException.h; sourceTree = ""; }; @@ -938,10 +944,12 @@ 4BC090421584F6760040640F /* OFInvalidJSONException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFInvalidJSONException.h; path = src/exceptions/OFInvalidJSONException.h; sourceTree = ""; }; 4BC090431584F6760040640F /* OFInvalidJSONException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFInvalidJSONException.m; path = src/exceptions/OFInvalidJSONException.m; sourceTree = ""; }; 4BC1C3EA184B5EB200BBF50F /* OFMapTable+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFMapTable+Private.h"; path = "src/OFMapTable+Private.h"; sourceTree = ""; }; 4BCAA9AD1772432E003EF859 /* OFMessagePackExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMessagePackExtension.h; path = src/OFMessagePackExtension.h; sourceTree = ""; }; 4BCAA9AE1772432E003EF859 /* OFMessagePackExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFMessagePackExtension.m; path = src/OFMessagePackExtension.m; sourceTree = ""; }; + 4BD1125E1CCB739A0076FDB9 /* OFGZIPStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFGZIPStream.h; path = src/OFGZIPStream.h; sourceTree = ""; }; + 4BD1125F1CCB739A0076FDB9 /* OFGZIPStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFGZIPStream.m; path = src/OFGZIPStream.m; sourceTree = ""; }; 4BD653C3143B8489006182F0 /* OFTCPSocket+SOCKS5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFTCPSocket+SOCKS5.h"; path = "src/OFTCPSocket+SOCKS5.h"; sourceTree = ""; }; 4BD653C4143B8489006182F0 /* OFTCPSocket+SOCKS5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFTCPSocket+SOCKS5.m"; path = "src/OFTCPSocket+SOCKS5.m"; sourceTree = ""; }; 4BD77FDC176E4BC40031C497 /* OFUnboundPrefixException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFUnboundPrefixException.h; path = src/exceptions/OFUnboundPrefixException.h; sourceTree = ""; }; 4BD77FDD176E4BC40031C497 /* OFUnboundPrefixException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFUnboundPrefixException.m; path = src/exceptions/OFUnboundPrefixException.m; sourceTree = ""; }; 4BD86D801237A6C600ED9912 /* OFBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFBlock.h; path = src/OFBlock.h; sourceTree = SOURCE_ROOT; }; @@ -1307,10 +1315,12 @@ 4B0108CA10EB8C9300631877 /* OFEnumerator.m */, 4B6799661099E7C50041064A /* OFFile.h */, 4B6799671099E7C50041064A /* OFFile.m */, 4B2C72881B888B6900717583 /* OFFileManager.h */, 4B2C72891B888B6900717583 /* OFFileManager.m */, + 4BD1125E1CCB739A0076FDB9 /* OFGZIPStream.h */, + 4BD1125F1CCB739A0076FDB9 /* OFGZIPStream.m */, 4BF1BCC011C9663F0025511F /* OFHash.h */, 4BB4B53F16775FF4002A2DCE /* OFHTTPClient.h */, 4BB4B54016775FF4002A2DCE /* OFHTTPClient.m */, 4B99250F12E0780000215DBE /* OFHTTPRequest.h */, 4B99251012E0780000215DBE /* OFHTTPRequest.m */, @@ -1490,10 +1500,12 @@ 4BA9CFA315E129D30076DC74 /* autorelease.h */, 4B3D236D1337FB5800DD29B8 /* base64.h */, 4B3D236E1337FB5800DD29B8 /* base64.m */, 4B837D7716829C5F007A3E83 /* block.h */, 4BB52CC617B8EA7F00B7EBF5 /* codepage_437.m */, + 4B881D391CCBFE0700E2F7D8 /* crc32.h */, + 4B881D3A1CCBFE0700E2F7D8 /* crc32.m */, 4B837D7816829C5F007A3E83 /* instance.h */, 4B6AF96F10A8D40E0003FB0A /* iso_8859_15.m */, 4BE17AD812FD744C002CEB0B /* foundation-compat.m */, 4BBA36C511406AB700CBA3AC /* macros.h */, 4BF1BCBF11C9663F0025511F /* objfw-defs.h.in */, @@ -1650,10 +1662,11 @@ 4B3D23C51337FCB000DD29B8 /* OFDictionary.h in Headers */, 4B3D23C61337FCB000DD29B8 /* OFEnumerator.h in Headers */, 4B17FF74133A2AAB003E6DCD /* OFException.h in Headers */, 4B3D23C81337FCB000DD29B8 /* OFFile.h in Headers */, 4B2C728C1B888B8700717583 /* OFFileManager.h in Headers */, + 4BD112621CCB73A90076FDB9 /* OFGZIPStream.h in Headers */, 4B3D23C91337FCB000DD29B8 /* OFHash.h in Headers */, 4BB4B54416775FF4002A2DCE /* OFHTTPClient.h in Headers */, 4B3D23CA1337FCB000DD29B8 /* OFHTTPRequest.h in Headers */, 4B7161AD17A6FC7600B74970 /* OFHTTPResponse.h in Headers */, 4BB4B54616775FF4002A2DCE /* OFHTTPServer.h in Headers */, @@ -1729,10 +1742,11 @@ 4B8B025917BBA7C7009ED983 /* OFZIPArchiveEntry.h in Headers */, 4B3D23E41337FCB000DD29B8 /* ObjFW.h in Headers */, 4B3D23E61337FCB000DD29B8 /* atomic.h in Headers */, 4BA9CFA415E129D30076DC74 /* autorelease.h in Headers */, 4B3D23E71337FCB000DD29B8 /* base64.h in Headers */, + 4B881D3C1CCBFE2600E2F7D8 /* crc32.h in Headers */, 4B837D7916829C5F007A3E83 /* block.h in Headers */, 4B837D7A16829C5F007A3E83 /* instance.h in Headers */, 4B3D23E81337FCB000DD29B8 /* macros.h in Headers */, 4BD98C03133814220048DD5B /* objfw-defs.h in Headers */, 4B3D23E91337FCB000DD29B8 /* of_asprintf.h in Headers */, @@ -1912,11 +1926,11 @@ /* Begin PBXProject section */ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0730; }; buildConfigurationList = 1DEB919308733D9F0010E9CD /* Build configuration list for PBXProject "ObjFW" */; compatibilityVersion = "Xcode 3.1"; developmentRegion = English; hasScannedForEncodings = 1; @@ -2041,10 +2055,11 @@ 4B70A9961B07DF9700CC5593 /* OFInflate64Stream.m in Sources */, 4B70A9971B07DF9700CC5593 /* OFInflateStream.m in Sources */, 4B06855418B2AD3800FC731A /* OFINICategory.m in Sources */, 4B5B02BF18B288A400CE6AE4 /* OFINIFile.m in Sources */, 4BA49D9113DB113B00381CDB /* OFIntrospection.m in Sources */, + 4BD112611CCB73A60076FDB9 /* OFGZIPStream.m in Sources */, 4B0EA9221898690E00F573A4 /* OFKernelEventObserver.m in Sources */, 4B0EA91C1898690E00F573A4 /* OFKernelEventObserver_kqueue.m in Sources */, 4B0EA91E1898690E00F573A4 /* OFKernelEventObserver_poll.m in Sources */, 4B0EA9201898690E00F573A4 /* OFKernelEventObserver_select.m in Sources */, 4B3D23991337FC0D00DD29B8 /* OFList.m in Sources */, @@ -2114,10 +2129,11 @@ 4B48B95514DC23B100546D39 /* OFXMLProcessingInstructions.m in Sources */, 4BE52D2217B990B4005958D1 /* OFZIPArchive.m in Sources */, 4B8B025A17BBA7C7009ED983 /* OFZIPArchiveEntry.m in Sources */, 4B3D23B31337FC0D00DD29B8 /* base64.m in Sources */, 4BB52CC717B8EA7F00B7EBF5 /* codepage_437.m in Sources */, + 4B881D3D1CCBFE2A00E2F7D8 /* crc32.m in Sources */, 4B3D23B41337FC0D00DD29B8 /* iso_8859_15.m in Sources */, 4B3D23B51337FC0D00DD29B8 /* foundation-compat.m in Sources */, 4B3D23EE1337FFD000DD29B8 /* of_asprintf.m in Sources */, 4BA355BA14879BDD00442EF4 /* of_strptime.m in Sources */, 4B7769EE1895C07D00D12284 /* resolver.m in Sources */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -21,10 +21,11 @@ OFDataArray+Hashing.m \ OFDataArray+MessagePackValue.m \ OFDate.m \ OFDictionary.m \ OFEnumerator.m \ + OFGZIPStream.m \ OFInflateStream.m \ OFInflate64Stream.m \ OFIntrospection.m \ OFList.m \ OFMapTable.m \ @@ -75,10 +76,11 @@ OFXMLElementBuilder.m \ OFXMLNode.m \ OFXMLParser.m \ OFXMLProcessingInstructions.m \ base64.m \ + crc32.m \ of_asprintf.m \ of_strptime.m \ unicode.m \ ${USE_SRCS_FILES} \ ${USE_SRCS_PLUGINS} \ ADDED src/OFGZIPStream.h Index: src/OFGZIPStream.h ================================================================== --- src/OFGZIPStream.h +++ src/OFGZIPStream.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 + * 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 + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFStream.h" +#import "OFDate.h" + +@class OFInflateStream; + +OF_ASSUME_NONNULL_BEGIN + +@interface OFGZIPStream: OFStream +{ + OFStream *_stream; + OFInflateStream *_inflateStream; + enum { + OF_GZIP_STREAM_ID1, + OF_GZIP_STREAM_ID2, + OF_GZIP_STREAM_COMPRESSION_METHOD, + OF_GZIP_STREAM_FLAGS, + OF_GZIP_STREAM_MODIFICATION_TIME, + OF_GZIP_STREAM_EXTRA_FLAGS, + OF_GZIP_STREAM_OS, + OF_GZIP_STREAM_EXTRA_LENGTH, + OF_GZIP_STREAM_EXTRA, + OF_GZIP_STREAM_NAME, + OF_GZIP_STREAM_COMMENT, + OF_GZIP_STREAM_HEADER_CRC16, + OF_GZIP_STREAM_DATA, + OF_GZIP_STREAM_CRC32, + OF_GZIP_STREAM_UNCOMPRESSED_SIZE + } _state; + enum { + OF_GZIP_STREAM_FLAG_TEXT = 0x01, + OF_GZIP_STREAM_FLAG_HEADER_CRC16 = 0x02, + OF_GZIP_STREAM_FLAG_EXTRA = 0x04, + OF_GZIP_STREAM_FLAG_NAME = 0x08, + OF_GZIP_STREAM_FLAG_COMMENT = 0x10 + } _flags; + uint8_t _extraFlags; + enum { + OF_GZIP_STREAM_OS_FAT = 0, + OF_GZIP_STREAM_OS_AMIGA = 1, + OF_GZIP_STREAM_OS_VMS = 2, + OF_GZIP_STREAM_OS_UNIX = 3, + OF_GZIP_STREAM_OS_VM_CMS = 4, + OF_GZIP_STREAM_OS_ATARI_TOS = 5, + OF_GZIP_STREAM_OS_HPFS = 6, + OF_GZIP_STREAM_OS_MACINTOSH = 7, + OF_GZIP_STREAM_OS_Z_SYSTEM = 8, + OF_GZIP_STREAM_OS_CP_M = 9, + OF_GZIP_STREAM_OS_TOPS_20 = 10, + OF_GZIP_STREAM_OS_NTFS = 11, + OF_GZIP_STREAM_OS_QDOS = 12, + OF_GZIP_STREAM_OS_ACORN_RISCOS = 13, + OF_GZIP_STREAM_OS_UNKNOWN = 255 + } _OS; + size_t _bytesRead; + uint8_t _buffer[4]; + OFDate *_modificationDate; + uint16_t _extraLength; + uint32_t _CRC32, _uncompressedSize; +} + ++ (instancetype)streamWithStream: (OFStream*)stream; +- initWithStream: (OFStream*)stream; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFGZIPStream.m Index: src/OFGZIPStream.m ================================================================== --- src/OFGZIPStream.m +++ src/OFGZIPStream.m @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 + * 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 + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFGZIPStream.h" +#import "OFInflateStream.h" +#import "OFDate.h" + +#import "crc32.h" + +#import "OFChecksumFailedException.h" +#import "OFInvalidFormatException.h" + +@implementation OFGZIPStream ++ (instancetype)streamWithStream: (OFStream*)stream +{ + return [[[self alloc] initWithStream: stream] autorelease]; +} + +- initWithStream: (OFStream*)stream +{ + self = [super init]; + + @try { + _stream = [stream retain]; + _CRC32 = ~0; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_stream release]; + [_inflateStream release]; + [_modificationDate release]; + + [super dealloc]; +} + +- (size_t)lowlevelReadIntoBuffer: (void*)buffer + length: (size_t)length +{ + uint8_t byte; + + for (;;) { + switch (_state) { + case OF_GZIP_STREAM_ID1: + case OF_GZIP_STREAM_ID2: + case OF_GZIP_STREAM_COMPRESSION_METHOD: + if ([_stream readIntoBuffer: &byte + length: 1] < 1) + return 0; + + if ((_state == OF_GZIP_STREAM_ID1 && byte != 0x1F) || + (_state == OF_GZIP_STREAM_ID2 && byte != 0x8B) || + (_state == OF_GZIP_STREAM_COMPRESSION_METHOD && + byte != 8)) + @throw [OFInvalidFormatException exception]; + + _state++; + break; + case OF_GZIP_STREAM_FLAGS: + if ([_stream readIntoBuffer: &byte + length: 1] < 1) + return 0; + + _flags = byte; + _state++; + break; + case OF_GZIP_STREAM_MODIFICATION_TIME: + _bytesRead += [_stream + readIntoBuffer: _buffer + _bytesRead + length: 4 - _bytesRead]; + + if (_bytesRead < 4) + return 0; + + _modificationDate = [[OFDate alloc] + initWithTimeIntervalSince1970: + (_buffer[3] << 24) | (_buffer[2] << 16) | + (_buffer[1] << 8) | _buffer[0]]; + + _bytesRead = 0; + _state++; + break; + case OF_GZIP_STREAM_EXTRA_FLAGS: + if ([_stream readIntoBuffer: &byte + length: 1] < 1) + return 0; + + _extraFlags = byte; + _state++; + break; + case OF_GZIP_STREAM_OS: + if ([_stream readIntoBuffer: &byte + length: 1] < 1) + return 0; + + _OS = byte; + _state++; + break; + case OF_GZIP_STREAM_EXTRA_LENGTH: + if (!(_flags & OF_GZIP_STREAM_FLAG_EXTRA)) { + _state += 2; + break; + } + + _bytesRead += [_stream + readIntoBuffer: _buffer + _bytesRead + length: 2 - _bytesRead]; + + if (_bytesRead < 2) + return 0; + + _extraLength = (_buffer[1] << 8) | _buffer[0]; + _bytesRead = 0; + _state++; + break; + case OF_GZIP_STREAM_EXTRA: + { + char tmp[512]; + size_t toRead = _extraLength - _bytesRead; + + if (toRead > 512) + toRead = 512; + + _bytesRead += [_stream readIntoBuffer: tmp + length: toRead]; + } + + if (_bytesRead < _extraLength) + return 0; + + _bytesRead = 0; + _state++; + break; + case OF_GZIP_STREAM_NAME: + if (!(_flags & OF_GZIP_STREAM_FLAG_NAME)) { + _state++; + break; + } + + do { + if ([_stream readIntoBuffer: &byte + length: 1] < 1) + return 0; + } while (byte != 0); + + _state++; + break; + case OF_GZIP_STREAM_COMMENT: + if (!(_flags & OF_GZIP_STREAM_FLAG_COMMENT)) { + _state++; + break; + } + + do { + if ([_stream readIntoBuffer: &byte + length: 1] < 1) + return 0; + } while (byte != 0); + + _state++; + break; + case OF_GZIP_STREAM_HEADER_CRC16: + if (!(_flags & OF_GZIP_STREAM_FLAG_HEADER_CRC16)) { + _state++; + break; + } + + _bytesRead += [_stream + readIntoBuffer: _buffer + _bytesRead + length: 2 - _bytesRead]; + + if (_bytesRead < 2) + return 0; + + /* + * Header CRC16 is not checked, as I could not find a + * single file in the wild that actually has a header + * CRC16 - and thus no file to test against. + */ + + _bytesRead = 0; + _state++; + break; + case OF_GZIP_STREAM_DATA: + if (_inflateStream == nil) + _inflateStream = [[OFInflateStream alloc] + initWithStream: _stream]; + + if (![_inflateStream isAtEndOfStream]) { + size_t bytesRead = [_inflateStream + readIntoBuffer: buffer + length: length]; + + _CRC32 = of_crc32(_CRC32, buffer, bytesRead); + _uncompressedSize += bytesRead; + + return bytesRead; + } + + [_inflateStream release]; + _inflateStream = nil; + + _state++; + break; + case OF_GZIP_STREAM_CRC32: + _bytesRead += [_stream readIntoBuffer: _buffer + length: 4 - _bytesRead]; + + if (_bytesRead < 4) + return 0; + + if (((_buffer[3] << 24) | (_buffer[2] << 16) | + (_buffer[1] << 8) | _buffer[0]) != ~_CRC32) + @throw [OFChecksumFailedException exception]; + + _bytesRead = 0; + _CRC32 = ~0; + _state++; + break; + case OF_GZIP_STREAM_UNCOMPRESSED_SIZE: + _bytesRead += [_stream readIntoBuffer: _buffer + length: 4 - _bytesRead]; + + if (((_buffer[3] << 24) | (_buffer[2] << 16) | + (_buffer[1] << 8) | _buffer[0]) != + _uncompressedSize) + @throw [OFChecksumFailedException exception]; + + _bytesRead = 0; + _uncompressedSize = 0; + _state = OF_GZIP_STREAM_ID1; + break; + } + } +} + +- (bool)lowlevelIsAtEndOfStream +{ + return [_stream isAtEndOfStream]; +} + +- (bool)hasDataInReadBuffer +{ + if (_state == OF_GZIP_STREAM_DATA) + return ([super hasDataInReadBuffer] || + [_inflateStream hasDataInReadBuffer]); + + return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer]); +} +@end Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -25,10 +25,12 @@ #import "OFArray.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFInflateStream.h" #import "OFInflate64Stream.h" + +#import "crc32.h" #import "OFChecksumFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" @@ -36,12 +38,10 @@ #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSeekFailedException.h" #import "OFUnsupportedVersionException.h" -#define CRC32_MAGIC 0xEDB88320 - /* * FIXME: Current limitations: * - Split archives are not supported. * - Write support is missing. * - The ZIP has to be a file on the local file system. @@ -114,23 +114,10 @@ *size -= 8; return field; } -static uint32_t -calculateCRC32(uint32_t crc, uint8_t *bytes, size_t length) -{ - for (size_t i = 0; i < length; i++) { - crc ^= bytes[i]; - - for (uint8_t j = 0; j < 8; j++) - crc = (crc >> 1) ^ (CRC32_MAGIC & (~(crc & 1) + 1)); - } - - return crc; -} - static void seekOrThrowInvalidFormat(OFSeekableStream *stream, of_offset_t offset, int whence) { @try { @@ -561,15 +548,15 @@ ret = [_decompressedStream readIntoBuffer: buffer length: min]; _size -= ret; } - _CRC32 = calculateCRC32(_CRC32, buffer, ret); + _CRC32 = of_crc32(_CRC32, buffer, ret); return ret; } - (void)close { _closed = true; } @end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -45,10 +45,11 @@ #import "OFStream.h" #import "OFStdIOStream.h" #import "OFInflateStream.h" #import "OFInflate64Stream.h" +#import "OFGZIPStream.h" #ifdef OF_HAVE_FILES # import "OFFile.h" # import "OFFileManager.h" # import "OFINIFile.h" # import "OFSettings.h" ADDED src/crc32.h Index: src/crc32.h ================================================================== --- src/crc32.h +++ src/crc32.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 + * 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 + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern uint32_t of_crc32(uint32_t crc, unsigned char *bytes, size_t length); +#ifdef __cplusplus +} +#endif ADDED src/crc32.m Index: src/crc32.m ================================================================== --- src/crc32.m +++ src/crc32.m @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 + * 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 + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "crc32.h" + +#define CRC32_MAGIC 0xEDB88320 + +uint32_t +of_crc32(uint32_t crc, unsigned char *bytes, size_t length) +{ + for (size_t i = 0; i < length; i++) { + crc ^= bytes[i]; + + for (uint8_t j = 0; j < 8; j++) + crc = (crc >> 1) ^ (CRC32_MAGIC & (~(crc & 1) + 1)); + } + + return crc; +}