Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -204,12 +204,10 @@ 4B2C212A1DA292BE00735907 /* OFCountedSet_hashtable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA85BC5140ECCE800E91D51 /* OFCountedSet_hashtable.m */; }; 4B2C212B1DA292BE00735907 /* OFDataArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6799611099E7C50041064A /* OFDataArray.m */; }; 4B2C212C1DA292BE00735907 /* OFDataArray+CryptoHashing.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE17ADA12FD746D002CEB0B /* OFDataArray+CryptoHashing.m */; }; 4B2C212D1DA292BE00735907 /* OFDataArray+MessagePackValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B879A8A177231F000EBCEA4 /* OFDataArray+MessagePackValue.m */; }; 4B2C212E1DA292BE00735907 /* OFDate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5F0DA12DF4225005C7A0C /* OFDate.m */; }; - 4B2C212F1DA292BE00735907 /* OFDeflate64Stream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC176201D04963000C32718 /* OFDeflate64Stream.m */; }; - 4B2C21301DA292BE00735907 /* OFDeflateStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC176221D04963000C32718 /* OFDeflateStream.m */; }; 4B2C21311DA292BE00735907 /* OFDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6799631099E7C50041064A /* OFDictionary.m */; }; 4B2C21321DA292BE00735907 /* OFDictionary_hashtable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3E76140D430500EC2F7C /* OFDictionary_hashtable.m */; }; 4B2C21331DA292BE00735907 /* OFEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B0108CA10EB8C9300631877 /* OFEnumerator.m */; }; 4B2C21341DA292BE00735907 /* OFFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6799671099E7C50041064A /* OFFile.m */; }; 4B2C21351DA292BE00735907 /* OFFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2C72891B888B6900717583 /* OFFileManager.m */; }; @@ -382,12 +380,10 @@ 4B2C21E11DA292BE00735907 /* OFCryptoHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF1BCC011C9663F0025511F /* OFCryptoHash.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21E21DA292BE00735907 /* OFDataArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6799601099E7C50041064A /* OFDataArray.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21E31DA292BE00735907 /* OFDataArray+CryptoHashing.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BE17AD912FD746D002CEB0B /* OFDataArray+CryptoHashing.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21E41DA292BE00735907 /* OFDataArray+MessagePackValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B879A89177231F000EBCEA4 /* OFDataArray+MessagePackValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21E51DA292BE00735907 /* OFDate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BE5F0D912DF4225005C7A0C /* OFDate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4B2C21E61DA292BE00735907 /* OFDeflateStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC176211D04963000C32718 /* OFDeflateStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4B2C21E71DA292BE00735907 /* OFDeflate64Stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC1761F1D04963000C32718 /* OFDeflate64Stream.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21E81DA292BE00735907 /* OFDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6799621099E7C50041064A /* OFDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21E91DA292BE00735907 /* OFEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0108C910EB8C9300631877 /* OFEnumerator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21EA1DA292BE00735907 /* OFException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B17FF70133A28FC003E6DCD /* OFException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21EB1DA292BE00735907 /* OFFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6799661099E7C50041064A /* OFFile.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B2C21EC1DA292BE00735907 /* OFFileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B2C72881B888B6900717583 /* OFFileManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -884,14 +880,10 @@ 4BB524C1143D1E4E0085FBCC /* OFProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB524BF143D1E4E0085FBCC /* OFProcess.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BB524C2143D1E4E0085FBCC /* OFProcess.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB524C0143D1E4E0085FBCC /* OFProcess.m */; settings = {ATTRIBUTES = (Public, ); }; }; 4BB52CC717B8EA7F00B7EBF5 /* codepage_437.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB52CC617B8EA7F00B7EBF5 /* codepage_437.m */; }; 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 */; }; - 4BC1762B1D04963000C32718 /* OFDeflate64Stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC1761F1D04963000C32718 /* OFDeflate64Stream.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4BC1762C1D04963000C32718 /* OFDeflate64Stream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC176201D04963000C32718 /* OFDeflate64Stream.m */; }; - 4BC1762D1D04963000C32718 /* OFDeflateStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC176211D04963000C32718 /* OFDeflateStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4BC1762E1D04963000C32718 /* OFDeflateStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC176221D04963000C32718 /* OFDeflateStream.m */; }; 4BC1762F1D04963000C32718 /* OFKeyValueCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC176231D04963000C32718 /* OFKeyValueCoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BC176301D04963000C32718 /* OFObject+KeyValueCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC176241D04963000C32718 /* OFObject+KeyValueCoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BC176311D04963000C32718 /* OFObject+KeyValueCoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC176251D04963000C32718 /* OFObject+KeyValueCoding.m */; }; 4BC176321D04963000C32718 /* OFTarArchive.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC176261D04963000C32718 /* OFTarArchive.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BC176331D04963000C32718 /* OFTarArchive.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC176271D04963000C32718 /* OFTarArchive.m */; }; @@ -964,10 +956,18 @@ 4BEC83B919B7CB7100E4BB08 /* OFRIPEMD160Hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BEC83B719B7CB7100E4BB08 /* OFRIPEMD160Hash.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BEC83BA19B7CB7100E4BB08 /* OFRIPEMD160Hash.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BEC83B819B7CB7100E4BB08 /* OFRIPEMD160Hash.m */; }; 4BEC83BC19B7CBDE00E4BB08 /* OFRIPEMD160HashTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BEC83BB19B7CBDE00E4BB08 /* OFRIPEMD160HashTests.m */; }; 4BF0DD741D44645D001D9949 /* OFHMACTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0DD731D44645D001D9949 /* OFHMACTests.m */; }; 4BF171B21C949A3300F5B47B /* OFStdIOStream+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF171B11C9499F300F5B47B /* OFStdIOStream+Private.h */; }; + 4BF20C511EEBF5F000C53220 /* OFInflate64Stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF20C4D1EEBF5F000C53220 /* OFInflate64Stream.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BF20C521EEBF5F000C53220 /* OFInflate64Stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF20C4D1EEBF5F000C53220 /* OFInflate64Stream.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BF20C531EEBF5F000C53220 /* OFInflate64Stream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF20C4E1EEBF5F000C53220 /* OFInflate64Stream.m */; }; + 4BF20C541EEBF5F000C53220 /* OFInflate64Stream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF20C4E1EEBF5F000C53220 /* OFInflate64Stream.m */; }; + 4BF20C551EEBF5F000C53220 /* OFInflateStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF20C4F1EEBF5F000C53220 /* OFInflateStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BF20C561EEBF5F000C53220 /* OFInflateStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF20C4F1EEBF5F000C53220 /* OFInflateStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BF20C571EEBF5F000C53220 /* OFInflateStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF20C501EEBF5F000C53220 /* OFInflateStream.m */; }; + 4BF20C581EEBF5F000C53220 /* OFInflateStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF20C501EEBF5F000C53220 /* OFInflateStream.m */; }; 4BF33AFB133807590059CEF7 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B3D23761337FBC800DD29B8 /* ObjFW.framework */; }; 4BF33AFC133807A20059CEF7 /* OFArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6EF66E1235358D0076B512 /* OFArrayTests.m */; }; 4BF33AFD133807A20059CEF7 /* OFBlockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5F0E412DF4259005C7A0C /* OFBlockTests.m */; }; 4BF33AFE133807A20059CEF7 /* OFDataArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6EF66F1235358D0076B512 /* OFDataArrayTests.m */; }; 4BF33AFF133807A20059CEF7 /* OFDateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5F0E512DF4259005C7A0C /* OFDateTests.m */; }; @@ -1560,14 +1560,10 @@ 4BB52CC617B8EA7F00B7EBF5 /* codepage_437.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = codepage_437.m; path = src/encodings/codepage_437.m; sourceTree = ""; }; 4BBA36C411406AB700CBA3AC /* atomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atomic.h; path = src/atomic.h; sourceTree = ""; }; 4BBA36C511406AB700CBA3AC /* macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macros.h; path = src/macros.h; sourceTree = ""; }; 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 = ""; }; - 4BC1761F1D04963000C32718 /* OFDeflate64Stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFDeflate64Stream.h; path = src/OFDeflate64Stream.h; sourceTree = ""; }; - 4BC176201D04963000C32718 /* OFDeflate64Stream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFDeflate64Stream.m; path = src/OFDeflate64Stream.m; sourceTree = ""; }; - 4BC176211D04963000C32718 /* OFDeflateStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFDeflateStream.h; path = src/OFDeflateStream.h; sourceTree = ""; }; - 4BC176221D04963000C32718 /* OFDeflateStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFDeflateStream.m; path = src/OFDeflateStream.m; sourceTree = ""; }; 4BC176231D04963000C32718 /* OFKeyValueCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFKeyValueCoding.h; path = src/OFKeyValueCoding.h; sourceTree = ""; }; 4BC176241D04963000C32718 /* OFObject+KeyValueCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFObject+KeyValueCoding.h"; path = "src/OFObject+KeyValueCoding.h"; sourceTree = ""; }; 4BC176251D04963000C32718 /* OFObject+KeyValueCoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFObject+KeyValueCoding.m"; path = "src/OFObject+KeyValueCoding.m"; sourceTree = ""; }; 4BC176261D04963000C32718 /* OFTarArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFTarArchive.h; path = src/OFTarArchive.h; sourceTree = ""; }; 4BC176271D04963000C32718 /* OFTarArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFTarArchive.m; path = src/OFTarArchive.m; sourceTree = ""; }; @@ -1625,10 +1621,14 @@ 4BF1BCCB11C9663F0025511F /* OFString+XMLEscaping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFString+XMLEscaping.m"; path = "src/OFString+XMLEscaping.m"; sourceTree = ""; }; 4BF1BCCC11C9663F0025511F /* OFString+XMLUnescaping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFString+XMLUnescaping.h"; path = "src/OFString+XMLUnescaping.h"; sourceTree = ""; }; 4BF1BCCD11C9663F0025511F /* OFString+XMLUnescaping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFString+XMLUnescaping.m"; path = "src/OFString+XMLUnescaping.m"; sourceTree = ""; }; 4BF1BCCE11C9663F0025511F /* OFXMLAttribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFXMLAttribute.h; path = src/OFXMLAttribute.h; sourceTree = ""; }; 4BF1BCCF11C9663F0025511F /* OFXMLAttribute.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFXMLAttribute.m; path = src/OFXMLAttribute.m; sourceTree = ""; }; + 4BF20C4D1EEBF5F000C53220 /* OFInflate64Stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFInflate64Stream.h; path = src/OFInflate64Stream.h; sourceTree = ""; }; + 4BF20C4E1EEBF5F000C53220 /* OFInflate64Stream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFInflate64Stream.m; path = src/OFInflate64Stream.m; sourceTree = ""; }; + 4BF20C4F1EEBF5F000C53220 /* OFInflateStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFInflateStream.h; path = src/OFInflateStream.h; sourceTree = ""; }; + 4BF20C501EEBF5F000C53220 /* OFInflateStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFInflateStream.m; path = src/OFInflateStream.m; sourceTree = ""; }; 4BF33AF0133807310059CEF7 /* Tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Tests; sourceTree = BUILT_PRODUCTS_DIR; }; 4BF33B4213380CD40059CEF7 /* testfile.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = testfile.bin; path = tests/testfile.bin; sourceTree = ""; }; 4BF33B4313380CD40059CEF7 /* testfile.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = testfile.txt; path = tests/testfile.txt; sourceTree = ""; }; 4BF3A2281E25EA48002EA46F /* windows_1251.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = windows_1251.m; path = src/encodings/windows_1251.m; sourceTree = ""; }; 4BF48CDF18A95F83000E8D04 /* OFBigDataArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFBigDataArray.h; path = src/OFBigDataArray.h; sourceTree = ""; }; @@ -2005,14 +2005,10 @@ 4BE17ADA12FD746D002CEB0B /* OFDataArray+CryptoHashing.m */, 4B879A89177231F000EBCEA4 /* OFDataArray+MessagePackValue.h */, 4B879A8A177231F000EBCEA4 /* OFDataArray+MessagePackValue.m */, 4BE5F0D912DF4225005C7A0C /* OFDate.h */, 4BE5F0DA12DF4225005C7A0C /* OFDate.m */, - 4BC1761F1D04963000C32718 /* OFDeflate64Stream.h */, - 4BC176201D04963000C32718 /* OFDeflate64Stream.m */, - 4BC176211D04963000C32718 /* OFDeflateStream.h */, - 4BC176221D04963000C32718 /* OFDeflateStream.m */, 4B6799621099E7C50041064A /* OFDictionary.h */, 4B6799631099E7C50041064A /* OFDictionary.m */, 4B2B3E75140D430500EC2F7C /* OFDictionary_hashtable.h */, 4B2B3E76140D430500EC2F7C /* OFDictionary_hashtable.m */, 4B0108C910EB8C9300631877 /* OFEnumerator.h */, @@ -2035,10 +2031,14 @@ 4B99251012E0780000215DBE /* OFHTTPRequest.m */, 4B7161AB17A6FC7600B74970 /* OFHTTPResponse.h */, 4B7161AC17A6FC7600B74970 /* OFHTTPResponse.m */, 4BB4B54116775FF4002A2DCE /* OFHTTPServer.h */, 4BB4B54216775FF4002A2DCE /* OFHTTPServer.m */, + 4BF20C4D1EEBF5F000C53220 /* OFInflate64Stream.h */, + 4BF20C4E1EEBF5F000C53220 /* OFInflate64Stream.m */, + 4BF20C4F1EEBF5F000C53220 /* OFInflateStream.h */, + 4BF20C501EEBF5F000C53220 /* OFInflateStream.m */, 4B06855018B2AD3800FC731A /* OFINICategory.h */, 4B06855118B2AD3800FC731A /* OFINICategory.m */, 4B06855218B2AD3800FC731A /* OFINICategory+Private.h */, 4B5B02BC18B288A400CE6AE4 /* OFINIFile.h */, 4B5B02BD18B288A400CE6AE4 /* OFINIFile.m */, @@ -2410,12 +2410,10 @@ 4B2C21E11DA292BE00735907 /* OFCryptoHash.h in Headers */, 4B2C21E21DA292BE00735907 /* OFDataArray.h in Headers */, 4B2C21E31DA292BE00735907 /* OFDataArray+CryptoHashing.h in Headers */, 4B2C21E41DA292BE00735907 /* OFDataArray+MessagePackValue.h in Headers */, 4B2C21E51DA292BE00735907 /* OFDate.h in Headers */, - 4B2C21E61DA292BE00735907 /* OFDeflateStream.h in Headers */, - 4B2C21E71DA292BE00735907 /* OFDeflate64Stream.h in Headers */, 4B2C21E81DA292BE00735907 /* OFDictionary.h in Headers */, 4B2C21E91DA292BE00735907 /* OFEnumerator.h in Headers */, 4B2C21EA1DA292BE00735907 /* OFException.h in Headers */, 4B2C21EB1DA292BE00735907 /* OFFile.h in Headers */, 4B2C21EC1DA292BE00735907 /* OFFileManager.h in Headers */, @@ -2425,10 +2423,12 @@ 4B2C21F01DA292BE00735907 /* OFHTTPCookie.h in Headers */, 4B6255171EC274FA003D49F4 /* OFHTTPCookieManager.h in Headers */, 4B2C21F11DA292BE00735907 /* OFHTTPRequest.h in Headers */, 4B2C21F21DA292BE00735907 /* OFHTTPResponse.h in Headers */, 4B2C21F31DA292BE00735907 /* OFHTTPServer.h in Headers */, + 4BF20C521EEBF5F000C53220 /* OFInflate64Stream.h in Headers */, + 4BF20C561EEBF5F000C53220 /* OFInflateStream.h in Headers */, 4B2C21F41DA292BE00735907 /* OFINICategory.h in Headers */, 4B2C21F51DA292BE00735907 /* OFINIFile.h in Headers */, 4B2C21F61DA292BE00735907 /* OFIntrospection.h in Headers */, 4B2C21F71DA292BE00735907 /* OFJSONRepresentation.h in Headers */, 4B2C21F81DA292BE00735907 /* OFKernelEventObserver.h in Headers */, @@ -2634,12 +2634,10 @@ 4B3D23C91337FCB000DD29B8 /* OFCryptoHash.h in Headers */, 4B3D23C21337FC8300DD29B8 /* OFDataArray.h in Headers */, 4B3D23C31337FC8300DD29B8 /* OFDataArray+CryptoHashing.h in Headers */, 4B879A8C177231F000EBCEA4 /* OFDataArray+MessagePackValue.h in Headers */, 4B3D23C41337FC8300DD29B8 /* OFDate.h in Headers */, - 4BC1762D1D04963000C32718 /* OFDeflateStream.h in Headers */, - 4BC1762B1D04963000C32718 /* OFDeflate64Stream.h in Headers */, 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 */, @@ -2649,10 +2647,12 @@ 4B2610C31D863007001F16C9 /* OFHTTPCookie.h in Headers */, 4B6255161EC274FA003D49F4 /* OFHTTPCookieManager.h in Headers */, 4B3D23CA1337FCB000DD29B8 /* OFHTTPRequest.h in Headers */, 4B7161AD17A6FC7600B74970 /* OFHTTPResponse.h in Headers */, 4BB4B54616775FF4002A2DCE /* OFHTTPServer.h in Headers */, + 4BF20C511EEBF5F000C53220 /* OFInflate64Stream.h in Headers */, + 4BF20C551EEBF5F000C53220 /* OFInflateStream.h in Headers */, 4B06855318B2AD3800FC731A /* OFINICategory.h in Headers */, 4B5B02BE18B288A400CE6AE4 /* OFINIFile.h in Headers */, 4BA49D9013DB113B00381CDB /* OFIntrospection.h in Headers */, 4BA02BA115041F5900002F84 /* OFJSONRepresentation.h in Headers */, 4B0EA9211898690E00F573A4 /* OFKernelEventObserver.h in Headers */, @@ -3177,12 +3177,10 @@ 4B2C212A1DA292BE00735907 /* OFCountedSet_hashtable.m in Sources */, 4B2C212B1DA292BE00735907 /* OFDataArray.m in Sources */, 4B2C212C1DA292BE00735907 /* OFDataArray+CryptoHashing.m in Sources */, 4B2C212D1DA292BE00735907 /* OFDataArray+MessagePackValue.m in Sources */, 4B2C212E1DA292BE00735907 /* OFDate.m in Sources */, - 4B2C212F1DA292BE00735907 /* OFDeflate64Stream.m in Sources */, - 4B2C21301DA292BE00735907 /* OFDeflateStream.m in Sources */, 4B2C21311DA292BE00735907 /* OFDictionary.m in Sources */, 4B2C21321DA292BE00735907 /* OFDictionary_hashtable.m in Sources */, 4B2C21331DA292BE00735907 /* OFEnumerator.m in Sources */, 4B2C21341DA292BE00735907 /* OFFile.m in Sources */, 4B2C21351DA292BE00735907 /* OFFileManager.m in Sources */, @@ -3191,10 +3189,12 @@ 4B2C21381DA292BE00735907 /* OFHTTPCookie.m in Sources */, 4B6255191EC274FA003D49F4 /* OFHTTPCookieManager.m in Sources */, 4B2C21391DA292BE00735907 /* OFHTTPRequest.m in Sources */, 4B2C213A1DA292BE00735907 /* OFHTTPResponse.m in Sources */, 4B2C213B1DA292BE00735907 /* OFHTTPServer.m in Sources */, + 4BF20C541EEBF5F000C53220 /* OFInflate64Stream.m in Sources */, + 4BF20C581EEBF5F000C53220 /* OFInflateStream.m in Sources */, 4B2C213C1DA292BE00735907 /* OFINICategory.m in Sources */, 4B2C213D1DA292BE00735907 /* OFINIFile.m in Sources */, 4B2C213E1DA292BE00735907 /* OFIntrospection.m in Sources */, 4B2C213F1DA292BE00735907 /* OFGZIPStream.m in Sources */, 4B2C21401DA292BE00735907 /* OFKernelEventObserver.m in Sources */, @@ -3376,12 +3376,10 @@ 4BA85BCB140ECCE800E91D51 /* OFCountedSet_hashtable.m in Sources */, 4B3D23901337FC0D00DD29B8 /* OFDataArray.m in Sources */, 4B3D23911337FC0D00DD29B8 /* OFDataArray+CryptoHashing.m in Sources */, 4B879A8D177231F000EBCEA4 /* OFDataArray+MessagePackValue.m in Sources */, 4B3D23921337FC0D00DD29B8 /* OFDate.m in Sources */, - 4BC1762C1D04963000C32718 /* OFDeflate64Stream.m in Sources */, - 4BC1762E1D04963000C32718 /* OFDeflateStream.m in Sources */, 4B3D23931337FC0D00DD29B8 /* OFDictionary.m in Sources */, 4B2B3E80140D430500EC2F7C /* OFDictionary_hashtable.m in Sources */, 4B3D23941337FC0D00DD29B8 /* OFEnumerator.m in Sources */, 4B3D23961337FC0D00DD29B8 /* OFFile.m in Sources */, 4B2C728B1B888B8300717583 /* OFFileManager.m in Sources */, @@ -3390,10 +3388,12 @@ 4B2610C41D863007001F16C9 /* OFHTTPCookie.m in Sources */, 4B6255181EC274FA003D49F4 /* OFHTTPCookieManager.m in Sources */, 4B3D23981337FC0D00DD29B8 /* OFHTTPRequest.m in Sources */, 4B7161AE17A6FC7600B74970 /* OFHTTPResponse.m in Sources */, 4BB4B54716775FF4002A2DCE /* OFHTTPServer.m in Sources */, + 4BF20C531EEBF5F000C53220 /* OFInflate64Stream.m in Sources */, + 4BF20C571EEBF5F000C53220 /* 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 */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -18,20 +18,20 @@ OFCountedSet.m \ OFDataArray.m \ OFDataArray+CryptoHashing.m \ OFDataArray+MessagePackValue.m \ OFDate.m \ - OFDeflateStream.m \ - OFDeflate64Stream.m \ OFDictionary.m \ OFEnumerator.m \ OFGZIPStream.m \ OFHMAC.m \ OFHTTPCookie.m \ OFHTTPCookieManager.m \ OFHTTPRequest.m \ OFHTTPResponse.m \ + OFInflateStream.m \ + OFInflate64Stream.m \ OFIntrospection.m \ OFList.m \ OFLocalization.m \ OFMapTable.m \ OFMD5Hash.m \ DELETED src/OFDeflate64Stream.h Index: src/OFDeflate64Stream.h ================================================================== --- src/OFDeflate64Stream.h +++ src/OFDeflate64Stream.h @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 - * 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 "OFDeflateStream.h" - -OF_ASSUME_NONNULL_BEGIN - -/*! - * @class OFDeflate64Stream OFDeflate64Stream.h ObjFW/OFDeflate64Stream.h - * - * @brief A class that handles Deflate64 decompression transparently for an - * underlying stream. - */ -@interface OFDeflate64Stream: OFDeflateStream -@end - -OF_ASSUME_NONNULL_END DELETED src/OFDeflate64Stream.m Index: src/OFDeflate64Stream.m ================================================================== --- src/OFDeflate64Stream.m +++ src/OFDeflate64Stream.m @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 - * 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. - */ - -#define DEFLATE64 -#include "OFDeflateStream.m" DELETED src/OFDeflateStream.h Index: src/OFDeflateStream.h ================================================================== --- src/OFDeflateStream.h +++ src/OFDeflateStream.h @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 - * 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" - -OF_ASSUME_NONNULL_BEGIN - -#define OF_INFLATE_STREAM_BUFFER_SIZE 4096 - -/*! - * @class OFDeflateStream OFDeflateStream.h ObjFW/OFDeflateStream.h - * - * @brief A class that handles Deflate decompression transparently for an - * underlying stream. - */ -@interface OFDeflateStream: OFStream -{ -#ifdef OF_INFLATE_STREAM_M -@public -#endif - OFStream *_stream; - struct of_deflate_stream_decompression_ivars { - uint8_t buffer[OF_INFLATE_STREAM_BUFFER_SIZE]; - uint16_t bufferIndex, bufferLength; - uint8_t byte; - uint8_t bitIndex, savedBitsLength; - uint16_t savedBits; - uint8_t *slidingWindow; - uint16_t slidingWindowIndex, slidingWindowMask; - int state; - union { - struct { - uint8_t position; - uint8_t length[4]; - } uncompressedHeader; - struct { - uint16_t position, length; - } uncompressed; - struct { - struct huffman_tree *litLenTree, *distTree; - struct huffman_tree *codeLenTree, *treeIter; - uint8_t *lengths; - uint16_t receivedCount; - uint8_t value, litLenCodesCount, distCodesCount; - uint8_t codeLenCodesCount; - } huffmanTree; - struct { - struct huffman_tree *litLenTree, *distTree; - struct huffman_tree *treeIter; - int state; - uint16_t value, length, distance; - uint16_t extraBits; - } huffman; - } context; - bool inLastBlock, atEndOfStream; - } *_decompression; -} - -/*! - * @brief Creates a new OFDeflateStream with the specified underlying stream. - * - * @param stream The underlying stream to which compressed data is written or - * from which compressed data is read - * @return A new, autoreleased OFDeflateStream - */ -+ (instancetype)streamWithStream: (OFStream *)stream; - -- init OF_UNAVAILABLE; - -/*! - * @brief Initializes an already allocated OFDeflateStream with the specified - * underlying stream. - * - * @param stream The underlying stream to which compressed data is written or - * from which compressed data is read - * @return A initialized OFDeflateStream - */ -- initWithStream: (OFStream *)stream OF_DESIGNATED_INITIALIZER; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFDeflateStream.m Index: src/OFDeflateStream.m ================================================================== --- src/OFDeflateStream.m +++ src/OFDeflateStream.m @@ -1,852 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 - * 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. - */ - -#define OF_INFLATE_STREAM_M - -#include "config.h" - -#include -#include - -#include - -#ifndef DEFLATE64 -# import "OFDeflateStream.h" -#else -# import "OFDeflate64Stream.h" -# define OFDeflateStream OFDeflate64Stream -#endif -#import "OFDataArray.h" - -#import "OFInitializationFailedException.h" -#import "OFInvalidFormatException.h" -#import "OFNotOpenException.h" -#import "OFOutOfMemoryException.h" - -#define BUFFER_SIZE OF_INFLATE_STREAM_BUFFER_SIZE - -#define MAX_BITS 15 - -enum state { - BLOCK_HEADER, - UNCOMPRESSED_BLOCK_HEADER, - UNCOMPRESSED_BLOCK, - HUFFMAN_TREE, - HUFFMAN_BLOCK -}; - -enum huffman_state { - WRITE_VALUE, - AWAIT_CODE, - AWAIT_LENGTH_EXTRA_BITS, - AWAIT_DISTANCE, - AWAIT_DISTANCE_EXTRA_BITS, - PROCESS_PAIR -}; - -struct huffman_tree { - struct huffman_tree *leafs[2]; - uint16_t value; -}; - -@interface OFDeflateStream () -- (void)of_initDecompression; -@end - -#ifndef DEFLATE64 -static const uint8_t numDistanceCodes = 30; -static const uint8_t lengthCodes[29] = { - /* indices are -257, values -3 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, - 64, 80, 96, 112, 128, 160, 192, 224, 255 -}; -static const uint8_t lengthExtraBits[29] = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, - 5, 5, 5, 5, 0 -}; -static const uint16_t distanceCodes[30] = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, - 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 -}; -static const uint8_t distanceExtraBits[30] = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, - 10, 11, 11, 12, 12, 13, 13 -}; -#else -static const uint8_t numDistanceCodes = 32; -static const uint8_t lengthCodes[29] = { - /* indices are -257, values -3 */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, - 64, 80, 96, 112, 128, 160, 192, 224, 0 -}; -static const uint8_t lengthExtraBits[29] = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, - 5, 5, 5, 5, 16 -}; -static const uint16_t distanceCodes[32] = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, - 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, - 32769, 49153 -}; -static const uint8_t distanceExtraBits[32] = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, - 10, 11, 11, 12, 12, 13, 13, 14, 14 -}; -#endif -static const uint8_t codeLengthsOrder[19] = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -}; -static struct huffman_tree *fixedLitLenTree, *fixedDistTree; - -static bool -tryReadBits(OFDeflateStream *stream, - struct of_deflate_stream_decompression_ivars *ivars, - uint16_t *bits, uint8_t count) -{ - uint16_t ret = ivars->savedBits; - - assert(ivars->savedBitsLength < count); - - for (uint8_t i = ivars->savedBitsLength; i < count; i++) { - if OF_UNLIKELY (ivars->bitIndex == 8) { - if (ivars->bufferIndex < ivars->bufferLength) - ivars->byte = - ivars->buffer[ivars->bufferIndex++]; - else { - size_t length = [stream->_stream - readIntoBuffer: ivars->buffer - length: BUFFER_SIZE]; - - if OF_UNLIKELY (length < 1) { - ivars->savedBits = ret; - ivars->savedBitsLength = i; - return false; - } - - ivars->byte = ivars->buffer[0]; - ivars->bufferIndex = 1; - ivars->bufferLength = (uint16_t)length; - } - - ivars->bitIndex = 0; - } - - ret |= ((ivars->byte >> ivars->bitIndex++) & 1) << i; - } - - ivars->savedBits = 0; - ivars->savedBitsLength = 0; - *bits = ret; - - return true; -} - -static struct huffman_tree * -newTree(void) -{ - struct huffman_tree *tree; - - if ((tree = malloc(sizeof(*tree))) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: sizeof(*tree)]; - - tree->leafs[0] = tree->leafs[1] = NULL; - tree->value = 0xFFFF; - - return tree; -} - -static void -treeInsert(struct huffman_tree *tree, uint16_t code, uint8_t length, - uint16_t value) -{ - while (length > 0) { - uint8_t bit; - - length--; - bit = (code & (1 << length)) >> length; - - if (tree->leafs[bit] == NULL) - tree->leafs[bit] = newTree(); - - tree = tree->leafs[bit]; - } - - tree->value = value; -} - -static struct huffman_tree * -constructTree(uint8_t lengths[], uint16_t count) -{ - struct huffman_tree *tree; - uint16_t lengthCount[MAX_BITS + 1] = { 0 }; - uint16_t code, maxCode = 0, nextCode[MAX_BITS + 1]; - - for (uint16_t i = 0; i < count; i++) { - uint8_t length = lengths[i]; - - if OF_UNLIKELY (length > MAX_BITS) - @throw [OFInvalidFormatException exception]; - - if (length > 0) { - lengthCount[length]++; - maxCode = i; - } - } - - code = 0; - for (size_t i = 1; i <= MAX_BITS; i++) { - code = (code + lengthCount[i - 1]) << 1; - nextCode[i] = code; - } - - tree = newTree(); - - for (uint16_t i = 0; i <= maxCode; i++) { - uint8_t length = lengths[i]; - - if (length > 0) - treeInsert(tree, nextCode[length]++, length, i); - } - - return tree; -} - -static bool -walkTree(OFDeflateStream *stream, - struct of_deflate_stream_decompression_ivars *ivars, - struct huffman_tree **tree, uint16_t *value) -{ - struct huffman_tree *iter = *tree; - uint16_t bits; - - while (iter->value == 0xFFFF) { - if OF_UNLIKELY (!tryReadBits(stream, ivars, &bits, 1)) { - *tree = iter; - return false; - } - - if OF_UNLIKELY (iter->leafs[bits] == NULL) - @throw [OFInvalidFormatException exception]; - - iter = iter->leafs[bits]; - } - - *value = iter->value; - return true; -} - -static void -releaseTree(struct huffman_tree *tree) -{ - for (uint8_t i = 0; i < 2; i++) - if OF_LIKELY (tree->leafs[i] != NULL) - releaseTree(tree->leafs[i]); - - free(tree); -} - -@implementation OFDeflateStream -+ (void)initialize -{ - uint8_t lengths[288]; - - if (self != [OFDeflateStream class]) - return; - - for (uint16_t i = 0; i <= 143; i++) - lengths[i] = 8; - for (uint16_t i = 144; i <= 255; i++) - lengths[i] = 9; - for (uint16_t i = 256; i <= 279; i++) - lengths[i] = 7; - for (uint16_t i = 280; i <= 287; i++) - lengths[i] = 8; - - fixedLitLenTree = constructTree(lengths, 288); - - for (uint16_t i = 0; i <= 31; i++) - lengths[i] = 5; - - fixedDistTree = constructTree(lengths, 32); -} - -#ifndef DEFLATE64 -+ (instancetype)streamWithStream: (OFStream *)stream -{ - return [[[self alloc] initWithStream: stream] autorelease]; -} - -- init -{ - OF_INVALID_INIT_METHOD -} - -- initWithStream: (OFStream *)stream -{ - self = [super init]; - - _stream = [stream retain]; - - return self; -} - -- (void)dealloc -{ - [self close]; - - if (_decompression != NULL && _decompression->state == HUFFMAN_TREE) - if (_decompression->context.huffmanTree.codeLenTree != NULL) - releaseTree( - _decompression->context.huffmanTree.codeLenTree); - - if (_decompression != NULL && (_decompression->state == HUFFMAN_TREE || - _decompression->state == HUFFMAN_BLOCK)) { - if (_decompression->context.huffman.litLenTree != - fixedLitLenTree) - releaseTree(_decompression->context.huffman.litLenTree); - if (_decompression->context.huffman.distTree != fixedDistTree) - releaseTree(_decompression->context.huffman.distTree); - } - - [super dealloc]; -} -#endif - -- (void)of_initDecompression -{ - _decompression = [self allocMemoryWithSize: sizeof(*_decompression)]; - memset(_decompression, 0, sizeof(*_decompression)); - - /* 0-7 address the bit, 8 means fetch next byte */ - _decompression->bitIndex = 8; -#ifdef DEFLATE64 - _decompression->slidingWindowMask = 0xFFFF; -#else - _decompression->slidingWindowMask = 0x7FFF; -#endif -} - -- (size_t)lowlevelReadIntoBuffer: (void *)buffer_ - length: (size_t)length -{ - struct of_deflate_stream_decompression_ivars *ivars = _decompression; - uint8_t *buffer = buffer_; - uint16_t bits, tmp; - uint16_t value; - size_t bytesWritten = 0; - uint8_t *slidingWindow; - uint16_t slidingWindowIndex; - - if (_stream == nil) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (ivars == NULL) { - [self of_initDecompression]; - ivars = _decompression; - } - - if (ivars->atEndOfStream) - return 0; - -start: - switch ((enum state)ivars->state) { - case BLOCK_HEADER: - if OF_UNLIKELY (ivars->inLastBlock) { - [_stream unreadFromBuffer: ivars->buffer + - ivars->bufferIndex - length: ivars->bufferLength - - ivars->bufferIndex]; - - ivars->atEndOfStream = true; - return bytesWritten; - } - - if OF_UNLIKELY (!tryReadBits(self, ivars, &bits, 3)) - return bytesWritten; - - ivars->inLastBlock = (bits & 1); - - switch (bits >> 1) { - case 0: /* No compression */ - ivars->state = UNCOMPRESSED_BLOCK_HEADER; - ivars->bitIndex = 8; - ivars->context.uncompressedHeader.position = 0; - memset(ivars->context.uncompressedHeader.length, 0, 4); - break; - case 1: /* Fixed Huffman */ - ivars->state = HUFFMAN_BLOCK; - ivars->context.huffman.state = AWAIT_CODE; - ivars->context.huffman.litLenTree = fixedLitLenTree; - ivars->context.huffman.distTree = fixedDistTree; - ivars->context.huffman.treeIter = fixedLitLenTree; - break; - case 2: /* Dynamic Huffman */ - ivars->state = HUFFMAN_TREE; - ivars->context.huffmanTree.lengths = NULL; - ivars->context.huffmanTree.receivedCount = 0; - ivars->context.huffmanTree.value = 0xFE; - ivars->context.huffmanTree.litLenCodesCount = 0xFF; - ivars->context.huffmanTree.distCodesCount = 0xFF; - ivars->context.huffmanTree.codeLenCodesCount = 0xFF; - break; - default: - @throw [OFInvalidFormatException exception]; - } - - goto start; - case UNCOMPRESSED_BLOCK_HEADER: -#define CTX ivars->context.uncompressedHeader - /* FIXME: This can be done more efficiently than unreading */ - [_stream unreadFromBuffer: ivars->buffer + ivars->bufferIndex - length: ivars->bufferLength - - ivars->bufferIndex]; - ivars->bufferIndex = ivars->bufferLength = 0; - - CTX.position += [_stream - readIntoBuffer: CTX.length + CTX.position - length: 4 - CTX.position]; - - if OF_UNLIKELY (CTX.position < 4) - return bytesWritten; - - if OF_UNLIKELY ((CTX.length[0] | (CTX.length[1] << 8)) != - (uint16_t)~(CTX.length[2] | (CTX.length[3] << 8))) - @throw [OFInvalidFormatException exception]; - - ivars->state = UNCOMPRESSED_BLOCK; - - /* - * Do not reorder! ivars->context.uncompressed.position and - * ivars->context.uncompressedHeader.length overlap! - */ - ivars->context.uncompressed.length = - CTX.length[0] | (CTX.length[1] << 8); - ivars->context.uncompressed.position = 0; - - goto start; -#undef CTX - case UNCOMPRESSED_BLOCK: -#define CTX ivars->context.uncompressed - if OF_UNLIKELY (length == 0) - return bytesWritten; - - tmp = (length < (size_t)CTX.length - CTX.position - ? (uint16_t)length : CTX.length - CTX.position); - - tmp = (uint16_t)[_stream readIntoBuffer: buffer + bytesWritten - length: tmp]; - - if OF_UNLIKELY (ivars->slidingWindow == NULL) { - ivars->slidingWindow = [self allocMemoryWithSize: - ivars->slidingWindowMask + 1]; - /* Avoid leaking data */ - memset(ivars->slidingWindow, 0, - ivars->slidingWindowMask + 1); - } - - slidingWindow = ivars->slidingWindow; - slidingWindowIndex = ivars->slidingWindowIndex; - for (uint16_t i = 0; i < tmp; i++) { - slidingWindow[slidingWindowIndex] = - buffer[bytesWritten + i]; - slidingWindowIndex = (slidingWindowIndex + 1) & - ivars->slidingWindowMask; - } - ivars->slidingWindowIndex = slidingWindowIndex; - - length -= tmp; - bytesWritten += tmp; - - CTX.position += tmp; - if OF_UNLIKELY (CTX.position == CTX.length) - ivars->state = BLOCK_HEADER; - - goto start; -#undef CTX - case HUFFMAN_TREE: -#define CTX ivars->context.huffmanTree - if OF_LIKELY (CTX.value == 0xFE) { - if OF_LIKELY (CTX.litLenCodesCount == 0xFF) { - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, 5)) - return bytesWritten; - - if OF_UNLIKELY (bits > 29) - @throw [OFInvalidFormatException - exception]; - - CTX.litLenCodesCount = bits; - } - - if OF_LIKELY (CTX.distCodesCount == 0xFF) { - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, 5)) - return bytesWritten; - - CTX.distCodesCount = bits; - } - - if OF_LIKELY (CTX.codeLenCodesCount == 0xFF) { - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, 4)) - return bytesWritten; - - CTX.codeLenCodesCount = bits; - } - - if OF_LIKELY (CTX.lengths == NULL) { - CTX.lengths = [self allocMemoryWithSize: 19]; - memset(CTX.lengths, 0, 19); - } - - for (uint16_t i = CTX.receivedCount; - i < CTX.codeLenCodesCount + 4; i++) { - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, 3)) { - CTX.receivedCount = i; - return bytesWritten; - } - - CTX.lengths[codeLengthsOrder[i]] = bits; - } - - CTX.codeLenTree = constructTree(CTX.lengths, 19); - CTX.treeIter = CTX.codeLenTree; - - [self freeMemory: CTX.lengths]; - CTX.lengths = NULL; - CTX.receivedCount = 0; - CTX.value = 0xFF; - } - - if OF_LIKELY (CTX.lengths == NULL) - CTX.lengths = [self allocMemoryWithSize: - CTX.litLenCodesCount + CTX.distCodesCount + 258]; - - for (uint16_t i = CTX.receivedCount; - i < CTX.litLenCodesCount + CTX.distCodesCount + 258;) { - uint8_t j, count; - - if OF_LIKELY (CTX.value == 0xFF) { - if OF_UNLIKELY (!walkTree(self, ivars, - &CTX.treeIter, &value)) { - CTX.receivedCount = i; - return bytesWritten; - } - - CTX.treeIter = CTX.codeLenTree; - - if (value < 16) { - CTX.lengths[i++] = value; - continue; - } - } else - value = CTX.value; - - switch (value) { - case 16: - if OF_UNLIKELY (i < 1) - @throw [OFInvalidFormatException - exception]; - - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, 2)) { - CTX.receivedCount = i; - CTX.value = value; - return bytesWritten; - } - - value = CTX.lengths[i - 1]; - count = bits + 3; - - break; - case 17: - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, 3)) { - CTX.receivedCount = i; - CTX.value = value; - return bytesWritten; - } - - value = 0; - count = bits + 3; - - break; - case 18: - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, 7)) { - CTX.receivedCount = i; - CTX.value = value; - return bytesWritten; - } - - value = 0; - count = bits + 11; - - break; - default: - @throw [OFInvalidFormatException exception]; - } - - if OF_UNLIKELY (i + count > - CTX.litLenCodesCount + CTX.distCodesCount + 258) - @throw [OFInvalidFormatException exception]; - - for (j = 0; j < count; j++) - CTX.lengths[i++] = value; - - CTX.value = 0xFF; - } - - releaseTree(CTX.codeLenTree); - CTX.codeLenTree = NULL; - - CTX.litLenTree = constructTree(CTX.lengths, - CTX.litLenCodesCount + 257); - CTX.distTree = constructTree( - CTX.lengths + CTX.litLenCodesCount + 257, - CTX.distCodesCount + 1); - - [self freeMemory: CTX.lengths]; - - /* - * litLenTree and distTree are at the same location in - * ivars->context.huffman and ivars->context.huffmanTree, thus - * no need to set them. - */ - ivars->state = HUFFMAN_BLOCK; - ivars->context.huffman.state = AWAIT_CODE; - ivars->context.huffman.treeIter = CTX.litLenTree; - - goto start; -#undef CTX - case HUFFMAN_BLOCK: -#define CTX ivars->context.huffman - for (;;) { - uint8_t extraBits, lengthCodeIndex; - - if OF_UNLIKELY (CTX.state == WRITE_VALUE) { - if OF_UNLIKELY (length == 0) - return bytesWritten; - - buffer[bytesWritten++] = CTX.value; - length--; - - if (ivars->slidingWindow == NULL) { - ivars->slidingWindow = [self - allocMemoryWithSize: - ivars->slidingWindowMask + 1]; - /* Avoid leaking data */ - memset(ivars->slidingWindow, 0, - ivars->slidingWindowMask + 1); - } - - ivars->slidingWindow[ - ivars->slidingWindowIndex] = CTX.value; - ivars->slidingWindowIndex = - (ivars->slidingWindowIndex + 1) & - ivars->slidingWindowMask; - - CTX.state = AWAIT_CODE; - CTX.treeIter = CTX.litLenTree; - } - - if OF_UNLIKELY (CTX.state == AWAIT_LENGTH_EXTRA_BITS) { - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, CTX.extraBits)) - return bytesWritten; - - CTX.length += bits; - - CTX.state = AWAIT_DISTANCE; - CTX.treeIter = CTX.distTree; - } - - /* Distance of length distance pair */ - if (CTX.state == AWAIT_DISTANCE) { - if OF_UNLIKELY (!walkTree(self, ivars, - &CTX.treeIter, &value)) - return bytesWritten; - - if OF_UNLIKELY (value >= numDistanceCodes) - @throw [OFInvalidFormatException - exception]; - - CTX.distance = distanceCodes[value]; - extraBits = distanceExtraBits[value]; - - if (extraBits > 0) { - if OF_UNLIKELY (!tryReadBits(self, - ivars, &bits, extraBits)) { - CTX.state = - AWAIT_DISTANCE_EXTRA_BITS; - CTX.extraBits = extraBits; - return bytesWritten; - } - - CTX.distance += bits; - } - - CTX.state = PROCESS_PAIR; - } else if (CTX.state == AWAIT_DISTANCE_EXTRA_BITS) { - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, CTX.extraBits)) - return bytesWritten; - - CTX.distance += bits; - - CTX.state = PROCESS_PAIR; - } - - /* Length distance pair */ - if (CTX.state == PROCESS_PAIR) { - uint16_t j; - - if OF_UNLIKELY (ivars->slidingWindow == NULL) - @throw [OFInvalidFormatException - exception]; - - for (j = 0; j < CTX.length; j++) { - uint16_t index; - - if OF_UNLIKELY (length == 0) { - CTX.length -= j; - return bytesWritten; - } - - index = (ivars->slidingWindowIndex - - CTX.distance) & - ivars->slidingWindowMask; - value = ivars->slidingWindow[index]; - - buffer[bytesWritten++] = value; - length--; - - ivars->slidingWindow[ - ivars->slidingWindowIndex] = value; - ivars->slidingWindowIndex = - (ivars->slidingWindowIndex + 1) & - ivars->slidingWindowMask; - } - - CTX.state = AWAIT_CODE; - CTX.treeIter = CTX.litLenTree; - } - - if OF_UNLIKELY (!walkTree(self, ivars, - &CTX.treeIter, &value)) - return bytesWritten; - - /* End of block */ - if OF_UNLIKELY (value == 256) { - if (CTX.litLenTree != fixedLitLenTree) - releaseTree(CTX.litLenTree); - if (CTX.distTree != fixedDistTree) - releaseTree(CTX.distTree); - - ivars->state = BLOCK_HEADER; - goto start; - } - - /* Literal byte */ - if (value < 256) { - if OF_UNLIKELY (length == 0) { - CTX.state = WRITE_VALUE; - CTX.value = value; - return bytesWritten; - } - - buffer[bytesWritten++] = value; - length--; - - if (ivars->slidingWindow == NULL) { - ivars->slidingWindow = [self - allocMemoryWithSize: - ivars->slidingWindowMask + 1]; - /* Avoid leaking data */ - memset(ivars->slidingWindow, 0, - ivars->slidingWindowMask + 1); - } - - ivars->slidingWindow[ - ivars->slidingWindowIndex] = value; - ivars->slidingWindowIndex = - (ivars->slidingWindowIndex + 1) & - ivars->slidingWindowMask; - - CTX.treeIter = CTX.litLenTree; - continue; - } - - if OF_UNLIKELY (value > 285) - @throw [OFInvalidFormatException exception]; - - /* Length of length distance pair */ - lengthCodeIndex = value - 257; - CTX.length = lengthCodes[lengthCodeIndex] + 3; - extraBits = lengthExtraBits[lengthCodeIndex]; - - if (extraBits > 0) { - if OF_UNLIKELY (!tryReadBits(self, ivars, - &bits, extraBits)) { - CTX.extraBits = extraBits; - CTX.state = AWAIT_LENGTH_EXTRA_BITS; - return bytesWritten; - } - - CTX.length += bits; - } - - CTX.treeIter = CTX.distTree; - CTX.state = AWAIT_DISTANCE; - } - - break; -#undef CTX - } - - OF_UNREACHABLE -} - -#ifndef DEFLATE64 -- (bool)lowlevelIsAtEndOfStream -{ - if (_stream == nil) - @throw [OFNotOpenException exceptionWithObject: self]; - - return _decompression->atEndOfStream; -} - -- (int)fileDescriptorForReading -{ - return [_stream fileDescriptorForReading]; -} - -- (bool)hasDataInReadBuffer -{ - return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer]); -} -#endif - -- (void)close -{ - [_stream release]; - _stream = nil; - - [super close]; -} -@end Index: src/OFGZIPStream.h ================================================================== --- src/OFGZIPStream.h +++ src/OFGZIPStream.h @@ -15,18 +15,18 @@ */ #import "OFStream.h" #import "OFDate.h" -@class OFDeflateStream; +@class OFInflateStream; OF_ASSUME_NONNULL_BEGIN @interface OFGZIPStream: OFStream { OFStream *_stream; - OFDeflateStream *_inflateStream; + OFInflateStream *_inflateStream; enum of_gzip_stream_state { OF_GZIP_STREAM_ID1, OF_GZIP_STREAM_ID2, OF_GZIP_STREAM_COMPRESSION_METHOD, OF_GZIP_STREAM_FLAGS, Index: src/OFGZIPStream.m ================================================================== --- src/OFGZIPStream.m +++ src/OFGZIPStream.m @@ -15,11 +15,11 @@ */ #include "config.h" #import "OFGZIPStream.h" -#import "OFDeflateStream.h" +#import "OFInflateStream.h" #import "OFDate.h" #import "crc32.h" #import "OFChecksumFailedException.h" @@ -223,11 +223,11 @@ _bytesRead = 0; _state++; break; case OF_GZIP_STREAM_DATA: if (_inflateStream == nil) - _inflateStream = [[OFDeflateStream alloc] + _inflateStream = [[OFInflateStream alloc] initWithStream: _stream]; if (![_inflateStream isAtEndOfStream]) { size_t bytesRead = [_inflateStream readIntoBuffer: buffer ADDED src/OFInflate64Stream.h Index: src/OFInflate64Stream.h ================================================================== --- src/OFInflate64Stream.h +++ src/OFInflate64Stream.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * 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 "OFInflateStream.h" + +OF_ASSUME_NONNULL_BEGIN + +/*! + * @class OFInflate64Stream OFInflate64Stream.h ObjFW/OFInflate64Stream.h + * + * @brief A class that handles Deflate64 decompression transparently for an + * underlying stream. + */ +@interface OFInflate64Stream: OFInflateStream +@end + +OF_ASSUME_NONNULL_END ADDED src/OFInflate64Stream.m Index: src/OFInflate64Stream.m ================================================================== --- src/OFInflate64Stream.m +++ src/OFInflate64Stream.m @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * 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. + */ + +#define INFLATE64 +#include "OFInflateStream.m" ADDED src/OFInflateStream.h Index: src/OFInflateStream.h ================================================================== --- src/OFInflateStream.h +++ src/OFInflateStream.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * 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" + +OF_ASSUME_NONNULL_BEGIN + +#define OF_INFLATE_STREAM_BUFFER_SIZE 4096 + +/*! + * @class OFInflateStream OFInflateStream.h ObjFW/OFInflateStream.h + * + * @brief A class that handles Deflate decompression transparently for an + * underlying stream. + */ +@interface OFInflateStream: OFStream +{ +#ifdef OF_INFLATE_STREAM_M +@public +#endif + OFStream *_stream; + uint8_t _buffer[OF_INFLATE_STREAM_BUFFER_SIZE]; + uint16_t _bufferIndex, _bufferLength; + uint8_t _byte; + uint8_t _bitIndex, _savedBitsLength; + uint16_t _savedBits; + uint8_t *_slidingWindow; + uint16_t _slidingWindowIndex, _slidingWindowMask; + int _state; + union { + struct { + uint8_t position; + uint8_t length[4]; + } uncompressedHeader; + struct { + uint16_t position, length; + } uncompressed; + struct { + struct huffman_tree *litLenTree, *distTree; + struct huffman_tree *codeLenTree, *treeIter; + uint8_t *lengths; + uint16_t receivedCount; + uint8_t value, litLenCodesCount, distCodesCount; + uint8_t codeLenCodesCount; + } huffmanTree; + struct { + struct huffman_tree *litLenTree, *distTree; + struct huffman_tree *treeIter; + int state; + uint16_t value, length, distance, extraBits; + } huffman; + } _context; + bool _inLastBlock, _atEndOfStream; +} + +/*! + * @brief Creates a new OFInflateStream with the specified underlying stream. + * + * @param stream The underlying stream to which compressed data is written or + * from which compressed data is read + * @return A new, autoreleased OFInflateStream + */ ++ (instancetype)streamWithStream: (OFStream *)stream; + +- init OF_UNAVAILABLE; + +/*! + * @brief Initializes an already allocated OFInflateStream with the specified + * underlying stream. + * + * @param stream The underlying stream to which compressed data is written or + * from which compressed data is read + * @return A initialized OFInflateStream + */ +- initWithStream: (OFStream *)stream OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFInflateStream.m Index: src/OFInflateStream.m ================================================================== --- src/OFInflateStream.m +++ src/OFInflateStream.m @@ -0,0 +1,815 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * 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. + */ + +#define OF_INFLATE_STREAM_M + +#include "config.h" + +#include +#include + +#include + +#ifndef INFLATE64 +# import "OFInflateStream.h" +#else +# import "OFInflate64Stream.h" +# define OFInflateStream OFInflate64Stream +#endif +#import "OFDataArray.h" + +#import "OFInitializationFailedException.h" +#import "OFInvalidFormatException.h" +#import "OFNotOpenException.h" +#import "OFOutOfMemoryException.h" + +#define BUFFER_SIZE OF_INFLATE_STREAM_BUFFER_SIZE + +#define MAX_BITS 15 + +enum state { + BLOCK_HEADER, + UNCOMPRESSED_BLOCK_HEADER, + UNCOMPRESSED_BLOCK, + HUFFMAN_TREE, + HUFFMAN_BLOCK +}; + +enum huffman_state { + WRITE_VALUE, + AWAIT_CODE, + AWAIT_LENGTH_EXTRA_BITS, + AWAIT_DISTANCE, + AWAIT_DISTANCE_EXTRA_BITS, + PROCESS_PAIR +}; + +struct huffman_tree { + struct huffman_tree *leafs[2]; + uint16_t value; +}; + +#ifndef INFLATE64 +static const uint8_t numDistanceCodes = 30; +static const uint8_t lengthCodes[29] = { + /* indices are -257, values -3 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, + 64, 80, 96, 112, 128, 160, 192, 224, 255 +}; +static const uint8_t lengthExtraBits[29] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, + 5, 5, 5, 5, 0 +}; +static const uint16_t distanceCodes[30] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, + 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 +}; +static const uint8_t distanceExtraBits[30] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13 +}; +#else +static const uint8_t numDistanceCodes = 32; +static const uint8_t lengthCodes[29] = { + /* indices are -257, values -3 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, + 64, 80, 96, 112, 128, 160, 192, 224, 0 +}; +static const uint8_t lengthExtraBits[29] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, + 5, 5, 5, 5, 16 +}; +static const uint16_t distanceCodes[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, + 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, + 32769, 49153 +}; +static const uint8_t distanceExtraBits[32] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14 +}; +#endif +static const uint8_t codeLengthsOrder[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; +static struct huffman_tree *fixedLitLenTree, *fixedDistTree; + +static bool +tryReadBits(OFInflateStream *stream, uint16_t *bits, uint8_t count) +{ + uint16_t ret = stream->_savedBits; + + assert(stream->_savedBitsLength < count); + + for (uint8_t i = stream->_savedBitsLength; i < count; i++) { + if OF_UNLIKELY (stream->_bitIndex == 8) { + if (stream->_bufferIndex < stream->_bufferLength) + stream->_byte = + stream->_buffer[stream->_bufferIndex++]; + else { + size_t length = [stream->_stream + readIntoBuffer: stream->_buffer + length: BUFFER_SIZE]; + + if OF_UNLIKELY (length < 1) { + stream->_savedBits = ret; + stream->_savedBitsLength = i; + return false; + } + + stream->_byte = stream->_buffer[0]; + stream->_bufferIndex = 1; + stream->_bufferLength = (uint16_t)length; + } + + stream->_bitIndex = 0; + } + + ret |= ((stream->_byte >> stream->_bitIndex++) & 1) << i; + } + + stream->_savedBits = 0; + stream->_savedBitsLength = 0; + *bits = ret; + + return true; +} + +static struct huffman_tree * +newTree(void) +{ + struct huffman_tree *tree; + + if ((tree = malloc(sizeof(*tree))) == NULL) + @throw [OFOutOfMemoryException + exceptionWithRequestedSize: sizeof(*tree)]; + + tree->leafs[0] = tree->leafs[1] = NULL; + tree->value = 0xFFFF; + + return tree; +} + +static void +treeInsert(struct huffman_tree *tree, uint16_t code, uint8_t length, + uint16_t value) +{ + while (length > 0) { + uint8_t bit; + + length--; + bit = (code & (1 << length)) >> length; + + if (tree->leafs[bit] == NULL) + tree->leafs[bit] = newTree(); + + tree = tree->leafs[bit]; + } + + tree->value = value; +} + +static struct huffman_tree * +constructTree(uint8_t lengths[], uint16_t count) +{ + struct huffman_tree *tree; + uint16_t lengthCount[MAX_BITS + 1] = { 0 }; + uint16_t code, maxCode = 0, nextCode[MAX_BITS + 1]; + + for (uint16_t i = 0; i < count; i++) { + uint8_t length = lengths[i]; + + if OF_UNLIKELY (length > MAX_BITS) + @throw [OFInvalidFormatException exception]; + + if (length > 0) { + lengthCount[length]++; + maxCode = i; + } + } + + code = 0; + for (size_t i = 1; i <= MAX_BITS; i++) { + code = (code + lengthCount[i - 1]) << 1; + nextCode[i] = code; + } + + tree = newTree(); + + for (uint16_t i = 0; i <= maxCode; i++) { + uint8_t length = lengths[i]; + + if (length > 0) + treeInsert(tree, nextCode[length]++, length, i); + } + + return tree; +} + +static bool +walkTree(OFInflateStream *stream, struct huffman_tree **tree, uint16_t *value) +{ + struct huffman_tree *iter = *tree; + uint16_t bits; + + while (iter->value == 0xFFFF) { + if OF_UNLIKELY (!tryReadBits(stream, &bits, 1)) { + *tree = iter; + return false; + } + + if OF_UNLIKELY (iter->leafs[bits] == NULL) + @throw [OFInvalidFormatException exception]; + + iter = iter->leafs[bits]; + } + + *value = iter->value; + return true; +} + +static void +releaseTree(struct huffman_tree *tree) +{ + for (uint8_t i = 0; i < 2; i++) + if OF_LIKELY (tree->leafs[i] != NULL) + releaseTree(tree->leafs[i]); + + free(tree); +} + +@implementation OFInflateStream ++ (void)initialize +{ + uint8_t lengths[288]; + + if (self != [OFInflateStream class]) + return; + + for (uint16_t i = 0; i <= 143; i++) + lengths[i] = 8; + for (uint16_t i = 144; i <= 255; i++) + lengths[i] = 9; + for (uint16_t i = 256; i <= 279; i++) + lengths[i] = 7; + for (uint16_t i = 280; i <= 287; i++) + lengths[i] = 8; + + fixedLitLenTree = constructTree(lengths, 288); + + for (uint16_t i = 0; i <= 31; i++) + lengths[i] = 5; + + fixedDistTree = constructTree(lengths, 32); +} + +#ifndef INFLATE64 ++ (instancetype)streamWithStream: (OFStream *)stream +{ + return [[[self alloc] initWithStream: stream] autorelease]; +} + +- init +{ + OF_INVALID_INIT_METHOD +} + +- initWithStream: (OFStream *)stream +{ + self = [super init]; + + _stream = [stream retain]; + + /* 0-7 address the bit, 8 means fetch next byte */ + _bitIndex = 8; +#ifdef INFLATE64 + _slidingWindowMask = 0xFFFF; +#else + _slidingWindowMask = 0x7FFF; +#endif + + return self; +} + +- (void)dealloc +{ + [self close]; + + if (_state == HUFFMAN_TREE) + if (_context.huffmanTree.codeLenTree != NULL) + releaseTree(_context.huffmanTree.codeLenTree); + + if (_state == HUFFMAN_TREE || _state == HUFFMAN_BLOCK) { + if (_context.huffman.litLenTree != fixedLitLenTree) + releaseTree(_context.huffman.litLenTree); + if (_context.huffman.distTree != fixedDistTree) + releaseTree(_context.huffman.distTree); + } + + [super dealloc]; +} +#endif + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer_ + length: (size_t)length +{ + uint8_t *buffer = buffer_; + uint16_t bits, tmp; + uint16_t value; + size_t bytesWritten = 0; + uint8_t *slidingWindow; + uint16_t slidingWindowIndex; + + if (_stream == nil) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_atEndOfStream) + return 0; + +start: + switch ((enum state)_state) { + case BLOCK_HEADER: + if OF_UNLIKELY (_inLastBlock) { + [_stream unreadFromBuffer: _buffer + _bufferIndex + length: _bufferLength - + _bufferIndex]; + + _atEndOfStream = true; + return bytesWritten; + } + + if OF_UNLIKELY (!tryReadBits(self, &bits, 3)) + return bytesWritten; + + _inLastBlock = (bits & 1); + + switch (bits >> 1) { + case 0: /* No compression */ + _state = UNCOMPRESSED_BLOCK_HEADER; + _bitIndex = 8; + _context.uncompressedHeader.position = 0; + memset(_context.uncompressedHeader.length, 0, 4); + break; + case 1: /* Fixed Huffman */ + _state = HUFFMAN_BLOCK; + _context.huffman.state = AWAIT_CODE; + _context.huffman.litLenTree = fixedLitLenTree; + _context.huffman.distTree = fixedDistTree; + _context.huffman.treeIter = fixedLitLenTree; + break; + case 2: /* Dynamic Huffman */ + _state = HUFFMAN_TREE; + _context.huffmanTree.lengths = NULL; + _context.huffmanTree.receivedCount = 0; + _context.huffmanTree.value = 0xFE; + _context.huffmanTree.litLenCodesCount = 0xFF; + _context.huffmanTree.distCodesCount = 0xFF; + _context.huffmanTree.codeLenCodesCount = 0xFF; + break; + default: + @throw [OFInvalidFormatException exception]; + } + + goto start; + case UNCOMPRESSED_BLOCK_HEADER: +#define CTX _context.uncompressedHeader + /* FIXME: This can be done more efficiently than unreading */ + [_stream unreadFromBuffer: _buffer + _bufferIndex + length: _bufferLength - _bufferIndex]; + _bufferIndex = _bufferLength = 0; + + CTX.position += [_stream + readIntoBuffer: CTX.length + CTX.position + length: 4 - CTX.position]; + + if OF_UNLIKELY (CTX.position < 4) + return bytesWritten; + + if OF_UNLIKELY ((CTX.length[0] | (CTX.length[1] << 8)) != + (uint16_t)~(CTX.length[2] | (CTX.length[3] << 8))) + @throw [OFInvalidFormatException exception]; + + _state = UNCOMPRESSED_BLOCK; + + /* + * Do not reorder! _context.uncompressed.position and + * _context.uncompressedHeader.length overlap! + */ + _context.uncompressed.length = + CTX.length[0] | (CTX.length[1] << 8); + _context.uncompressed.position = 0; + + goto start; +#undef CTX + case UNCOMPRESSED_BLOCK: +#define CTX _context.uncompressed + if OF_UNLIKELY (length == 0) + return bytesWritten; + + tmp = (length < (size_t)CTX.length - CTX.position + ? (uint16_t)length : CTX.length - CTX.position); + + tmp = (uint16_t)[_stream readIntoBuffer: buffer + bytesWritten + length: tmp]; + + if OF_UNLIKELY (_slidingWindow == NULL) { + _slidingWindow = + [self allocMemoryWithSize: _slidingWindowMask + 1]; + /* Avoid leaking data */ + memset(_slidingWindow, 0, _slidingWindowMask + 1); + } + + slidingWindow = _slidingWindow; + slidingWindowIndex = _slidingWindowIndex; + for (uint16_t i = 0; i < tmp; i++) { + slidingWindow[slidingWindowIndex] = + buffer[bytesWritten + i]; + slidingWindowIndex = (slidingWindowIndex + 1) & + _slidingWindowMask; + } + _slidingWindowIndex = slidingWindowIndex; + + length -= tmp; + bytesWritten += tmp; + + CTX.position += tmp; + if OF_UNLIKELY (CTX.position == CTX.length) + _state = BLOCK_HEADER; + + goto start; +#undef CTX + case HUFFMAN_TREE: +#define CTX _context.huffmanTree + if OF_LIKELY (CTX.value == 0xFE) { + if OF_LIKELY (CTX.litLenCodesCount == 0xFF) { + if OF_UNLIKELY (!tryReadBits(self, &bits, 5)) + return bytesWritten; + + if OF_UNLIKELY (bits > 29) + @throw [OFInvalidFormatException + exception]; + + CTX.litLenCodesCount = bits; + } + + if OF_LIKELY (CTX.distCodesCount == 0xFF) { + if OF_UNLIKELY (!tryReadBits(self, &bits, 5)) + return bytesWritten; + + CTX.distCodesCount = bits; + } + + if OF_LIKELY (CTX.codeLenCodesCount == 0xFF) { + if OF_UNLIKELY (!tryReadBits(self, &bits, 4)) + return bytesWritten; + + CTX.codeLenCodesCount = bits; + } + + if OF_LIKELY (CTX.lengths == NULL) { + CTX.lengths = [self allocMemoryWithSize: 19]; + memset(CTX.lengths, 0, 19); + } + + for (uint16_t i = CTX.receivedCount; + i < CTX.codeLenCodesCount + 4; i++) { + if OF_UNLIKELY (!tryReadBits(self, &bits, 3)) { + CTX.receivedCount = i; + return bytesWritten; + } + + CTX.lengths[codeLengthsOrder[i]] = bits; + } + + CTX.codeLenTree = constructTree(CTX.lengths, 19); + CTX.treeIter = CTX.codeLenTree; + + [self freeMemory: CTX.lengths]; + CTX.lengths = NULL; + CTX.receivedCount = 0; + CTX.value = 0xFF; + } + + if OF_LIKELY (CTX.lengths == NULL) + CTX.lengths = [self allocMemoryWithSize: + CTX.litLenCodesCount + CTX.distCodesCount + 258]; + + for (uint16_t i = CTX.receivedCount; + i < CTX.litLenCodesCount + CTX.distCodesCount + 258;) { + uint8_t j, count; + + if OF_LIKELY (CTX.value == 0xFF) { + if OF_UNLIKELY (!walkTree(self, &CTX.treeIter, + &value)) { + CTX.receivedCount = i; + return bytesWritten; + } + + CTX.treeIter = CTX.codeLenTree; + + if (value < 16) { + CTX.lengths[i++] = value; + continue; + } + } else + value = CTX.value; + + switch (value) { + case 16: + if OF_UNLIKELY (i < 1) + @throw [OFInvalidFormatException + exception]; + + if OF_UNLIKELY (!tryReadBits(self, &bits, 2)) { + CTX.receivedCount = i; + CTX.value = value; + return bytesWritten; + } + + value = CTX.lengths[i - 1]; + count = bits + 3; + + break; + case 17: + if OF_UNLIKELY (!tryReadBits(self, &bits, 3)) { + CTX.receivedCount = i; + CTX.value = value; + return bytesWritten; + } + + value = 0; + count = bits + 3; + + break; + case 18: + if OF_UNLIKELY (!tryReadBits(self, &bits, 7)) { + CTX.receivedCount = i; + CTX.value = value; + return bytesWritten; + } + + value = 0; + count = bits + 11; + + break; + default: + @throw [OFInvalidFormatException exception]; + } + + if OF_UNLIKELY (i + count > + CTX.litLenCodesCount + CTX.distCodesCount + 258) + @throw [OFInvalidFormatException exception]; + + for (j = 0; j < count; j++) + CTX.lengths[i++] = value; + + CTX.value = 0xFF; + } + + releaseTree(CTX.codeLenTree); + CTX.codeLenTree = NULL; + + CTX.litLenTree = constructTree(CTX.lengths, + CTX.litLenCodesCount + 257); + CTX.distTree = constructTree( + CTX.lengths + CTX.litLenCodesCount + 257, + CTX.distCodesCount + 1); + + [self freeMemory: CTX.lengths]; + + /* + * litLenTree and distTree are at the same location in + * _context.huffman and _context.huffmanTree, thus no need to + * set them. + */ + _state = HUFFMAN_BLOCK; + _context.huffman.state = AWAIT_CODE; + _context.huffman.treeIter = CTX.litLenTree; + + goto start; +#undef CTX + case HUFFMAN_BLOCK: +#define CTX _context.huffman + for (;;) { + uint8_t extraBits, lengthCodeIndex; + + if OF_UNLIKELY (CTX.state == WRITE_VALUE) { + if OF_UNLIKELY (length == 0) + return bytesWritten; + + buffer[bytesWritten++] = CTX.value; + length--; + + if (_slidingWindow == NULL) { + _slidingWindow = [self + allocMemoryWithSize: + _slidingWindowMask + 1]; + /* Avoid leaking data */ + memset(_slidingWindow, 0, + _slidingWindowMask + 1); + } + + _slidingWindow[_slidingWindowIndex] = CTX.value; + _slidingWindowIndex = + (_slidingWindowIndex + 1) & + _slidingWindowMask; + + CTX.state = AWAIT_CODE; + CTX.treeIter = CTX.litLenTree; + } + + if OF_UNLIKELY (CTX.state == AWAIT_LENGTH_EXTRA_BITS) { + if OF_UNLIKELY (!tryReadBits(self, &bits, + CTX.extraBits)) + return bytesWritten; + + CTX.length += bits; + + CTX.state = AWAIT_DISTANCE; + CTX.treeIter = CTX.distTree; + } + + /* Distance of length distance pair */ + if (CTX.state == AWAIT_DISTANCE) { + if OF_UNLIKELY (!walkTree(self, &CTX.treeIter, + &value)) + return bytesWritten; + + if OF_UNLIKELY (value >= numDistanceCodes) + @throw [OFInvalidFormatException + exception]; + + CTX.distance = distanceCodes[value]; + extraBits = distanceExtraBits[value]; + + if (extraBits > 0) { + if OF_UNLIKELY (!tryReadBits(self, + &bits, extraBits)) { + CTX.state = + AWAIT_DISTANCE_EXTRA_BITS; + CTX.extraBits = extraBits; + return bytesWritten; + } + + CTX.distance += bits; + } + + CTX.state = PROCESS_PAIR; + } else if (CTX.state == AWAIT_DISTANCE_EXTRA_BITS) { + if OF_UNLIKELY (!tryReadBits(self, &bits, + CTX.extraBits)) + return bytesWritten; + + CTX.distance += bits; + + CTX.state = PROCESS_PAIR; + } + + /* Length distance pair */ + if (CTX.state == PROCESS_PAIR) { + uint16_t j; + + if OF_UNLIKELY (_slidingWindow == NULL) + @throw [OFInvalidFormatException + exception]; + + for (j = 0; j < CTX.length; j++) { + uint16_t index; + + if OF_UNLIKELY (length == 0) { + CTX.length -= j; + return bytesWritten; + } + + index = (_slidingWindowIndex - + CTX.distance) & _slidingWindowMask; + value = _slidingWindow[index]; + + buffer[bytesWritten++] = value; + length--; + + _slidingWindow[_slidingWindowIndex] = + value; + _slidingWindowIndex = + (_slidingWindowIndex + 1) & + _slidingWindowMask; + } + + CTX.state = AWAIT_CODE; + CTX.treeIter = CTX.litLenTree; + } + + if OF_UNLIKELY (!walkTree(self, &CTX.treeIter, &value)) + return bytesWritten; + + /* End of block */ + if OF_UNLIKELY (value == 256) { + if (CTX.litLenTree != fixedLitLenTree) + releaseTree(CTX.litLenTree); + if (CTX.distTree != fixedDistTree) + releaseTree(CTX.distTree); + + _state = BLOCK_HEADER; + goto start; + } + + /* Literal byte */ + if (value < 256) { + if OF_UNLIKELY (length == 0) { + CTX.state = WRITE_VALUE; + CTX.value = value; + return bytesWritten; + } + + buffer[bytesWritten++] = value; + length--; + + if (_slidingWindow == NULL) { + _slidingWindow = [self + allocMemoryWithSize: + _slidingWindowMask + 1]; + /* Avoid leaking data */ + memset(_slidingWindow, 0, + _slidingWindowMask + 1); + } + + _slidingWindow[_slidingWindowIndex] = value; + _slidingWindowIndex = + (_slidingWindowIndex + 1) & + _slidingWindowMask; + + CTX.treeIter = CTX.litLenTree; + continue; + } + + if OF_UNLIKELY (value > 285) + @throw [OFInvalidFormatException exception]; + + /* Length of length distance pair */ + lengthCodeIndex = value - 257; + CTX.length = lengthCodes[lengthCodeIndex] + 3; + extraBits = lengthExtraBits[lengthCodeIndex]; + + if (extraBits > 0) { + if OF_UNLIKELY (!tryReadBits(self, &bits, + extraBits)) { + CTX.extraBits = extraBits; + CTX.state = AWAIT_LENGTH_EXTRA_BITS; + return bytesWritten; + } + + CTX.length += bits; + } + + CTX.treeIter = CTX.distTree; + CTX.state = AWAIT_DISTANCE; + } + + break; +#undef CTX + } + + OF_UNREACHABLE +} + +#ifndef INFLATE64 +- (bool)lowlevelIsAtEndOfStream +{ + if (_stream == nil) + @throw [OFNotOpenException exceptionWithObject: self]; + + return _atEndOfStream; +} + +- (int)fileDescriptorForReading +{ + return [_stream fileDescriptorForReading]; +} + +- (bool)hasDataInReadBuffer +{ + return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer]); +} +#endif + +- (void)close +{ + [_stream release]; + _stream = nil; + + [super close]; +} +@end Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -26,12 +26,12 @@ #import "OFDictionary.h" #import "OFSeekableStream.h" #ifdef OF_HAVE_FILES # import "OFFile.h" #endif -#import "OFDeflateStream.h" -#import "OFDeflate64Stream.h" +#import "OFInflateStream.h" +#import "OFInflate64Stream.h" #import "crc32.h" #import "OFChecksumFailedException.h" #import "OFInvalidArgumentException.h" @@ -463,15 +463,15 @@ switch (localFileHeader->_compressionMethod) { case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE: _decompressedStream = [stream retain]; break; case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE: - _decompressedStream = [[OFDeflateStream alloc] + _decompressedStream = [[OFInflateStream alloc] initWithStream: stream]; break; case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE64: - _decompressedStream = [[OFDeflate64Stream alloc] + _decompressedStream = [[OFInflate64Stream alloc] initWithStream: stream]; break; default: @throw [OFNotImplementedException exceptionWithSelector: _cmd Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -43,12 +43,12 @@ #import "OFDate.h" #import "OFURL.h" #import "OFStream.h" #import "OFStdIOStream.h" -#import "OFDeflateStream.h" -#import "OFDeflate64Stream.h" +#import "OFInflateStream.h" +#import "OFInflate64Stream.h" #import "OFGZIPStream.h" #import "OFTarArchive.h" #import "OFTarArchiveEntry.h" #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h"