summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip
diff options
context:
space:
mode:
authorkh1 <karsten.heimrich@nokia.com>2012-03-15 14:53:47 +0100
committerKarsten Heimrich <karsten.heimrich@nokia.com>2012-03-19 16:14:04 +0100
commitbe3b47d0d504a3409ce66bd77bb8c0acff87c4f5 (patch)
tree09dfb02d484a4f395991972b828da71400fb761a /src/libs/7zip
parent9fd62353cf7f973d78cd2093328ac15b5c4980b6 (diff)
Reorganize the tree, have better ifw.pri. Shadow build support.
Change-Id: I01fb12537f863ed0744979973c7e4153889cc5cb Reviewed-by: Tim Jenssen <tim.jenssen@nokia.com>
Diffstat (limited to 'src/libs/7zip')
-rw-r--r--src/libs/7zip/7zip.pri4
-rw-r--r--src/libs/7zip/unix/C/7zBuf.h39
-rw-r--r--src/libs/7zip/unix/C/7zBuf2.c45
-rw-r--r--src/libs/7zip/unix/C/7zCrc.c76
-rw-r--r--src/libs/7zip/unix/C/7zCrc.h25
-rw-r--r--src/libs/7zip/unix/C/7zCrcOpt.c34
-rw-r--r--src/libs/7zip/unix/C/7zCrcT8.c43
-rw-r--r--src/libs/7zip/unix/C/7zStream.c169
-rw-r--r--src/libs/7zip/unix/C/7zVersion.h7
-rw-r--r--src/libs/7zip/unix/C/Aes.c284
-rw-r--r--src/libs/7zip/unix/C/Aes.h38
-rw-r--r--src/libs/7zip/unix/C/Alloc.c280
-rw-r--r--src/libs/7zip/unix/C/Alloc.h27
-rw-r--r--src/libs/7zip/unix/C/Bra.c133
-rw-r--r--src/libs/7zip/unix/C/Bra.h68
-rw-r--r--src/libs/7zip/unix/C/Bra86.c85
-rw-r--r--src/libs/7zip/unix/C/BraIA64.c67
-rw-r--r--src/libs/7zip/unix/C/BwtSort.c516
-rw-r--r--src/libs/7zip/unix/C/BwtSort.h30
-rw-r--r--src/libs/7zip/unix/C/CpuArch.c168
-rw-r--r--src/libs/7zip/unix/C/CpuArch.h155
-rw-r--r--src/libs/7zip/unix/C/Delta.c62
-rw-r--r--src/libs/7zip/unix/C/Delta.h23
-rw-r--r--src/libs/7zip/unix/C/HuffEnc.c146
-rw-r--r--src/libs/7zip/unix/C/HuffEnc.h27
-rw-r--r--src/libs/7zip/unix/C/LzFind.c761
-rw-r--r--src/libs/7zip/unix/C/LzFind.h115
-rw-r--r--src/libs/7zip/unix/C/LzFindMt.c793
-rw-r--r--src/libs/7zip/unix/C/LzFindMt.h105
-rw-r--r--src/libs/7zip/unix/C/LzHash.h54
-rw-r--r--src/libs/7zip/unix/C/Lzma2Dec.c356
-rw-r--r--src/libs/7zip/unix/C/Lzma2Dec.h84
-rw-r--r--src/libs/7zip/unix/C/Lzma2Enc.c477
-rw-r--r--src/libs/7zip/unix/C/Lzma2Enc.h66
-rw-r--r--src/libs/7zip/unix/C/LzmaDec.c999
-rw-r--r--src/libs/7zip/unix/C/LzmaDec.h231
-rw-r--r--src/libs/7zip/unix/C/LzmaEnc.c2268
-rw-r--r--src/libs/7zip/unix/C/LzmaEnc.h80
-rw-r--r--src/libs/7zip/unix/C/LzmaUtil/Lzma86Dec.c61
-rw-r--r--src/libs/7zip/unix/C/LzmaUtil/Lzma86Dec.h51
-rw-r--r--src/libs/7zip/unix/C/LzmaUtil/Lzma86Enc.c113
-rw-r--r--src/libs/7zip/unix/C/LzmaUtil/Lzma86Enc.h78
-rw-r--r--src/libs/7zip/unix/C/MtCoder.c327
-rw-r--r--src/libs/7zip/unix/C/MtCoder.h98
-rw-r--r--src/libs/7zip/unix/C/Ppmd.h85
-rw-r--r--src/libs/7zip/unix/C/Ppmd7.c708
-rw-r--r--src/libs/7zip/unix/C/Ppmd7.h140
-rw-r--r--src/libs/7zip/unix/C/Ppmd7Dec.c187
-rw-r--r--src/libs/7zip/unix/C/Ppmd7Enc.c185
-rw-r--r--src/libs/7zip/unix/C/Ppmd8.c1120
-rw-r--r--src/libs/7zip/unix/C/Ppmd8.h133
-rw-r--r--src/libs/7zip/unix/C/Ppmd8Dec.c155
-rw-r--r--src/libs/7zip/unix/C/Ppmd8Enc.c161
-rw-r--r--src/libs/7zip/unix/C/RotateDefs.h20
-rw-r--r--src/libs/7zip/unix/C/Sha256.c204
-rw-r--r--src/libs/7zip/unix/C/Sha256.h26
-rw-r--r--src/libs/7zip/unix/C/Sort.c93
-rw-r--r--src/libs/7zip/unix/C/Sort.h20
-rw-r--r--src/libs/7zip/unix/C/Threads.c582
-rw-r--r--src/libs/7zip/unix/C/Threads.h123
-rw-r--r--src/libs/7zip/unix/C/Types.h254
-rw-r--r--src/libs/7zip/unix/C/Xz.c88
-rw-r--r--src/libs/7zip/unix/C/Xz.h252
-rw-r--r--src/libs/7zip/unix/C/XzCrc64.c33
-rw-r--r--src/libs/7zip/unix/C/XzCrc64.h26
-rw-r--r--src/libs/7zip/unix/C/XzDec.c875
-rw-r--r--src/libs/7zip/unix/C/XzEnc.c497
-rw-r--r--src/libs/7zip/unix/C/XzEnc.h25
-rw-r--r--src/libs/7zip/unix/C/XzIn.c306
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.cpp3
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.h50
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp332
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.h68
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.cpp444
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.h55
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zExtract.cpp270
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.cpp123
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.h58
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.cpp149
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.h58
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.cpp482
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.h119
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp483
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.cpp14
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.h97
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.cpp1276
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.h245
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zItem.h268
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp866
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.h152
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.cpp164
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.h22
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zRegister.cpp18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.cpp24
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.h35
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.cpp1216
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.h88
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/ApmHandler.cpp356
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/ArchiveExports.cpp135
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/ArjHandler.cpp798
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Bz2Handler.cpp423
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabBlockInStream.cpp189
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabBlockInStream.h44
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHandler.cpp929
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHandler.h28
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHeader.cpp15
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHeader.h44
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabIn.cpp272
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabIn.h161
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabItem.h63
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabRegister.cpp13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHandler.cpp721
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHandler.h29
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHeader.cpp24
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHeader.h28
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmIn.cpp937
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmIn.h244
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmRegister.cpp13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Com/ComHandler.cpp239
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Com/ComHandler.h28
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Com/ComIn.cpp389
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Com/ComIn.h119
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Com/ComRegister.cpp13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.cpp121
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.h174
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.cpp240
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.h80
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2ST.cpp239
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2ST.h88
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/CrossThreadProgress.cpp15
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/CrossThreadProgress.h37
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.cpp22
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.h24
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.cpp62
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.h12
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.cpp623
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.h87
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.cpp42
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.h67
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.cpp61
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.h24
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.cpp190
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.h84
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.h36
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithSha1.h36
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.cpp177
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.h18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/CpioHandler.cpp624
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp644
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp413
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/DeflateProps.cpp118
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/DeflateProps.h35
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/DllExports2.cpp76
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/DmgHandler.cpp918
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/ElfHandler.cpp534
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/FatHandler.cpp996
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/FlvHandler.cpp544
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/GzHandler.cpp698
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsHandler.cpp243
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsHandler.h26
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsIn.cpp480
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsIn.h154
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsRegister.cpp13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/IArchive.h234
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHandler.cpp326
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHandler.h30
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHeader.cpp21
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHeader.h61
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoIn.cpp453
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoIn.h315
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoItem.h141
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoRegister.cpp13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/LzhHandler.cpp775
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/LzmaHandler.cpp430
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/MachoHandler.cpp500
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/MbrHandler.cpp507
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/MslzHandler.cpp257
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/MubHandler.cpp266
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisDecode.cpp130
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisDecode.h47
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisHandler.cpp510
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisHandler.h43
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisIn.cpp1461
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisIn.h181
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisRegister.cpp13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/NtfsHandler.cpp1764
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/PeHandler.cpp1752
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/PpmdHandler.cpp456
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHandler.cpp869
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHandler.h66
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHeader.cpp21
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHeader.h205
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarIn.cpp478
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarIn.h123
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarItem.cpp55
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarItem.h79
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarRegister.cpp13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp78
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarVolumeInStream.h49
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/RpmHandler.cpp292
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/SplitHandler.cpp366
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/SquashfsHandler.cpp2155
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/SwfHandler.cpp706
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp386
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.h61
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandlerOut.cpp122
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHeader.cpp25
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHeader.h108
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarIn.cpp207
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarIn.h17
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarItem.h72
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarOut.cpp187
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarOut.h28
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarRegister.cpp18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarUpdate.cpp139
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarUpdate.h34
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfHandler.cpp451
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfHandler.h37
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp876
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.h375
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfRegister.cpp13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/VhdHandler.cpp734
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandler.cpp660
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandler.h77
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandlerOut.cpp639
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimIn.cpp855
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimIn.h297
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimRegister.cpp18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/XarHandler.cpp588
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/XzHandler.cpp707
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/ZHandler.cpp161
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipAddCommon.cpp379
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipAddCommon.h56
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipCompressionMode.h42
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandler.cpp822
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandler.h101
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp537
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHeader.cpp36
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHeader.h284
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipIn.cpp893
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipIn.h125
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItem.cpp181
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItem.h281
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItemEx.h34
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipOut.cpp289
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipOut.h56
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipRegister.cpp18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipUpdate.cpp1076
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipUpdate.h58
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/CWrappers.cpp226
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/CWrappers.h109
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.cpp293
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.h98
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.cpp55
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.h10
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/FileStreams.cpp273
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/FileStreams.h134
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.cpp247
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.h128
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/InBuffer.cpp83
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/InBuffer.h81
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.cpp122
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.h48
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.cpp154
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.h125
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/LockedStream.cpp23
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/LockedStream.h38
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/MemBlocks.cpp183
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/MemBlocks.h71
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/MethodId.cpp27
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/MethodId.h10
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/MethodProps.cpp99
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/MethodProps.h41
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/OffsetStream.cpp35
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/OffsetStream.h25
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.cpp116
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.h64
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/OutMemStream.cpp142
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/OutMemStream.h96
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/ProgressMt.cpp53
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/ProgressMt.h46
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.cpp42
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.h34
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h32
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h34
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.cpp152
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.h38
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.cpp221
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.h135
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.cpp56
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.h13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/VirtThread.cpp46
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Common/VirtThread.h23
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder1.cpp309
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder1.h98
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder2.cpp90
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder2.h59
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BZip2Const.h54
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BZip2Crc.cpp26
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BZip2Crc.h31
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BZip2Decoder.cpp943
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BZip2Decoder.h205
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BZip2Encoder.cpp895
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BZip2Encoder.h245
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BZip2Register.cpp20
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp386
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.h115
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Register.cpp19
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.cpp15
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.h19
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BcjRegister.cpp19
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BitlDecoder.cpp24
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BitlDecoder.h141
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BitlEncoder.h57
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BitmDecoder.h66
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BitmEncoder.h50
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.cpp19
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.h44
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.cpp37
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.h14
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/BranchRegister.cpp30
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ByteSwap.cpp73
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/CodecExports.cpp160
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.cpp67
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.h34
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/CopyRegister.cpp14
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Deflate64Register.cpp20
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DeflateConst.h134
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DeflateDecoder.cpp353
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DeflateDecoder.h157
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DeflateEncoder.cpp986
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DeflateEncoder.h211
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DeflateNsisRegister.cpp14
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DeflateRegister.cpp21
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DeltaFilter.cpp112
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DllExports.cpp39
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/DllExports2.cpp28
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/HuffmanDecoder.h89
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ImplodeDecoder.cpp219
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ImplodeDecoder.h57
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp89
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ImplodeHuffmanDecoder.h34
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp531
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp1018
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h48
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp311
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h20
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzOutWindow.cpp14
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzOutWindow.h66
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzhDecoder.cpp220
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzhDecoder.h106
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.cpp189
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.h73
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.cpp94
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.h36
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Register.cpp20
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.cpp252
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.h84
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.cpp149
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.h36
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzmaRegister.cpp20
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Lzx.h61
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Lzx86Converter.cpp90
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Lzx86Converter.h46
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp387
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.h159
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Mtf8.h193
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PPMD_Alone/PpmdAlone.cpp348
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdContext.h490
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecode.h156
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecoder.cpp167
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecoder.h78
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncode.h142
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncoder.cpp119
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncoder.h48
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdRegister.cpp21
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdSubAlloc.h293
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdType.h14
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdZip.cpp223
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/PpmdZip.h72
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/QuantumDecoder.cpp175
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/QuantumDecoder.h264
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/RangeCoder.h205
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/RangeCoderBit.h114
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp480
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.h88
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar2Decoder.cpp391
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar2Decoder.h174
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar3Decoder.cpp897
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar3Decoder.h267
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar3Vm.cpp1091
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar3Vm.h179
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/RarCodecsRegister.cpp26
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ShrinkDecoder.cpp145
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ShrinkDecoder.h38
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ZDecoder.cpp159
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ZDecoder.h42
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ZlibDecoder.cpp89
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ZlibDecoder.h48
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ZlibEncoder.cpp61
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/ZlibEncoder.h48
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.cpp244
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.h117
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/7zAesRegister.cpp18
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.cpp109
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.h39
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.cpp48
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.h38
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp83
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.h21
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.cpp107
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.h21
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.cpp133
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.h50
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.cpp134
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.h47
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.cpp229
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.h68
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.cpp221
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.h125
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.cpp88
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.h56
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.cpp164
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.h47
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Guid.txt170
-rw-r--r--src/libs/7zip/unix/CPP/7zip/ICoder.h186
-rw-r--r--src/libs/7zip/unix/CPP/7zip/IDecl.h15
-rw-r--r--src/libs/7zip/unix/CPP/7zip/IPassword.h24
-rw-r--r--src/libs/7zip/unix/CPP/7zip/IProgress.h33
-rw-r--r--src/libs/7zip/unix/CPP/7zip/IStream.h58
-rw-r--r--src/libs/7zip/unix/CPP/7zip/MyVersion.h11
-rw-r--r--src/libs/7zip/unix/CPP/7zip/PropID.h76
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.cpp1010
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.h111
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp488
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.h143
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveName.cpp54
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveName.h10
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp133
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.h103
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/Bench.cpp1028
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/Bench.h42
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/CompressCall.cpp470
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/CompressCall.h24
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.cpp35
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.h11
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/DirItem.h69
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.cpp361
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.h25
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ExitCode.h27
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp263
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.h76
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractMode.h31
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.cpp142
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.h13
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/HandlerLoader.h38
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/IFileExtractCallback.h46
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.cpp716
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.h235
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.cpp536
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.h87
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.cpp120
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.h12
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/Property.h14
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.cpp79
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.h10
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.cpp22
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.h10
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.cpp22
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.h16
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/Update.cpp912
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/Update.h175
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.cpp64
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.h57
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.cpp249
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.h74
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.cpp158
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.h25
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.cpp58
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.h35
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/WorkDir.cpp59
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/WorkDir.h10
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ZipRegistry.cpp293
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Common/ZipRegistry.h105
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/BenchCon.cpp297
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/BenchCon.h16
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/ConsoleClose.cpp49
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/ConsoleClose.h26
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp228
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/ExtractCallbackConsole.h73
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/List.cpp654
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/List.h20
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/Main.cpp628
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/MainAr.cpp127
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/OpenCallbackConsole.cpp58
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/OpenCallbackConsole.h24
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.cpp90
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.h31
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp261
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/UpdateCallbackConsole.h62
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/UserInputUtils.cpp96
-rw-r--r--src/libs/7zip/unix/CPP/7zip/UI/Console/UserInputUtils.h24
-rw-r--r--src/libs/7zip/unix/CPP/Common/AutoPtr.h35
-rw-r--r--src/libs/7zip/unix/CPP/Common/Buffer.h77
-rw-r--r--src/libs/7zip/unix/CPP/Common/CRC.cpp7
-rw-r--r--src/libs/7zip/unix/CPP/Common/C_FileIO.cpp88
-rw-r--r--src/libs/7zip/unix/CPP/Common/C_FileIO.h47
-rw-r--r--src/libs/7zip/unix/CPP/Common/ComTry.h18
-rw-r--r--src/libs/7zip/unix/CPP/Common/CommandLineParser.cpp230
-rw-r--r--src/libs/7zip/unix/CPP/Common/CommandLineParser.h72
-rw-r--r--src/libs/7zip/unix/CPP/Common/Defs.h20
-rw-r--r--src/libs/7zip/unix/CPP/Common/DynamicBuffer.h50
-rw-r--r--src/libs/7zip/unix/CPP/Common/IntToString.cpp77
-rw-r--r--src/libs/7zip/unix/CPP/Common/IntToString.h19
-rw-r--r--src/libs/7zip/unix/CPP/Common/Lang.cpp130
-rw-r--r--src/libs/7zip/unix/CPP/Common/Lang.h28
-rw-r--r--src/libs/7zip/unix/CPP/Common/ListFileUtils.cpp75
-rw-r--r--src/libs/7zip/unix/CPP/Common/ListFileUtils.h11
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyCom.h225
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyException.h14
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyGuidDef.h54
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyInitGuid.h22
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyMap.cpp140
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyMap.h28
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyString.cpp206
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyString.h601
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyUnknown.h13
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyVector.cpp87
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyVector.h266
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyWindows.cpp111
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyWindows.h218
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyXml.cpp209
-rw-r--r--src/libs/7zip/unix/CPP/Common/MyXml.h40
-rw-r--r--src/libs/7zip/unix/CPP/Common/NewHandler.h16
-rw-r--r--src/libs/7zip/unix/CPP/Common/StdInStream.cpp100
-rw-r--r--src/libs/7zip/unix/CPP/Common/StdInStream.h32
-rw-r--r--src/libs/7zip/unix/CPP/Common/StdOutStream.cpp93
-rw-r--r--src/libs/7zip/unix/CPP/Common/StdOutStream.h35
-rw-r--r--src/libs/7zip/unix/CPP/Common/StringConvert.cpp181
-rw-r--r--src/libs/7zip/unix/CPP/Common/StringConvert.h73
-rw-r--r--src/libs/7zip/unix/CPP/Common/StringToInt.cpp90
-rw-r--r--src/libs/7zip/unix/CPP/Common/StringToInt.h18
-rw-r--r--src/libs/7zip/unix/CPP/Common/TextConfig.cpp138
-rw-r--r--src/libs/7zip/unix/CPP/Common/TextConfig.h22
-rw-r--r--src/libs/7zip/unix/CPP/Common/Types.h11
-rw-r--r--src/libs/7zip/unix/CPP/Common/UTFConvert.cpp145
-rw-r--r--src/libs/7zip/unix/CPP/Common/UTFConvert.h11
-rw-r--r--src/libs/7zip/unix/CPP/Common/Wildcard.cpp462
-rw-r--r--src/libs/7zip/unix/CPP/Common/Wildcard.h80
-rw-r--r--src/libs/7zip/unix/CPP/Windows/COM.cpp37
-rw-r--r--src/libs/7zip/unix/CPP/Windows/COM.h69
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Clipboard.cpp160
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Clipboard.h28
-rw-r--r--src/libs/7zip/unix/CPP/Windows/CommonDialog.h19
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/ComboBox.h82
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/Controls.cpp515
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/Dialog.cpp560
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/Dialog.h179
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/DialogImpl.h73
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/Edit.h24
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/ListView.h164
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/ProgressBar.h34
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/Static.h23
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/StatusBar.h56
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/Window2.cpp211
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Control/Window2.h111
-rw-r--r--src/libs/7zip/unix/CPP/Windows/DLL.cpp193
-rw-r--r--src/libs/7zip/unix/CPP/Windows/DLL.h48
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Defs.h17
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Error.cpp58
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Error.h33
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileDir.cpp927
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileDir.h115
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileFind.cpp604
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileFind.h126
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileIO.cpp475
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileIO.h110
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileName.cpp50
-rw-r--r--src/libs/7zip/unix/CPP/Windows/FileName.h27
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Handle.h37
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Menu.h4
-rw-r--r--src/libs/7zip/unix/CPP/Windows/NtCheck.h44
-rw-r--r--src/libs/7zip/unix/CPP/Windows/PropVariant.cpp243
-rw-r--r--src/libs/7zip/unix/CPP/Windows/PropVariant.h56
-rw-r--r--src/libs/7zip/unix/CPP/Windows/PropVariantConversions.cpp142
-rw-r--r--src/libs/7zip/unix/CPP/Windows/PropVariantConversions.h14
-rw-r--r--src/libs/7zip/unix/CPP/Windows/PropVariantUtils.cpp78
-rw-r--r--src/libs/7zip/unix/CPP/Windows/PropVariantUtils.h28
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Registry.cpp313
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Registry.h113
-rw-r--r--src/libs/7zip/unix/CPP/Windows/ResourceString.h22
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Shell.h21
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Synchronization.cpp157
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Synchronization.h187
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Synchronization2.h218
-rw-r--r--src/libs/7zip/unix/CPP/Windows/System.cpp166
-rw-r--r--src/libs/7zip/unix/CPP/Windows/System.h16
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Thread.h41
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Time.cpp88
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Time.h21
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Window.cpp101
-rw-r--r--src/libs/7zip/unix/CPP/Windows/Window.h43
-rw-r--r--src/libs/7zip/unix/CPP/include_windows/basetyps.h19
-rw-r--r--src/libs/7zip/unix/CPP/include_windows/tchar.h89
-rw-r--r--src/libs/7zip/unix/CPP/include_windows/windows.h194
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/StdAfx.h124
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/config.h67
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/initguid.h4
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/myAddExeFlag.cpp20
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/myGetTickCount.cpp8
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/myPrivate.h17
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/mySplitCommandLine.cpp82
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/test_emul.cpp745
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/wine_GetXXXDefaultLangID.cpp741
-rw-r--r--src/libs/7zip/unix/CPP/myWindows/wine_date_and_time.cpp434
-rw-r--r--src/libs/7zip/unix/ChangeLog914
-rw-r--r--src/libs/7zip/unix/DOCS/7zC.txt194
-rw-r--r--src/libs/7zip/unix/DOCS/7zFormat.txt469
-rw-r--r--src/libs/7zip/unix/DOCS/License.txt52
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/add.htm87
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/bench.htm79
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/delete.htm59
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/extract.htm91
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/extract_full.htm68
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/index.htm33
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/list.htm77
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/style.css232
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/test.htm46
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/commands/update.htm66
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/exit_codes.htm27
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/index.htm29
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/style.css232
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/ar_exclude.htm56
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/ar_include.htm83
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/ar_no.htm52
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/charset.htm49
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/exclude.htm60
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/include.htm87
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/index.htm64
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/large_pages.htm50
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/list_tech.htm36
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/method.htm625
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/output_dir.htm53
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/overwrite.htm56
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/password.htm54
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/recurse.htm83
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/sfx.htm156
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/ssc.htm50
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/stdin.htm55
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/stdout.htm50
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/stop_switch.htm31
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/style.css232
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/type.htm83
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/update.htm176
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/volume.htm49
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/working_dir.htm55
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/switches/yes.htm48
-rw-r--r--src/libs/7zip/unix/DOCS/MANUAL/syntax.htm120
-rw-r--r--src/libs/7zip/unix/DOCS/Methods.txt152
-rw-r--r--src/libs/7zip/unix/DOCS/copying.txt504
-rw-r--r--src/libs/7zip/unix/DOCS/history.txt456
-rw-r--r--src/libs/7zip/unix/DOCS/lzma.txt598
-rw-r--r--src/libs/7zip/unix/DOCS/readme.txt181
-rw-r--r--src/libs/7zip/unix/DOCS/unRarLicense.txt41
-rw-r--r--src/libs/7zip/unix/README358
-rw-r--r--src/libs/7zip/unix/TODO39
-rw-r--r--src/libs/7zip/unix/installer_framework_changes.txt511
-rw-r--r--src/libs/7zip/unix/unix.pri228
-rw-r--r--src/libs/7zip/win/C/7z.h203
-rw-r--r--src/libs/7zip/win/C/7zAlloc.c76
-rw-r--r--src/libs/7zip/win/C/7zAlloc.h15
-rw-r--r--src/libs/7zip/win/C/7zBuf.c36
-rw-r--r--src/libs/7zip/win/C/7zBuf.h39
-rw-r--r--src/libs/7zip/win/C/7zBuf2.c45
-rw-r--r--src/libs/7zip/win/C/7zCrc.c74
-rw-r--r--src/libs/7zip/win/C/7zCrc.h25
-rw-r--r--src/libs/7zip/win/C/7zCrcOpt.c34
-rw-r--r--src/libs/7zip/win/C/7zDec.c470
-rw-r--r--src/libs/7zip/win/C/7zFile.c284
-rw-r--r--src/libs/7zip/win/C/7zFile.h83
-rw-r--r--src/libs/7zip/win/C/7zIn.c1402
-rw-r--r--src/libs/7zip/win/C/7zStream.c169
-rw-r--r--src/libs/7zip/win/C/7zVersion.h7
-rw-r--r--src/libs/7zip/win/C/Aes.c282
-rw-r--r--src/libs/7zip/win/C/Aes.h38
-rw-r--r--src/libs/7zip/win/C/AesOpt.c182
-rw-r--r--src/libs/7zip/win/C/Alloc.c127
-rw-r--r--src/libs/7zip/win/C/Alloc.h38
-rw-r--r--src/libs/7zip/win/C/Bcj2.c132
-rw-r--r--src/libs/7zip/win/C/Bcj2.h38
-rw-r--r--src/libs/7zip/win/C/Bra.c133
-rw-r--r--src/libs/7zip/win/C/Bra.h68
-rw-r--r--src/libs/7zip/win/C/Bra86.c85
-rw-r--r--src/libs/7zip/win/C/BraIA64.c67
-rw-r--r--src/libs/7zip/win/C/BwtSort.c516
-rw-r--r--src/libs/7zip/win/C/BwtSort.h30
-rw-r--r--src/libs/7zip/win/C/CpuArch.c168
-rw-r--r--src/libs/7zip/win/C/CpuArch.h155
-rw-r--r--src/libs/7zip/win/C/Delta.c62
-rw-r--r--src/libs/7zip/win/C/Delta.h23
-rw-r--r--src/libs/7zip/win/C/HuffEnc.c146
-rw-r--r--src/libs/7zip/win/C/HuffEnc.h27
-rw-r--r--src/libs/7zip/win/C/LzFind.c761
-rw-r--r--src/libs/7zip/win/C/LzFind.h115
-rw-r--r--src/libs/7zip/win/C/LzFindMt.c793
-rw-r--r--src/libs/7zip/win/C/LzFindMt.h105
-rw-r--r--src/libs/7zip/win/C/LzHash.h54
-rw-r--r--src/libs/7zip/win/C/Lzma2Dec.c356
-rw-r--r--src/libs/7zip/win/C/Lzma2Dec.h84
-rw-r--r--src/libs/7zip/win/C/Lzma2Enc.c477
-rw-r--r--src/libs/7zip/win/C/Lzma2Enc.h66
-rw-r--r--src/libs/7zip/win/C/Lzma86.h111
-rw-r--r--src/libs/7zip/win/C/Lzma86Dec.c56
-rw-r--r--src/libs/7zip/win/C/Lzma86Enc.c108
-rw-r--r--src/libs/7zip/win/C/LzmaDec.c999
-rw-r--r--src/libs/7zip/win/C/LzmaDec.h231
-rw-r--r--src/libs/7zip/win/C/LzmaEnc.c2268
-rw-r--r--src/libs/7zip/win/C/LzmaEnc.h80
-rw-r--r--src/libs/7zip/win/C/LzmaLib.c46
-rw-r--r--src/libs/7zip/win/C/LzmaLib.h135
-rw-r--r--src/libs/7zip/win/C/MtCoder.c327
-rw-r--r--src/libs/7zip/win/C/MtCoder.h98
-rw-r--r--src/libs/7zip/win/C/Ppmd.h81
-rw-r--r--src/libs/7zip/win/C/Ppmd7.c708
-rw-r--r--src/libs/7zip/win/C/Ppmd7.h140
-rw-r--r--src/libs/7zip/win/C/Ppmd7Dec.c187
-rw-r--r--src/libs/7zip/win/C/Ppmd7Enc.c185
-rw-r--r--src/libs/7zip/win/C/Ppmd8.c1120
-rw-r--r--src/libs/7zip/win/C/Ppmd8.h133
-rw-r--r--src/libs/7zip/win/C/Ppmd8Dec.c155
-rw-r--r--src/libs/7zip/win/C/Ppmd8Enc.c161
-rw-r--r--src/libs/7zip/win/C/RotateDefs.h20
-rw-r--r--src/libs/7zip/win/C/Sha256.c204
-rw-r--r--src/libs/7zip/win/C/Sha256.h26
-rw-r--r--src/libs/7zip/win/C/Sort.c93
-rw-r--r--src/libs/7zip/win/C/Sort.h20
-rw-r--r--src/libs/7zip/win/C/Threads.c84
-rw-r--r--src/libs/7zip/win/C/Threads.h59
-rw-r--r--src/libs/7zip/win/C/Types.h254
-rw-r--r--src/libs/7zip/win/C/Xz.c88
-rw-r--r--src/libs/7zip/win/C/Xz.h252
-rw-r--r--src/libs/7zip/win/C/XzCrc64.c33
-rw-r--r--src/libs/7zip/win/C/XzCrc64.h26
-rw-r--r--src/libs/7zip/win/C/XzDec.c875
-rw-r--r--src/libs/7zip/win/C/XzEnc.c497
-rw-r--r--src/libs/7zip/win/C/XzEnc.h25
-rw-r--r--src/libs/7zip/win/C/XzIn.c306
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.cpp3
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.h50
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.cpp332
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.h68
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.cpp444
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.h55
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zExtract.cpp270
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.cpp123
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.h58
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.cpp149
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.h58
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.cpp482
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.h119
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandlerOut.cpp483
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.cpp14
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.h97
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.cpp1276
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.h245
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zItem.h268
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp866
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.h152
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.cpp164
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.h22
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zRegister.cpp18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.cpp24
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.h35
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.cpp1177
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.h88
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.cpp3
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/ApmHandler.cpp356
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/ArchiveExports.cpp135
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp798
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Bz2Handler.cpp423
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.cpp189
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.h44
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.cpp929
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.h28
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.cpp15
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.h44
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp272
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.h161
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabItem.h63
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/CabRegister.cpp13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Cab/StdAfx.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.cpp721
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.h29
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.cpp24
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.h28
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.cpp937
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.h244
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmRegister.cpp13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Chm/StdAfx.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.cpp239
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.h28
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.cpp389
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.h119
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Com/ComRegister.cpp13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.cpp19
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.h32
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.cpp121
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.h174
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.cpp240
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.h80
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.cpp239
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.h88
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.cpp99
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.h69
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.cpp15
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.h37
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.cpp22
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.h24
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.cpp62
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.h12
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.cpp623
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.h87
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.cpp42
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.h67
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.cpp61
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.h24
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.cpp190
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.h84
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.h36
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithSha1.h36
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.cpp177
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.h18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Common/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/CpioHandler.cpp624
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/CramfsHandler.cpp644
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/DebHandler.cpp413
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/DeflateProps.cpp118
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/DeflateProps.h35
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/DllExports.cpp47
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/DllExports2.cpp74
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp918
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/ElfHandler.cpp534
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp996
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/FlvHandler.cpp544
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/GzHandler.cpp698
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.cpp243
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.h26
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.cpp480
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.h154
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsRegister.cpp13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/IArchive.h234
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHandler.cpp326
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHandler.h30
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHeader.cpp21
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHeader.h61
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoIn.cpp453
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoIn.h315
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoItem.h141
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoRegister.cpp13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Iso/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/LzhHandler.cpp775
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp430
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/MachoHandler.cpp500
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/MbrHandler.cpp507
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/MslzHandler.cpp257
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/MubHandler.cpp266
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisDecode.cpp130
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisDecode.h47
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisHandler.cpp510
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisHandler.h43
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisIn.cpp1461
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisIn.h181
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisRegister.cpp13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Nsis/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp1764
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp1752
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/PpmdHandler.cpp456
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.cpp869
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.h66
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.cpp21
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.h205
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.cpp478
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.h123
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.cpp55
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.h79
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarRegister.cpp13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp78
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.h49
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.cpp3
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/RpmHandler.cpp292
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/SplitHandler.cpp366
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/SquashfsHandler.cpp2155
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/SwfHandler.cpp706
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandler.cpp386
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandler.h61
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandlerOut.cpp122
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHeader.cpp25
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHeader.h108
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarIn.cpp207
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarIn.h17
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarItem.h72
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarOut.cpp187
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarOut.h28
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarRegister.cpp18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarUpdate.cpp139
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Tar/TarUpdate.h34
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Udf/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfHandler.cpp451
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfHandler.h37
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfIn.cpp876
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfIn.h375
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfRegister.cpp13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp734
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Wim/StdAfx.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandler.cpp660
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandler.h77
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp639
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp855
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.h297
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Wim/WimRegister.cpp18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/XarHandler.cpp588
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/XzHandler.cpp707
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/ZHandler.cpp161
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/StdAfx.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.cpp379
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.h56
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipCompressionMode.h42
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.cpp822
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.h101
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp531
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.cpp36
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.h284
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.cpp893
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.h125
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.cpp172
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.h281
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItemEx.h34
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.cpp289
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.h56
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipRegister.cpp18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.cpp1068
-rw-r--r--src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.h58
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/CWrappers.cpp226
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/CWrappers.h109
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/CreateCoder.cpp293
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/CreateCoder.h98
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.cpp55
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.h10
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/FileStreams.cpp422
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/FileStreams.h144
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/FilterCoder.cpp247
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/FilterCoder.h128
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/InBuffer.cpp83
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/InBuffer.h81
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/InMemStream.cpp222
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/InMemStream.h284
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.cpp122
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.h48
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.cpp154
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.h125
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/LockedStream.cpp23
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/LockedStream.h38
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/MemBlocks.cpp183
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/MemBlocks.h71
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/MethodId.cpp27
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/MethodId.h10
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/MethodProps.cpp99
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/MethodProps.h41
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/OffsetStream.cpp35
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/OffsetStream.h25
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/OutBuffer.cpp116
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/OutBuffer.h64
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/OutMemStream.cpp142
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/OutMemStream.h96
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/ProgressMt.cpp53
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/ProgressMt.h46
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.cpp42
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.h34
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h32
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h34
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/StreamBinder.cpp150
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/StreamBinder.h32
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/StreamObjects.cpp221
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/StreamObjects.h135
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/StreamUtils.cpp56
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/StreamUtils.h13
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/VirtThread.cpp46
-rw-r--r--src/libs/7zip/win/CPP/7zip/Common/VirtThread.h23
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder1.cpp309
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder1.h98
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder2.cpp90
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder2.h59
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BZip2Const.h54
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BZip2Crc.cpp26
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BZip2Crc.h31
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BZip2Decoder.cpp943
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BZip2Decoder.h205
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BZip2Encoder.cpp895
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BZip2Encoder.h245
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BZip2Register.cpp20
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.cpp386
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.h115
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Bcj2Register.cpp19
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.cpp15
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.h19
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BcjRegister.cpp19
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BitlDecoder.cpp24
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BitlDecoder.h141
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BitlEncoder.h57
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BitmDecoder.h66
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BitmEncoder.h50
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.cpp19
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.h44
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.cpp37
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.h14
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/BranchRegister.cpp30
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ByteSwap.cpp73
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/CodecExports.cpp160
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.cpp67
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.h34
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/CopyRegister.cpp14
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Deflate64Register.cpp20
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DeflateConst.h134
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DeflateDecoder.cpp353
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DeflateDecoder.h157
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DeflateEncoder.cpp986
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DeflateEncoder.h211
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DeflateRegister.cpp21
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DeltaFilter.cpp112
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DllExports.cpp45
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/DllExports2.cpp28
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/HuffmanDecoder.h89
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ImplodeDecoder.cpp219
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ImplodeDecoder.h57
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp89
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ImplodeHuffmanDecoder.h34
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzOutWindow.cpp14
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzOutWindow.h66
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzhDecoder.cpp220
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzhDecoder.h106
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.cpp189
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.h73
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.cpp94
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.h36
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Lzma2Register.cpp20
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.cpp252
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.h84
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.cpp149
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.h36
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzmaRegister.cpp20
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Lzx.h61
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Lzx86Converter.cpp90
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Lzx86Converter.h46
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzxDecoder.cpp387
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/LzxDecoder.h159
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Mtf8.h193
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/PpmdDecoder.cpp167
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/PpmdDecoder.h78
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/PpmdEncoder.cpp119
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/PpmdEncoder.h48
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/PpmdRegister.cpp21
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp223
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.h72
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/QuantumDecoder.cpp175
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/QuantumDecoder.h264
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/RangeCoder.h205
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/RangeCoderBit.h114
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Rar1Decoder.cpp480
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Rar1Decoder.h88
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Rar2Decoder.cpp391
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Rar2Decoder.h174
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Rar3Decoder.cpp897
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Rar3Decoder.h267
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Rar3Vm.cpp1091
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/Rar3Vm.h179
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/RarCodecsRegister.cpp26
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ShrinkDecoder.cpp145
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ShrinkDecoder.h38
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/StdAfx.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp159
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.h42
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ZlibDecoder.cpp89
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ZlibDecoder.h48
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ZlibEncoder.cpp61
-rw-r--r--src/libs/7zip/win/CPP/7zip/Compress/ZlibEncoder.h48
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/7zAes.cpp244
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/7zAes.h117
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/7zAesRegister.cpp18
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/HmacSha1.cpp109
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/HmacSha1.h39
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/MyAes.cpp48
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/MyAes.h38
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp83
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/Pbkdf2HmacSha1.h21
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/RandGen.cpp107
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/RandGen.h21
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/Rar20Crypto.cpp133
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/Rar20Crypto.h50
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/RarAes.cpp134
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/RarAes.h47
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/Sha1.cpp229
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/Sha1.h68
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/StdAfx.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/WzAes.cpp221
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/WzAes.h125
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/ZipCrypto.cpp88
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/ZipCrypto.h56
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/ZipStrong.cpp164
-rw-r--r--src/libs/7zip/win/CPP/7zip/Crypto/ZipStrong.h47
-rw-r--r--src/libs/7zip/win/CPP/7zip/Guid.txt170
-rw-r--r--src/libs/7zip/win/CPP/7zip/ICoder.h186
-rw-r--r--src/libs/7zip/win/CPP/7zip/IDecl.h15
-rw-r--r--src/libs/7zip/win/CPP/7zip/IPassword.h24
-rw-r--r--src/libs/7zip/win/CPP/7zip/IProgress.h33
-rw-r--r--src/libs/7zip/win/CPP/7zip/IStream.h58
-rw-r--r--src/libs/7zip/win/CPP/7zip/MyVersion.h8
-rw-r--r--src/libs/7zip/win/CPP/7zip/PropID.h76
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp1042
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h111
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp488
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h143
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp54
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h10
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp133
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h103
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp1028
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h42
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.cpp246
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.h24
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp178
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp35
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h11
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h69
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp361
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h25
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ExitCode.h27
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp263
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h76
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h31
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp142
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h13
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h46
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp681
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h235
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp536
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h87
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp120
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h12
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/Property.h14
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp79
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.h10
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp22
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h10
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp22
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h16
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp910
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/Update.h175
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp64
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.h57
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp249
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h74
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp158
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h25
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp58
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h35
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp59
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.h10
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp293
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h105
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/BenchCon.cpp297
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/BenchCon.h16
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/ConsoleClose.cpp73
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/ConsoleClose.h24
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp228
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/ExtractCallbackConsole.h73
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/List.cpp654
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/List.h20
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/Main.cpp598
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/MainAr.cpp125
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/OpenCallbackConsole.cpp58
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/OpenCallbackConsole.h24
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.cpp90
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.h31
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.cpp3
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp261
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/UpdateCallbackConsole.h62
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/UserInputUtils.cpp87
-rw-r--r--src/libs/7zip/win/CPP/7zip/UI/Console/UserInputUtils.h24
-rw-r--r--src/libs/7zip/win/CPP/Common/AutoPtr.h35
-rw-r--r--src/libs/7zip/win/CPP/Common/Buffer.h77
-rw-r--r--src/libs/7zip/win/CPP/Common/CRC.cpp7
-rw-r--r--src/libs/7zip/win/CPP/Common/C_FileIO.cpp88
-rw-r--r--src/libs/7zip/win/CPP/Common/C_FileIO.h47
-rw-r--r--src/libs/7zip/win/CPP/Common/ComTry.h17
-rw-r--r--src/libs/7zip/win/CPP/Common/CommandLineParser.cpp229
-rw-r--r--src/libs/7zip/win/CPP/Common/CommandLineParser.h72
-rw-r--r--src/libs/7zip/win/CPP/Common/Defs.h20
-rw-r--r--src/libs/7zip/win/CPP/Common/DynamicBuffer.h50
-rw-r--r--src/libs/7zip/win/CPP/Common/IntToString.cpp77
-rw-r--r--src/libs/7zip/win/CPP/Common/IntToString.h19
-rw-r--r--src/libs/7zip/win/CPP/Common/Lang.cpp130
-rw-r--r--src/libs/7zip/win/CPP/Common/Lang.h28
-rw-r--r--src/libs/7zip/win/CPP/Common/ListFileUtils.cpp75
-rw-r--r--src/libs/7zip/win/CPP/Common/ListFileUtils.h11
-rw-r--r--src/libs/7zip/win/CPP/Common/MyCom.h225
-rw-r--r--src/libs/7zip/win/CPP/Common/MyException.h14
-rw-r--r--src/libs/7zip/win/CPP/Common/MyGuidDef.h54
-rw-r--r--src/libs/7zip/win/CPP/Common/MyInitGuid.h22
-rw-r--r--src/libs/7zip/win/CPP/Common/MyMap.cpp140
-rw-r--r--src/libs/7zip/win/CPP/Common/MyMap.h28
-rw-r--r--src/libs/7zip/win/CPP/Common/MyString.cpp200
-rw-r--r--src/libs/7zip/win/CPP/Common/MyString.h627
-rw-r--r--src/libs/7zip/win/CPP/Common/MyUnknown.h13
-rw-r--r--src/libs/7zip/win/CPP/Common/MyVector.cpp87
-rw-r--r--src/libs/7zip/win/CPP/Common/MyVector.h266
-rw-r--r--src/libs/7zip/win/CPP/Common/MyWindows.cpp109
-rw-r--r--src/libs/7zip/win/CPP/Common/MyWindows.h204
-rw-r--r--src/libs/7zip/win/CPP/Common/MyXml.cpp209
-rw-r--r--src/libs/7zip/win/CPP/Common/MyXml.h40
-rw-r--r--src/libs/7zip/win/CPP/Common/NewHandler.cpp116
-rw-r--r--src/libs/7zip/win/CPP/Common/NewHandler.h16
-rw-r--r--src/libs/7zip/win/CPP/Common/Random.cpp26
-rw-r--r--src/libs/7zip/win/CPP/Common/Random.h16
-rw-r--r--src/libs/7zip/win/CPP/Common/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/Common/StdInStream.cpp107
-rw-r--r--src/libs/7zip/win/CPP/Common/StdInStream.h32
-rw-r--r--src/libs/7zip/win/CPP/Common/StdOutStream.cpp104
-rw-r--r--src/libs/7zip/win/CPP/Common/StdOutStream.h35
-rw-r--r--src/libs/7zip/win/CPP/Common/StringConvert.cpp97
-rw-r--r--src/libs/7zip/win/CPP/Common/StringConvert.h73
-rw-r--r--src/libs/7zip/win/CPP/Common/StringToInt.cpp90
-rw-r--r--src/libs/7zip/win/CPP/Common/StringToInt.h18
-rw-r--r--src/libs/7zip/win/CPP/Common/TextConfig.cpp138
-rw-r--r--src/libs/7zip/win/CPP/Common/TextConfig.h22
-rw-r--r--src/libs/7zip/win/CPP/Common/Types.h11
-rw-r--r--src/libs/7zip/win/CPP/Common/UTFConvert.cpp145
-rw-r--r--src/libs/7zip/win/CPP/Common/UTFConvert.h11
-rw-r--r--src/libs/7zip/win/CPP/Common/Wildcard.cpp462
-rw-r--r--src/libs/7zip/win/CPP/Common/Wildcard.h80
-rw-r--r--src/libs/7zip/win/CPP/Windows/COM.cpp37
-rw-r--r--src/libs/7zip/win/CPP/Windows/COM.h69
-rw-r--r--src/libs/7zip/win/CPP/Windows/Clipboard.cpp135
-rw-r--r--src/libs/7zip/win/CPP/Windows/Clipboard.h28
-rw-r--r--src/libs/7zip/win/CPP/Windows/CommonDialog.cpp184
-rw-r--r--src/libs/7zip/win/CPP/Windows/CommonDialog.h19
-rw-r--r--src/libs/7zip/win/CPP/Windows/Console.cpp10
-rw-r--r--src/libs/7zip/win/CPP/Windows/Console.h52
-rw-r--r--src/libs/7zip/win/CPP/Windows/DLL.cpp110
-rw-r--r--src/libs/7zip/win/CPP/Windows/DLL.h59
-rw-r--r--src/libs/7zip/win/CPP/Windows/Defs.h17
-rw-r--r--src/libs/7zip/win/CPP/Windows/Error.cpp50
-rw-r--r--src/libs/7zip/win/CPP/Windows/Error.h33
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileDir.cpp909
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileDir.h177
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileFind.cpp462
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileFind.h161
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileIO.cpp434
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileIO.h136
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileMapping.cpp12
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileMapping.h62
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileName.cpp50
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileName.h27
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileSystem.cpp126
-rw-r--r--src/libs/7zip/win/CPP/Windows/FileSystem.h51
-rw-r--r--src/libs/7zip/win/CPP/Windows/Handle.h37
-rw-r--r--src/libs/7zip/win/CPP/Windows/Memory.cpp36
-rw-r--r--src/libs/7zip/win/CPP/Windows/Memory.h53
-rw-r--r--src/libs/7zip/win/CPP/Windows/MemoryLock.cpp82
-rw-r--r--src/libs/7zip/win/CPP/Windows/MemoryLock.h15
-rw-r--r--src/libs/7zip/win/CPP/Windows/Menu.cpp191
-rw-r--r--src/libs/7zip/win/CPP/Windows/Menu.h153
-rw-r--r--src/libs/7zip/win/CPP/Windows/NationalTime.cpp37
-rw-r--r--src/libs/7zip/win/CPP/Windows/NationalTime.h20
-rw-r--r--src/libs/7zip/win/CPP/Windows/Net.cpp380
-rw-r--r--src/libs/7zip/win/CPP/Windows/Net.h87
-rw-r--r--src/libs/7zip/win/CPP/Windows/NtCheck.h44
-rw-r--r--src/libs/7zip/win/CPP/Windows/Process.cpp81
-rw-r--r--src/libs/7zip/win/CPP/Windows/Process.h100
-rw-r--r--src/libs/7zip/win/CPP/Windows/ProcessMessages.cpp22
-rw-r--r--src/libs/7zip/win/CPP/Windows/ProcessMessages.h14
-rw-r--r--src/libs/7zip/win/CPP/Windows/PropVariant.cpp243
-rw-r--r--src/libs/7zip/win/CPP/Windows/PropVariant.h56
-rw-r--r--src/libs/7zip/win/CPP/Windows/PropVariantConversions.cpp105
-rw-r--r--src/libs/7zip/win/CPP/Windows/PropVariantConversions.h14
-rw-r--r--src/libs/7zip/win/CPP/Windows/PropVariantUtils.cpp78
-rw-r--r--src/libs/7zip/win/CPP/Windows/PropVariantUtils.h28
-rw-r--r--src/libs/7zip/win/CPP/Windows/Registry.cpp369
-rw-r--r--src/libs/7zip/win/CPP/Windows/Registry.h85
-rw-r--r--src/libs/7zip/win/CPP/Windows/ResourceString.cpp64
-rw-r--r--src/libs/7zip/win/CPP/Windows/ResourceString.h22
-rw-r--r--src/libs/7zip/win/CPP/Windows/Security.cpp179
-rw-r--r--src/libs/7zip/win/CPP/Windows/Security.h167
-rw-r--r--src/libs/7zip/win/CPP/Windows/Shell.cpp335
-rw-r--r--src/libs/7zip/win/CPP/Windows/Shell.h93
-rw-r--r--src/libs/7zip/win/CPP/Windows/StdAfx.h9
-rw-r--r--src/libs/7zip/win/CPP/Windows/Synchronization.cpp10
-rw-r--r--src/libs/7zip/win/CPP/Windows/Synchronization.h164
-rw-r--r--src/libs/7zip/win/CPP/Windows/System.cpp72
-rw-r--r--src/libs/7zip/win/CPP/Windows/System.h16
-rw-r--r--src/libs/7zip/win/CPP/Windows/Thread.h38
-rw-r--r--src/libs/7zip/win/CPP/Windows/Time.cpp170
-rw-r--r--src/libs/7zip/win/CPP/Windows/Time.h21
-rw-r--r--src/libs/7zip/win/CPP/Windows/Window.cpp169
-rw-r--r--src/libs/7zip/win/CPP/Windows/Window.h261
-rw-r--r--src/libs/7zip/win/DOC/7zC.txt194
-rw-r--r--src/libs/7zip/win/DOC/7zFormat.txt469
-rw-r--r--src/libs/7zip/win/DOC/License.txt52
-rw-r--r--src/libs/7zip/win/DOC/Methods.txt152
-rw-r--r--src/libs/7zip/win/DOC/copying.txt504
-rw-r--r--src/libs/7zip/win/DOC/history.txt456
-rw-r--r--src/libs/7zip/win/DOC/lzma.txt598
-rw-r--r--src/libs/7zip/win/DOC/readme.txt181
-rw-r--r--src/libs/7zip/win/DOC/unRarLicense.txt41
-rw-r--r--src/libs/7zip/win/installer_framework_changes.txt519
-rw-r--r--src/libs/7zip/win/win.pri272
1326 files changed, 248037 insertions, 0 deletions
diff --git a/src/libs/7zip/7zip.pri b/src/libs/7zip/7zip.pri
new file mode 100644
index 000000000..1aa92d294
--- /dev/null
+++ b/src/libs/7zip/7zip.pri
@@ -0,0 +1,4 @@
+7ZIP_BASE=$$PWD
+
+win32:include($$7ZIP_BASE/win/win.pri) #this is 7zip
+unix:include($$7ZIP_BASE/unix/unix.pri) #this is p7zip
diff --git a/src/libs/7zip/unix/C/7zBuf.h b/src/libs/7zip/unix/C/7zBuf.h
new file mode 100644
index 000000000..e9f2f316d
--- /dev/null
+++ b/src/libs/7zip/unix/C/7zBuf.h
@@ -0,0 +1,39 @@
+/* 7zBuf.h -- Byte Buffer
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_BUF_H
+#define __7Z_BUF_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+ Byte *data;
+ size_t size;
+} CBuf;
+
+void Buf_Init(CBuf *p);
+int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc);
+void Buf_Free(CBuf *p, ISzAlloc *alloc);
+
+typedef struct
+{
+ Byte *data;
+ size_t size;
+ size_t pos;
+} CDynBuf;
+
+void DynBuf_Construct(CDynBuf *p);
+void DynBuf_SeekToBeg(CDynBuf *p);
+int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc);
+void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/7zBuf2.c b/src/libs/7zip/unix/C/7zBuf2.c
new file mode 100644
index 000000000..8d17e0dcf
--- /dev/null
+++ b/src/libs/7zip/unix/C/7zBuf2.c
@@ -0,0 +1,45 @@
+/* 7zBuf2.c -- Byte Buffer
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include <string.h>
+#include "7zBuf.h"
+
+void DynBuf_Construct(CDynBuf *p)
+{
+ p->data = 0;
+ p->size = 0;
+ p->pos = 0;
+}
+
+void DynBuf_SeekToBeg(CDynBuf *p)
+{
+ p->pos = 0;
+}
+
+int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc)
+{
+ if (size > p->size - p->pos)
+ {
+ size_t newSize = p->pos + size;
+ Byte *data;
+ newSize += newSize / 4;
+ data = (Byte *)alloc->Alloc(alloc, newSize);
+ if (data == 0)
+ return 0;
+ p->size = newSize;
+ memcpy(data, p->data, p->pos);
+ alloc->Free(alloc, p->data);
+ p->data = data;
+ }
+ memcpy(p->data + p->pos, buf, size);
+ p->pos += size;
+ return 1;
+}
+
+void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->data);
+ p->data = 0;
+ p->size = 0;
+ p->pos = 0;
+}
diff --git a/src/libs/7zip/unix/C/7zCrc.c b/src/libs/7zip/unix/C/7zCrc.c
new file mode 100644
index 000000000..404090ef3
--- /dev/null
+++ b/src/libs/7zip/unix/C/7zCrc.c
@@ -0,0 +1,76 @@
+/* 7zCrc.c -- CRC32 calculation
+2009-11-23 : Igor Pavlov : Public domain */
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define kCrcPoly 0xEDB88320
+
+#ifdef MY_CPU_LE
+#define CRC_NUM_TABLES 8
+#else
+#define CRC_NUM_TABLES 1
+#endif
+
+typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+static CRC_FUNC g_CrcUpdate;
+UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
+
+#if CRC_NUM_TABLES == 1
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+static UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+#else
+
+UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+#endif
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+ return g_CrcUpdate(v, data, size, g_CrcTable);
+}
+
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
+{
+ return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
+}
+
+void MY_FAST_CALL CrcGenerateTable()
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ g_CrcTable[i] = r;
+ }
+ #if CRC_NUM_TABLES == 1
+ g_CrcUpdate = CrcUpdateT1;
+ #else
+ for (; i < 256 * CRC_NUM_TABLES; i++)
+ {
+ UInt32 r = g_CrcTable[i - 256];
+ g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+ }
+ g_CrcUpdate = CrcUpdateT4;
+/* FIXME
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (!CPU_Is_InOrder())
+ g_CrcUpdate = CrcUpdateT8;
+ #endif
+*/
+ #endif
+}
diff --git a/src/libs/7zip/unix/C/7zCrc.h b/src/libs/7zip/unix/C/7zCrc.h
new file mode 100644
index 000000000..38e3e5fbc
--- /dev/null
+++ b/src/libs/7zip/unix/C/7zCrc.h
@@ -0,0 +1,25 @@
+/* 7zCrc.h -- CRC32 calculation
+2009-11-21 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_CRC_H
+#define __7Z_CRC_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+extern UInt32 g_CrcTable[];
+
+/* Call CrcGenerateTable one time before other CRC functions */
+void MY_FAST_CALL CrcGenerateTable(void);
+
+#define CRC_INIT_VAL 0xFFFFFFFF
+#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
+#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/7zCrcOpt.c b/src/libs/7zip/unix/C/7zCrcOpt.c
new file mode 100644
index 000000000..6c766a209
--- /dev/null
+++ b/src/libs/7zip/unix/C/7zCrcOpt.c
@@ -0,0 +1,34 @@
+/* 7zCrcOpt.c -- CRC32 calculation : optimized version
+2009-11-23 : Igor Pavlov : Public domain */
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_LE
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ for (; size >= 4; size -= 4, p += 4)
+ {
+ v ^= *(const UInt32 *)p;
+ v =
+ table[0x300 + (v & 0xFF)] ^
+ table[0x200 + ((v >> 8) & 0xFF)] ^
+ table[0x100 + ((v >> 16) & 0xFF)] ^
+ table[0x000 + ((v >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ return CrcUpdateT4(v, data, size, table);
+}
+
+#endif
diff --git a/src/libs/7zip/unix/C/7zCrcT8.c b/src/libs/7zip/unix/C/7zCrcT8.c
new file mode 100644
index 000000000..cd80e262b
--- /dev/null
+++ b/src/libs/7zip/unix/C/7zCrcT8.c
@@ -0,0 +1,43 @@
+/* 7zCrcT8.c -- CRC32 calculation with 8 tables
+2008-03-19
+Igor Pavlov
+Public domain */
+
+#include "7zCrc.h"
+
+#define kCrcPoly 0xEDB88320
+#define CRC_NUM_TABLES 8
+
+UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
+
+void MY_FAST_CALL CrcGenerateTable()
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ g_CrcTable[i] = r;
+ }
+ #if CRC_NUM_TABLES > 1
+ for (; i < 256 * CRC_NUM_TABLES; i++)
+ {
+ UInt32 r = g_CrcTable[i - 256];
+ g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+ }
+ #endif
+}
+
+UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+ return CrcUpdateT8(v, data, size, g_CrcTable);
+}
+
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
+{
+ return CrcUpdateT8(CRC_INIT_VAL, data, size, g_CrcTable) ^ 0xFFFFFFFF;
+}
diff --git a/src/libs/7zip/unix/C/7zStream.c b/src/libs/7zip/unix/C/7zStream.c
new file mode 100644
index 000000000..0ebb7b5f9
--- /dev/null
+++ b/src/libs/7zip/unix/C/7zStream.c
@@ -0,0 +1,169 @@
+/* 7zStream.c -- 7z Stream functions
+2010-03-11 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "Types.h"
+
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(stream->Read(stream, buf, &processed));
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size)
+{
+ return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf)
+{
+ size_t processed = 1;
+ RINOK(stream->Read(stream, buf, &processed));
+ return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
+}
+
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset)
+{
+ Int64 t = offset;
+ return stream->Seek(stream, &t, SZ_SEEK_SET);
+}
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size)
+{
+ const void *lookBuf;
+ if (*size == 0)
+ return SZ_OK;
+ RINOK(stream->Look(stream, &lookBuf, size));
+ memcpy(buf, lookBuf, *size);
+ return stream->Skip(stream, *size);
+}
+
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(stream->Read(stream, buf, &processed));
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size)
+{
+ return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size > 0)
+ {
+ p->pos = 0;
+ size2 = LookToRead_BUF_SIZE;
+ res = p->realStream->Read(p->realStream, p->buf, &size2);
+ p->size = size2;
+ }
+ if (size2 < *size)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size > 0)
+ {
+ p->pos = 0;
+ if (*size > LookToRead_BUF_SIZE)
+ *size = LookToRead_BUF_SIZE;
+ res = p->realStream->Read(p->realStream, p->buf, size);
+ size2 = p->size = *size;
+ }
+ if (size2 < *size)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead_Skip(void *pp, size_t offset)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ p->pos += offset;
+ return SZ_OK;
+}
+
+static SRes LookToRead_Read(void *pp, void *buf, size_t *size)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t rem = p->size - p->pos;
+ if (rem == 0)
+ return p->realStream->Read(p->realStream, buf, size);
+ if (rem > *size)
+ rem = *size;
+ memcpy(buf, p->buf + p->pos, rem);
+ p->pos += rem;
+ *size = rem;
+ return SZ_OK;
+}
+
+static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ p->pos = p->size = 0;
+ return p->realStream->Seek(p->realStream, pos, origin);
+}
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead)
+{
+ p->s.Look = lookahead ?
+ LookToRead_Look_Lookahead :
+ LookToRead_Look_Exact;
+ p->s.Skip = LookToRead_Skip;
+ p->s.Read = LookToRead_Read;
+ p->s.Seek = LookToRead_Seek;
+}
+
+void LookToRead_Init(CLookToRead *p)
+{
+ p->pos = p->size = 0;
+}
+
+static SRes SecToLook_Read(void *pp, void *buf, size_t *size)
+{
+ CSecToLook *p = (CSecToLook *)pp;
+ return LookInStream_LookRead(p->realStream, buf, size);
+}
+
+void SecToLook_CreateVTable(CSecToLook *p)
+{
+ p->s.Read = SecToLook_Read;
+}
+
+static SRes SecToRead_Read(void *pp, void *buf, size_t *size)
+{
+ CSecToRead *p = (CSecToRead *)pp;
+ return p->realStream->Read(p->realStream, buf, size);
+}
+
+void SecToRead_CreateVTable(CSecToRead *p)
+{
+ p->s.Read = SecToRead_Read;
+}
diff --git a/src/libs/7zip/unix/C/7zVersion.h b/src/libs/7zip/unix/C/7zVersion.h
new file mode 100644
index 000000000..9d99c5dff
--- /dev/null
+++ b/src/libs/7zip/unix/C/7zVersion.h
@@ -0,0 +1,7 @@
+#define MY_VER_MAJOR 9
+#define MY_VER_MINOR 20
+#define MY_VER_BUILD 0
+#define MY_VERSION "9.20"
+#define MY_DATE "2010-11-18"
+#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
diff --git a/src/libs/7zip/unix/C/Aes.c b/src/libs/7zip/unix/C/Aes.c
new file mode 100644
index 000000000..1bb658793
--- /dev/null
+++ b/src/libs/7zip/unix/C/Aes.c
@@ -0,0 +1,284 @@
+/* Aes.c -- AES encryption / decryption
+2009-11-23 : Igor Pavlov : Public domain */
+
+#include "Aes.h"
+#include "CpuArch.h"
+
+static UInt32 T[256 * 4];
+static Byte Sbox[256] = {
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
+
+void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);
+
+void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
+
+AES_CODE_FUNC g_AesCbc_Encode;
+AES_CODE_FUNC g_AesCbc_Decode;
+AES_CODE_FUNC g_AesCtr_Code;
+
+static UInt32 D[256 * 4];
+static Byte InvS[256];
+
+static Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
+
+#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF)
+
+#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24))
+
+#define gb0(x) ( (x) & 0xFF)
+#define gb1(x) (((x) >> ( 8)) & 0xFF)
+#define gb2(x) (((x) >> (16)) & 0xFF)
+#define gb3(x) (((x) >> (24)) & 0xFF)
+
+void AesGenTables(void)
+{
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ InvS[Sbox[i]] = (Byte)i;
+ for (i = 0; i < 256; i++)
+ {
+ {
+ UInt32 a1 = Sbox[i];
+ UInt32 a2 = xtime(a1);
+ UInt32 a3 = a2 ^ a1;
+ T[ i] = Ui32(a2, a1, a1, a3);
+ T[0x100 + i] = Ui32(a3, a2, a1, a1);
+ T[0x200 + i] = Ui32(a1, a3, a2, a1);
+ T[0x300 + i] = Ui32(a1, a1, a3, a2);
+ }
+ {
+ UInt32 a1 = InvS[i];
+ UInt32 a2 = xtime(a1);
+ UInt32 a4 = xtime(a2);
+ UInt32 a8 = xtime(a4);
+ UInt32 a9 = a8 ^ a1;
+ UInt32 aB = a8 ^ a2 ^ a1;
+ UInt32 aD = a8 ^ a4 ^ a1;
+ UInt32 aE = a8 ^ a4 ^ a2;
+ D[ i] = Ui32(aE, a9, aD, aB);
+ D[0x100 + i] = Ui32(aB, aE, a9, aD);
+ D[0x200 + i] = Ui32(aD, aB, aE, a9);
+ D[0x300 + i] = Ui32(a9, aD, aB, aE);
+ }
+ }
+ g_AesCbc_Encode = AesCbc_Encode;
+ g_AesCbc_Decode = AesCbc_Decode;
+ g_AesCtr_Code = AesCtr_Code;
+/* FIXME
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (CPU_Is_Aes_Supported())
+ {
+ g_AesCbc_Encode = AesCbc_Encode_Intel;
+ g_AesCbc_Decode = AesCbc_Decode_Intel;
+ g_AesCtr_Code = AesCtr_Code_Intel;
+ }
+ #endif
+*/
+}
+
+#define HT(i, x, s) (T + (x << 8))[gb ## x(s[(i + x) & 3])]
+#define HT4(m, i, s, p) m[i] = \
+ HT(i, 0, s) ^ \
+ HT(i, 1, s) ^ \
+ HT(i, 2, s) ^ \
+ HT(i, 3, s) ^ w[p + i]
+/* such order (2031) in HT16 is for VC6/K8 speed optimization) */
+#define HT16(m, s, p) \
+ HT4(m, 2, s, p); \
+ HT4(m, 0, s, p); \
+ HT4(m, 3, s, p); \
+ HT4(m, 1, s, p); \
+
+#define FT(i, x) Sbox[gb ## x(m[(i + x) & 3])]
+#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i];
+
+#define HD(i, x, s) (D + (x << 8))[gb ## x(s[(i - x) & 3])]
+#define HD4(m, i, s, p) m[i] = \
+ HD(i, 0, s) ^ \
+ HD(i, 1, s) ^ \
+ HD(i, 2, s) ^ \
+ HD(i, 3, s) ^ w[p + i];
+/* such order (0231) in HD16 is for VC6/K8 speed optimization) */
+#define HD16(m, s, p) \
+ HD4(m, 0, s, p); \
+ HD4(m, 2, s, p); \
+ HD4(m, 3, s, p); \
+ HD4(m, 1, s, p); \
+
+#define FD(i, x) InvS[gb ## x(m[(i - x) & 3])]
+#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i];
+
+void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize)
+{
+ unsigned i, wSize;
+ wSize = keySize + 28;
+ keySize /= 4;
+ w[0] = ((UInt32)keySize / 2) + 3;
+ w += 4;
+
+ for (i = 0; i < keySize; i++, key += 4)
+ w[i] = GetUi32(key);
+
+ for (; i < wSize; i++)
+ {
+ UInt32 t = w[i - 1];
+ unsigned rem = i % keySize;
+ if (rem == 0)
+ t = Ui32(Sbox[gb1(t)] ^ Rcon[i / keySize], Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]);
+ else if (keySize > 6 && rem == 4)
+ t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]);
+ w[i] = w[i - keySize] ^ t;
+ }
+}
+
+void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize)
+{
+ unsigned i, num;
+ Aes_SetKey_Enc(w, key, keySize);
+ num = keySize + 20;
+ w += 8;
+ for (i = 0; i < num; i++)
+ {
+ UInt32 r = w[i];
+ w[i] =
+ D[ Sbox[gb0(r)]] ^
+ D[0x100 + Sbox[gb1(r)]] ^
+ D[0x200 + Sbox[gb2(r)]] ^
+ D[0x300 + Sbox[gb3(r)]];
+ }
+}
+
+/* Aes_Encode and Aes_Decode functions work with little-endian words.
+ src and dest are pointers to 4 UInt32 words.
+ arc and dest can point to same block */
+
+static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
+{
+ UInt32 s[4];
+ UInt32 m[4];
+ UInt32 numRounds2 = w[0];
+ w += 4;
+ s[0] = src[0] ^ w[0];
+ s[1] = src[1] ^ w[1];
+ s[2] = src[2] ^ w[2];
+ s[3] = src[3] ^ w[3];
+ w += 4;
+ for (;;)
+ {
+ HT16(m, s, 0);
+ if (--numRounds2 == 0)
+ break;
+ HT16(s, m, 4);
+ w += 8;
+ }
+ w += 4;
+ FT4(0); FT4(1); FT4(2); FT4(3);
+}
+
+static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
+{
+ UInt32 s[4];
+ UInt32 m[4];
+ UInt32 numRounds2 = w[0];
+ w += 4 + numRounds2 * 8;
+ s[0] = src[0] ^ w[0];
+ s[1] = src[1] ^ w[1];
+ s[2] = src[2] ^ w[2];
+ s[3] = src[3] ^ w[3];
+ for (;;)
+ {
+ w -= 8;
+ HD16(m, s, 4);
+ if (--numRounds2 == 0)
+ break;
+ HD16(s, m, 0);
+ }
+ FD4(0); FD4(1); FD4(2); FD4(3);
+}
+
+void AesCbc_Init(UInt32 *p, const Byte *iv)
+{
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ p[i] = GetUi32(iv + i * 4);
+}
+
+void MY_FAST_CALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
+ {
+ p[0] ^= GetUi32(data);
+ p[1] ^= GetUi32(data + 4);
+ p[2] ^= GetUi32(data + 8);
+ p[3] ^= GetUi32(data + 12);
+
+ Aes_Encode(p + 4, p, p);
+
+ SetUi32(data, p[0]);
+ SetUi32(data + 4, p[1]);
+ SetUi32(data + 8, p[2]);
+ SetUi32(data + 12, p[3]);
+ }
+}
+
+void MY_FAST_CALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ UInt32 in[4], out[4];
+ for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
+ {
+ in[0] = GetUi32(data);
+ in[1] = GetUi32(data + 4);
+ in[2] = GetUi32(data + 8);
+ in[3] = GetUi32(data + 12);
+
+ Aes_Decode(p + 4, out, in);
+
+ SetUi32(data, p[0] ^ out[0]);
+ SetUi32(data + 4, p[1] ^ out[1]);
+ SetUi32(data + 8, p[2] ^ out[2]);
+ SetUi32(data + 12, p[3] ^ out[3]);
+
+ p[0] = in[0];
+ p[1] = in[1];
+ p[2] = in[2];
+ p[3] = in[3];
+ }
+}
+
+void MY_FAST_CALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ for (; numBlocks != 0; numBlocks--)
+ {
+ UInt32 temp[4];
+ Byte buf[16];
+ int i;
+ if (++p[0] == 0)
+ p[1]++;
+ Aes_Encode(p + 4, temp, p);
+ SetUi32(buf, temp[0]);
+ SetUi32(buf + 4, temp[1]);
+ SetUi32(buf + 8, temp[2]);
+ SetUi32(buf + 12, temp[3]);
+ for (i = 0; i < 16; i++)
+ *data++ ^= buf[i];
+ }
+}
diff --git a/src/libs/7zip/unix/C/Aes.h b/src/libs/7zip/unix/C/Aes.h
new file mode 100644
index 000000000..c9b0677c8
--- /dev/null
+++ b/src/libs/7zip/unix/C/Aes.h
@@ -0,0 +1,38 @@
+/* Aes.h -- AES encryption / decryption
+2009-11-23 : Igor Pavlov : Public domain */
+
+#ifndef __AES_H
+#define __AES_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+#define AES_BLOCK_SIZE 16
+
+/* Call AesGenTables one time before other AES functions */
+void AesGenTables(void);
+
+/* UInt32 pointers must be 16-byte aligned */
+
+/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */
+#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4)
+
+/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */
+/* keySize = 16 or 24 or 32 (bytes) */
+typedef void (MY_FAST_CALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize);
+void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize);
+void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize);
+
+/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */
+void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */
+/* data - 16-byte aligned pointer to data */
+/* numBlocks - the number of 16-byte blocks in data array */
+typedef void (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks);
+extern AES_CODE_FUNC g_AesCbc_Encode;
+extern AES_CODE_FUNC g_AesCbc_Decode;
+extern AES_CODE_FUNC g_AesCtr_Code;
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/Alloc.c b/src/libs/7zip/unix/C/Alloc.c
new file mode 100644
index 000000000..be02a9299
--- /dev/null
+++ b/src/libs/7zip/unix/C/Alloc.c
@@ -0,0 +1,280 @@
+/* Alloc.c -- Memory allocation functions
+2008-09-24
+Igor Pavlov
+Public domain */
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef _7ZIP_LARGE_PAGES
+#ifdef __linux__
+#ifndef _7ZIP_ST
+#include <pthread.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <mntent.h>
+#endif
+#endif
+
+#include "Alloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef _SZ_ALLOC_DEBUG
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountMid = 0;
+int g_allocCountBig = 0;
+#endif
+
+void *MyAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ {
+ void *p = malloc(size);
+ fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p);
+ return p;
+ }
+ #else
+ return malloc(size);
+ #endif
+}
+
+void MyFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address);
+ #endif
+ free(address);
+}
+
+#ifndef _WIN32
+
+#ifdef _7ZIP_LARGE_PAGES
+
+#ifdef __linux__
+#define _7ZIP_MAX_HUGE_ALLOCS 64
+static void *g_HugePageAddr[_7ZIP_MAX_HUGE_ALLOCS] = { NULL };
+static size_t g_HugePageLen[_7ZIP_MAX_HUGE_ALLOCS];
+static char *g_HugetlbPath;
+#endif
+
+#endif
+
+static void *VirtualAlloc(size_t size, int memLargePages)
+{
+ #ifdef _7ZIP_LARGE_PAGES
+ if (memLargePages)
+ {
+ #ifdef __linux__
+ /* huge pages support for Linux; added by Joachim Henke */
+ #ifndef _7ZIP_ST
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ #endif
+ int i;
+
+ void * address = NULL;
+ #ifndef _7ZIP_ST
+ pthread_mutex_lock(&mutex);
+ #endif
+ for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i)
+ {
+ if (g_HugePageAddr[i] == NULL)
+ {
+ int fd, pathlen = strlen(g_HugetlbPath);
+ char tempname[pathlen+12];
+
+ memcpy(tempname, g_HugetlbPath, pathlen);
+ memcpy(tempname + pathlen, "/7z-XXXXXX", 11);
+ fd = mkstemp(tempname);
+ unlink(tempname);
+ if (fd < 0)
+ {
+ fprintf(stderr,"cant't open %s (%s)\n",tempname,strerror(errno));
+ break;
+ }
+ address = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ close(fd);
+ if (address == MAP_FAILED)
+ {
+ address = NULL;
+ break;
+ }
+ g_HugePageLen[i] = size;
+ g_HugePageAddr[i] = address;
+// fprintf(stderr,"HUGE[%d]=%ld %p\n",i,(long)size,address);
+ break;
+ }
+ }
+ #ifndef _7ZIP_ST
+ pthread_mutex_unlock(&mutex);
+ #endif
+ return address;
+ #endif
+ }
+ #endif
+ return malloc(size);
+}
+
+static int VirtualFree(void *address)
+{
+ #ifdef _7ZIP_LARGE_PAGES
+ #ifdef __linux__
+ int i;
+
+ for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i)
+ {
+ if (g_HugePageAddr[i] == address)
+ {
+ munmap(address, g_HugePageLen[i]);
+ g_HugePageAddr[i] = NULL;
+ return 1;
+ }
+ }
+ #endif
+ #endif
+ free(address);
+ return 1;
+}
+
+#endif
+
+void *MidAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++);
+ #endif
+ return VirtualAlloc(size, 0);
+}
+
+void MidFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
+ #endif
+ if (address == 0)
+ return;
+ VirtualFree(address);
+}
+
+#ifdef _7ZIP_LARGE_PAGES
+size_t g_LargePageSize = 0;
+#ifdef _WIN32
+typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
+#elif defined(__linux__)
+size_t largePageMinimum()
+{
+ size_t size;
+
+ g_HugetlbPath = getenv("HUGETLB_PATH");
+
+ if (g_HugetlbPath == NULL)
+ {
+ // not defined => try to find out the directory
+ static char dir_hugetlbfs[1024];
+ const char * filename = "/etc/mtab"; // mounted filesystems
+ FILE *fp;
+ struct mntent * info;
+
+ dir_hugetlbfs[0]=0;
+
+ fp = setmntent(filename,"r");
+ if (fp)
+ {
+ info = getmntent(fp);
+ while(info)
+ {
+/*
+ printf("%s:\n",info->mnt_fsname);
+ printf(" dir='%s'\n",info->mnt_dir);
+ printf(" type='%s'\n",info->mnt_type);
+*/
+
+ if (strcmp(info->mnt_type,"hugetlbfs") == 0)
+ {
+ strcpy(dir_hugetlbfs,info->mnt_dir);
+ break;
+ }
+
+ info = getmntent(fp);
+ }
+ endmntent(fp);
+ }
+
+ if (dir_hugetlbfs[0])
+ {
+ g_HugetlbPath = dir_hugetlbfs;
+ // fprintf(stderr," Found hugetlbfs = '%s'\n",g_HugetlbPath);
+ }
+ }
+ if (g_HugetlbPath == NULL || (size = pathconf(g_HugetlbPath, _PC_REC_MIN_XFER_SIZE)) <= getpagesize())
+ return 0;
+ return size;
+}
+#else
+#define largePageMinimum() 0
+#endif
+#endif
+
+void SetLargePageSize()
+{
+ #ifdef _7ZIP_LARGE_PAGES
+ size_t size;
+ #ifdef _WIN32
+ GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
+ GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
+ if (largePageMinimum == 0)
+ return;
+ #endif
+ size = largePageMinimum();
+ if (size == 0 || (size & (size - 1)) != 0)
+ return;
+ g_LargePageSize = size;
+ // fprintf(stderr,"SetLargePageSize : %ld\n",(long)g_LargePageSize);
+ #endif
+}
+
+
+void *BigAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++);
+ #endif
+
+ #ifdef _7ZIP_LARGE_PAGES
+ if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18))
+ {
+ void *res = VirtualAlloc( (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), 1);
+ if (res != 0)
+ return res;
+ }
+ #endif
+ return VirtualAlloc(size, 0);
+}
+
+void BigFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
+ #endif
+
+ if (address == 0)
+ return;
+ VirtualFree(address);
+}
diff --git a/src/libs/7zip/unix/C/Alloc.h b/src/libs/7zip/unix/C/Alloc.h
new file mode 100644
index 000000000..7ef372e3a
--- /dev/null
+++ b/src/libs/7zip/unix/C/Alloc.h
@@ -0,0 +1,27 @@
+/* Alloc.h -- Memory allocation functions
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __COMMON_ALLOC_H
+#define __COMMON_ALLOC_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *MyAlloc(size_t size);
+void MyFree(void *address);
+
+void SetLargePageSize();
+
+void *MidAlloc(size_t size);
+void MidFree(void *address);
+void *BigAlloc(size_t size);
+void BigFree(void *address);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/Bra.c b/src/libs/7zip/unix/C/Bra.c
new file mode 100644
index 000000000..2e47b1413
--- /dev/null
+++ b/src/libs/7zip/unix/C/Bra.c
@@ -0,0 +1,133 @@
+/* Bra.c -- Converters for RISC code
+2010-04-16 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ ip += 8;
+ for (i = 0; i <= size; i += 4)
+ {
+ if (data[i + 3] == 0xEB)
+ {
+ UInt32 dest;
+ UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]);
+ src <<= 2;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ dest >>= 2;
+ data[i + 2] = (Byte)(dest >> 16);
+ data[i + 1] = (Byte)(dest >> 8);
+ data[i + 0] = (Byte)dest;
+ }
+ }
+ return i;
+}
+
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ ip += 4;
+ for (i = 0; i <= size; i += 2)
+ {
+ if ((data[i + 1] & 0xF8) == 0xF0 &&
+ (data[i + 3] & 0xF8) == 0xF8)
+ {
+ UInt32 dest;
+ UInt32 src =
+ (((UInt32)data[i + 1] & 0x7) << 19) |
+ ((UInt32)data[i + 0] << 11) |
+ (((UInt32)data[i + 3] & 0x7) << 8) |
+ (data[i + 2]);
+
+ src <<= 1;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ dest >>= 1;
+
+ data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7));
+ data[i + 0] = (Byte)(dest >> 11);
+ data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7));
+ data[i + 2] = (Byte)dest;
+ i += 2;
+ }
+ }
+ return i;
+}
+
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ for (i = 0; i <= size; i += 4)
+ {
+ if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1)
+ {
+ UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3] & (~3));
+
+ UInt32 dest;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3));
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] &= 0x3;
+ data[i + 3] |= dest;
+ }
+ }
+ return i;
+}
+
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ UInt32 i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ for (i = 0; i <= size; i += 4)
+ {
+ if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) ||
+ (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0))
+ {
+ UInt32 src =
+ ((UInt32)data[i + 0] << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3]);
+ UInt32 dest;
+
+ src <<= 2;
+ if (encoding)
+ dest = ip + i + src;
+ else
+ dest = src - (ip + i);
+ dest >>= 2;
+
+ dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
+
+ data[i + 0] = (Byte)(dest >> 24);
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] = (Byte)dest;
+ }
+ }
+ return i;
+}
diff --git a/src/libs/7zip/unix/C/Bra.h b/src/libs/7zip/unix/C/Bra.h
new file mode 100644
index 000000000..5748c1c05
--- /dev/null
+++ b/src/libs/7zip/unix/C/Bra.h
@@ -0,0 +1,68 @@
+/* Bra.h -- Branch converters for executables
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __BRA_H
+#define __BRA_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+These functions convert relative addresses to absolute addresses
+in CALL instructions to increase the compression ratio.
+
+ In:
+ data - data buffer
+ size - size of data
+ ip - current virtual Instruction Pinter (IP) value
+ state - state variable for x86 converter
+ encoding - 0 (for decoding), 1 (for encoding)
+
+ Out:
+ state - state variable for x86 converter
+
+ Returns:
+ The number of processed bytes. If you call these functions with multiple calls,
+ you must start next call with first byte after block of processed bytes.
+
+ Type Endian Alignment LookAhead
+
+ x86 little 1 4
+ ARMT little 2 2
+ ARM little 4 0
+ PPC big 4 0
+ SPARC big 4 0
+ IA64 little 16 0
+
+ size must be >= Alignment + LookAhead, if it's not last block.
+ If (size < Alignment + LookAhead), converter returns 0.
+
+ Example:
+
+ UInt32 ip = 0;
+ for ()
+ {
+ ; size must be >= Alignment + LookAhead, if it's not last block
+ SizeT processed = Convert(data, size, ip, 1);
+ data += processed;
+ size -= processed;
+ ip += processed;
+ }
+*/
+
+#define x86_Convert_Init(state) { state = 0; }
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/Bra86.c b/src/libs/7zip/unix/C/Bra86.c
new file mode 100644
index 000000000..1ee0e709b
--- /dev/null
+++ b/src/libs/7zip/unix/C/Bra86.c
@@ -0,0 +1,85 @@
+/* Bra86.c -- Converter for x86 code (BCJ)
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
+const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
+{
+ SizeT bufferPos = 0, prevPosT;
+ UInt32 prevMask = *state & 0x7;
+ if (size < 5)
+ return 0;
+ ip += 5;
+ prevPosT = (SizeT)0 - 1;
+
+ for (;;)
+ {
+ Byte *p = data + bufferPos;
+ Byte *limit = data + size - 4;
+ for (; p < limit; p++)
+ if ((*p & 0xFE) == 0xE8)
+ break;
+ bufferPos = (SizeT)(p - data);
+ if (p >= limit)
+ break;
+ prevPosT = bufferPos - prevPosT;
+ if (prevPosT > 3)
+ prevMask = 0;
+ else
+ {
+ prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
+ if (prevMask != 0)
+ {
+ Byte b = p[4 - kMaskToBitNumber[prevMask]];
+ if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
+ {
+ prevPosT = bufferPos;
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ continue;
+ }
+ }
+ }
+ prevPosT = bufferPos;
+
+ if (Test86MSByte(p[4]))
+ {
+ UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+ UInt32 dest;
+ for (;;)
+ {
+ Byte b;
+ int index;
+ if (encoding)
+ dest = (ip + (UInt32)bufferPos) + src;
+ else
+ dest = src - (ip + (UInt32)bufferPos);
+ if (prevMask == 0)
+ break;
+ index = kMaskToBitNumber[prevMask] * 8;
+ b = (Byte)(dest >> (24 - index));
+ if (!Test86MSByte(b))
+ break;
+ src = dest ^ ((1 << (32 - index)) - 1);
+ }
+ p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
+ p[3] = (Byte)(dest >> 16);
+ p[2] = (Byte)(dest >> 8);
+ p[1] = (Byte)dest;
+ bufferPos += 5;
+ }
+ else
+ {
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ }
+ }
+ prevPosT = bufferPos - prevPosT;
+ *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
+ return bufferPos;
+}
diff --git a/src/libs/7zip/unix/C/BraIA64.c b/src/libs/7zip/unix/C/BraIA64.c
new file mode 100644
index 000000000..0b4ee85bc
--- /dev/null
+++ b/src/libs/7zip/unix/C/BraIA64.c
@@ -0,0 +1,67 @@
+/* BraIA64.c -- Converter for IA-64 code
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+static const Byte kBranchTable[32] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+};
+
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 16)
+ return 0;
+ size -= 16;
+ for (i = 0; i <= size; i += 16)
+ {
+ UInt32 instrTemplate = data[i] & 0x1F;
+ UInt32 mask = kBranchTable[instrTemplate];
+ UInt32 bitPos = 5;
+ int slot;
+ for (slot = 0; slot < 3; slot++, bitPos += 41)
+ {
+ UInt32 bytePos, bitRes;
+ UInt64 instruction, instNorm;
+ int j;
+ if (((mask >> slot) & 1) == 0)
+ continue;
+ bytePos = (bitPos >> 3);
+ bitRes = bitPos & 0x7;
+ instruction = 0;
+ for (j = 0; j < 6; j++)
+ instruction += (UInt64)data[i + j + bytePos] << (8 * j);
+
+ instNorm = instruction >> bitRes;
+ if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0)
+ {
+ UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
+ UInt32 dest;
+ src |= ((UInt32)(instNorm >> 36) & 1) << 20;
+
+ src <<= 4;
+
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+
+ dest >>= 4;
+
+ instNorm &= ~((UInt64)(0x8FFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
+
+ instruction &= (1 << bitRes) - 1;
+ instruction |= (instNorm << bitRes);
+ for (j = 0; j < 6; j++)
+ data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
+ }
+ }
+ }
+ return i;
+}
diff --git a/src/libs/7zip/unix/C/BwtSort.c b/src/libs/7zip/unix/C/BwtSort.c
new file mode 100644
index 000000000..207305072
--- /dev/null
+++ b/src/libs/7zip/unix/C/BwtSort.c
@@ -0,0 +1,516 @@
+/* BwtSort.c -- BWT block sorting
+2008-08-17
+Igor Pavlov
+Public domain */
+
+#include "BwtSort.h"
+#include "Sort.h"
+
+/* #define BLOCK_SORT_USE_HEAP_SORT */
+
+#define NO_INLINE MY_FAST_CALL
+
+/* Don't change it !!! */
+#define kNumHashBytes 2
+#define kNumHashValues (1 << (kNumHashBytes * 8))
+
+/* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */
+#define kNumRefBitsMax 12
+
+#define BS_TEMP_SIZE kNumHashValues
+
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
+
+/* 32 Flags in UInt32 word */
+#define kNumFlagsBits 5
+#define kNumFlagsInWord (1 << kNumFlagsBits)
+#define kFlagsMask (kNumFlagsInWord - 1)
+#define kAllFlags 0xFFFFFFFF
+
+#else
+
+#define kNumBitsMax 20
+#define kIndexMask ((1 << kNumBitsMax) - 1)
+#define kNumExtraBits (32 - kNumBitsMax)
+#define kNumExtra0Bits (kNumExtraBits - 2)
+#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1)
+
+#define SetFinishedGroupSize(p, size) \
+ { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \
+ if ((size) > (1 << kNumExtra0Bits)) { \
+ *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \
+
+static void SetGroupSize(UInt32 *p, UInt32 size)
+{
+ if (--size == 0)
+ return;
+ *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax);
+ if (size >= (1 << kNumExtra0Bits))
+ {
+ *p |= 0x40000000;
+ p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax);
+ }
+}
+
+#endif
+
+/*
+SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks
+ "range" is not real range. It's only for optimization.
+returns: 1 - if there are groups, 0 - no more groups
+*/
+
+UInt32 NO_INLINE SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ , UInt32 left, UInt32 range
+ #endif
+ )
+{
+ UInt32 *ind2 = Indices + groupOffset;
+ UInt32 *Groups;
+ if (groupSize <= 1)
+ {
+ /*
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetFinishedGroupSize(ind2, 1);
+ #endif
+ */
+ return 0;
+ }
+ Groups = Indices + BlockSize + BS_TEMP_SIZE;
+ if (groupSize <= ((UInt32)1 << NumRefBits)
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ && groupSize <= range
+ #endif
+ )
+ {
+ UInt32 *temp = Indices + BlockSize;
+ UInt32 j;
+ UInt32 mask, thereAreGroups, group, cg;
+ {
+ UInt32 gPrev;
+ UInt32 gRes = 0;
+ {
+ UInt32 sp = ind2[0] + NumSortedBytes;
+ if (sp >= BlockSize) sp -= BlockSize;
+ gPrev = Groups[sp];
+ temp[0] = (gPrev << NumRefBits);
+ }
+
+ for (j = 1; j < groupSize; j++)
+ {
+ UInt32 sp = ind2[j] + NumSortedBytes;
+ UInt32 g;
+ if (sp >= BlockSize) sp -= BlockSize;
+ g = Groups[sp];
+ temp[j] = (g << NumRefBits) | j;
+ gRes |= (gPrev ^ g);
+ }
+ if (gRes == 0)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ }
+
+ HeapSort(temp, groupSize);
+ mask = ((1 << NumRefBits) - 1);
+ thereAreGroups = 0;
+
+ group = groupOffset;
+ cg = (temp[0] >> NumRefBits);
+ temp[0] = ind2[temp[0] & mask];
+
+ {
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags = Groups + BlockSize;
+ #else
+ UInt32 prevGroupStart = 0;
+ #endif
+
+ for (j = 1; j < groupSize; j++)
+ {
+ UInt32 val = temp[j];
+ UInt32 cgCur = (val >> NumRefBits);
+
+ if (cgCur != cg)
+ {
+ cg = cgCur;
+ group = groupOffset + j;
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = group - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #else
+ SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
+ prevGroupStart = j;
+ #endif
+ }
+ else
+ thereAreGroups = 1;
+ {
+ UInt32 ind = ind2[val & mask];
+ temp[j] = ind;
+ Groups[ind] = group;
+ }
+ }
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
+ #endif
+ }
+
+ for (j = 0; j < groupSize; j++)
+ ind2[j] = temp[j];
+ return thereAreGroups;
+ }
+
+ /* Check that all strings are in one group (cannot sort) */
+ {
+ UInt32 group, j;
+ UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ group = Groups[sp];
+ for (j = 1; j < groupSize; j++)
+ {
+ sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] != group)
+ break;
+ }
+ if (j == groupSize)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ }
+
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ {
+ /* ---------- Range Sort ---------- */
+ UInt32 i;
+ UInt32 mid;
+ for (;;)
+ {
+ UInt32 j;
+ if (range <= 1)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ mid = left + ((range + 1) >> 1);
+ j = groupSize;
+ i = 0;
+ do
+ {
+ UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] >= mid)
+ {
+ for (j--; j > i; j--)
+ {
+ sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] < mid)
+ {
+ UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp;
+ break;
+ }
+ }
+ if (i >= j)
+ break;
+ }
+ }
+ while (++i < j);
+ if (i == 0)
+ {
+ range = range - (mid - left);
+ left = mid;
+ }
+ else if (i == groupSize)
+ range = (mid - left);
+ else
+ break;
+ }
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = (groupOffset + i - 1);
+ UInt32 *Flags = Groups + BlockSize;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #endif
+
+ {
+ UInt32 j;
+ for (j = i; j < groupSize; j++)
+ Groups[ind2[j]] = groupOffset + i;
+ }
+
+ {
+ UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left);
+ return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left));
+ }
+
+ }
+
+ #else
+
+ /* ---------- Heap Sort ---------- */
+
+ {
+ UInt32 j;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ ind2[j] = sp;
+ }
+
+ HeapSortRef(ind2, Groups, groupSize);
+
+ /* Write Flags */
+ {
+ UInt32 sp = ind2[0];
+ UInt32 group = Groups[sp];
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags = Groups + BlockSize;
+ #else
+ UInt32 prevGroupStart = 0;
+ #endif
+
+ for (j = 1; j < groupSize; j++)
+ {
+ sp = ind2[j];
+ if (Groups[sp] != group)
+ {
+ group = Groups[sp];
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = groupOffset + j - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #else
+ SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
+ prevGroupStart = j;
+ #endif
+ }
+ }
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
+ #endif
+ }
+ {
+ /* Write new Groups values and Check that there are groups */
+ UInt32 thereAreGroups = 0;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 group = groupOffset + j;
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax);
+ if ((ind2[j] & 0x40000000) != 0)
+ subGroupSize += ((ind2[j + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ subGroupSize++;
+ for (;;)
+ {
+ UInt32 original = ind2[j];
+ UInt32 sp = original & kIndexMask;
+ if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
+ ind2[j] = sp | (original & ~kIndexMask);
+ Groups[sp] = group;
+ if (--subGroupSize == 0)
+ break;
+ j++;
+ thereAreGroups = 1;
+ }
+ #else
+ UInt32 *Flags = Groups + BlockSize;
+ for (;;)
+ {
+ UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
+ ind2[j] = sp;
+ Groups[sp] = group;
+ if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0)
+ break;
+ j++;
+ thereAreGroups = 1;
+ }
+ #endif
+ }
+ return thereAreGroups;
+ }
+ }
+ #endif
+}
+
+/* conditions: blockSize > 0 */
+UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize)
+{
+ UInt32 *counters = Indices + blockSize;
+ UInt32 i;
+ UInt32 *Groups;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags;
+ #endif
+
+ /* Radix-Sort for 2 bytes */
+ for (i = 0; i < kNumHashValues; i++)
+ counters[i] = 0;
+ for (i = 0; i < blockSize - 1; i++)
+ counters[((UInt32)data[i] << 8) | data[i + 1]]++;
+ counters[((UInt32)data[i] << 8) | data[0]]++;
+
+ Groups = counters + BS_TEMP_SIZE;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ Flags = Groups + blockSize;
+ {
+ UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits;
+ for (i = 0; i < numWords; i++)
+ Flags[i] = kAllFlags;
+ }
+ #endif
+
+ {
+ UInt32 sum = 0;
+ for (i = 0; i < kNumHashValues; i++)
+ {
+ UInt32 groupSize = counters[i];
+ if (groupSize > 0)
+ {
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 t = sum + groupSize - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ #endif
+ sum += groupSize;
+ }
+ counters[i] = sum - groupSize;
+ }
+
+ for (i = 0; i < blockSize - 1; i++)
+ Groups[i] = counters[((UInt32)data[i] << 8) | data[i + 1]];
+ Groups[i] = counters[((UInt32)data[i] << 8) | data[0]];
+
+ for (i = 0; i < blockSize - 1; i++)
+ Indices[counters[((UInt32)data[i] << 8) | data[i + 1]]++] = i;
+ Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i;
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 prev = 0;
+ for (i = 0; i < kNumHashValues; i++)
+ {
+ UInt32 prevGroupSize = counters[i] - prev;
+ if (prevGroupSize == 0)
+ continue;
+ SetGroupSize(Indices + prev, prevGroupSize);
+ prev = counters[i];
+ }
+ }
+ #endif
+ }
+
+ {
+ int NumRefBits;
+ UInt32 NumSortedBytes;
+ for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++);
+ NumRefBits = 32 - NumRefBits;
+ if (NumRefBits > kNumRefBitsMax)
+ NumRefBits = kNumRefBitsMax;
+
+ for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 finishedGroupSize = 0;
+ #endif
+ UInt32 newLimit = 0;
+ for (i = 0; i < blockSize;)
+ {
+ UInt32 groupSize;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+
+ if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0)
+ {
+ i++;
+ continue;
+ }
+ for (groupSize = 1;
+ (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0;
+ groupSize++);
+
+ groupSize++;
+
+ #else
+
+ groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
+ {
+ Bool finishedGroup = ((Indices[i] & 0x80000000) == 0);
+ if ((Indices[i] & 0x40000000) != 0)
+ {
+ groupSize += ((Indices[i + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ Indices[i + 1] &= kIndexMask;
+ }
+ Indices[i] &= kIndexMask;
+ groupSize++;
+ if (finishedGroup || groupSize == 1)
+ {
+ Indices[i - finishedGroupSize] &= kIndexMask;
+ if (finishedGroupSize > 1)
+ Indices[i - finishedGroupSize + 1] &= kIndexMask;
+ {
+ UInt32 newGroupSize = groupSize + finishedGroupSize;
+ SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize);
+ finishedGroupSize = newGroupSize;
+ }
+ i += groupSize;
+ continue;
+ }
+ finishedGroupSize = 0;
+ }
+
+ #endif
+
+ if (NumSortedBytes >= blockSize)
+ {
+ UInt32 j;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 t = (i + j);
+ /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */
+ Groups[Indices[t]] = t;
+ }
+ }
+ else
+ if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ , 0, blockSize
+ #endif
+ ) != 0)
+ newLimit = i + groupSize;
+ i += groupSize;
+ }
+ if (newLimit == 0)
+ break;
+ }
+ }
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ for (i = 0; i < blockSize;)
+ {
+ UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
+ if ((Indices[i] & 0x40000000) != 0)
+ {
+ groupSize += ((Indices[i + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ Indices[i + 1] &= kIndexMask;
+ }
+ Indices[i] &= kIndexMask;
+ groupSize++;
+ i += groupSize;
+ }
+ #endif
+ return Groups[0];
+}
+
diff --git a/src/libs/7zip/unix/C/BwtSort.h b/src/libs/7zip/unix/C/BwtSort.h
new file mode 100644
index 000000000..ce5598f0f
--- /dev/null
+++ b/src/libs/7zip/unix/C/BwtSort.h
@@ -0,0 +1,30 @@
+/* BwtSort.h -- BWT block sorting
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __BWT_SORT_H
+#define __BWT_SORT_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */
+/* #define BLOCK_SORT_EXTERNAL_FLAGS */
+
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5))
+#else
+#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0
+#endif
+
+#define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16))
+
+UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/CpuArch.c b/src/libs/7zip/unix/C/CpuArch.c
new file mode 100644
index 000000000..260cc1f45
--- /dev/null
+++ b/src/libs/7zip/unix/C/CpuArch.c
@@ -0,0 +1,168 @@
+/* CpuArch.c -- CPU specific code
+2010-10-26: Igor Pavlov : Public domain */
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
+#define USE_ASM
+#endif
+
+#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
+static UInt32 CheckFlag(UInt32 flag)
+{
+ #ifdef _MSC_VER
+ __asm pushfd;
+ __asm pop EAX;
+ __asm mov EDX, EAX;
+ __asm xor EAX, flag;
+ __asm push EAX;
+ __asm popfd;
+ __asm pushfd;
+ __asm pop EAX;
+ __asm xor EAX, EDX;
+ __asm push EDX;
+ __asm popfd;
+ __asm and flag, EAX;
+ #else
+ __asm__ __volatile__ (
+ "pushf\n\t"
+ "pop %%EAX\n\t"
+ "movl %%EAX,%%EDX\n\t"
+ "xorl %0,%%EAX\n\t"
+ "push %%EAX\n\t"
+ "popf\n\t"
+ "pushf\n\t"
+ "pop %%EAX\n\t"
+ "xorl %%EDX,%%EAX\n\t"
+ "push %%EDX\n\t"
+ "popf\n\t"
+ "andl %%EAX, %0\n\t":
+ "=c" (flag) : "c" (flag));
+ #endif
+ return flag;
+}
+#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
+#else
+#define CHECK_CPUID_IS_SUPPORTED
+#endif
+
+static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
+{
+ #ifdef USE_ASM
+
+ #ifdef _MSC_VER
+
+ UInt32 a2, b2, c2, d2;
+ __asm xor EBX, EBX;
+ __asm xor ECX, ECX;
+ __asm xor EDX, EDX;
+ __asm mov EAX, function;
+ __asm cpuid;
+ __asm mov a2, EAX;
+ __asm mov b2, EBX;
+ __asm mov c2, ECX;
+ __asm mov d2, EDX;
+
+ *a = a2;
+ *b = b2;
+ *c = c2;
+ *d = d2;
+
+ #else
+
+ __asm__ __volatile__ (
+ "cpuid"
+ : "=a" (*a) ,
+ "=b" (*b) ,
+ "=c" (*c) ,
+ "=d" (*d)
+ : "0" (function)) ;
+
+ #endif
+
+ #else
+
+ int CPUInfo[4];
+ __cpuid(CPUInfo, function);
+ *a = CPUInfo[0];
+ *b = CPUInfo[1];
+ *c = CPUInfo[2];
+ *d = CPUInfo[3];
+
+ #endif
+}
+
+Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
+{
+ CHECK_CPUID_IS_SUPPORTED
+ MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
+ MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
+ return True;
+}
+
+static UInt32 kVendors[][3] =
+{
+ { 0x756E6547, 0x49656E69, 0x6C65746E},
+ { 0x68747541, 0x69746E65, 0x444D4163},
+ { 0x746E6543, 0x48727561, 0x736C7561}
+};
+
+int x86cpuid_GetFirm(const Cx86cpuid *p)
+{
+ unsigned i;
+ for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
+ {
+ const UInt32 *v = kVendors[i];
+ if (v[0] == p->vendor[0] &&
+ v[1] == p->vendor[1] &&
+ v[2] == p->vendor[2])
+ return (int)i;
+ }
+ return -1;
+}
+
+Bool CPU_Is_InOrder()
+{
+ Cx86cpuid p;
+ int firm;
+ UInt32 family, model;
+ if (!x86cpuid_CheckAndRead(&p))
+ return True;
+ family = x86cpuid_GetFamily(&p);
+ model = x86cpuid_GetModel(&p);
+ firm = x86cpuid_GetFirm(&p);
+ switch (firm)
+ {
+ case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C));
+ case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
+ case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
+ }
+ return True;
+}
+
+#if !defined(MY_CPU_AMD64) && defined(_WIN32)
+static Bool CPU_Sys_Is_SSE_Supported()
+{
+ OSVERSIONINFO vi;
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ if (!GetVersionEx(&vi))
+ return False;
+ return (vi.dwMajorVersion >= 5);
+}
+#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
+#else
+#define CHECK_SYS_SSE_SUPPORT
+#endif
+
+Bool CPU_Is_Aes_Supported()
+{
+ Cx86cpuid p;
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_CheckAndRead(&p))
+ return False;
+ return (p.c >> 25) & 1;
+}
+
+#endif
diff --git a/src/libs/7zip/unix/C/CpuArch.h b/src/libs/7zip/unix/C/CpuArch.h
new file mode 100644
index 000000000..01930c7e6
--- /dev/null
+++ b/src/libs/7zip/unix/C/CpuArch.h
@@ -0,0 +1,155 @@
+/* CpuArch.h -- CPU specific code
+2010-10-26: Igor Pavlov : Public domain */
+
+#ifndef __CPU_ARCH_H
+#define __CPU_ARCH_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+/*
+MY_CPU_LE means that CPU is LITTLE ENDIAN.
+If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
+
+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
+If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
+*/
+
+#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
+#define MY_CPU_AMD64
+#endif
+
+#if defined(MY_CPU_AMD64) || defined(_M_IA64)
+#define MY_CPU_64BIT
+#endif
+
+#if defined(_M_IX86) || defined(__i386__)
+#define MY_CPU_X86
+#endif
+
+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
+#define MY_CPU_X86_OR_AMD64
+#endif
+
+#if defined(MY_CPU_X86) || defined(_M_ARM)
+#define MY_CPU_32BIT
+#endif
+
+#if defined(_WIN32) && defined(_M_ARM)
+#define MY_CPU_ARM_LE
+#endif
+
+#if defined(_WIN32) && defined(_M_IA64)
+#define MY_CPU_IA64_LE
+#endif
+
+#if defined(MY_CPU_X86_OR_AMD64)
+#define MY_CPU_LE_UNALIGN
+#endif
+
+#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
+#define MY_CPU_LE
+#endif
+
+#if defined(__BIG_ENDIAN__)
+#define MY_CPU_BE
+#endif
+
+#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
+Stop_Compiling_Bad_Endian
+#endif
+
+#ifdef MY_CPU_LE_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(p))
+#define GetUi32(p) (*(const UInt32 *)(p))
+#define GetUi64(p) (*(const UInt64 *)(p))
+#define SetUi16(p, d) *(UInt16 *)(p) = (d);
+#define SetUi32(p, d) *(UInt32 *)(p) = (d);
+#define SetUi64(p, d) *(UInt64 *)(p) = (d);
+
+#else
+
+#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
+
+#define GetUi32(p) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((UInt32)((const Byte *)(p))[2] << 16) | \
+ ((UInt32)((const Byte *)(p))[3] << 24))
+
+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
+
+#define SetUi16(p, d) { UInt32 _x_ = (d); \
+ ((Byte *)(p))[0] = (Byte)_x_; \
+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
+
+#define SetUi32(p, d) { UInt32 _x_ = (d); \
+ ((Byte *)(p))[0] = (Byte)_x_; \
+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
+ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
+ ((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
+
+#define SetUi64(p, d) { UInt64 _x64_ = (d); \
+ SetUi32(p, (UInt32)_x64_); \
+ SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
+
+#endif
+
+#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
+
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+
+#else
+
+#define GetBe32(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 24) | \
+ ((UInt32)((const Byte *)(p))[1] << 16) | \
+ ((UInt32)((const Byte *)(p))[2] << 8) | \
+ ((const Byte *)(p))[3] )
+
+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+
+#endif
+
+#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+typedef struct
+{
+ UInt32 maxFunc;
+ UInt32 vendor[3];
+ UInt32 ver;
+ UInt32 b;
+ UInt32 c;
+ UInt32 d;
+} Cx86cpuid;
+
+enum
+{
+ CPU_FIRM_INTEL,
+ CPU_FIRM_AMD,
+ CPU_FIRM_VIA
+};
+
+Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
+int x86cpuid_GetFirm(const Cx86cpuid *p);
+
+#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
+#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
+#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
+
+Bool CPU_Is_InOrder();
+Bool CPU_Is_Aes_Supported();
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/Delta.c b/src/libs/7zip/unix/C/Delta.c
new file mode 100644
index 000000000..2b327f15f
--- /dev/null
+++ b/src/libs/7zip/unix/C/Delta.c
@@ -0,0 +1,62 @@
+/* Delta.c -- Delta converter
+2009-05-26 : Igor Pavlov : Public domain */
+
+#include "Delta.h"
+
+void Delta_Init(Byte *state)
+{
+ unsigned i;
+ for (i = 0; i < DELTA_STATE_SIZE; i++)
+ state[i] = 0;
+}
+
+static void MyMemCpy(Byte *dest, const Byte *src, unsigned size)
+{
+ unsigned i;
+ for (i = 0; i < size; i++)
+ dest[i] = src[i];
+}
+
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte buf[DELTA_STATE_SIZE];
+ unsigned j = 0;
+ MyMemCpy(buf, state, delta);
+ {
+ SizeT i;
+ for (i = 0; i < size;)
+ {
+ for (j = 0; j < delta && i < size; i++, j++)
+ {
+ Byte b = data[i];
+ data[i] = (Byte)(b - buf[j]);
+ buf[j] = b;
+ }
+ }
+ }
+ if (j == delta)
+ j = 0;
+ MyMemCpy(state, buf + j, delta - j);
+ MyMemCpy(state + delta - j, buf, j);
+}
+
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte buf[DELTA_STATE_SIZE];
+ unsigned j = 0;
+ MyMemCpy(buf, state, delta);
+ {
+ SizeT i;
+ for (i = 0; i < size;)
+ {
+ for (j = 0; j < delta && i < size; i++, j++)
+ {
+ buf[j] = data[i] = (Byte)(buf[j] + data[i]);
+ }
+ }
+ }
+ if (j == delta)
+ j = 0;
+ MyMemCpy(state, buf + j, delta - j);
+ MyMemCpy(state + delta - j, buf, j);
+}
diff --git a/src/libs/7zip/unix/C/Delta.h b/src/libs/7zip/unix/C/Delta.h
new file mode 100644
index 000000000..0d4cd6274
--- /dev/null
+++ b/src/libs/7zip/unix/C/Delta.h
@@ -0,0 +1,23 @@
+/* Delta.h -- Delta converter
+2009-04-15 : Igor Pavlov : Public domain */
+
+#ifndef __DELTA_H
+#define __DELTA_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DELTA_STATE_SIZE 256
+
+void Delta_Init(Byte *state);
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/HuffEnc.c b/src/libs/7zip/unix/C/HuffEnc.c
new file mode 100644
index 000000000..561c7e5da
--- /dev/null
+++ b/src/libs/7zip/unix/C/HuffEnc.c
@@ -0,0 +1,146 @@
+/* HuffEnc.c -- functions for Huffman encoding
+2009-09-02 : Igor Pavlov : Public domain */
+
+#include "HuffEnc.h"
+#include "Sort.h"
+
+#define kMaxLen 16
+#define NUM_BITS 10
+#define MASK ((1 << NUM_BITS) - 1)
+
+#define NUM_COUNTERS 64
+
+#define HUFFMAN_SPEED_OPT
+
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
+{
+ UInt32 num = 0;
+ /* if (maxLen > 10) maxLen = 10; */
+ {
+ UInt32 i;
+
+ #ifdef HUFFMAN_SPEED_OPT
+
+ UInt32 counters[NUM_COUNTERS];
+ for (i = 0; i < NUM_COUNTERS; i++)
+ counters[i] = 0;
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
+ }
+
+ for (i = 1; i < NUM_COUNTERS; i++)
+ {
+ UInt32 temp = counters[i];
+ counters[i] = num;
+ num += temp;
+ }
+
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ if (freq == 0)
+ lens[i] = 0;
+ else
+ p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS);
+ }
+ counters[0] = 0;
+ HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
+
+ #else
+
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ if (freq == 0)
+ lens[i] = 0;
+ else
+ p[num++] = i | (freq << NUM_BITS);
+ }
+ HeapSort(p, num);
+
+ #endif
+ }
+
+ if (num < 2)
+ {
+ unsigned minCode = 0;
+ unsigned maxCode = 1;
+ if (num == 1)
+ {
+ maxCode = (unsigned)p[0] & MASK;
+ if (maxCode == 0)
+ maxCode++;
+ }
+ p[minCode] = 0;
+ p[maxCode] = 1;
+ lens[minCode] = lens[maxCode] = 1;
+ return;
+ }
+
+ {
+ UInt32 b, e, i;
+
+ i = b = e = 0;
+ do
+ {
+ UInt32 n, m, freq;
+ n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+ freq = (p[n] & ~MASK);
+ p[n] = (p[n] & MASK) | (e << NUM_BITS);
+ m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+ freq += (p[m] & ~MASK);
+ p[m] = (p[m] & MASK) | (e << NUM_BITS);
+ p[e] = (p[e] & MASK) | freq;
+ e++;
+ }
+ while (num - e > 1);
+
+ {
+ UInt32 lenCounters[kMaxLen + 1];
+ for (i = 0; i <= kMaxLen; i++)
+ lenCounters[i] = 0;
+
+ p[--e] &= MASK;
+ lenCounters[1] = 2;
+ while (e > 0)
+ {
+ UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
+ p[e] = (p[e] & MASK) | (len << NUM_BITS);
+ if (len >= maxLen)
+ for (len = maxLen - 1; lenCounters[len] == 0; len--);
+ lenCounters[len]--;
+ lenCounters[len + 1] += 2;
+ }
+
+ {
+ UInt32 len;
+ i = 0;
+ for (len = maxLen; len != 0; len--)
+ {
+ UInt32 num;
+ for (num = lenCounters[len]; num != 0; num--)
+ lens[p[i++] & MASK] = (Byte)len;
+ }
+ }
+
+ {
+ UInt32 nextCodes[kMaxLen + 1];
+ {
+ UInt32 code = 0;
+ UInt32 len;
+ for (len = 1; len <= kMaxLen; len++)
+ nextCodes[len] = code = (code + lenCounters[len - 1]) << 1;
+ }
+ /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
+
+ {
+ UInt32 i;
+ for (i = 0; i < numSymbols; i++)
+ p[i] = nextCodes[lens[i]]++;
+ }
+ }
+ }
+ }
+}
diff --git a/src/libs/7zip/unix/C/HuffEnc.h b/src/libs/7zip/unix/C/HuffEnc.h
new file mode 100644
index 000000000..9cf4bfde8
--- /dev/null
+++ b/src/libs/7zip/unix/C/HuffEnc.h
@@ -0,0 +1,27 @@
+/* HuffEnc.h -- Huffman encoding
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __HUFF_ENC_H
+#define __HUFF_ENC_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Conditions:
+ num <= 1024 = 2 ^ NUM_BITS
+ Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS)
+ maxLen <= 16 = kMaxLen
+ Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
+*/
+
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/LzFind.c b/src/libs/7zip/unix/C/LzFind.c
new file mode 100644
index 000000000..e3ecb0542
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzFind.c
@@ -0,0 +1,761 @@
+/* LzFind.c -- Match finder for LZ algorithms
+2009-04-22 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "LzFind.h"
+#include "LzHash.h"
+
+#define kEmptyHashValue 0
+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
+#define kNormalizeMask (~(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)3 << 30)
+
+#define kStartMaxLen 3
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ if (!p->directInput)
+ {
+ alloc->Free(alloc, p->bufferBase);
+ p->bufferBase = 0;
+ }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+{
+ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+ if (p->directInput)
+ {
+ p->blockSize = blockSize;
+ return 1;
+ }
+ if (p->bufferBase == 0 || p->blockSize != blockSize)
+ {
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
+ }
+ return (p->bufferBase != 0);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+
+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+{
+ p->posLimit -= subValue;
+ p->pos -= subValue;
+ p->streamPos -= subValue;
+}
+
+static void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return;
+ if (p->directInput)
+ {
+ UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+ if (curSize > p->directInputRem)
+ curSize = (UInt32)p->directInputRem;
+ p->directInputRem -= curSize;
+ p->streamPos += curSize;
+ if (p->directInputRem == 0)
+ p->streamEndWasReached = 1;
+ return;
+ }
+ for (;;)
+ {
+ Byte *dest = p->buffer + (p->streamPos - p->pos);
+ size_t size = (p->bufferBase + p->blockSize - dest);
+ if (size == 0)
+ return;
+ p->result = p->stream->Read(p->stream, dest, &size);
+ if (p->result != SZ_OK)
+ return;
+ if (size == 0)
+ {
+ p->streamEndWasReached = 1;
+ return;
+ }
+ p->streamPos += (UInt32)size;
+ if (p->streamPos - p->pos > p->keepSizeAfter)
+ return;
+ }
+}
+
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+ memmove(p->bufferBase,
+ p->buffer - p->keepSizeBefore,
+ (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
+ p->buffer = p->bufferBase + p->keepSizeBefore;
+}
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+ if (p->directInput)
+ return 0;
+ /* if (p->streamEndWasReached) return 0; */
+ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+ if (p->streamEndWasReached)
+ return;
+ if (p->keepSizeAfter >= p->streamPos - p->pos)
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+{
+ if (MatchFinder_NeedMove(p))
+ MatchFinder_MoveBlock(p);
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+ p->cutValue = 32;
+ p->btMode = 1;
+ p->numHashBytes = 4;
+ p->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+ UInt32 i;
+ p->bufferBase = 0;
+ p->directInput = 0;
+ p->hash = 0;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ p->crc[i] = r;
+ }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hash);
+ p->hash = 0;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+{
+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return 0;
+ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc)
+{
+ UInt32 sizeReserv;
+ if (historySize > kMaxHistorySize)
+ {
+ MatchFinder_Free(p, alloc);
+ return 0;
+ }
+ sizeReserv = historySize >> 1;
+ if (historySize > ((UInt32)2 << 30))
+ sizeReserv = historySize >> 2;
+ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
+
+ p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
+ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+ if (LzInWindow_Create(p, sizeReserv, alloc))
+ {
+ UInt32 newCyclicBufferSize = historySize + 1;
+ UInt32 hs;
+ p->matchMaxLen = matchMaxLen;
+ {
+ p->fixedHashSize = 0;
+ if (p->numHashBytes == 2)
+ hs = (1 << 16) - 1;
+ else
+ {
+ hs = historySize - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ hs |= 0xFFFF; /* don't change it! It's required for Deflate */
+ if (hs > (1 << 24))
+ {
+ if (p->numHashBytes == 3)
+ hs = (1 << 24) - 1;
+ else
+ hs >>= 1;
+ }
+ }
+ p->hashMask = hs;
+ hs++;
+ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
+ hs += p->fixedHashSize;
+ }
+
+ {
+ UInt32 prevSize = p->hashSizeSum + p->numSons;
+ UInt32 newSize;
+ p->historySize = historySize;
+ p->hashSizeSum = hs;
+ p->cyclicBufferSize = newCyclicBufferSize;
+ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
+ newSize = p->hashSizeSum + p->numSons;
+ if (p->hash != 0 && prevSize == newSize)
+ return 1;
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->hash = AllocRefs(newSize, alloc);
+ if (p->hash != 0)
+ {
+ p->son = p->hash + p->hashSizeSum;
+ return 1;
+ }
+ }
+ }
+ MatchFinder_Free(p, alloc);
+ return 0;
+}
+
+static void MatchFinder_SetLimits(CMatchFinder *p)
+{
+ UInt32 limit = kMaxValForNormalize - p->pos;
+ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+ if (limit2 < limit)
+ limit = limit2;
+ limit2 = p->streamPos - p->pos;
+ if (limit2 <= p->keepSizeAfter)
+ {
+ if (limit2 > 0)
+ limit2 = 1;
+ }
+ else
+ limit2 -= p->keepSizeAfter;
+ if (limit2 < limit)
+ limit = limit2;
+ {
+ UInt32 lenLimit = p->streamPos - p->pos;
+ if (lenLimit > p->matchMaxLen)
+ lenLimit = p->matchMaxLen;
+ p->lenLimit = lenLimit;
+ }
+ p->posLimit = p->pos + limit;
+}
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+ UInt32 i;
+ for (i = 0; i < p->hashSizeSum; i++)
+ p->hash[i] = kEmptyHashValue;
+ p->cyclicBufferPos = 0;
+ p->buffer = p->bufferBase;
+ p->pos = p->streamPos = p->cyclicBufferSize;
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+ MatchFinder_ReadBlock(p);
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
+{
+ return (p->pos - p->historySize - 1) & kNormalizeMask;
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+{
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 value = items[i];
+ if (value <= subValue)
+ value = kEmptyHashValue;
+ else
+ value -= subValue;
+ items[i] = value;
+ }
+}
+
+static void MatchFinder_Normalize(CMatchFinder *p)
+{
+ UInt32 subValue = MatchFinder_GetSubValue(p);
+ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
+ MatchFinder_ReduceOffsets(p, subValue);
+}
+
+static void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+ if (p->pos == kMaxValForNormalize)
+ MatchFinder_Normalize(p);
+ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
+ MatchFinder_CheckAndMoveAndRead(p);
+ if (p->cyclicBufferPos == p->cyclicBufferSize)
+ p->cyclicBufferPos = 0;
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ son[_cyclicBufferPos] = curMatch;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ return distances;
+ {
+ const Byte *pb = cur - delta;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+ {
+ UInt32 len = 0;
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ return distances;
+ }
+ }
+ }
+ }
+}
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return distances;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return distances;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ {
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+#define MOVE_POS \
+ ++p->cyclicBufferPos; \
+ p->buffer++; \
+ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+
+#define MOVE_POS_RET MOVE_POS return offset;
+
+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+ cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
+#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define GET_MATCHES_FOOTER(offset, maxLen) \
+ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
+ distances + offset, maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 2)
+}
+
+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, delta2, maxLen, offset;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC;
+
+ delta2 = p->pos - p->hash[hash2Value];
+ curMatch = p->hash[kFix3HashSize + hashValue];
+
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+
+
+ maxLen = 2;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[0] = maxLen;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances + offset, maxLen) - (distances));
+ MOVE_POS_RET
+}
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances, 2) - (distances));
+ MOVE_POS_RET
+}
+
+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value;
+ SKIP_HEADER(3)
+ HASH3_CALC;
+ curMatch = p->hash[kFix3HashSize + hashValue];
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] = p->pos;
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 2)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 3)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+}
diff --git a/src/libs/7zip/unix/C/LzFind.h b/src/libs/7zip/unix/C/LzFind.h
new file mode 100644
index 000000000..010c4b92b
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzFind.h
@@ -0,0 +1,115 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2009-04-22 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_H
+#define __LZ_FIND_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+ Byte *buffer;
+ UInt32 pos;
+ UInt32 posLimit;
+ UInt32 streamPos;
+ UInt32 lenLimit;
+
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufferBase;
+ ISeqInStream *stream;
+ int streamEndWasReached;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ int directInput;
+ size_t directInputRem;
+ int btMode;
+ int bigHash;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ UInt32 hashSizeSum;
+ UInt32 numSons;
+ SRes result;
+ UInt32 crc[256];
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+ historySize <= 3 GB
+ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *distances, UInt32 maxLen);
+
+/*
+Conditions:
+ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+ Mf_Init_Func Init;
+ Mf_GetIndexByte_Func GetIndexByte;
+ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+ Mf_GetMatches_Func GetMatches;
+ Mf_Skip_Func Skip;
+} IMatchFinder;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+
+void MatchFinder_Init(CMatchFinder *p);
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/LzFindMt.c b/src/libs/7zip/unix/C/LzFindMt.c
new file mode 100644
index 000000000..aa41ed98a
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzFindMt.c
@@ -0,0 +1,793 @@
+/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
+2009-09-20 : Igor Pavlov : Public domain */
+
+#include "LzHash.h"
+
+#include "LzFindMt.h"
+
+void MtSync_Construct(CMtSync *p)
+{
+ p->wasCreated = False;
+ p->csWasInitialized = False;
+ p->csWasEntered = False;
+ Thread_Construct(&p->thread);
+ Event_Construct(&p->canStart);
+ Event_Construct(&p->wasStarted);
+ Event_Construct(&p->wasStopped);
+ Semaphore_Construct(&p->freeSemaphore);
+ Semaphore_Construct(&p->filledSemaphore);
+}
+
+void MtSync_GetNextBlock(CMtSync *p)
+{
+ if (p->needStart)
+ {
+ p->numProcessedBlocks = 1;
+ p->needStart = False;
+ p->stopWriting = False;
+ p->exit = False;
+ Event_Reset(&p->wasStarted);
+ Event_Reset(&p->wasStopped);
+
+ Event_Set(&p->canStart);
+ Event_Wait(&p->wasStarted);
+ }
+ else
+ {
+ CriticalSection_Leave(&p->cs);
+ p->csWasEntered = False;
+ p->numProcessedBlocks++;
+ Semaphore_Release1(&p->freeSemaphore);
+ }
+ Semaphore_Wait(&p->filledSemaphore);
+ CriticalSection_Enter(&p->cs);
+ p->csWasEntered = True;
+}
+
+/* MtSync_StopWriting must be called if Writing was started */
+
+void MtSync_StopWriting(CMtSync *p)
+{
+ UInt32 myNumBlocks = p->numProcessedBlocks;
+ if (!Thread_WasCreated(&p->thread) || p->needStart)
+ return;
+ p->stopWriting = True;
+ if (p->csWasEntered)
+ {
+ CriticalSection_Leave(&p->cs);
+ p->csWasEntered = False;
+ }
+ Semaphore_Release1(&p->freeSemaphore);
+
+ Event_Wait(&p->wasStopped);
+
+ while (myNumBlocks++ != p->numProcessedBlocks)
+ {
+ Semaphore_Wait(&p->filledSemaphore);
+ Semaphore_Release1(&p->freeSemaphore);
+ }
+ p->needStart = True;
+}
+
+void MtSync_Destruct(CMtSync *p)
+{
+ if (Thread_WasCreated(&p->thread))
+ {
+ MtSync_StopWriting(p);
+ p->exit = True;
+ if (p->needStart)
+ Event_Set(&p->canStart);
+ Thread_Wait(&p->thread);
+ Thread_Close(&p->thread);
+ }
+ if (p->csWasInitialized)
+ {
+ CriticalSection_Delete(&p->cs);
+ p->csWasInitialized = False;
+ }
+
+ Event_Close(&p->canStart);
+ Event_Close(&p->wasStarted);
+ Event_Close(&p->wasStopped);
+ Semaphore_Close(&p->freeSemaphore);
+ Semaphore_Close(&p->filledSemaphore);
+
+ p->wasCreated = False;
+}
+
+#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
+
+static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+ if (p->wasCreated)
+ return SZ_OK;
+
+ RINOK_THREAD(CriticalSection_Init(&p->cs));
+ p->csWasInitialized = True;
+
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
+
+ RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
+ RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
+
+ p->needStart = True;
+
+ RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj));
+ p->wasCreated = True;
+ return SZ_OK;
+}
+
+static SRes MtSync_Create(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+ SRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
+ if (res != SZ_OK)
+ MtSync_Destruct(p);
+ return res;
+}
+
+void MtSync_Init(CMtSync *p) { p->needStart = True; }
+
+#define kMtMaxValForNormalize 0xFFFFFFFF
+
+#define DEF_GetHeads2(name, v, action) \
+static void GetHeads ## name(const Byte *p, UInt32 pos, \
+UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
+{ action; for (; numHeads != 0; numHeads--) { \
+const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
+
+#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
+
+DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; )
+DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
+DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask)
+DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
+/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */
+
+void HashThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->hashSync;
+ for (;;)
+ {
+ UInt32 numProcessedBlocks = 0;
+ Event_Wait(&p->canStart);
+ Event_Set(&p->wasStarted);
+ for (;;)
+ {
+ if (p->exit)
+ return;
+ if (p->stopWriting)
+ {
+ p->numProcessedBlocks = numProcessedBlocks;
+ Event_Set(&p->wasStopped);
+ break;
+ }
+
+ {
+ CMatchFinder *mf = mt->MatchFinder;
+ if (MatchFinder_NeedMove(mf))
+ {
+ CriticalSection_Enter(&mt->btSync.cs);
+ CriticalSection_Enter(&mt->hashSync.cs);
+ {
+ const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf);
+ const Byte *afterPtr;
+ MatchFinder_MoveBlock(mf);
+ afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
+ mt->pointerToCurPos -= beforePtr - afterPtr;
+ mt->buffer -= beforePtr - afterPtr;
+ }
+ CriticalSection_Leave(&mt->btSync.cs);
+ CriticalSection_Leave(&mt->hashSync.cs);
+ continue;
+ }
+
+ Semaphore_Wait(&p->freeSemaphore);
+
+ MatchFinder_ReadIfRequired(mf);
+ if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
+ {
+ UInt32 subValue = (mf->pos - mf->historySize - 1);
+ MatchFinder_ReduceOffsets(mf, subValue);
+ MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1);
+ }
+ {
+ UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+ UInt32 num = mf->streamPos - mf->pos;
+ heads[0] = 2;
+ heads[1] = num;
+ if (num >= mf->numHashBytes)
+ {
+ num = num - mf->numHashBytes + 1;
+ if (num > kMtHashBlockSize - 2)
+ num = kMtHashBlockSize - 2;
+ mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc);
+ heads[0] += num;
+ }
+ mf->pos += num;
+ mf->buffer += num;
+ }
+ }
+
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+ }
+}
+
+void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
+{
+ MtSync_GetNextBlock(&p->hashSync);
+ p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+ p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
+ p->hashNumAvail = p->hashBuf[p->hashBufPos++];
+}
+
+#define kEmptyHashValue 0
+
+/* #define MFMT_GM_INLINE */
+
+#ifdef MFMT_GM_INLINE
+
+#define NO_INLINE MY_FAST_CALL
+
+Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
+{
+ do
+ {
+ UInt32 *distances = _distances + 1;
+ UInt32 curMatch = pos - *hash++;
+
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ UInt32 cutValue = _cutValue;
+ UInt32 maxLen = _maxLen;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ break;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ break;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+ pos++;
+ _cyclicBufferPos++;
+ cur++;
+ {
+ UInt32 num = (UInt32)(distances - _distances);
+ *_distances = num - 1;
+ _distances += num;
+ limit -= num;
+ }
+ }
+ while (limit > 0 && --size != 0);
+ *posRes = pos;
+ return limit;
+}
+
+#endif
+
+void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ UInt32 numProcessed = 0;
+ UInt32 curPos = 2;
+ UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
+ distances[1] = p->hashNumAvail;
+ while (curPos < limit)
+ {
+ if (p->hashBufPos == p->hashBufPosLimit)
+ {
+ MatchFinderMt_GetNextBlock_Hash(p);
+ distances[1] = numProcessed + p->hashNumAvail;
+ if (p->hashNumAvail >= p->numHashBytes)
+ continue;
+ for (; p->hashNumAvail != 0; p->hashNumAvail--)
+ distances[curPos++] = 0;
+ break;
+ }
+ {
+ UInt32 size = p->hashBufPosLimit - p->hashBufPos;
+ UInt32 lenLimit = p->matchMaxLen;
+ UInt32 pos = p->pos;
+ UInt32 cyclicBufferPos = p->cyclicBufferPos;
+ if (lenLimit >= p->hashNumAvail)
+ lenLimit = p->hashNumAvail;
+ {
+ UInt32 size2 = p->hashNumAvail - lenLimit + 1;
+ if (size2 < size)
+ size = size2;
+ size2 = p->cyclicBufferSize - cyclicBufferPos;
+ if (size2 < size)
+ size = size2;
+ }
+ #ifndef MFMT_GM_INLINE
+ while (curPos < limit && size-- != 0)
+ {
+ UInt32 *startDistances = distances + curPos;
+ UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
+ pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ startDistances + 1, p->numHashBytes - 1) - startDistances);
+ *startDistances = num - 1;
+ curPos += num;
+ cyclicBufferPos++;
+ pos++;
+ p->buffer++;
+ }
+ #else
+ {
+ UInt32 posRes;
+ curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
+ p->hashBufPos += posRes - pos;
+ cyclicBufferPos += posRes - pos;
+ p->buffer += posRes - pos;
+ pos = posRes;
+ }
+ #endif
+
+ numProcessed += pos - p->pos;
+ p->hashNumAvail -= pos - p->pos;
+ p->pos = pos;
+ if (cyclicBufferPos == p->cyclicBufferSize)
+ cyclicBufferPos = 0;
+ p->cyclicBufferPos = cyclicBufferPos;
+ }
+ }
+ distances[0] = curPos;
+}
+
+void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
+{
+ CMtSync *sync = &p->hashSync;
+ if (!sync->needStart)
+ {
+ CriticalSection_Enter(&sync->cs);
+ sync->csWasEntered = True;
+ }
+
+ BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
+
+ if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
+ {
+ UInt32 subValue = p->pos - p->cyclicBufferSize;
+ MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2);
+ p->pos -= subValue;
+ }
+
+ if (!sync->needStart)
+ {
+ CriticalSection_Leave(&sync->cs);
+ sync->csWasEntered = False;
+ }
+}
+
+void BtThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->btSync;
+ for (;;)
+ {
+ UInt32 blockIndex = 0;
+ Event_Wait(&p->canStart);
+ Event_Set(&p->wasStarted);
+ for (;;)
+ {
+ if (p->exit)
+ return;
+ if (p->stopWriting)
+ {
+ p->numProcessedBlocks = blockIndex;
+ MtSync_StopWriting(&mt->hashSync);
+ Event_Set(&p->wasStopped);
+ break;
+ }
+ Semaphore_Wait(&p->freeSemaphore);
+ BtFillBlock(mt, blockIndex++);
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+ }
+}
+
+void MatchFinderMt_Construct(CMatchFinderMt *p)
+{
+ p->hashBuf = 0;
+ MtSync_Construct(&p->hashSync);
+ MtSync_Construct(&p->btSync);
+}
+
+void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hashBuf);
+ p->hashBuf = 0;
+}
+
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+ MtSync_Destruct(&p->hashSync);
+ MtSync_Destruct(&p->btSync);
+ MatchFinderMt_FreeMem(p, alloc);
+}
+
+#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
+#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
+
+static unsigned MY_STD_CALL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
+static unsigned MY_STD_CALL BtThreadFunc2(void *p)
+{
+ Byte allocaDummy[0x180];
+ int i = 0;
+ for (i = 0; i < 16; i++)
+ allocaDummy[i] = (Byte)i;
+ BtThreadFunc((CMatchFinderMt *)p);
+ return 0;
+}
+
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
+{
+ CMatchFinder *mf = p->MatchFinder;
+ p->historySize = historySize;
+ if (kMtBtBlockSize <= matchMaxLen * 4)
+ return SZ_ERROR_PARAM;
+ if (p->hashBuf == 0)
+ {
+ p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
+ if (p->hashBuf == 0)
+ return SZ_ERROR_MEM;
+ p->btBuf = p->hashBuf + kHashBufferSize;
+ }
+ keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
+ keepAddBufferAfter += kMtHashBlockSize;
+ if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
+ return SZ_ERROR_MEM;
+
+ RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
+ RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
+ return SZ_OK;
+}
+
+/* Call it after ReleaseStream / SetStream */
+void MatchFinderMt_Init(CMatchFinderMt *p)
+{
+ CMatchFinder *mf = p->MatchFinder;
+ p->btBufPos = p->btBufPosLimit = 0;
+ p->hashBufPos = p->hashBufPosLimit = 0;
+ MatchFinder_Init(mf);
+ p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf);
+ p->btNumAvailBytes = 0;
+ p->lzPos = p->historySize + 1;
+
+ p->hash = mf->hash;
+ p->fixedHashSize = mf->fixedHashSize;
+ p->crc = mf->crc;
+
+ p->son = mf->son;
+ p->matchMaxLen = mf->matchMaxLen;
+ p->numHashBytes = mf->numHashBytes;
+ p->pos = mf->pos;
+ p->buffer = mf->buffer;
+ p->cyclicBufferPos = mf->cyclicBufferPos;
+ p->cyclicBufferSize = mf->cyclicBufferSize;
+ p->cutValue = mf->cutValue;
+}
+
+/* ReleaseStream is required to finish multithreading */
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
+{
+ MtSync_StopWriting(&p->btSync);
+ /* p->MatchFinder->ReleaseStream(); */
+}
+
+void MatchFinderMt_Normalize(CMatchFinderMt *p)
+{
+ MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
+ p->lzPos = p->historySize + 1;
+}
+
+void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
+{
+ UInt32 blockIndex;
+ MtSync_GetNextBlock(&p->btSync);
+ blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
+ p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
+ p->btBufPosLimit += p->btBuf[p->btBufPos++];
+ p->btNumAvailBytes = p->btBuf[p->btBufPos++];
+ if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize)
+ MatchFinderMt_Normalize(p);
+}
+
+const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+{
+ return p->pointerToCurPos;
+}
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+{
+ GET_NEXT_BLOCK_IF_REQUIRED;
+ return p->btNumAvailBytes;
+}
+
+Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
+{
+ return p->pointerToCurPos[index];
+}
+
+UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, curMatch2;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH2_CALC
+
+ curMatch2 = hash[hash2Value];
+ hash[hash2Value] = lzPos;
+
+ if (curMatch2 >= matchMinPos)
+ if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ *distances++ = 2;
+ *distances++ = lzPos - curMatch2 - 1;
+ }
+ return distances;
+}
+
+UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH3_CALC
+
+ curMatch2 = hash[ hash2Value];
+ curMatch3 = hash[kFix3HashSize + hash3Value];
+
+ hash[ hash2Value] =
+ hash[kFix3HashSize + hash3Value] =
+ lzPos;
+
+ if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch2 - 1;
+ if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+ {
+ distances[0] = 3;
+ return distances + 2;
+ }
+ distances[0] = 2;
+ distances += 2;
+ }
+ if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+ {
+ *distances++ = 3;
+ *distances++ = lzPos - curMatch3 - 1;
+ }
+ return distances;
+}
+
+/*
+UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH4_CALC
+
+ curMatch2 = hash[ hash2Value];
+ curMatch3 = hash[kFix3HashSize + hash3Value];
+ curMatch4 = hash[kFix4HashSize + hash4Value];
+
+ hash[ hash2Value] =
+ hash[kFix3HashSize + hash3Value] =
+ hash[kFix4HashSize + hash4Value] =
+ lzPos;
+
+ if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch2 - 1;
+ if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+ {
+ distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
+ return distances + 2;
+ }
+ distances[0] = 2;
+ distances += 2;
+ }
+ if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch3 - 1;
+ if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
+ {
+ distances[0] = 4;
+ return distances + 2;
+ }
+ distances[0] = 3;
+ distances += 2;
+ }
+
+ if (curMatch4 >= matchMinPos)
+ if (
+ cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
+ cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
+ )
+ {
+ *distances++ = 4;
+ *distances++ = lzPos - curMatch4 - 1;
+ }
+ return distances;
+}
+*/
+
+#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
+
+UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ const UInt32 *btBuf = p->btBuf + p->btBufPos;
+ UInt32 len = *btBuf++;
+ p->btBufPos += 1 + len;
+ p->btNumAvailBytes--;
+ {
+ UInt32 i;
+ for (i = 0; i < len; i += 2)
+ {
+ *distances++ = *btBuf++;
+ *distances++ = *btBuf++;
+ }
+ }
+ INCREASE_LZ_POS
+ return len;
+}
+
+UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ const UInt32 *btBuf = p->btBuf + p->btBufPos;
+ UInt32 len = *btBuf++;
+ p->btBufPos += 1 + len;
+
+ if (len == 0)
+ {
+ if (p->btNumAvailBytes-- >= 4)
+ len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
+ }
+ else
+ {
+ /* Condition: there are matches in btBuf with length < p->numHashBytes */
+ UInt32 *distances2;
+ p->btNumAvailBytes--;
+ distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
+ do
+ {
+ *distances2++ = *btBuf++;
+ *distances2++ = *btBuf++;
+ }
+ while ((len -= 2) != 0);
+ len = (UInt32)(distances2 - (distances));
+ }
+ INCREASE_LZ_POS
+ return len;
+}
+
+#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
+#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
+#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0);
+
+void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER2_MT { p->btNumAvailBytes--;
+ SKIP_FOOTER_MT
+}
+
+void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(2)
+ UInt32 hash2Value;
+ MT_HASH2_CALC
+ hash[hash2Value] = p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(3)
+ UInt32 hash2Value, hash3Value;
+ MT_HASH3_CALC
+ hash[kFix3HashSize + hash3Value] =
+ hash[ hash2Value] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+/*
+void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(4)
+ UInt32 hash2Value, hash3Value, hash4Value;
+ MT_HASH4_CALC
+ hash[kFix4HashSize + hash4Value] =
+ hash[kFix3HashSize + hash3Value] =
+ hash[ hash2Value] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+*/
+
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
+ switch(p->MatchFinder->numHashBytes)
+ {
+ case 2:
+ p->GetHeadsFunc = GetHeads2;
+ p->MixMatchesFunc = (Mf_Mix_Matches)0;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
+ break;
+ case 3:
+ p->GetHeadsFunc = GetHeads3;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
+ break;
+ default:
+ /* case 4: */
+ p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
+ /* p->GetHeadsFunc = GetHeads4; */
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
+ break;
+ /*
+ default:
+ p->GetHeadsFunc = GetHeads5;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;
+ break;
+ */
+ }
+}
diff --git a/src/libs/7zip/unix/C/LzFindMt.h b/src/libs/7zip/unix/C/LzFindMt.h
new file mode 100644
index 000000000..b985af5fe
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzFindMt.h
@@ -0,0 +1,105 @@
+/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_MT_H
+#define __LZ_FIND_MT_H
+
+#include "LzFind.h"
+#include "Threads.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define kMtHashBlockSize (1 << 13)
+#define kMtHashNumBlocks (1 << 3)
+#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1)
+
+#define kMtBtBlockSize (1 << 14)
+#define kMtBtNumBlocks (1 << 6)
+#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1)
+
+typedef struct _CMtSync
+{
+ Bool wasCreated;
+ Bool needStart;
+ Bool exit;
+ Bool stopWriting;
+
+ CThread thread;
+ CAutoResetEvent canStart;
+ CAutoResetEvent wasStarted;
+ CAutoResetEvent wasStopped;
+ CSemaphore freeSemaphore;
+ CSemaphore filledSemaphore;
+ Bool csWasInitialized;
+ Bool csWasEntered;
+ CCriticalSection cs;
+ UInt32 numProcessedBlocks;
+} CMtSync;
+
+typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
+
+/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
+#define kMtCacheLineDummy 128
+
+typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
+ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc);
+
+typedef struct _CMatchFinderMt
+{
+ /* LZ */
+ const Byte *pointerToCurPos;
+ UInt32 *btBuf;
+ UInt32 btBufPos;
+ UInt32 btBufPosLimit;
+ UInt32 lzPos;
+ UInt32 btNumAvailBytes;
+
+ UInt32 *hash;
+ UInt32 fixedHashSize;
+ UInt32 historySize;
+ const UInt32 *crc;
+
+ Mf_Mix_Matches MixMatchesFunc;
+
+ /* LZ + BT */
+ CMtSync btSync;
+ Byte btDummy[kMtCacheLineDummy];
+
+ /* BT */
+ UInt32 *hashBuf;
+ UInt32 hashBufPos;
+ UInt32 hashBufPosLimit;
+ UInt32 hashNumAvail;
+
+ CLzRef *son;
+ UInt32 matchMaxLen;
+ UInt32 numHashBytes;
+ UInt32 pos;
+ Byte *buffer;
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be historySize + 1 */
+ UInt32 cutValue;
+
+ /* BT + Hash */
+ CMtSync hashSync;
+ /* Byte hashDummy[kMtCacheLineDummy]; */
+
+ /* Hash */
+ Mf_GetHeads GetHeadsFunc;
+ CMatchFinder *MatchFinder;
+} CMatchFinderMt;
+
+void MatchFinderMt_Construct(CMatchFinderMt *p);
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc);
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc);
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable);
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/LzHash.h b/src/libs/7zip/unix/C/LzHash.h
new file mode 100644
index 000000000..f3e89966c
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzHash.h
@@ -0,0 +1,54 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_HASH_H
+#define __LZ_HASH_H
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+#define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
+ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
+ hash4Value &= (kHash4Size - 1); }
+
+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/src/libs/7zip/unix/C/Lzma2Dec.c b/src/libs/7zip/unix/C/Lzma2Dec.c
new file mode 100644
index 000000000..7ea1cc953
--- /dev/null
+++ b/src/libs/7zip/unix/C/Lzma2Dec.c
@@ -0,0 +1,356 @@
+/* Lzma2Dec.c -- LZMA2 Decoder
+2009-05-03 : Igor Pavlov : Public domain */
+
+/* #define SHOW_DEBUG_INFO */
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include <string.h>
+
+#include "Lzma2Dec.h"
+
+/*
+00000000 - EOS
+00000001 U U - Uncompressed Reset Dic
+00000010 U U - Uncompressed No Reset
+100uuuuu U U P P - LZMA no reset
+101uuuuu U U P P - LZMA reset state
+110uuuuu U U P P S - LZMA reset state + new prop
+111uuuuu U U P P S - LZMA reset state + new prop + reset dic
+
+ u, U - Unpack Size
+ P - Pack Size
+ S - Props
+*/
+
+#define LZMA2_CONTROL_LZMA (1 << 7)
+#define LZMA2_CONTROL_COPY_NO_RESET 2
+#define LZMA2_CONTROL_COPY_RESET_DIC 1
+#define LZMA2_CONTROL_EOF 0
+
+#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0)
+
+#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3)
+#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2)
+
+#define LZMA2_LCLP_MAX 4
+#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+typedef enum
+{
+ LZMA2_STATE_CONTROL,
+ LZMA2_STATE_UNPACK0,
+ LZMA2_STATE_UNPACK1,
+ LZMA2_STATE_PACK0,
+ LZMA2_STATE_PACK1,
+ LZMA2_STATE_PROP,
+ LZMA2_STATE_DATA,
+ LZMA2_STATE_DATA_CONT,
+ LZMA2_STATE_FINISHED,
+ LZMA2_STATE_ERROR
+} ELzma2State;
+
+static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
+{
+ UInt32 dicSize;
+ if (prop > 40)
+ return SZ_ERROR_UNSUPPORTED;
+ dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
+ props[0] = (Byte)LZMA2_LCLP_MAX;
+ props[1] = (Byte)(dicSize);
+ props[2] = (Byte)(dicSize >> 8);
+ props[3] = (Byte)(dicSize >> 16);
+ props[4] = (Byte)(dicSize >> 24);
+ return SZ_OK;
+}
+
+SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ RINOK(Lzma2Dec_GetOldProps(prop, props));
+ return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
+}
+
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ RINOK(Lzma2Dec_GetOldProps(prop, props));
+ return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
+}
+
+void Lzma2Dec_Init(CLzma2Dec *p)
+{
+ p->state = LZMA2_STATE_CONTROL;
+ p->needInitDic = True;
+ p->needInitState = True;
+ p->needInitProp = True;
+ LzmaDec_Init(&p->decoder);
+}
+
+static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
+{
+ switch(p->state)
+ {
+ case LZMA2_STATE_CONTROL:
+ p->control = b;
+ PRF(printf("\n %4X ", p->decoder.dicPos));
+ PRF(printf(" %2X", b));
+ if (p->control == 0)
+ return LZMA2_STATE_FINISHED;
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if ((p->control & 0x7F) > 2)
+ return LZMA2_STATE_ERROR;
+ p->unpackSize = 0;
+ }
+ else
+ p->unpackSize = (UInt32)(p->control & 0x1F) << 16;
+ return LZMA2_STATE_UNPACK0;
+
+ case LZMA2_STATE_UNPACK0:
+ p->unpackSize |= (UInt32)b << 8;
+ return LZMA2_STATE_UNPACK1;
+
+ case LZMA2_STATE_UNPACK1:
+ p->unpackSize |= (UInt32)b;
+ p->unpackSize++;
+ PRF(printf(" %8d", p->unpackSize));
+ return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
+
+ case LZMA2_STATE_PACK0:
+ p->packSize = (UInt32)b << 8;
+ return LZMA2_STATE_PACK1;
+
+ case LZMA2_STATE_PACK1:
+ p->packSize |= (UInt32)b;
+ p->packSize++;
+ PRF(printf(" %8d", p->packSize));
+ return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP:
+ (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA);
+
+ case LZMA2_STATE_PROP:
+ {
+ int lc, lp;
+ if (b >= (9 * 5 * 5))
+ return LZMA2_STATE_ERROR;
+ lc = b % 9;
+ b /= 9;
+ p->decoder.prop.pb = b / 5;
+ lp = b % 5;
+ if (lc + lp > LZMA2_LCLP_MAX)
+ return LZMA2_STATE_ERROR;
+ p->decoder.prop.lc = lc;
+ p->decoder.prop.lp = lp;
+ p->needInitProp = False;
+ return LZMA2_STATE_DATA;
+ }
+ }
+ return LZMA2_STATE_ERROR;
+}
+
+static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
+{
+ memcpy(p->dic + p->dicPos, src, size);
+ p->dicPos += size;
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
+ p->checkDicSize = p->prop.dicSize;
+ p->processedPos += (UInt32)size;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState);
+
+SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->state != LZMA2_STATE_FINISHED)
+ {
+ SizeT dicPos = p->decoder.dicPos;
+ if (p->state == LZMA2_STATE_ERROR)
+ return SZ_ERROR_DATA;
+ if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
+ {
+ if (*srcLen == inSize)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ (*srcLen)++;
+ p->state = Lzma2Dec_UpdateState(p, *src++);
+ continue;
+ }
+ {
+ SizeT destSizeCur = dicLimit - dicPos;
+ SizeT srcSizeCur = inSize - *srcLen;
+ ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
+
+ if (p->unpackSize <= destSizeCur)
+ {
+ destSizeCur = (SizeT)p->unpackSize;
+ curFinishMode = LZMA_FINISH_END;
+ }
+
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if (*srcLen == inSize)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
+ if (initDic)
+ p->needInitProp = p->needInitState = True;
+ else if (p->needInitDic)
+ return SZ_ERROR_DATA;
+ p->needInitDic = False;
+ LzmaDec_InitDicAndState(&p->decoder, initDic, False);
+ }
+
+ if (srcSizeCur > destSizeCur)
+ srcSizeCur = destSizeCur;
+
+ if (srcSizeCur == 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);
+
+ src += srcSizeCur;
+ *srcLen += srcSizeCur;
+ p->unpackSize -= (UInt32)srcSizeCur;
+ p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
+ }
+ else
+ {
+ SizeT outSizeProcessed;
+ SRes res;
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ int mode = LZMA2_GET_LZMA_MODE(p);
+ Bool initDic = (mode == 3);
+ Bool initState = (mode > 0);
+ if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
+ p->needInitDic = False;
+ p->needInitState = False;
+ p->state = LZMA2_STATE_DATA_CONT;
+ }
+ if (srcSizeCur > p->packSize)
+ srcSizeCur = (SizeT)p->packSize;
+
+ res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status);
+
+ src += srcSizeCur;
+ *srcLen += srcSizeCur;
+ p->packSize -= (UInt32)srcSizeCur;
+
+ outSizeProcessed = p->decoder.dicPos - dicPos;
+ p->unpackSize -= (UInt32)outSizeProcessed;
+
+ RINOK(res);
+ if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ return res;
+
+ if (srcSizeCur == 0 && outSizeProcessed == 0)
+ {
+ if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ||
+ p->unpackSize != 0 || p->packSize != 0)
+ return SZ_ERROR_DATA;
+ p->state = LZMA2_STATE_CONTROL;
+ }
+ if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ *status = LZMA_STATUS_NOT_FINISHED;
+ }
+ }
+ }
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+}
+
+SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT srcSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->decoder.dicPos == p->decoder.dicBufSize)
+ p->decoder.dicPos = 0;
+ dicPos = p->decoder.dicPos;
+ if (outSize > p->decoder.dicBufSize - dicPos)
+ {
+ outSizeCur = p->decoder.dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status);
+ src += srcSizeCur;
+ inSize -= srcSizeCur;
+ *srcLen += srcSizeCur;
+ outSizeCur = p->decoder.dicPos - dicPos;
+ memcpy(dest, p->decoder.dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzma2Dec decoder;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ Byte props[LZMA_PROPS_SIZE];
+
+ Lzma2Dec_Construct(&decoder);
+
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ decoder.decoder.dic = dest;
+ decoder.decoder.dicBufSize = outSize;
+
+ RINOK(Lzma2Dec_GetOldProps(prop, props));
+ RINOK(LzmaDec_AllocateProbs(&decoder.decoder, props, LZMA_PROPS_SIZE, alloc));
+
+ *srcLen = inSize;
+ res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status);
+ *destLen = decoder.decoder.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+
+ LzmaDec_FreeProbs(&decoder.decoder, alloc);
+ return res;
+}
diff --git a/src/libs/7zip/unix/C/Lzma2Dec.h b/src/libs/7zip/unix/C/Lzma2Dec.h
new file mode 100644
index 000000000..6bc07bbc1
--- /dev/null
+++ b/src/libs/7zip/unix/C/Lzma2Dec.h
@@ -0,0 +1,84 @@
+/* Lzma2Dec.h -- LZMA2 Decoder
+2009-05-03 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA2_DEC_H
+#define __LZMA2_DEC_H
+
+#include "LzmaDec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ---------- State Interface ---------- */
+
+typedef struct
+{
+ CLzmaDec decoder;
+ UInt32 packSize;
+ UInt32 unpackSize;
+ int state;
+ Byte control;
+ Bool needInitDic;
+ Bool needInitState;
+ Bool needInitProp;
+} CLzma2Dec;
+
+#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder)
+#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc);
+#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc);
+
+SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
+void Lzma2Dec_Init(CLzma2Dec *p);
+
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/Lzma2Enc.c b/src/libs/7zip/unix/C/Lzma2Enc.c
new file mode 100644
index 000000000..e97597f63
--- /dev/null
+++ b/src/libs/7zip/unix/C/Lzma2Enc.c
@@ -0,0 +1,477 @@
+/* Lzma2Enc.c -- LZMA2 Encoder
+2010-09-24 : Igor Pavlov : Public domain */
+
+/* #include <stdio.h> */
+#include <string.h>
+
+/* #define _7ZIP_ST */
+
+#include "Lzma2Enc.h"
+
+#ifndef _7ZIP_ST
+#include "MtCoder.h"
+#else
+#define NUM_MT_CODER_THREADS_MAX 1
+#endif
+
+#define LZMA2_CONTROL_LZMA (1 << 7)
+#define LZMA2_CONTROL_COPY_NO_RESET 2
+#define LZMA2_CONTROL_COPY_RESET_DIC 1
+#define LZMA2_CONTROL_EOF 0
+
+#define LZMA2_LCLP_MAX 4
+
+#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
+
+#define LZMA2_PACK_SIZE_MAX (1 << 16)
+#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX
+#define LZMA2_UNPACK_SIZE_MAX (1 << 21)
+#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX
+
+#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16)
+
+
+#define PRF(x) /* x */
+
+/* ---------- CLzma2EncInt ---------- */
+
+typedef struct
+{
+ CLzmaEncHandle enc;
+ UInt64 srcPos;
+ Byte props;
+ Bool needInitState;
+ Bool needInitProp;
+} CLzma2EncInt;
+
+static SRes Lzma2EncInt_Init(CLzma2EncInt *p, const CLzma2EncProps *props)
+{
+ Byte propsEncoded[LZMA_PROPS_SIZE];
+ SizeT propsSize = LZMA_PROPS_SIZE;
+ RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps));
+ RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize));
+ p->srcPos = 0;
+ p->props = propsEncoded[0];
+ p->needInitState = True;
+ p->needInitProp = True;
+ return SZ_OK;
+}
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize,
+ ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp);
+void LzmaEnc_Finish(CLzmaEncHandle pp);
+void LzmaEnc_SaveState(CLzmaEncHandle pp);
+void LzmaEnc_RestoreState(CLzmaEncHandle pp);
+
+
+static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
+ size_t *packSizeRes, ISeqOutStream *outStream)
+{
+ size_t packSizeLimit = *packSizeRes;
+ size_t packSize = packSizeLimit;
+ UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX;
+ unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0);
+ Bool useCopyBlock;
+ SRes res;
+
+ *packSizeRes = 0;
+ if (packSize < lzHeaderSize)
+ return SZ_ERROR_OUTPUT_EOF;
+ packSize -= lzHeaderSize;
+
+ LzmaEnc_SaveState(p->enc);
+ res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState,
+ outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize);
+
+ PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize));
+
+ if (unpackSize == 0)
+ return res;
+
+ if (res == SZ_OK)
+ useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16));
+ else
+ {
+ if (res != SZ_ERROR_OUTPUT_EOF)
+ return res;
+ res = SZ_OK;
+ useCopyBlock = True;
+ }
+
+ if (useCopyBlock)
+ {
+ size_t destPos = 0;
+ PRF(printf("################# COPY "));
+ while (unpackSize > 0)
+ {
+ UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE;
+ if (packSizeLimit - destPos < u + 3)
+ return SZ_ERROR_OUTPUT_EOF;
+ outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET);
+ outBuf[destPos++] = (Byte)((u - 1) >> 8);
+ outBuf[destPos++] = (Byte)(u - 1);
+ memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u);
+ unpackSize -= u;
+ destPos += u;
+ p->srcPos += u;
+ if (outStream)
+ {
+ *packSizeRes += destPos;
+ if (outStream->Write(outStream, outBuf, destPos) != destPos)
+ return SZ_ERROR_WRITE;
+ destPos = 0;
+ }
+ else
+ *packSizeRes = destPos;
+ /* needInitState = True; */
+ }
+ LzmaEnc_RestoreState(p->enc);
+ return SZ_OK;
+ }
+ {
+ size_t destPos = 0;
+ UInt32 u = unpackSize - 1;
+ UInt32 pm = (UInt32)(packSize - 1);
+ unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0);
+
+ PRF(printf(" "));
+
+ outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F));
+ outBuf[destPos++] = (Byte)(u >> 8);
+ outBuf[destPos++] = (Byte)u;
+ outBuf[destPos++] = (Byte)(pm >> 8);
+ outBuf[destPos++] = (Byte)pm;
+
+ if (p->needInitProp)
+ outBuf[destPos++] = p->props;
+
+ p->needInitProp = False;
+ p->needInitState = False;
+ destPos += packSize;
+ p->srcPos += unpackSize;
+
+ if (outStream)
+ if (outStream->Write(outStream, outBuf, destPos) != destPos)
+ return SZ_ERROR_WRITE;
+ *packSizeRes = destPos;
+ return SZ_OK;
+ }
+}
+
+/* ---------- Lzma2 Props ---------- */
+
+void Lzma2EncProps_Init(CLzma2EncProps *p)
+{
+ LzmaEncProps_Init(&p->lzmaProps);
+ p->numTotalThreads = -1;
+ p->numBlockThreads = -1;
+ p->blockSize = 0;
+}
+
+void Lzma2EncProps_Normalize(CLzma2EncProps *p)
+{
+ int t1, t1n, t2, t3;
+ {
+ CLzmaEncProps lzmaProps = p->lzmaProps;
+ LzmaEncProps_Normalize(&lzmaProps);
+ t1n = lzmaProps.numThreads;
+ }
+
+ t1 = p->lzmaProps.numThreads;
+ t2 = p->numBlockThreads;
+ t3 = p->numTotalThreads;
+
+ if (t2 > NUM_MT_CODER_THREADS_MAX)
+ t2 = NUM_MT_CODER_THREADS_MAX;
+
+ if (t3 <= 0)
+ {
+ if (t2 <= 0)
+ t2 = 1;
+ t3 = t1n * t2;
+ }
+ else if (t2 <= 0)
+ {
+ t2 = t3 / t1n;
+ if (t2 == 0)
+ {
+ t1 = 1;
+ t2 = t3;
+ }
+ if (t2 > NUM_MT_CODER_THREADS_MAX)
+ t2 = NUM_MT_CODER_THREADS_MAX;
+ }
+ else if (t1 <= 0)
+ {
+ t1 = t3 / t2;
+ if (t1 == 0)
+ t1 = 1;
+ }
+ else
+ t3 = t1n * t2;
+
+ p->lzmaProps.numThreads = t1;
+ p->numBlockThreads = t2;
+ p->numTotalThreads = t3;
+ LzmaEncProps_Normalize(&p->lzmaProps);
+
+ if (p->blockSize == 0)
+ {
+ UInt32 dictSize = p->lzmaProps.dictSize;
+ UInt64 blockSize = (UInt64)dictSize << 2;
+ const UInt32 kMinSize = (UInt32)1 << 20;
+ const UInt32 kMaxSize = (UInt32)1 << 28;
+ if (blockSize < kMinSize) blockSize = kMinSize;
+ if (blockSize > kMaxSize) blockSize = kMaxSize;
+ if (blockSize < dictSize) blockSize = dictSize;
+ p->blockSize = (size_t)blockSize;
+ }
+}
+
+static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
+{
+ return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
+}
+
+/* ---------- Lzma2 ---------- */
+
+typedef struct
+{
+ Byte propEncoded;
+ CLzma2EncProps props;
+
+ Byte *outBuf;
+
+ ISzAlloc *alloc;
+ ISzAlloc *allocBig;
+
+ CLzma2EncInt coders[NUM_MT_CODER_THREADS_MAX];
+
+ #ifndef _7ZIP_ST
+ CMtCoder mtCoder;
+ #endif
+
+} CLzma2Enc;
+
+
+/* ---------- Lzma2EncThread ---------- */
+
+static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
+{
+ UInt64 packTotal = 0;
+ SRes res = SZ_OK;
+
+ if (mainEncoder->outBuf == 0)
+ {
+ mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX);
+ if (mainEncoder->outBuf == 0)
+ return SZ_ERROR_MEM;
+ }
+ RINOK(Lzma2EncInt_Init(p, &mainEncoder->props));
+ RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE,
+ mainEncoder->alloc, mainEncoder->allocBig));
+ for (;;)
+ {
+ size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX;
+ res = Lzma2EncInt_EncodeSubblock(p, mainEncoder->outBuf, &packSize, outStream);
+ if (res != SZ_OK)
+ break;
+ packTotal += packSize;
+ res = Progress(progress, p->srcPos, packTotal);
+ if (res != SZ_OK)
+ break;
+ if (packSize == 0)
+ break;
+ }
+ LzmaEnc_Finish(p->enc);
+ if (res == SZ_OK)
+ {
+ Byte b = 0;
+ if (outStream->Write(outStream, &b, 1) != 1)
+ return SZ_ERROR_WRITE;
+ }
+ return res;
+}
+
+#ifndef _7ZIP_ST
+
+typedef struct
+{
+ IMtCoderCallback funcTable;
+ CLzma2Enc *lzma2Enc;
+} CMtCallbackImp;
+
+static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *destSize,
+ const Byte *src, size_t srcSize, int finished)
+{
+ CMtCallbackImp *imp = (CMtCallbackImp *)pp;
+ CLzma2Enc *mainEncoder = imp->lzma2Enc;
+ CLzma2EncInt *p = &mainEncoder->coders[index];
+
+ SRes res = SZ_OK;
+ {
+ size_t destLim = *destSize;
+ *destSize = 0;
+
+ if (srcSize != 0)
+ {
+ RINOK(Lzma2EncInt_Init(p, &mainEncoder->props));
+
+ RINOK(LzmaEnc_MemPrepare(p->enc, src, srcSize, LZMA2_KEEP_WINDOW_SIZE,
+ mainEncoder->alloc, mainEncoder->allocBig));
+
+ while (p->srcPos < srcSize)
+ {
+ size_t packSize = destLim - *destSize;
+ res = Lzma2EncInt_EncodeSubblock(p, dest + *destSize, &packSize, NULL);
+ if (res != SZ_OK)
+ break;
+ *destSize += packSize;
+
+ if (packSize == 0)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+
+ if (MtProgress_Set(&mainEncoder->mtCoder.mtProgress, index, p->srcPos, *destSize) != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ LzmaEnc_Finish(p->enc);
+ if (res != SZ_OK)
+ return res;
+ }
+ if (finished)
+ {
+ if (*destSize == destLim)
+ return SZ_ERROR_OUTPUT_EOF;
+ dest[(*destSize)++] = 0;
+ }
+ }
+ return res;
+}
+
+#endif
+
+/* ---------- Lzma2Enc ---------- */
+
+CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc));
+ if (p == 0)
+ return NULL;
+ Lzma2EncProps_Init(&p->props);
+ Lzma2EncProps_Normalize(&p->props);
+ p->outBuf = 0;
+ p->alloc = alloc;
+ p->allocBig = allocBig;
+ {
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ p->coders[i].enc = 0;
+ }
+ #ifndef _7ZIP_ST
+ MtCoder_Construct(&p->mtCoder);
+ #endif
+
+ return p;
+}
+
+void Lzma2Enc_Destroy(CLzma2EncHandle pp)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ {
+ CLzma2EncInt *t = &p->coders[i];
+ if (t->enc)
+ {
+ LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig);
+ t->enc = 0;
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ MtCoder_Destruct(&p->mtCoder);
+ #endif
+
+ IAlloc_Free(p->alloc, p->outBuf);
+ IAlloc_Free(p->alloc, pp);
+}
+
+SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ CLzmaEncProps lzmaProps = props->lzmaProps;
+ LzmaEncProps_Normalize(&lzmaProps);
+ if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX)
+ return SZ_ERROR_PARAM;
+ p->props = *props;
+ Lzma2EncProps_Normalize(&p->props);
+ return SZ_OK;
+}
+
+Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ unsigned i;
+ UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps);
+ for (i = 0; i < 40; i++)
+ if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i))
+ break;
+ return (Byte)i;
+}
+
+SRes Lzma2Enc_Encode(CLzma2EncHandle pp,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ int i;
+
+ for (i = 0; i < p->props.numBlockThreads; i++)
+ {
+ CLzma2EncInt *t = &p->coders[i];
+ if (t->enc == NULL)
+ {
+ t->enc = LzmaEnc_Create(p->alloc);
+ if (t->enc == NULL)
+ return SZ_ERROR_MEM;
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ if (p->props.numBlockThreads <= 1)
+ #endif
+ return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress);
+
+ #ifndef _7ZIP_ST
+
+ {
+ CMtCallbackImp mtCallback;
+
+ mtCallback.funcTable.Code = MtCallbackImp_Code;
+ mtCallback.lzma2Enc = p;
+
+ p->mtCoder.progress = progress;
+ p->mtCoder.inStream = inStream;
+ p->mtCoder.outStream = outStream;
+ p->mtCoder.alloc = p->alloc;
+ p->mtCoder.mtCallback = &mtCallback.funcTable;
+
+ p->mtCoder.blockSize = p->props.blockSize;
+ p->mtCoder.destBlockSize = p->props.blockSize + (p->props.blockSize >> 10) + 16;
+ p->mtCoder.numThreads = p->props.numBlockThreads;
+
+ return MtCoder_Code(&p->mtCoder);
+ }
+ #endif
+}
diff --git a/src/libs/7zip/unix/C/Lzma2Enc.h b/src/libs/7zip/unix/C/Lzma2Enc.h
new file mode 100644
index 000000000..283525581
--- /dev/null
+++ b/src/libs/7zip/unix/C/Lzma2Enc.h
@@ -0,0 +1,66 @@
+/* Lzma2Enc.h -- LZMA2 Encoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA2_ENC_H
+#define __LZMA2_ENC_H
+
+#include "LzmaEnc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+ CLzmaEncProps lzmaProps;
+ size_t blockSize;
+ int numBlockThreads;
+ int numTotalThreads;
+} CLzma2EncProps;
+
+void Lzma2EncProps_Init(CLzma2EncProps *p);
+void Lzma2EncProps_Normalize(CLzma2EncProps *p);
+
+/* ---------- CLzmaEnc2Handle Interface ---------- */
+
+/* Lzma2Enc_* functions can return the following exit codes:
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - Write callback error
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzma2EncHandle;
+
+CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig);
+void Lzma2Enc_Destroy(CLzma2EncHandle p);
+SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props);
+Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p);
+SRes Lzma2Enc_Encode(CLzma2EncHandle p,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress);
+
+/* ---------- One Call Interface ---------- */
+
+/* Lzma2Encode
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+/*
+SRes Lzma2Encode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/LzmaDec.c b/src/libs/7zip/unix/C/LzmaDec.c
new file mode 100644
index 000000000..2036761bf
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzmaDec.c
@@ -0,0 +1,999 @@
+/* LzmaDec.c -- LZMA Decoder
+2009-09-20 : Igor Pavlov : Public domain */
+
+#include "LzmaDec.h"
+
+#include <string.h>
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_INIT_SIZE 5
+
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p); i = (i + i); A0; } else \
+ { UPDATE_1(p); i = (i + i) + 1; A1; }
+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
+
+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ i -= 0x40; }
+#endif
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/* First LZMA-symbol is always decoded.
+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
+Out:
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : Flush marker
+ = kMatchSpecLenStart + 2 : State Init Marker
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = p->probs;
+
+ unsigned state = p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
+ unsigned lc = p->prop.lc;
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = processedPos & pbMask;
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (checkDicSize != 0 || processedPos != 0)
+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+
+ if (state < kNumLitStates)
+ {
+ state -= (state < 4) ? state : 3;
+ symbol = 1;
+ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ state -= (state < 10) ? 3 : 6;
+ symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ dic[dicPos++] = (Byte)symbol;
+ processedPos++;
+ continue;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob);
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob);
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = (1 << kLenNumMidBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance);
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ int numDirectBits = (int)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos + distance - posSlot - 1;
+ {
+ UInt32 mask = 1;
+ unsigned i = 1;
+ do
+ {
+ GET_BIT2(prob + i, i, ; , distance |= mask);
+ mask <<= 1;
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ GET_BIT2(prob + i, i, ; , distance |= 1);
+ GET_BIT2(prob + i, i, ; , distance |= 2);
+ GET_BIT2(prob + i, i, ; , distance |= 4);
+ GET_BIT2(prob + i, i, ; , distance |= 8);
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len += kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ if (checkDicSize == 0)
+ {
+ if (distance >= processedPos)
+ return SZ_ERROR_DATA;
+ }
+ else if (distance >= checkDicSize)
+ return SZ_ERROR_DATA;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ }
+
+ len += kMatchMinLen;
+
+ if (limit == dicPos)
+ return SZ_ERROR_DATA;
+ {
+ SizeT rem = limit - dicPos;
+ unsigned curLen = ((rem < len) ? (unsigned)rem : len);
+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (pos + curLen <= dicBufSize)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += curLen;
+ do
+ *(dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+ NORMALIZE;
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = len;
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = state;
+
+ return SZ_OK;
+}
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
+ {
+ Byte *dic = p->dic;
+ SizeT dicPos = p->dicPos;
+ SizeT dicBufSize = p->dicBufSize;
+ unsigned len = p->remainLen;
+ UInt32 rep0 = p->reps[0];
+ if (limit - dicPos < len)
+ len = (unsigned)(limit - dicPos);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len-- != 0)
+ {
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ do
+ {
+ SizeT limit2 = limit;
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit2 = p->dicPos + rem;
+ }
+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
+ if (p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ p->remainLen = kMatchSpecLenStart;
+ }
+ return 0;
+}
+
+typedef enum
+{
+ DUMMY_ERROR, /* unexpected end of input stream */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = buf + inSize;
+ CLzmaProb *probs = p->probs;
+ unsigned state = p->state;
+ ELzmaDummy res;
+
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += (LZMA_LIT_SIZE *
+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK;
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ NORMALIZE_CHECK;
+ return DUMMY_REP;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumMidBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ do
+ {
+ GET_BIT_CHECK(prob + i, i);
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+
+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
+{
+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->needFlush = 1;
+ p->remainLen = 0;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->needInitState = 1;
+ }
+ if (initState)
+ p->needInitState = 1;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+static void LzmaDec_InitStateReal(CLzmaDec *p)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
+ UInt32 i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ p->needInitState = 0;
+}
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ LzmaDec_WriteRem(p, dicLimit);
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int checkEndMarkNow;
+
+ if (p->needFlush != 0)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitRc(p, p->tempBuf);
+ p->tempBufSize = 0;
+ }
+
+ checkEndMarkNow = 0;
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ checkEndMarkNow = 1;
+ }
+
+ if (p->needInitState)
+ LzmaDec_InitStateReal(p);
+
+ if (p->tempBufSize == 0)
+ {
+ SizeT processed;
+ const Byte *bufLimit;
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, src, inSize);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ memcpy(p->tempBuf, src, inSize);
+ p->tempBufSize = (unsigned)inSize;
+ (*srcLen) += inSize;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ bufLimit = src;
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+ p->buf = src;
+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
+ return SZ_ERROR_DATA;
+ processed = (SizeT)(p->buf - src);
+ (*srcLen) += processed;
+ src += processed;
+ inSize -= processed;
+ }
+ else
+ {
+ unsigned rem = p->tempBufSize, lookAhead = 0;
+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
+ p->tempBuf[rem++] = src[lookAhead++];
+ p->tempBufSize = rem;
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ (*srcLen) += lookAhead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ }
+ p->buf = p->tempBuf;
+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
+ return SZ_ERROR_DATA;
+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+ if (p->code == 0)
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+}
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->probs);
+ p->probs = 0;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->dic);
+ p->dic = 0;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = d % 9;
+ d /= 9;
+ p->pb = d / 5;
+ p->lp = d % 5;
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (p->probs == 0 || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ p->numProbs = numProbs;
+ if (p->probs == 0)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ dicBufSize = propNew.dicSize;
+ if (p->dic == 0 || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+ if (p->dic == 0)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT inSize = *srcLen;
+ SizeT outSize = *destLen;
+ *srcLen = *destLen = 0;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+
+ LzmaDec_Construct(&p);
+ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
+ if (res != 0)
+ return res;
+ p.dic = dest;
+ p.dicBufSize = outSize;
+
+ LzmaDec_Init(&p);
+
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+
+ (*destLen) = p.dicPos;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/src/libs/7zip/unix/C/LzmaDec.h b/src/libs/7zip/unix/C/LzmaDec.h
new file mode 100644
index 000000000..bf7f084ba
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzmaDec.h
@@ -0,0 +1,231 @@
+/* LzmaDec.h -- LZMA Decoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_DEC_H
+#define __LZMA_DEC_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ unsigned lc, lp, pb;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ Byte *dic;
+ const Byte *buf;
+ UInt32 range, code;
+ SizeT dicPos;
+ SizeT dicBufSize;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ unsigned state;
+ UInt32 reps[4];
+ unsigned remainLen;
+ int needFlush;
+ int needInitState;
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Constr()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/LzmaEnc.c b/src/libs/7zip/unix/C/LzmaEnc.c
new file mode 100644
index 000000000..cf131388a
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzmaEnc.c
@@ -0,0 +1,2268 @@
+/* LzmaEnc.c -- LZMA Encoder
+2010-04-16 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+/* #define SHOW_STAT */
+/* #define SHOW_STAT2 */
+
+#if defined(SHOW_STAT) || defined(SHOW_STAT2)
+#include <stdio.h>
+#endif
+
+#include "LzmaEnc.h"
+
+#include "LzFind.h"
+#ifndef _7ZIP_ST
+#include "LzFindMt.h"
+#endif
+
+#ifdef SHOW_STAT
+static int ttt = 0;
+#endif
+
+#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
+
+#define kBlockSize (9 << 10)
+#define kUnpackBlockSize (1 << 18)
+#define kMatchArraySize (1 << 21)
+#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
+
+#define kNumMaxDirectBits (31)
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+#define kProbInitValue (kBitModelTotal >> 1)
+
+#define kNumMoveReducingBits 4
+#define kNumBitPriceShiftBits 4
+#define kBitPrice (1 << kNumBitPriceShiftBits)
+
+void LzmaEncProps_Init(CLzmaEncProps *p)
+{
+ p->level = 5;
+ p->dictSize = p->mc = 0;
+ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
+ p->writeEndMark = 0;
+}
+
+void LzmaEncProps_Normalize(CLzmaEncProps *p)
+{
+ int level = p->level;
+ if (level < 0) level = 5;
+ p->level = level;
+ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
+ if (p->lc < 0) p->lc = 3;
+ if (p->lp < 0) p->lp = 0;
+ if (p->pb < 0) p->pb = 2;
+ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
+ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
+ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
+ if (p->numHashBytes < 0) p->numHashBytes = 4;
+ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
+ if (p->numThreads < 0)
+ p->numThreads =
+ #ifndef _7ZIP_ST
+ ((p->btMode && p->algo) ? 2 : 1);
+ #else
+ 1;
+ #endif
+}
+
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+{
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+ return props.dictSize;
+}
+
+/* #define LZMA_LOG_BSR */
+/* Define it for Intel's CPU */
+
+
+#ifdef LZMA_LOG_BSR
+
+#define kDicLogSizeMaxCompress 30
+
+#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
+
+UInt32 GetPosSlot1(UInt32 pos)
+{
+ UInt32 res;
+ BSR2_RET(pos, res);
+ return res;
+}
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
+
+#else
+
+#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
+#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+
+void LzmaEnc_FastPosInit(Byte *g_FastPos)
+{
+ int c = 2, slotFast;
+ g_FastPos[0] = 0;
+ g_FastPos[1] = 1;
+
+ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
+ {
+ UInt32 k = (1 << ((slotFast >> 1) - 1));
+ UInt32 j;
+ for (j = 0; j < k; j++, c++)
+ g_FastPos[c] = (Byte)slotFast;
+ }
+}
+
+#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
+ res = p->g_FastPos[pos >> i] + (i * 2); }
+/*
+#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
+ p->g_FastPos[pos >> 6] + 12 : \
+ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
+*/
+
+#define GetPosSlot1(pos) p->g_FastPos[pos]
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
+
+#endif
+
+
+#define LZMA_NUM_REPS 4
+
+typedef unsigned CState;
+
+typedef struct
+{
+ UInt32 price;
+
+ CState state;
+ int prev1IsChar;
+ int prev2;
+
+ UInt32 posPrev2;
+ UInt32 backPrev2;
+
+ UInt32 posPrev;
+ UInt32 backPrev;
+ UInt32 backs[LZMA_NUM_REPS];
+} COptimal;
+
+#define kNumOpts (1 << 12)
+
+#define kNumLenToPosStates 4
+#define kNumPosSlotBits 6
+#define kDicLogSizeMin 0
+#define kDicLogSizeMax 32
+#define kDistTableSizeMax (kDicLogSizeMax * 2)
+
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+#define kAlignMask (kAlignTableSize - 1)
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
+
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+#define LZMA_PB_MAX 4
+#define LZMA_LC_MAX 8
+#define LZMA_LP_MAX 4
+
+#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
+
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define LZMA_MATCH_LEN_MIN 2
+#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
+
+#define kNumStates 12
+
+typedef struct
+{
+ CLzmaProb choice;
+ CLzmaProb choice2;
+ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
+ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
+ CLzmaProb high[kLenNumHighSymbols];
+} CLenEnc;
+
+typedef struct
+{
+ CLenEnc p;
+ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
+ UInt32 tableSize;
+ UInt32 counters[LZMA_NUM_PB_STATES_MAX];
+} CLenPriceEnc;
+
+typedef struct
+{
+ UInt32 range;
+ Byte cache;
+ UInt64 low;
+ UInt64 cacheSize;
+ Byte *buf;
+ Byte *bufLim;
+ Byte *bufBase;
+ ISeqOutStream *outStream;
+ UInt64 processed;
+ SRes res;
+} CRangeEnc;
+
+typedef struct
+{
+ CLzmaProb *litProbs;
+
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+} CSaveState;
+
+typedef struct
+{
+ IMatchFinder matchFinder;
+ void *matchFinderObj;
+
+ #ifndef _7ZIP_ST
+ Bool mtMode;
+ CMatchFinderMt matchFinderMt;
+ #endif
+
+ CMatchFinder matchFinderBase;
+
+ #ifndef _7ZIP_ST
+ Byte pad[128];
+ #endif
+
+ UInt32 optimumEndIndex;
+ UInt32 optimumCurrentIndex;
+
+ UInt32 longestMatchLength;
+ UInt32 numPairs;
+ UInt32 numAvail;
+ COptimal opt[kNumOpts];
+
+ #ifndef LZMA_LOG_BSR
+ Byte g_FastPos[1 << kNumLogBits];
+ #endif
+
+ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
+ UInt32 numFastBytes;
+ UInt32 additionalOffset;
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+
+ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
+ UInt32 alignPrices[kAlignTableSize];
+ UInt32 alignPriceCount;
+
+ UInt32 distTableSize;
+
+ unsigned lc, lp, pb;
+ unsigned lpMask, pbMask;
+
+ CLzmaProb *litProbs;
+
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ unsigned lclp;
+
+ Bool fastMode;
+
+ CRangeEnc rc;
+
+ Bool writeEndMark;
+ UInt64 nowPos64;
+ UInt32 matchPriceCount;
+ Bool finished;
+ Bool multiThread;
+
+ SRes result;
+ UInt32 dictSize;
+ UInt32 matchFinderCycles;
+
+ int needInit;
+
+ CSaveState saveState;
+} CLzmaEnc;
+
+void LzmaEnc_SaveState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CSaveState *dest = &p->saveState;
+ int i;
+ dest->lenEnc = p->lenEnc;
+ dest->repLenEnc = p->repLenEnc;
+ dest->state = p->state;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+ }
+ for (i = 0; i < kNumLenToPosStates; i++)
+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+ memcpy(dest->reps, p->reps, sizeof(p->reps));
+ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+}
+
+void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *dest = (CLzmaEnc *)pp;
+ const CSaveState *p = &dest->saveState;
+ int i;
+ dest->lenEnc = p->lenEnc;
+ dest->repLenEnc = p->repLenEnc;
+ dest->state = p->state;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+ }
+ for (i = 0; i < kNumLenToPosStates; i++)
+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+ memcpy(dest->reps, p->reps, sizeof(p->reps));
+ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
+}
+
+SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+
+ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
+ props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30))
+ return SZ_ERROR_PARAM;
+ p->dictSize = props.dictSize;
+ p->matchFinderCycles = props.mc;
+ {
+ unsigned fb = props.fb;
+ if (fb < 5)
+ fb = 5;
+ if (fb > LZMA_MATCH_LEN_MAX)
+ fb = LZMA_MATCH_LEN_MAX;
+ p->numFastBytes = fb;
+ }
+ p->lc = props.lc;
+ p->lp = props.lp;
+ p->pb = props.pb;
+ p->fastMode = (props.algo == 0);
+ p->matchFinderBase.btMode = props.btMode;
+ {
+ UInt32 numHashBytes = 4;
+ if (props.btMode)
+ {
+ if (props.numHashBytes < 2)
+ numHashBytes = 2;
+ else if (props.numHashBytes < 4)
+ numHashBytes = props.numHashBytes;
+ }
+ p->matchFinderBase.numHashBytes = numHashBytes;
+ }
+
+ p->matchFinderBase.cutValue = props.mc;
+
+ p->writeEndMark = props.writeEndMark;
+
+ #ifndef _7ZIP_ST
+ /*
+ if (newMultiThread != _multiThread)
+ {
+ ReleaseMatchFinder();
+ _multiThread = newMultiThread;
+ }
+ */
+ p->multiThread = (props.numThreads > 1);
+ #endif
+
+ return SZ_OK;
+}
+
+static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
+static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+#define IsCharState(s) ((s) < 7)
+
+#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
+
+#define kInfinityPrice (1 << 30)
+
+static void RangeEnc_Construct(CRangeEnc *p)
+{
+ p->outStream = 0;
+ p->bufBase = 0;
+}
+
+#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
+
+#define RC_BUF_SIZE (1 << 16)
+static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
+{
+ if (p->bufBase == 0)
+ {
+ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
+ if (p->bufBase == 0)
+ return 0;
+ p->bufLim = p->bufBase + RC_BUF_SIZE;
+ }
+ return 1;
+}
+
+static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->bufBase);
+ p->bufBase = 0;
+}
+
+static void RangeEnc_Init(CRangeEnc *p)
+{
+ /* Stream.Init(); */
+ p->low = 0;
+ p->range = 0xFFFFFFFF;
+ p->cacheSize = 1;
+ p->cache = 0;
+
+ p->buf = p->bufBase;
+
+ p->processed = 0;
+ p->res = SZ_OK;
+}
+
+static void RangeEnc_FlushStream(CRangeEnc *p)
+{
+ size_t num;
+ if (p->res != SZ_OK)
+ return;
+ num = p->buf - p->bufBase;
+ if (num != p->outStream->Write(p->outStream, p->bufBase, num))
+ p->res = SZ_ERROR_WRITE;
+ p->processed += num;
+ p->buf = p->bufBase;
+}
+
+static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
+{
+ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
+ {
+ Byte temp = p->cache;
+ do
+ {
+ Byte *buf = p->buf;
+ *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
+ p->buf = buf;
+ if (buf == p->bufLim)
+ RangeEnc_FlushStream(p);
+ temp = 0xFF;
+ }
+ while (--p->cacheSize != 0);
+ p->cache = (Byte)((UInt32)p->low >> 24);
+ }
+ p->cacheSize++;
+ p->low = (UInt32)p->low << 8;
+}
+
+static void RangeEnc_FlushData(CRangeEnc *p)
+{
+ int i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
+{
+ do
+ {
+ p->range >>= 1;
+ p->low += p->range & (0 - ((value >> --numBits) & 1));
+ if (p->range < kTopValue)
+ {
+ p->range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+ }
+ while (numBits != 0);
+}
+
+static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
+{
+ UInt32 ttt = *prob;
+ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
+ if (symbol == 0)
+ {
+ p->range = newBound;
+ ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
+ }
+ else
+ {
+ p->low += newBound;
+ p->range -= newBound;
+ ttt -= ttt >> kNumMoveBits;
+ }
+ *prob = (CLzmaProb)ttt;
+ if (p->range < kTopValue)
+ {
+ p->range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
+{
+ symbol |= 0x100;
+ do
+ {
+ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
+ symbol <<= 1;
+ }
+ while (symbol < 0x10000);
+}
+
+static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
+{
+ UInt32 offs = 0x100;
+ symbol |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
+ symbol <<= 1;
+ offs &= ~(matchByte ^ symbol);
+ }
+ while (symbol < 0x10000);
+}
+
+void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+{
+ UInt32 i;
+ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
+ {
+ const int kCyclesBits = kNumBitPriceShiftBits;
+ UInt32 w = i;
+ UInt32 bitCount = 0;
+ int j;
+ for (j = 0; j < kCyclesBits; j++)
+ {
+ w = w * w;
+ bitCount <<= 1;
+ while (w >= ((UInt32)1 << 16))
+ {
+ w >>= 1;
+ bitCount++;
+ }
+ }
+ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
+ }
+}
+
+
+#define GET_PRICE(prob, symbol) \
+ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICEa(prob, symbol) \
+ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ symbol |= 0x100;
+ do
+ {
+ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
+ symbol <<= 1;
+ }
+ while (symbol < 0x10000);
+ return price;
+}
+
+static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 offs = 0x100;
+ symbol |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
+ symbol <<= 1;
+ offs &= ~(matchByte ^ symbol);
+ }
+ while (symbol < 0x10000);
+ return price;
+}
+
+
+static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
+{
+ UInt32 m = 1;
+ int i;
+ for (i = numBitLevels; i != 0;)
+ {
+ UInt32 bit;
+ i--;
+ bit = (symbol >> i) & 1;
+ RangeEnc_EncodeBit(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ }
+}
+
+static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
+{
+ UInt32 m = 1;
+ int i;
+ for (i = 0; i < numBitLevels; i++)
+ {
+ UInt32 bit = symbol & 1;
+ RangeEnc_EncodeBit(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ symbol >>= 1;
+ }
+}
+
+static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ symbol |= (1 << numBitLevels);
+ while (symbol != 1)
+ {
+ price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
+ symbol >>= 1;
+ }
+ return price;
+}
+
+static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 m = 1;
+ int i;
+ for (i = numBitLevels; i != 0; i--)
+ {
+ UInt32 bit = symbol & 1;
+ symbol >>= 1;
+ price += GET_PRICEa(probs[m], bit);
+ m = (m << 1) | bit;
+ }
+ return price;
+}
+
+
+static void LenEnc_Init(CLenEnc *p)
+{
+ unsigned i;
+ p->choice = p->choice2 = kProbInitValue;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
+ p->low[i] = kProbInitValue;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
+ p->mid[i] = kProbInitValue;
+ for (i = 0; i < kLenNumHighSymbols; i++)
+ p->high[i] = kProbInitValue;
+}
+
+static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
+{
+ if (symbol < kLenNumLowSymbols)
+ {
+ RangeEnc_EncodeBit(rc, &p->choice, 0);
+ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
+ }
+ else
+ {
+ RangeEnc_EncodeBit(rc, &p->choice, 1);
+ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
+ {
+ RangeEnc_EncodeBit(rc, &p->choice2, 0);
+ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
+ }
+ else
+ {
+ RangeEnc_EncodeBit(rc, &p->choice2, 1);
+ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
+ }
+ }
+}
+
+static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
+{
+ UInt32 a0 = GET_PRICE_0a(p->choice);
+ UInt32 a1 = GET_PRICE_1a(p->choice);
+ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
+ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
+ UInt32 i = 0;
+ for (i = 0; i < kLenNumLowSymbols; i++)
+ {
+ if (i >= numSymbols)
+ return;
+ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
+ }
+ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
+ {
+ if (i >= numSymbols)
+ return;
+ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
+ }
+ for (; i < numSymbols; i++)
+ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
+}
+
+static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
+{
+ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
+ p->counters[posState] = p->tableSize;
+}
+
+static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
+{
+ UInt32 posState;
+ for (posState = 0; posState < numPosStates; posState++)
+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
+}
+
+static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
+{
+ LenEnc_Encode(&p->p, rc, symbol, posState);
+ if (updatePrice)
+ if (--p->counters[posState] == 0)
+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
+}
+
+
+
+
+static void MovePos(CLzmaEnc *p, UInt32 num)
+{
+ #ifdef SHOW_STAT
+ ttt += num;
+ printf("\n MovePos %d", num);
+ #endif
+ if (num != 0)
+ {
+ p->additionalOffset += num;
+ p->matchFinder.Skip(p->matchFinderObj, num);
+ }
+}
+
+static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
+{
+ UInt32 lenRes = 0, numPairs;
+ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
+ #ifdef SHOW_STAT
+ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2);
+ ttt++;
+ {
+ UInt32 i;
+ for (i = 0; i < numPairs; i += 2)
+ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]);
+ }
+ #endif
+ if (numPairs > 0)
+ {
+ lenRes = p->matches[numPairs - 2];
+ if (lenRes == p->numFastBytes)
+ {
+ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ UInt32 distance = p->matches[numPairs - 1] + 1;
+ UInt32 numAvail = p->numAvail;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ {
+ const Byte *pby2 = pby - distance;
+ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
+ }
+ }
+ }
+ p->additionalOffset++;
+ *numDistancePairsRes = numPairs;
+ return lenRes;
+}
+
+
+#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
+#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
+#define IsShortRep(p) ((p)->backPrev == 0)
+
+static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
+{
+ return
+ GET_PRICE_0(p->isRepG0[state]) +
+ GET_PRICE_0(p->isRep0Long[state][posState]);
+}
+
+static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
+{
+ UInt32 price;
+ if (repIndex == 0)
+ {
+ price = GET_PRICE_0(p->isRepG0[state]);
+ price += GET_PRICE_1(p->isRep0Long[state][posState]);
+ }
+ else
+ {
+ price = GET_PRICE_1(p->isRepG0[state]);
+ if (repIndex == 1)
+ price += GET_PRICE_0(p->isRepG1[state]);
+ else
+ {
+ price += GET_PRICE_1(p->isRepG1[state]);
+ price += GET_PRICE(p->isRepG2[state], repIndex - 2);
+ }
+ }
+ return price;
+}
+
+static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
+{
+ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
+ GetPureRepPrice(p, repIndex, state, posState);
+}
+
+static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
+{
+ UInt32 posMem = p->opt[cur].posPrev;
+ UInt32 backMem = p->opt[cur].backPrev;
+ p->optimumEndIndex = cur;
+ do
+ {
+ if (p->opt[cur].prev1IsChar)
+ {
+ MakeAsChar(&p->opt[posMem])
+ p->opt[posMem].posPrev = posMem - 1;
+ if (p->opt[cur].prev2)
+ {
+ p->opt[posMem - 1].prev1IsChar = False;
+ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
+ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
+ }
+ }
+ {
+ UInt32 posPrev = posMem;
+ UInt32 backCur = backMem;
+
+ backMem = p->opt[posPrev].backPrev;
+ posMem = p->opt[posPrev].posPrev;
+
+ p->opt[posPrev].backPrev = backCur;
+ p->opt[posPrev].posPrev = cur;
+ cur = posPrev;
+ }
+ }
+ while (cur != 0);
+ *backRes = p->opt[0].backPrev;
+ p->optimumCurrentIndex = p->opt[0].posPrev;
+ return p->optimumCurrentIndex;
+}
+
+#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
+
+static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
+{
+ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
+ UInt32 matchPrice, repMatchPrice, normalMatchPrice;
+ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
+ UInt32 *matches;
+ const Byte *data;
+ Byte curByte, matchByte;
+ if (p->optimumEndIndex != p->optimumCurrentIndex)
+ {
+ const COptimal *opt = &p->opt[p->optimumCurrentIndex];
+ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
+ *backRes = opt->backPrev;
+ p->optimumCurrentIndex = opt->posPrev;
+ return lenRes;
+ }
+ p->optimumCurrentIndex = p->optimumEndIndex = 0;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLength;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ if (numAvail < 2)
+ {
+ *backRes = (UInt32)(-1);
+ return 1;
+ }
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ repMaxIndex = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 lenTest;
+ const Byte *data2;
+ reps[i] = p->reps[i];
+ data2 = data - (reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ {
+ repLens[i] = 0;
+ continue;
+ }
+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
+ repLens[i] = lenTest;
+ if (lenTest > repLens[repMaxIndex])
+ repMaxIndex = i;
+ }
+ if (repLens[repMaxIndex] >= p->numFastBytes)
+ {
+ UInt32 lenRes;
+ *backRes = repMaxIndex;
+ lenRes = repLens[repMaxIndex];
+ MovePos(p, lenRes - 1);
+ return lenRes;
+ }
+
+ matches = p->matches;
+ if (mainLen >= p->numFastBytes)
+ {
+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 1);
+ return mainLen;
+ }
+ curByte = *data;
+ matchByte = *(data - (reps[0] + 1));
+
+ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
+ {
+ *backRes = (UInt32)-1;
+ return 1;
+ }
+
+ p->opt[0].state = (CState)p->state;
+
+ posState = (position & p->pbMask);
+
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
+ (!IsCharState(p->state) ?
+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ MakeAsChar(&p->opt[1]);
+
+ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
+
+ if (matchByte == curByte)
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
+ if (shortRepPrice < p->opt[1].price)
+ {
+ p->opt[1].price = shortRepPrice;
+ MakeAsShortRep(&p->opt[1]);
+ }
+ }
+ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
+
+ if (lenEnd < 2)
+ {
+ *backRes = p->opt[1].backPrev;
+ return 1;
+ }
+
+ p->opt[1].posPrev = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ p->opt[0].backs[i] = reps[i];
+
+ len = lenEnd;
+ do
+ p->opt[len--].price = kInfinityPrice;
+ while (len >= 2);
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 repLen = repLens[i];
+ UInt32 price;
+ if (repLen < 2)
+ continue;
+ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
+ do
+ {
+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
+ COptimal *opt = &p->opt[repLen];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = 0;
+ opt->backPrev = i;
+ opt->prev1IsChar = False;
+ }
+ }
+ while (--repLen >= 2);
+ }
+
+ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
+
+ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
+ if (len <= mainLen)
+ {
+ UInt32 offs = 0;
+ while (len > matches[offs])
+ offs += 2;
+ for (; ; len++)
+ {
+ COptimal *opt;
+ UInt32 distance = matches[offs + 1];
+
+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
+ UInt32 lenToPosState = GetLenToPosState(len);
+ if (distance < kNumFullDistances)
+ curAndLenPrice += p->distancesPrices[lenToPosState][distance];
+ else
+ {
+ UInt32 slot;
+ GetPosSlot2(distance, slot);
+ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
+ }
+ opt = &p->opt[len];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = 0;
+ opt->backPrev = distance + LZMA_NUM_REPS;
+ opt->prev1IsChar = False;
+ }
+ if (len == matches[offs])
+ {
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ }
+ }
+ }
+
+ cur = 0;
+
+ #ifdef SHOW_STAT2
+ if (position >= 0)
+ {
+ unsigned i;
+ printf("\n pos = %4X", position);
+ for (i = cur; i <= lenEnd; i++)
+ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
+ }
+ #endif
+
+ for (;;)
+ {
+ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
+ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
+ Bool nextIsChar;
+ Byte curByte, matchByte;
+ const Byte *data;
+ COptimal *curOpt;
+ COptimal *nextOpt;
+
+ cur++;
+ if (cur == lenEnd)
+ return Backward(p, backRes, cur);
+
+ newLen = ReadMatchDistances(p, &numPairs);
+ if (newLen >= p->numFastBytes)
+ {
+ p->numPairs = numPairs;
+ p->longestMatchLength = newLen;
+ return Backward(p, backRes, cur);
+ }
+ position++;
+ curOpt = &p->opt[cur];
+ posPrev = curOpt->posPrev;
+ if (curOpt->prev1IsChar)
+ {
+ posPrev--;
+ if (curOpt->prev2)
+ {
+ state = p->opt[curOpt->posPrev2].state;
+ if (curOpt->backPrev2 < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+ else
+ state = p->opt[posPrev].state;
+ state = kLiteralNextStates[state];
+ }
+ else
+ state = p->opt[posPrev].state;
+ if (posPrev == cur - 1)
+ {
+ if (IsShortRep(curOpt))
+ state = kShortRepNextStates[state];
+ else
+ state = kLiteralNextStates[state];
+ }
+ else
+ {
+ UInt32 pos;
+ const COptimal *prevOpt;
+ if (curOpt->prev1IsChar && curOpt->prev2)
+ {
+ posPrev = curOpt->posPrev2;
+ pos = curOpt->backPrev2;
+ state = kRepNextStates[state];
+ }
+ else
+ {
+ pos = curOpt->backPrev;
+ if (pos < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+ prevOpt = &p->opt[posPrev];
+ if (pos < LZMA_NUM_REPS)
+ {
+ UInt32 i;
+ reps[0] = prevOpt->backs[pos];
+ for (i = 1; i <= pos; i++)
+ reps[i] = prevOpt->backs[i - 1];
+ for (; i < LZMA_NUM_REPS; i++)
+ reps[i] = prevOpt->backs[i];
+ }
+ else
+ {
+ UInt32 i;
+ reps[0] = (pos - LZMA_NUM_REPS);
+ for (i = 1; i < LZMA_NUM_REPS; i++)
+ reps[i] = prevOpt->backs[i - 1];
+ }
+ }
+ curOpt->state = (CState)state;
+
+ curOpt->backs[0] = reps[0];
+ curOpt->backs[1] = reps[1];
+ curOpt->backs[2] = reps[2];
+ curOpt->backs[3] = reps[3];
+
+ curPrice = curOpt->price;
+ nextIsChar = False;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ curByte = *data;
+ matchByte = *(data - (reps[0] + 1));
+
+ posState = (position & p->pbMask);
+
+ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ curAnd1Price +=
+ (!IsCharState(state) ?
+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ nextOpt = &p->opt[cur + 1];
+
+ if (curAnd1Price < nextOpt->price)
+ {
+ nextOpt->price = curAnd1Price;
+ nextOpt->posPrev = cur;
+ MakeAsChar(nextOpt);
+ nextIsChar = True;
+ }
+
+ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
+
+ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
+ if (shortRepPrice <= nextOpt->price)
+ {
+ nextOpt->price = shortRepPrice;
+ nextOpt->posPrev = cur;
+ MakeAsShortRep(nextOpt);
+ nextIsChar = True;
+ }
+ }
+ numAvailFull = p->numAvail;
+ {
+ UInt32 temp = kNumOpts - 1 - cur;
+ if (temp < numAvailFull)
+ numAvailFull = temp;
+ }
+
+ if (numAvailFull < 2)
+ continue;
+ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
+
+ if (!nextIsChar && matchByte != curByte) /* speed optimization */
+ {
+ /* try Literal + rep0 */
+ UInt32 temp;
+ UInt32 lenTest2;
+ const Byte *data2 = data - (reps[0] + 1);
+ UInt32 limit = p->numFastBytes + 1;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+
+ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
+ lenTest2 = temp - 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kLiteralNextStates[state];
+ UInt32 posStateNext = (position + 1) & p->pbMask;
+ UInt32 nextRepMatchPrice = curAnd1Price +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ UInt32 offset = cur + 1 + lenTest2;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = False;
+ }
+ }
+ }
+ }
+
+ startLen = 2; /* speed optimization */
+ {
+ UInt32 repIndex;
+ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
+ {
+ UInt32 lenTest;
+ UInt32 lenTestTemp;
+ UInt32 price;
+ const Byte *data2 = data - (reps[repIndex] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
+ while (lenEnd < cur + lenTest)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ lenTestTemp = lenTest;
+ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
+ do
+ {
+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
+ COptimal *opt = &p->opt[cur + lenTest];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur;
+ opt->backPrev = repIndex;
+ opt->prev1IsChar = False;
+ }
+ }
+ while (--lenTest >= 2);
+ lenTest = lenTestTemp;
+
+ if (repIndex == 0)
+ startLen = lenTest + 1;
+
+ /* if (_maxMode) */
+ {
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = lenTest2 + p->numFastBytes;
+ UInt32 nextRepMatchPrice;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kRepNextStates[state];
+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
+ UInt32 curAndLenCharPrice =
+ price + p->repLenEnc.prices[posState][lenTest - 2] +
+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
+ data[lenTest], data2[lenTest], p->ProbPrices);
+ state2 = kLiteralNextStates[state2];
+ posStateNext = (position + lenTest + 1) & p->pbMask;
+ nextRepMatchPrice = curAndLenCharPrice +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ UInt32 offset = cur + lenTest + 1 + lenTest2;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + lenTest + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = True;
+ opt->posPrev2 = cur;
+ opt->backPrev2 = repIndex;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
+ if (newLen > numAvail)
+ {
+ newLen = numAvail;
+ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
+ matches[numPairs] = newLen;
+ numPairs += 2;
+ }
+ if (newLen >= startLen)
+ {
+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
+ UInt32 offs, curBack, posSlot;
+ UInt32 lenTest;
+ while (lenEnd < cur + newLen)
+ p->opt[++lenEnd].price = kInfinityPrice;
+
+ offs = 0;
+ while (startLen > matches[offs])
+ offs += 2;
+ curBack = matches[offs + 1];
+ GetPosSlot2(curBack, posSlot);
+ for (lenTest = /*2*/ startLen; ; lenTest++)
+ {
+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
+ UInt32 lenToPosState = GetLenToPosState(lenTest);
+ COptimal *opt;
+ if (curBack < kNumFullDistances)
+ curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
+ else
+ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
+
+ opt = &p->opt[cur + lenTest];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur;
+ opt->backPrev = curBack + LZMA_NUM_REPS;
+ opt->prev1IsChar = False;
+ }
+
+ if (/*_maxMode && */lenTest == matches[offs])
+ {
+ /* Try Match + Literal + Rep0 */
+ const Byte *data2 = data - (curBack + 1);
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = lenTest2 + p->numFastBytes;
+ UInt32 nextRepMatchPrice;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kMatchNextStates[state];
+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
+ UInt32 curAndLenCharPrice = curAndLenPrice +
+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
+ data[lenTest], data2[lenTest], p->ProbPrices);
+ state2 = kLiteralNextStates[state2];
+ posStateNext = (posStateNext + 1) & p->pbMask;
+ nextRepMatchPrice = curAndLenCharPrice +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 offset = cur + lenTest + 1 + lenTest2;
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + lenTest + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = True;
+ opt->posPrev2 = cur;
+ opt->backPrev2 = curBack + LZMA_NUM_REPS;
+ }
+ }
+ }
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ curBack = matches[offs + 1];
+ if (curBack >= kNumFullDistances)
+ GetPosSlot2(curBack, posSlot);
+ }
+ }
+ }
+ }
+}
+
+#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
+
+static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
+{
+ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
+ const Byte *data;
+ const UInt32 *matches;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLength;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ *backRes = (UInt32)-1;
+ if (numAvail < 2)
+ return 1;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+
+ repLen = repIndex = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 len;
+ const Byte *data2 = data - (p->reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++);
+ if (len >= p->numFastBytes)
+ {
+ *backRes = i;
+ MovePos(p, len - 1);
+ return len;
+ }
+ if (len > repLen)
+ {
+ repIndex = i;
+ repLen = len;
+ }
+ }
+
+ matches = p->matches;
+ if (mainLen >= p->numFastBytes)
+ {
+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 1);
+ return mainLen;
+ }
+
+ mainDist = 0; /* for GCC */
+ if (mainLen >= 2)
+ {
+ mainDist = matches[numPairs - 1];
+ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
+ {
+ if (!ChangePair(matches[numPairs - 3], mainDist))
+ break;
+ numPairs -= 2;
+ mainLen = matches[numPairs - 2];
+ mainDist = matches[numPairs - 1];
+ }
+ if (mainLen == 2 && mainDist >= 0x80)
+ mainLen = 1;
+ }
+
+ if (repLen >= 2 && (
+ (repLen + 1 >= mainLen) ||
+ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
+ (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
+ {
+ *backRes = repIndex;
+ MovePos(p, repLen - 1);
+ return repLen;
+ }
+
+ if (mainLen < 2 || numAvail <= 2)
+ return 1;
+
+ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
+ if (p->longestMatchLength >= 2)
+ {
+ UInt32 newDistance = matches[p->numPairs - 1];
+ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
+ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
+ (p->longestMatchLength > mainLen + 1) ||
+ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
+ return 1;
+ }
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 len, limit;
+ const Byte *data2 = data - (p->reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ limit = mainLen - 1;
+ for (len = 2; len < limit && data[len] == data2[len]; len++);
+ if (len >= limit)
+ return 1;
+ }
+ *backRes = mainDist + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 2);
+ return mainLen;
+}
+
+static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
+{
+ UInt32 len;
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
+ p->state = kMatchNextStates[p->state];
+ len = LZMA_MATCH_LEN_MIN;
+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
+ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
+}
+
+static SRes CheckErrors(CLzmaEnc *p)
+{
+ if (p->result != SZ_OK)
+ return p->result;
+ if (p->rc.res != SZ_OK)
+ p->result = SZ_ERROR_WRITE;
+ if (p->matchFinderBase.result != SZ_OK)
+ p->result = SZ_ERROR_READ;
+ if (p->result != SZ_OK)
+ p->finished = True;
+ return p->result;
+}
+
+static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
+{
+ /* ReleaseMFStream(); */
+ p->finished = True;
+ if (p->writeEndMark)
+ WriteEndMarker(p, nowPos & p->pbMask);
+ RangeEnc_FlushData(&p->rc);
+ RangeEnc_FlushStream(&p->rc);
+ return CheckErrors(p);
+}
+
+static void FillAlignPrices(CLzmaEnc *p)
+{
+ UInt32 i;
+ for (i = 0; i < kAlignTableSize; i++)
+ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
+ p->alignPriceCount = 0;
+}
+
+static void FillDistancesPrices(CLzmaEnc *p)
+{
+ UInt32 tempPrices[kNumFullDistances];
+ UInt32 i, lenToPosState;
+ for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
+ {
+ UInt32 posSlot = GetPosSlot1(i);
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
+ }
+
+ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
+ {
+ UInt32 posSlot;
+ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
+ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
+ for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
+ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
+ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
+ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
+
+ {
+ UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
+ UInt32 i;
+ for (i = 0; i < kStartPosModelIndex; i++)
+ distancesPrices[i] = posSlotPrices[i];
+ for (; i < kNumFullDistances; i++)
+ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
+ }
+ }
+ p->matchPriceCount = 0;
+}
+
+void LzmaEnc_Construct(CLzmaEnc *p)
+{
+ RangeEnc_Construct(&p->rc);
+ MatchFinder_Construct(&p->matchFinderBase);
+ #ifndef _7ZIP_ST
+ MatchFinderMt_Construct(&p->matchFinderMt);
+ p->matchFinderMt.MatchFinder = &p->matchFinderBase;
+ #endif
+
+ {
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ LzmaEnc_SetProps(p, &props);
+ }
+
+ #ifndef LZMA_LOG_BSR
+ LzmaEnc_FastPosInit(p->g_FastPos);
+ #endif
+
+ LzmaEnc_InitPriceTables(p->ProbPrices);
+ p->litProbs = 0;
+ p->saveState.litProbs = 0;
+}
+
+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
+{
+ void *p;
+ p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
+ if (p != 0)
+ LzmaEnc_Construct((CLzmaEnc *)p);
+ return p;
+}
+
+void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->litProbs);
+ alloc->Free(alloc, p->saveState.litProbs);
+ p->litProbs = 0;
+ p->saveState.litProbs = 0;
+}
+
+void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ #ifndef _7ZIP_ST
+ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+ #endif
+ MatchFinder_Free(&p->matchFinderBase, allocBig);
+ LzmaEnc_FreeLits(p, alloc);
+ RangeEnc_Free(&p->rc, alloc);
+}
+
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
+ alloc->Free(alloc, p);
+}
+
+static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
+{
+ UInt32 nowPos32, startPos32;
+ if (p->needInit)
+ {
+ p->matchFinder.Init(p->matchFinderObj);
+ p->needInit = 0;
+ }
+
+ if (p->finished)
+ return p->result;
+ RINOK(CheckErrors(p));
+
+ nowPos32 = (UInt32)p->nowPos64;
+ startPos32 = nowPos32;
+
+ if (p->nowPos64 == 0)
+ {
+ UInt32 numPairs;
+ Byte curByte;
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ return Flush(p, nowPos32);
+ ReadMatchDistances(p, &numPairs);
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
+ p->state = kLiteralNextStates[p->state];
+ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
+ LitEnc_Encode(&p->rc, p->litProbs, curByte);
+ p->additionalOffset--;
+ nowPos32++;
+ }
+
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
+ for (;;)
+ {
+ UInt32 pos, len, posState;
+
+ if (p->fastMode)
+ len = GetOptimumFast(p, &pos);
+ else
+ len = GetOptimum(p, nowPos32, &pos);
+
+ #ifdef SHOW_STAT2
+ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos);
+ #endif
+
+ posState = nowPos32 & p->pbMask;
+ if (len == 1 && pos == (UInt32)-1)
+ {
+ Byte curByte;
+ CLzmaProb *probs;
+ const Byte *data;
+
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+ curByte = *data;
+ probs = LIT_PROBS(nowPos32, *(data - 1));
+ if (IsCharState(p->state))
+ LitEnc_Encode(&p->rc, probs, curByte);
+ else
+ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
+ p->state = kLiteralNextStates[p->state];
+ }
+ else
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
+ if (pos < LZMA_NUM_REPS)
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
+ if (pos == 0)
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
+ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
+ }
+ else
+ {
+ UInt32 distance = p->reps[pos];
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
+ if (pos == 1)
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
+ else
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
+ if (pos == 3)
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ }
+ p->reps[1] = p->reps[0];
+ p->reps[0] = distance;
+ }
+ if (len == 1)
+ p->state = kShortRepNextStates[p->state];
+ else
+ {
+ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ p->state = kRepNextStates[p->state];
+ }
+ }
+ else
+ {
+ UInt32 posSlot;
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
+ p->state = kMatchNextStates[p->state];
+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ pos -= LZMA_NUM_REPS;
+ GetPosSlot(pos, posSlot);
+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
+
+ if (posSlot >= kStartPosModelIndex)
+ {
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ UInt32 posReduced = pos - base;
+
+ if (posSlot < kEndPosModelIndex)
+ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
+ else
+ {
+ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
+ p->alignPriceCount++;
+ }
+ }
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ p->reps[1] = p->reps[0];
+ p->reps[0] = pos;
+ p->matchPriceCount++;
+ }
+ }
+ p->additionalOffset -= len;
+ nowPos32 += len;
+ if (p->additionalOffset == 0)
+ {
+ UInt32 processed;
+ if (!p->fastMode)
+ {
+ if (p->matchPriceCount >= (1 << 7))
+ FillDistancesPrices(p);
+ if (p->alignPriceCount >= kAlignTableSize)
+ FillAlignPrices(p);
+ }
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ break;
+ processed = nowPos32 - startPos32;
+ if (useLimits)
+ {
+ if (processed + kNumOpts + 300 >= maxUnpackSize ||
+ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
+ break;
+ }
+ else if (processed >= (1 << 15))
+ {
+ p->nowPos64 += nowPos32 - startPos32;
+ return CheckErrors(p);
+ }
+ }
+ }
+ p->nowPos64 += nowPos32 - startPos32;
+ return Flush(p, nowPos32);
+}
+
+#define kBigHashDicLimit ((UInt32)1 << 24)
+
+static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ UInt32 beforeSize = kNumOpts;
+ Bool btMode;
+ if (!RangeEnc_Alloc(&p->rc, alloc))
+ return SZ_ERROR_MEM;
+ btMode = (p->matchFinderBase.btMode != 0);
+ #ifndef _7ZIP_ST
+ p->mtMode = (p->multiThread && !p->fastMode && btMode);
+ #endif
+
+ {
+ unsigned lclp = p->lc + p->lp;
+ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
+ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
+ if (p->litProbs == 0 || p->saveState.litProbs == 0)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ p->lclp = lclp;
+ }
+ }
+
+ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
+
+ if (beforeSize + p->dictSize < keepWindowSize)
+ beforeSize = keepWindowSize - p->dictSize;
+
+ #ifndef _7ZIP_ST
+ if (p->mtMode)
+ {
+ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
+ p->matchFinderObj = &p->matchFinderMt;
+ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
+ }
+ else
+ #endif
+ {
+ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
+ return SZ_ERROR_MEM;
+ p->matchFinderObj = &p->matchFinderBase;
+ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
+ }
+ return SZ_OK;
+}
+
+void LzmaEnc_Init(CLzmaEnc *p)
+{
+ UInt32 i;
+ p->state = 0;
+ for (i = 0 ; i < LZMA_NUM_REPS; i++)
+ p->reps[i] = 0;
+
+ RangeEnc_Init(&p->rc);
+
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ UInt32 j;
+ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
+ {
+ p->isMatch[i][j] = kProbInitValue;
+ p->isRep0Long[i][j] = kProbInitValue;
+ }
+ p->isRep[i] = kProbInitValue;
+ p->isRepG0[i] = kProbInitValue;
+ p->isRepG1[i] = kProbInitValue;
+ p->isRepG2[i] = kProbInitValue;
+ }
+
+ {
+ UInt32 num = 0x300 << (p->lp + p->lc);
+ for (i = 0; i < num; i++)
+ p->litProbs[i] = kProbInitValue;
+ }
+
+ {
+ for (i = 0; i < kNumLenToPosStates; i++)
+ {
+ CLzmaProb *probs = p->posSlotEncoder[i];
+ UInt32 j;
+ for (j = 0; j < (1 << kNumPosSlotBits); j++)
+ probs[j] = kProbInitValue;
+ }
+ }
+ {
+ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
+ p->posEncoders[i] = kProbInitValue;
+ }
+
+ LenEnc_Init(&p->lenEnc.p);
+ LenEnc_Init(&p->repLenEnc.p);
+
+ for (i = 0; i < (1 << kNumAlignBits); i++)
+ p->posAlignEncoder[i] = kProbInitValue;
+
+ p->optimumEndIndex = 0;
+ p->optimumCurrentIndex = 0;
+ p->additionalOffset = 0;
+
+ p->pbMask = (1 << p->pb) - 1;
+ p->lpMask = (1 << p->lp) - 1;
+}
+
+void LzmaEnc_InitPrices(CLzmaEnc *p)
+{
+ if (!p->fastMode)
+ {
+ FillDistancesPrices(p);
+ FillAlignPrices(p);
+ }
+
+ p->lenEnc.tableSize =
+ p->repLenEnc.tableSize =
+ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
+ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
+ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
+}
+
+static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ UInt32 i;
+ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
+ if (p->dictSize <= ((UInt32)1 << i))
+ break;
+ p->distTableSize = i * 2;
+
+ p->finished = False;
+ p->result = SZ_OK;
+ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ p->nowPos64 = 0;
+ return SZ_OK;
+}
+
+static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ p->matchFinderBase.stream = inStream;
+ p->needInit = 1;
+ p->rc.outStream = outStream;
+ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+}
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
+ ISeqInStream *inStream, UInt32 keepWindowSize,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ p->matchFinderBase.stream = inStream;
+ p->needInit = 1;
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
+{
+ p->matchFinderBase.directInput = 1;
+ p->matchFinderBase.bufferBase = (Byte *)src;
+ p->matchFinderBase.directInputRem = srcLen;
+}
+
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+ p->needInit = 1;
+
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+void LzmaEnc_Finish(CLzmaEncHandle pp)
+{
+ #ifndef _7ZIP_ST
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ if (p->mtMode)
+ MatchFinderMt_ReleaseStream(&p->matchFinderMt);
+ #else
+ pp = pp;
+ #endif
+}
+
+typedef struct
+{
+ ISeqOutStream funcTable;
+ Byte *data;
+ SizeT rem;
+ Bool overflow;
+} CSeqOutStreamBuf;
+
+static size_t MyWrite(void *pp, const void *data, size_t size)
+{
+ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
+ if (p->rem < size)
+ {
+ size = p->rem;
+ p->overflow = True;
+ }
+ memcpy(p->data, data, size);
+ p->rem -= size;
+ p->data += size;
+ return size;
+}
+
+
+UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+}
+
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+}
+
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ UInt64 nowPos64;
+ SRes res;
+ CSeqOutStreamBuf outStream;
+
+ outStream.funcTable.Write = MyWrite;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = False;
+ p->finished = False;
+ p->result = SZ_OK;
+
+ if (reInit)
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ nowPos64 = p->nowPos64;
+ RangeEnc_Init(&p->rc);
+ p->rc.outStream = &outStream.funcTable;
+
+ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
+
+ *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ return res;
+}
+
+static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
+{
+ SRes res = SZ_OK;
+
+ #ifndef _7ZIP_ST
+ Byte allocaDummy[0x300];
+ int i = 0;
+ for (i = 0; i < 16; i++)
+ allocaDummy[i] = (Byte)i;
+ #endif
+
+ for (;;)
+ {
+ res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
+ if (res != SZ_OK || p->finished != 0)
+ break;
+ if (progress != 0)
+ {
+ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
+ if (res != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ }
+ LzmaEnc_Finish(p);
+ return res;
+}
+
+SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
+ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
+}
+
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ int i;
+ UInt32 dictSize = p->dictSize;
+ if (*size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_PARAM;
+ *size = LZMA_PROPS_SIZE;
+ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
+
+ for (i = 11; i <= 30; i++)
+ {
+ if (dictSize <= ((UInt32)2 << i))
+ {
+ dictSize = (2 << i);
+ break;
+ }
+ if (dictSize <= ((UInt32)3 << i))
+ {
+ dictSize = (3 << i);
+ break;
+ }
+ }
+
+ for (i = 0; i < 4; i++)
+ props[1 + i] = (Byte)(dictSize >> (8 * i));
+ return SZ_OK;
+}
+
+SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ SRes res;
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+
+ CSeqOutStreamBuf outStream;
+
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+
+ outStream.funcTable.Write = MyWrite;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = writeEndMark;
+
+ p->rc.outStream = &outStream.funcTable;
+ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
+ if (res == SZ_OK)
+ res = LzmaEnc_Encode2(p, progress);
+
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+ return res;
+}
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+ SRes res;
+ if (p == 0)
+ return SZ_ERROR_MEM;
+
+ res = LzmaEnc_SetProps(p, props);
+ if (res == SZ_OK)
+ {
+ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+ if (res == SZ_OK)
+ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+ writeEndMark, progress, alloc, allocBig);
+ }
+
+ LzmaEnc_Destroy(p, alloc, allocBig);
+ return res;
+}
diff --git a/src/libs/7zip/unix/C/LzmaEnc.h b/src/libs/7zip/unix/C/LzmaEnc.h
new file mode 100644
index 000000000..200d60eb8
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzmaEnc.h
@@ -0,0 +1,80 @@
+/* LzmaEnc.h -- LZMA Encoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_ENC_H
+#define __LZMA_ENC_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaEncProps
+{
+ int level; /* 0 <= level <= 9 */
+ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
+ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version
+ default = (1 << 24) */
+ int lc; /* 0 <= lc <= 8, default = 3 */
+ int lp; /* 0 <= lp <= 4, default = 0 */
+ int pb; /* 0 <= pb <= 4, default = 2 */
+ int algo; /* 0 - fast, 1 - normal, default = 1 */
+ int fb; /* 5 <= fb <= 273, default = 32 */
+ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
+ int numHashBytes; /* 2, 3 or 4, default = 4 */
+ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
+ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
+ int numThreads; /* 1 or 2, default = 2 */
+} CLzmaEncProps;
+
+void LzmaEncProps_Init(CLzmaEncProps *p);
+void LzmaEncProps_Normalize(CLzmaEncProps *p);
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+
+
+/* ---------- CLzmaEncHandle Interface ---------- */
+
+/* LzmaEnc_* functions can return the following exit codes:
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - Write callback error.
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzmaEncHandle;
+
+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaEncode
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/LzmaUtil/Lzma86Dec.c b/src/libs/7zip/unix/C/LzmaUtil/Lzma86Dec.c
new file mode 100644
index 000000000..b801dd1ca
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzmaUtil/Lzma86Dec.c
@@ -0,0 +1,61 @@
+/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder
+2008-04-07
+Igor Pavlov
+Public domain */
+
+#include "Lzma86Dec.h"
+
+#include "../Alloc.h"
+#include "../Bra.h"
+#include "../LzmaDec.h"
+
+#define LZMA86_SIZE_OFFSET (1 + LZMA_PROPS_SIZE)
+#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize)
+{
+ unsigned i;
+ if (srcLen < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+ *unpackSize = 0;
+ for (i = 0; i < sizeof(UInt64); i++)
+ *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i);
+ return SZ_OK;
+}
+
+SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
+{
+ SRes res;
+ int useFilter;
+ SizeT inSizePure;
+ ELzmaStatus status;
+
+ if (*srcLen < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+
+ useFilter = src[0];
+
+ if (useFilter > 1)
+ {
+ *destLen = 0;
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ inSizePure = *srcLen - LZMA86_HEADER_SIZE;
+ res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure,
+ src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc);
+ *srcLen = inSizePure + LZMA86_HEADER_SIZE;
+ if (res != SZ_OK)
+ return res;
+ if (useFilter == 1)
+ {
+ UInt32 x86State;
+ x86_Convert_Init(x86State);
+ x86_Convert(dest, *destLen, 0, &x86State, 0);
+ }
+ return SZ_OK;
+}
diff --git a/src/libs/7zip/unix/C/LzmaUtil/Lzma86Dec.h b/src/libs/7zip/unix/C/LzmaUtil/Lzma86Dec.h
new file mode 100644
index 000000000..138ce1ff7
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzmaUtil/Lzma86Dec.h
@@ -0,0 +1,51 @@
+/* Lzma86Dec.h -- LZMA + x86 (BCJ) Filter Decoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA86_DEC_H
+#define __LZMA86_DEC_H
+
+#include "../Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Lzma86_GetUnpackSize:
+ In:
+ src - input data
+ srcLen - input data size
+ Out:
+ unpackSize - size of uncompressed stream
+ Return code:
+ SZ_OK - OK
+ SZ_ERROR_INPUT_EOF - Error in headers
+*/
+
+SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize);
+
+/*
+Lzma86_Decode:
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+ Return code:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - unsupported file
+ SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer
+*/
+
+SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/LzmaUtil/Lzma86Enc.c b/src/libs/7zip/unix/C/LzmaUtil/Lzma86Enc.c
new file mode 100644
index 000000000..efc81ea35
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzmaUtil/Lzma86Enc.c
@@ -0,0 +1,113 @@
+/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
+2008-08-05
+Igor Pavlov
+Public domain */
+
+#include <string.h>
+
+#include "Lzma86Enc.h"
+
+#include "../Alloc.h"
+#include "../Bra.h"
+#include "../LzmaEnc.h"
+
+#define SZE_OUT_OVERFLOW SZE_DATA_ERROR
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+#define LZMA86_SIZE_OFFSET (1 + LZMA_PROPS_SIZE)
+#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
+
+int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
+ int level, UInt32 dictSize, int filterMode)
+{
+ size_t outSize2 = *destLen;
+ Byte *filteredStream;
+ Bool useFilter;
+ int mainResult = SZ_ERROR_OUTPUT_EOF;
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ props.level = level;
+ props.dictSize = dictSize;
+
+ *destLen = 0;
+ if (outSize2 < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ {
+ int i;
+ UInt64 t = srcLen;
+ for (i = 0; i < 8; i++, t >>= 8)
+ dest[LZMA86_SIZE_OFFSET + i] = (Byte)t;
+ }
+
+ filteredStream = 0;
+ useFilter = (filterMode != SZ_FILTER_NO);
+ if (useFilter)
+ {
+ if (srcLen != 0)
+ {
+ filteredStream = (Byte *)MyAlloc(srcLen);
+ if (filteredStream == 0)
+ return SZ_ERROR_MEM;
+ memcpy(filteredStream, src, srcLen);
+ }
+ {
+ UInt32 x86State;
+ x86_Convert_Init(x86State);
+ x86_Convert(filteredStream, srcLen, 0, &x86State, 1);
+ }
+ }
+
+ {
+ size_t minSize = 0;
+ Bool bestIsFiltered = False;
+
+ /* passes for SZ_FILTER_AUTO:
+ 0 - BCJ + LZMA
+ 1 - LZMA
+ 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better.
+ */
+ int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1;
+
+ int i;
+ for (i = 0; i < numPasses; i++)
+ {
+ size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE;
+ size_t outPropsSize = 5;
+ SRes curRes;
+ Bool curModeIsFiltered = (numPasses > 1 && i == numPasses - 1);
+ if (curModeIsFiltered && !bestIsFiltered)
+ break;
+ if (useFilter && i == 0)
+ curModeIsFiltered = True;
+
+ curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed,
+ curModeIsFiltered ? filteredStream : src, srcLen,
+ &props, dest + 1, &outPropsSize, 0,
+ NULL, &g_Alloc, &g_Alloc);
+
+ if (curRes != SZ_ERROR_OUTPUT_EOF)
+ {
+ if (curRes != SZ_OK)
+ {
+ mainResult = curRes;
+ break;
+ }
+ if (outSizeProcessed <= minSize || mainResult != SZ_OK)
+ {
+ minSize = outSizeProcessed;
+ bestIsFiltered = curModeIsFiltered;
+ mainResult = SZ_OK;
+ }
+ }
+ }
+ dest[0] = (bestIsFiltered ? 1 : 0);
+ *destLen = LZMA86_HEADER_SIZE + minSize;
+ }
+ if (useFilter)
+ MyFree(filteredStream);
+ return mainResult;
+}
diff --git a/src/libs/7zip/unix/C/LzmaUtil/Lzma86Enc.h b/src/libs/7zip/unix/C/LzmaUtil/Lzma86Enc.h
new file mode 100644
index 000000000..355bf343c
--- /dev/null
+++ b/src/libs/7zip/unix/C/LzmaUtil/Lzma86Enc.h
@@ -0,0 +1,78 @@
+/* Lzma86Enc.h -- LZMA + x86 (BCJ) Filter Encoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA86_ENC_H
+#define __LZMA86_ENC_H
+
+#include "../Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+It's an example for LZMA + x86 Filter use.
+You can use .lzma86 extension, if you write that stream to file.
+.lzma86 header adds one additional byte to standard .lzma header.
+.lzma86 header (14 bytes):
+ Offset Size Description
+ 0 1 = 0 - no filter,
+ = 1 - x86 filter
+ 1 1 lc, lp and pb in encoded form
+ 2 4 dictSize (little endian)
+ 6 8 uncompressed size (little endian)
+
+
+Lzma86_Encode
+-------------
+level - compression level: 0 <= level <= 9, the default value for "level" is 5.
+
+
+dictSize - The dictionary size in bytes. The maximum value is
+ 128 MB = (1 << 27) bytes for 32-bit version
+ 1 GB = (1 << 30) bytes for 64-bit version
+ The default value is 16 MB = (1 << 24) bytes, for level = 5.
+ It's recommended to use the dictionary that is larger than 4 KB and
+ that can be calculated as (1 << N) or (3 << N) sizes.
+ For better compression ratio dictSize must be >= inSize.
+
+filterMode:
+ SZ_FILTER_NO - no Filter
+ SZ_FILTER_YES - x86 Filter
+ SZ_FILTER_AUTO - it tries both alternatives to select best.
+ Encoder will use 2 or 3 passes:
+ 2 passes when FILTER_NO provides better compression.
+ 3 passes when FILTER_YES provides better compression.
+
+Lzma86Encode allocates Data with MyAlloc functions.
+RAM Requirements for compressing:
+ RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize
+ filterMode FilterBlockSize
+ SZ_FILTER_NO 0
+ SZ_FILTER_YES inSize
+ SZ_FILTER_AUTO inSize
+
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+enum ESzFilterMode
+{
+ SZ_FILTER_NO,
+ SZ_FILTER_YES,
+ SZ_FILTER_AUTO
+};
+
+SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
+ int level, UInt32 dictSize, int filterMode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/MtCoder.c b/src/libs/7zip/unix/C/MtCoder.c
new file mode 100644
index 000000000..946fbbc70
--- /dev/null
+++ b/src/libs/7zip/unix/C/MtCoder.c
@@ -0,0 +1,327 @@
+/* MtCoder.c -- Multi-thread Coder
+2010-09-24 : Igor Pavlov : Public domain */
+
+#include <stdio.h>
+
+#include "MtCoder.h"
+
+void LoopThread_Construct(CLoopThread *p)
+{
+ Thread_Construct(&p->thread);
+ Event_Construct(&p->startEvent);
+ Event_Construct(&p->finishedEvent);
+}
+
+void LoopThread_Close(CLoopThread *p)
+{
+ Thread_Close(&p->thread);
+ Event_Close(&p->startEvent);
+ Event_Close(&p->finishedEvent);
+}
+
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE LoopThreadFunc(void *pp)
+{
+ CLoopThread *p = (CLoopThread *)pp;
+ for (;;)
+ {
+ if (Event_Wait(&p->startEvent) != 0)
+ return SZ_ERROR_THREAD;
+ if (p->stop)
+ return 0;
+ p->res = p->func(p->param);
+ if (Event_Set(&p->finishedEvent) != 0)
+ return SZ_ERROR_THREAD;
+ }
+}
+
+WRes LoopThread_Create(CLoopThread *p)
+{
+ p->stop = 0;
+ RINOK(AutoResetEvent_CreateNotSignaled(&p->startEvent));
+ RINOK(AutoResetEvent_CreateNotSignaled(&p->finishedEvent));
+ return Thread_Create(&p->thread, LoopThreadFunc, p);
+}
+
+WRes LoopThread_StopAndWait(CLoopThread *p)
+{
+ p->stop = 1;
+ if (Event_Set(&p->startEvent) != 0)
+ return SZ_ERROR_THREAD;
+ return Thread_Wait(&p->thread);
+}
+
+WRes LoopThread_StartSubThread(CLoopThread *p) { return Event_Set(&p->startEvent); }
+WRes LoopThread_WaitSubThread(CLoopThread *p) { return Event_Wait(&p->finishedEvent); }
+
+static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
+{
+ return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
+}
+
+static void MtProgress_Init(CMtProgress *p, ICompressProgress *progress)
+{
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ p->inSizes[i] = p->outSizes[i] = 0;
+ p->totalInSize = p->totalOutSize = 0;
+ p->progress = progress;
+ p->res = SZ_OK;
+}
+
+static void MtProgress_Reinit(CMtProgress *p, unsigned index)
+{
+ p->inSizes[index] = 0;
+ p->outSizes[index] = 0;
+}
+
+#define UPDATE_PROGRESS(size, prev, total) \
+ if (size != (UInt64)(Int64)-1) { total += size - prev; prev = size; }
+
+SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize)
+{
+ SRes res;
+ CriticalSection_Enter(&p->cs);
+ UPDATE_PROGRESS(inSize, p->inSizes[index], p->totalInSize)
+ UPDATE_PROGRESS(outSize, p->outSizes[index], p->totalOutSize)
+ if (p->res == SZ_OK)
+ p->res = Progress(p->progress, p->totalInSize, p->totalOutSize);
+ res = p->res;
+ CriticalSection_Leave(&p->cs);
+ return res;
+}
+
+static void MtProgress_SetError(CMtProgress *p, SRes res)
+{
+ CriticalSection_Enter(&p->cs);
+ if (p->res == SZ_OK)
+ p->res = res;
+ CriticalSection_Leave(&p->cs);
+}
+
+static void MtCoder_SetError(CMtCoder* p, SRes res)
+{
+ CriticalSection_Enter(&p->cs);
+ if (p->res == SZ_OK)
+ p->res = res;
+ CriticalSection_Leave(&p->cs);
+}
+
+/* ---------- MtThread ---------- */
+
+void CMtThread_Construct(CMtThread *p, CMtCoder *mtCoder)
+{
+ p->mtCoder = mtCoder;
+ p->outBuf = 0;
+ p->inBuf = 0;
+ Event_Construct(&p->canRead);
+ Event_Construct(&p->canWrite);
+ LoopThread_Construct(&p->thread);
+}
+
+#define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; }
+
+static void CMtThread_CloseEvents(CMtThread *p)
+{
+ Event_Close(&p->canRead);
+ Event_Close(&p->canWrite);
+}
+
+static void CMtThread_Destruct(CMtThread *p)
+{
+ CMtThread_CloseEvents(p);
+
+ if (Thread_WasCreated(&p->thread.thread))
+ {
+ LoopThread_StopAndWait(&p->thread);
+ LoopThread_Close(&p->thread);
+ }
+
+ if (p->mtCoder->alloc)
+ IAlloc_Free(p->mtCoder->alloc, p->outBuf);
+ p->outBuf = 0;
+
+ if (p->mtCoder->alloc)
+ IAlloc_Free(p->mtCoder->alloc, p->inBuf);
+ p->inBuf = 0;
+}
+
+#define MY_BUF_ALLOC(buf, size, newSize) \
+ if (buf == 0 || size != newSize) \
+ { IAlloc_Free(p->mtCoder->alloc, buf); \
+ size = newSize; buf = (Byte *)IAlloc_Alloc(p->mtCoder->alloc, size); \
+ if (buf == 0) return SZ_ERROR_MEM; }
+
+static SRes CMtThread_Prepare(CMtThread *p)
+{
+ MY_BUF_ALLOC(p->inBuf, p->inBufSize, p->mtCoder->blockSize)
+ MY_BUF_ALLOC(p->outBuf, p->outBufSize, p->mtCoder->destBlockSize)
+
+ p->stopReading = False;
+ p->stopWriting = False;
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canRead));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canWrite));
+
+ return SZ_OK;
+}
+
+static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize)
+{
+ size_t size = *processedSize;
+ *processedSize = 0;
+ while (size != 0)
+ {
+ size_t curSize = size;
+ SRes res = stream->Read(stream, data, &curSize);
+ *processedSize += curSize;
+ data += curSize;
+ size -= curSize;
+ RINOK(res);
+ if (curSize == 0)
+ return SZ_OK;
+ }
+ return SZ_OK;
+}
+
+#define GET_NEXT_THREAD(p) &p->mtCoder->threads[p->index == p->mtCoder->numThreads - 1 ? 0 : p->index + 1]
+
+static SRes MtThread_Process(CMtThread *p, Bool *stop)
+{
+ CMtThread *next;
+ *stop = True;
+ if (Event_Wait(&p->canRead) != 0)
+ return SZ_ERROR_THREAD;
+
+ next = GET_NEXT_THREAD(p);
+
+ if (p->stopReading)
+ {
+ next->stopReading = True;
+ return Event_Set(&next->canRead) == 0 ? SZ_OK : SZ_ERROR_THREAD;
+ }
+
+ {
+ size_t size = p->mtCoder->blockSize;
+ size_t destSize = p->outBufSize;
+
+ RINOK(FullRead(p->mtCoder->inStream, p->inBuf, &size));
+ next->stopReading = *stop = (size != p->mtCoder->blockSize);
+ if (Event_Set(&next->canRead) != 0)
+ return SZ_ERROR_THREAD;
+
+ RINOK(p->mtCoder->mtCallback->Code(p->mtCoder->mtCallback, p->index,
+ p->outBuf, &destSize, p->inBuf, size, *stop));
+
+ MtProgress_Reinit(&p->mtCoder->mtProgress, p->index);
+
+ if (Event_Wait(&p->canWrite) != 0)
+ return SZ_ERROR_THREAD;
+ if (p->stopWriting)
+ return SZ_ERROR_FAIL;
+ if (p->mtCoder->outStream->Write(p->mtCoder->outStream, p->outBuf, destSize) != destSize)
+ return SZ_ERROR_WRITE;
+ return Event_Set(&next->canWrite) == 0 ? SZ_OK : SZ_ERROR_THREAD;
+ }
+}
+
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp)
+{
+ CMtThread *p = (CMtThread *)pp;
+ for (;;)
+ {
+ Bool stop;
+ CMtThread *next = GET_NEXT_THREAD(p);
+ SRes res = MtThread_Process(p, &stop);
+ if (res != SZ_OK)
+ {
+ MtCoder_SetError(p->mtCoder, res);
+ MtProgress_SetError(&p->mtCoder->mtProgress, res);
+ next->stopReading = True;
+ next->stopWriting = True;
+ Event_Set(&next->canRead);
+ Event_Set(&next->canWrite);
+ return res;
+ }
+ if (stop)
+ return 0;
+ }
+}
+
+void MtCoder_Construct(CMtCoder* p)
+{
+ unsigned i;
+ p->alloc = 0;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ t->index = i;
+ CMtThread_Construct(t, p);
+ }
+ CriticalSection_Init(&p->cs);
+ CriticalSection_Init(&p->mtProgress.cs);
+}
+
+void MtCoder_Destruct(CMtCoder* p)
+{
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ CMtThread_Destruct(&p->threads[i]);
+ CriticalSection_Delete(&p->cs);
+ CriticalSection_Delete(&p->mtProgress.cs);
+}
+
+SRes MtCoder_Code(CMtCoder *p)
+{
+ unsigned i, numThreads = p->numThreads;
+ SRes res = SZ_OK;
+ p->res = SZ_OK;
+
+ MtProgress_Init(&p->mtProgress, p->progress);
+
+ for (i = 0; i < numThreads; i++)
+ {
+ RINOK(CMtThread_Prepare(&p->threads[i]));
+ }
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ CLoopThread *lt = &t->thread;
+
+ if (!Thread_WasCreated(&lt->thread))
+ {
+ lt->func = ThreadFunc;
+ lt->param = t;
+
+ if (LoopThread_Create(lt) != SZ_OK)
+ {
+ res = SZ_ERROR_THREAD;
+ break;
+ }
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ unsigned j;
+ for (i = 0; i < numThreads; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ if (LoopThread_StartSubThread(&t->thread) != SZ_OK)
+ {
+ res = SZ_ERROR_THREAD;
+ p->threads[0].stopReading = True;
+ break;
+ }
+ }
+
+ Event_Set(&p->threads[0].canWrite);
+ Event_Set(&p->threads[0].canRead);
+
+ for (j = 0; j < i; j++)
+ LoopThread_WaitSubThread(&p->threads[j].thread);
+ }
+
+ for (i = 0; i < numThreads; i++)
+ CMtThread_CloseEvents(&p->threads[i]);
+ return (res == SZ_OK) ? p->res : res;
+}
diff --git a/src/libs/7zip/unix/C/MtCoder.h b/src/libs/7zip/unix/C/MtCoder.h
new file mode 100644
index 000000000..f0f06da28
--- /dev/null
+++ b/src/libs/7zip/unix/C/MtCoder.h
@@ -0,0 +1,98 @@
+/* MtCoder.h -- Multi-thread Coder
+2009-11-19 : Igor Pavlov : Public domain */
+
+#ifndef __MT_CODER_H
+#define __MT_CODER_H
+
+#include "Threads.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ CThread thread;
+ CAutoResetEvent startEvent;
+ CAutoResetEvent finishedEvent;
+ int stop;
+
+ THREAD_FUNC_TYPE func;
+ LPVOID param;
+ THREAD_FUNC_RET_TYPE res;
+} CLoopThread;
+
+void LoopThread_Construct(CLoopThread *p);
+void LoopThread_Close(CLoopThread *p);
+WRes LoopThread_Create(CLoopThread *p);
+WRes LoopThread_StopAndWait(CLoopThread *p);
+WRes LoopThread_StartSubThread(CLoopThread *p);
+WRes LoopThread_WaitSubThread(CLoopThread *p);
+
+#ifndef _7ZIP_ST
+#define NUM_MT_CODER_THREADS_MAX 32
+#else
+#define NUM_MT_CODER_THREADS_MAX 1
+#endif
+
+typedef struct
+{
+ UInt64 totalInSize;
+ UInt64 totalOutSize;
+ ICompressProgress *progress;
+ SRes res;
+ CCriticalSection cs;
+ UInt64 inSizes[NUM_MT_CODER_THREADS_MAX];
+ UInt64 outSizes[NUM_MT_CODER_THREADS_MAX];
+} CMtProgress;
+
+SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize);
+
+struct _CMtCoder;
+
+typedef struct
+{
+ struct _CMtCoder *mtCoder;
+ Byte *outBuf;
+ size_t outBufSize;
+ Byte *inBuf;
+ size_t inBufSize;
+ unsigned index;
+ CLoopThread thread;
+
+ Bool stopReading;
+ Bool stopWriting;
+ CAutoResetEvent canRead;
+ CAutoResetEvent canWrite;
+} CMtThread;
+
+typedef struct
+{
+ SRes (*Code)(void *p, unsigned index, Byte *dest, size_t *destSize,
+ const Byte *src, size_t srcSize, int finished);
+} IMtCoderCallback;
+
+typedef struct _CMtCoder
+{
+ size_t blockSize;
+ size_t destBlockSize;
+ unsigned numThreads;
+
+ ISeqInStream *inStream;
+ ISeqOutStream *outStream;
+ ICompressProgress *progress;
+ ISzAlloc *alloc;
+
+ IMtCoderCallback *mtCallback;
+ CCriticalSection cs;
+ SRes res;
+
+ CMtProgress mtProgress;
+ CMtThread threads[NUM_MT_CODER_THREADS_MAX];
+} CMtCoder;
+
+void MtCoder_Construct(CMtCoder* p);
+void MtCoder_Destruct(CMtCoder* p);
+SRes MtCoder_Code(CMtCoder *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/Ppmd.h b/src/libs/7zip/unix/C/Ppmd.h
new file mode 100644
index 000000000..621d92703
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd.h
@@ -0,0 +1,85 @@
+/* Ppmd.h -- PPMD codec common code
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#ifndef __PPMD_H
+#define __PPMD_H
+
+#include "Types.h"
+#include "CpuArch.h"
+
+EXTERN_C_BEGIN
+
+#ifdef MY_CPU_32BIT
+ #define PPMD_32BIT
+#endif
+
+#define PPMD_INT_BITS 7
+#define PPMD_PERIOD_BITS 7
+#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
+
+#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
+#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
+#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
+#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
+
+#define PPMD_N1 4
+#define PPMD_N2 4
+#define PPMD_N3 4
+#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
+#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
+
+#pragma pack(push,1)
+
+/* SEE-contexts for PPM-contexts with masked symbols */
+typedef struct
+{
+ UInt16 Summ; /* Freq */
+ Byte Shift; /* Speed of Freq change; low Shift is for fast change */
+ Byte Count; /* Count to next change of Shift */
+} CPpmd_See;
+
+#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
+ { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
+
+typedef struct
+{
+ Byte Symbol;
+ Byte Freq;
+ UInt16 SuccessorLow;
+ UInt16 SuccessorHigh;
+} CPpmd_State;
+
+#pragma pack(pop)
+
+typedef
+ #ifdef PPMD_32BIT
+ CPpmd_State *
+ #else
+ UInt32
+ #endif
+ CPpmd_State_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ void *
+ #else
+ UInt32
+ #endif
+ CPpmd_Void_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ Byte *
+ #else
+ UInt32
+ #endif
+ CPpmd_Byte_Ref;
+
+#define PPMD_SetAllBitsIn256Bytes(p) \
+ { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \
+ p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }}
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/Ppmd7.c b/src/libs/7zip/unix/C/Ppmd7.c
new file mode 100644
index 000000000..060d86d2e
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd7.c
@@ -0,0 +1,708 @@
+/* Ppmd7.c -- PPMdH codec
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include <memory.h>
+
+#include "Ppmd7.h"
+
+const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(nu) - 1])
+#define I2U(indx) (p->Indx2Units[indx])
+
+#ifdef PPMD_32BIT
+ #define REF(ptr) (ptr)
+#else
+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
+#endif
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+#define STATS(ctx) Ppmd7_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+typedef CPpmd7_Context * CTX_PTR;
+
+struct CPpmd7_Node_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Node_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Node_Ref;
+
+typedef struct CPpmd7_Node_
+{
+ UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
+ UInt16 NU;
+ CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
+ CPpmd7_Node_Ref Prev;
+} CPpmd7_Node;
+
+#ifdef PPMD_32BIT
+ #define NODE(ptr) (ptr)
+#else
+ #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))
+#endif
+
+void Ppmd7_Construct(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = 0;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while(--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 3; i++)
+ p->NS2Indx[i] = (Byte)i;
+ for (m = i, k = 1; i < 256; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 2;
+ }
+
+ memset(p->HB2Flag, 0, 0x40);
+ memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
+}
+
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = 0;
+}
+
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
+{
+ if (p->Base == 0 || p->Size != size)
+ {
+ Ppmd7_Free(p, alloc);
+ p->AlignOffset =
+ #ifdef PPMD_32BIT
+ (4 - size) & 3;
+ #else
+ 4 - (size & 3);
+ #endif
+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size
+ #ifndef PPMD_32BIT
+ + UNIT_SIZE
+ #endif
+ )) == 0)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+static void InsertNode(CPpmd7 *p, void *node, unsigned indx)
+{
+ *((CPpmd_Void_Ref *)node) = p->FreeList[indx];
+ p->FreeList[indx] = REF(node);
+}
+
+static void *RemoveNode(CPpmd7 *p, unsigned indx)
+{
+ CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
+ p->FreeList[indx] = *node;
+ return node;
+}
+
+static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ InsertNode(p, ptr, i);
+}
+
+static void GlueFreeBlocks(CPpmd7 *p)
+{
+ #ifdef PPMD_32BIT
+ CPpmd7_Node headItem;
+ CPpmd7_Node_Ref head = &headItem;
+ #else
+ CPpmd7_Node_Ref head = p->AlignOffset + p->Size;
+ #endif
+
+ CPpmd7_Node_Ref n = head;
+ unsigned i;
+
+ p->GlueCount = 255;
+
+ /* create doubly-linked list of free blocks */
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ UInt16 nu = I2U(i);
+ CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ CPpmd7_Node *node = NODE(next);
+ node->Next = n;
+ n = NODE(n)->Prev = next;
+ next = *(const CPpmd7_Node_Ref *)node;
+ node->Stamp = 0;
+ node->NU = (UInt16)nu;
+ }
+ }
+ NODE(head)->Stamp = 1;
+ NODE(head)->Next = n;
+ NODE(n)->Prev = head;
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;
+
+ /* Glue free blocks */
+ while (n != head)
+ {
+ CPpmd7_Node *node = NODE(n);
+ UInt32 nu = (UInt32)node->NU;
+ for (;;)
+ {
+ CPpmd7_Node *node2 = NODE(n) + nu;
+ nu += node2->NU;
+ if (node2->Stamp != 0 || nu >= 0x10000)
+ break;
+ NODE(node2->Prev)->Next = node2->Next;
+ NODE(node2->Next)->Prev = node2->Prev;
+ node->NU = (UInt16)nu;
+ }
+ n = node->Next;
+ }
+
+ /* Fill lists of free blocks */
+ for (n = NODE(head)->Next; n != head;)
+ {
+ CPpmd7_Node *node = NODE(n);
+ unsigned nu;
+ CPpmd7_Node_Ref next = node->Next;
+ for (nu = node->NU; nu > 128; nu -= 128, node += 128)
+ InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, node + k, nu - k - 1);
+ }
+ InsertNode(p, node, i);
+ n = next;
+ }
+}
+
+static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)
+{
+ unsigned i;
+ void *retVal;
+ if (p->GlueCount == 0)
+ {
+ GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ }
+ i = indx;
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ p->GlueCount--;
+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
+ }
+ }
+ while (p->FreeList[i] == 0);
+ retVal = RemoveNode(p, i);
+ SplitBlock(p, retVal, i, indx);
+ return retVal;
+}
+
+static void *AllocUnits(CPpmd7 *p, unsigned indx)
+{
+ UInt32 numBytes;
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ numBytes = U2B(I2U(indx));
+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
+ {
+ void *retVal = p->LoUnit;
+ p->LoUnit += numBytes;
+ return retVal;
+ }
+ return AllocUnitsRare(p, indx);
+}
+
+#define MyMem12Cpy(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }
+
+static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = RemoveNode(p, i1);
+ MyMem12Cpy(ptr, oldPtr, newNU);
+ InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+
+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
+
+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
+}
+
+static void RestartModel(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+ p->Text = p->Base + p->AlignOffset;
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ p->MinContext->Suffix = 0;
+ p->MinContext->NumStats = 256;
+ p->MinContext->SummFreq = 256 + 1;
+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+ p->LoUnit += U2B(256 / 2);
+ p->MinContext->Stats = REF(p->FoundState);
+ for (i = 0; i < 256; i++)
+ {
+ CPpmd_State *s = &p->FoundState[i];
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ SetSuccessor(s, 0);
+ }
+
+ for (i = 0; i < 128; i++)
+ for (k = 0; k < 8; k++)
+ {
+ UInt16 *dest = p->BinSumm[i] + k;
+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));
+ for (m = 0; m < 64; m += 8)
+ dest[m] = val;
+ }
+
+ for (i = 0; i < 25; i++)
+ for (k = 0; k < 16; k++)
+ {
+ CPpmd_See *s = &p->See[i][k];
+ s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));
+ s->Count = 4;
+ }
+}
+
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
+{
+ p->MaxOrder = maxOrder;
+ RestartModel(p);
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Count = 64; /* unused */
+}
+
+static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
+{
+ CPpmd_State upState;
+ CTX_PTR c = p->MinContext;
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ CPpmd_State *ps[PPMD7_MAX_ORDER];
+ unsigned numPs = 0;
+
+ if (!skip)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+ if (c->NumStats != 1)
+ {
+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
+ }
+ else
+ s = ONE_STATE(c);
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+ c = CTX(successor);
+ if (numPs == 0)
+ return c;
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+ upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
+ SetSuccessor(&upState, upBranch + 1);
+
+ if (c->NumStats == 1)
+ upState.Freq = ONE_STATE(c)->Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != upState.Symbol; s++);
+ cf = s->Freq - 1;
+ s0 = c->SummFreq - c->NumStats - cf;
+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
+ }
+
+ do
+ {
+ /* Create Child */
+ CTX_PTR c1; /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (CTX_PTR)RemoveNode(p, 0);
+ else
+ {
+ c1 = (CTX_PTR)AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+ c1->NumStats = 1;
+ *ONE_STATE(c1) = upState;
+ c1->Suffix = REF(c);
+ SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
+{
+ CPpmd_State tmp = *t1;
+ *t1 = *t2;
+ *t2 = tmp;
+}
+
+static void UpdateModel(CPpmd7 *p)
+{
+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
+ CTX_PTR c;
+ unsigned s0, ns;
+
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 1)
+ {
+ CPpmd_State *s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ CPpmd_State *s = STATS(c);
+ if (s->Symbol != p->FoundState->Symbol)
+ {
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ s--;
+ }
+ }
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ }
+
+ if (p->OrderFall == 0)
+ {
+ p->MinContext = p->MaxContext = CreateSuccessors(p, True);
+ if (p->MinContext == 0)
+ {
+ RestartModel(p);
+ return;
+ }
+ SetSuccessor(p->FoundState, REF(p->MinContext));
+ return;
+ }
+
+ *p->Text++ = p->FoundState->Symbol;
+ successor = REF(p->Text);
+ if (p->Text >= p->UnitsStart)
+ {
+ RestartModel(p);
+ return;
+ }
+
+ if (fSuccessor)
+ {
+ if (fSuccessor <= successor)
+ {
+ CTX_PTR cs = CreateSuccessors(p, False);
+ if (cs == NULL)
+ {
+ RestartModel(p);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+ if (--p->OrderFall == 0)
+ {
+ successor = fSuccessor;
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ }
+ else
+ {
+ SetSuccessor(p->FoundState, successor);
+ fSuccessor = REF(p->MinContext);
+ }
+
+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);
+
+ for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))
+ {
+ unsigned ns1;
+ UInt32 cf, sf;
+ if ((ns1 = c->NumStats) != 1)
+ {
+ if ((ns1 & 1) == 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = ns1 >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I(oldNU + 1))
+ {
+ void *ptr = AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ RestartModel(p);
+ return;
+ }
+ oldPtr = STATS(c);
+ MyMem12Cpy(ptr, oldPtr, oldNU);
+ InsertNode(p, oldPtr, i);
+ c->Stats = STATS_REF(ptr);
+ }
+ }
+ c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));
+ }
+ else
+ {
+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
+ if (!s)
+ {
+ RestartModel(p);
+ return;
+ }
+ *s = *ONE_STATE(c);
+ c->Stats = REF(s);
+ if (s->Freq < MAX_FREQ / 4 - 1)
+ s->Freq <<= 1;
+ else
+ s->Freq = MAX_FREQ - 4;
+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));
+ }
+ cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);
+ sf = (UInt32)s0 + c->SummFreq;
+ if (cf < 6 * sf)
+ {
+ cf = 1 + (cf > sf) + (cf >= 4 * sf);
+ c->SummFreq += 3;
+ }
+ else
+ {
+ cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
+ c->SummFreq = (UInt16)(c->SummFreq + cf);
+ }
+ {
+ CPpmd_State *s = STATS(c) + ns1;
+ SetSuccessor(s, successor);
+ s->Symbol = p->FoundState->Symbol;
+ s->Freq = (Byte)cf;
+ c->NumStats = (UInt16)(ns1 + 1);
+ }
+ }
+ p->MaxContext = p->MinContext = CTX(fSuccessor);
+}
+
+static void Rescale(CPpmd7 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+ {
+ CPpmd_State tmp = *s;
+ for (; s != stats; s--)
+ s[0] = s[-1];
+ *s = tmp;
+ }
+ escFreq = p->MinContext->SummFreq - s->Freq;
+ s->Freq += 4;
+ adder = (p->OrderFall != 0);
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq = s->Freq;
+
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ escFreq -= (++s)->Freq;
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq += s->Freq;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ CPpmd_State *s1 = s;
+ CPpmd_State tmp = *s1;
+ do
+ s1[0] = s1[-1];
+ while (--s1 != stats && tmp.Freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ unsigned numStats = p->MinContext->NumStats;
+ unsigned n0, n1;
+ do { i++; } while ((--s)->Freq == 0);
+ escFreq += i;
+ p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);
+ if (p->MinContext->NumStats == 1)
+ {
+ CPpmd_State tmp = *stats;
+ do
+ {
+ tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));
+ escFreq >>= 1;
+ }
+ while (escFreq > 1);
+ InsertNode(p, stats, U2I(((numStats + 1) >> 1)));
+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
+ return;
+ }
+ n0 = (numStats + 1) >> 1;
+ n1 = (p->MinContext->NumStats + 1) >> 1;
+ if (n0 != n1)
+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ }
+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ p->FoundState = STATS(p->MinContext);
+}
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ unsigned nonMasked = p->MinContext->NumStats - numMasked;
+ if (p->MinContext->NumStats != 256)
+ {
+ see = p->See[p->NS2Indx[nonMasked - 1]] +
+ (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
+ 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
+ 4 * (numMasked > nonMasked) +
+ p->HiBitsFlag;
+ {
+ unsigned r = (see->Summ >> see->Shift);
+ see->Summ = (UInt16)(see->Summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+static void NextContext(CPpmd7 *p)
+{
+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (Byte *)c > p->Text)
+ p->MinContext = p->MaxContext = c;
+ else
+ UpdateModel(p);
+}
+
+void Ppmd7_Update1(CPpmd7 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ s->Freq += 4;
+ p->MinContext->SummFreq += 4;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ p->FoundState = --s;
+ if (s->Freq > MAX_FREQ)
+ Rescale(p);
+ }
+ NextContext(p);
+}
+
+void Ppmd7_Update1_0(CPpmd7 *p)
+{
+ p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
+ p->RunLength += p->PrevSuccess;
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ NextContext(p);
+}
+
+void Ppmd7_UpdateBin(CPpmd7 *p)
+{
+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ NextContext(p);
+}
+
+void Ppmd7_Update2(CPpmd7 *p)
+{
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ p->RunLength = p->InitRL;
+ UpdateModel(p);
+}
diff --git a/src/libs/7zip/unix/C/Ppmd7.h b/src/libs/7zip/unix/C/Ppmd7.h
new file mode 100644
index 000000000..96521c31f
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd7.h
@@ -0,0 +1,140 @@
+/* Ppmd7.h -- PPMdH compression codec
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+/* This code supports virtual RangeDecoder and includes the implementation
+of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.
+If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */
+
+#ifndef __PPMD7_H
+#define __PPMD7_H
+
+#include "Ppmd.h"
+
+EXTERN_C_BEGIN
+
+#define PPMD7_MIN_ORDER 2
+#define PPMD7_MAX_ORDER 64
+
+#define PPMD7_MIN_MEM_SIZE (1 << 11)
+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
+
+struct CPpmd7_Context_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Context_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Context_Ref;
+
+typedef struct CPpmd7_Context_
+{
+ UInt16 NumStats;
+ UInt16 SummFreq;
+ CPpmd_State_Ref Stats;
+ CPpmd7_Context_Ref Suffix;
+} CPpmd7_Context;
+
+#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
+
+typedef struct
+{
+ CPpmd7_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+ UInt32 AlignOffset;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES];
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+ Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
+ CPpmd_See DummySee, See[25][16];
+ UInt16 BinSumm[128][64];
+} CPpmd7;
+
+void Ppmd7_Construct(CPpmd7 *p);
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc);
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
+#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
+
+
+/* ---------- Internal Functions ---------- */
+
+extern const Byte PPMD7_kExpEscape[16];
+
+#ifdef PPMD_32BIT
+ #define Ppmd7_GetPtr(p, ptr) (ptr)
+ #define Ppmd7_GetContext(p, ptr) (ptr)
+ #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)
+#else
+ #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
+ #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))
+ #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))
+#endif
+
+void Ppmd7_Update1(CPpmd7 *p);
+void Ppmd7_Update1_0(CPpmd7 *p);
+void Ppmd7_Update2(CPpmd7 *p);
+void Ppmd7_UpdateBin(CPpmd7 *p);
+
+#define Ppmd7_GetBinSumm(p) \
+ &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
+ p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
+ (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
+ 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \
+ ((p->RunLength >> 26) & 0x20)]
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
+
+
+/* ---------- Decode ---------- */
+
+typedef struct
+{
+ UInt32 (*GetThreshold)(void *p, UInt32 total);
+ void (*Decode)(void *p, UInt32 start, UInt32 size);
+ UInt32 (*DecodeBit)(void *p, UInt32 size0);
+} IPpmd7_RangeDec;
+
+typedef struct
+{
+ IPpmd7_RangeDec p;
+ UInt32 Range;
+ UInt32 Code;
+ IByteIn *Stream;
+} CPpmd7z_RangeDec;
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p);
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p);
+#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc);
+
+
+/* ---------- Encode ---------- */
+
+typedef struct
+{
+ UInt64 Low;
+ UInt32 Range;
+ Byte Cache;
+ UInt64 CacheSize;
+ IByteOut *Stream;
+} CPpmd7z_RangeEnc;
+
+void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p);
+void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p);
+
+void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/Ppmd7Dec.c b/src/libs/7zip/unix/C/Ppmd7Dec.c
new file mode 100644
index 000000000..68438d5ce
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd7Dec.c
@@ -0,0 +1,187 @@
+/* Ppmd7Dec.c -- PPMdH Decoder
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Ppmd7.h"
+
+#define kTopValue (1 << 24)
+
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
+{
+ unsigned i;
+ p->Code = 0;
+ p->Range = 0xFFFFFFFF;
+ if (p->Stream->Read((void *)p->Stream) != 0)
+ return False;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ return (p->Code) / (p->Range /= total);
+}
+
+static void Range_Normalize(CPpmd7z_RangeDec *p)
+{
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ }
+ }
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ p->Code -= start * p->Range;
+ p->Range *= size;
+ Range_Normalize(p);
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ UInt32 newBound = (p->Range >> 14) * size0;
+ UInt32 symbol;
+ if (p->Code < newBound)
+ {
+ symbol = 0;
+ p->Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ p->Code -= newBound;
+ p->Range -= newBound;
+ }
+ Range_Normalize(p);
+ return symbol;
+}
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
+{
+ p->p.GetThreshold = Range_GetThreshold;
+ p->p.Decode = Range_Decode;
+ p->p.DecodeBit = Range_DecodeBit;
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
+ {
+ Byte symbol;
+ rc->Decode(rc, 0, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1_0(p);
+ return symbol;
+ }
+ p->PrevSuccess = 0;
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ if ((hiCnt += (++s)->Freq) > count)
+ {
+ Byte symbol;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1(p);
+ return symbol;
+ }
+ }
+ while (--i);
+ if (count >= p->MinContext->SummFreq)
+ return -2;
+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
+ rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats - 1;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ if (rc->DecodeBit(rc, *prob) == 0)
+ {
+ Byte symbol;
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
+ Ppmd7_UpdateBin(p);
+ return symbol;
+ }
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ for (;;)
+ {
+ CPpmd_State *ps[256], *s;
+ UInt32 freqSum, count, hiCnt;
+ CPpmd_See *see;
+ unsigned i, num, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return -1;
+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+ hiCnt = 0;
+ s = Ppmd7_GetStats(p, p->MinContext);
+ i = 0;
+ num = p->MinContext->NumStats - numMasked;
+ do
+ {
+ int k = (int)(MASK(s->Symbol));
+ hiCnt += (s->Freq & k);
+ ps[i] = s++;
+ i -= k;
+ }
+ while (i != num);
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+ count = rc->GetThreshold(rc, freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte symbol;
+ CPpmd_State **pps = ps;
+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
+ s = *pps;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ Ppmd_See_Update(see);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update2(p);
+ return symbol;
+ }
+ if (count >= freqSum)
+ return -2;
+ rc->Decode(rc, hiCnt, freqSum - hiCnt);
+ see->Summ = (UInt16)(see->Summ + freqSum);
+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
+ }
+}
diff --git a/src/libs/7zip/unix/C/Ppmd7Enc.c b/src/libs/7zip/unix/C/Ppmd7Enc.c
new file mode 100644
index 000000000..8247757d0
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd7Enc.c
@@ -0,0 +1,185 @@
+/* Ppmd7Enc.c -- PPMdH Encoder
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Ppmd7.h"
+
+#define kTopValue (1 << 24)
+
+void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p)
+{
+ p->Low = 0;
+ p->Range = 0xFFFFFFFF;
+ p->Cache = 0;
+ p->CacheSize = 1;
+}
+
+static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
+{
+ if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0)
+ {
+ Byte temp = p->Cache;
+ do
+ {
+ p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32)));
+ temp = 0xFF;
+ }
+ while(--p->CacheSize != 0);
+ p->Cache = (Byte)((UInt32)p->Low >> 24);
+ }
+ p->CacheSize++;
+ p->Low = (UInt32)p->Low << 8;
+}
+
+static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)
+{
+ p->Low += start * (p->Range /= total);
+ p->Range *= size;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0)
+{
+ p->Range = (p->Range >> 14) * size0;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0)
+{
+ UInt32 newBound = (p->Range >> 14) * size0;
+ p->Low += newBound;
+ p->Range -= newBound;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p)
+{
+ unsigned i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ UInt32 sum;
+ unsigned i;
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd7_Update1_0(p);
+ return;
+ }
+ p->PrevSuccess = 0;
+ sum = s->Freq;
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ if ((++s)->Symbol == symbol)
+ {
+ RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd7_Update1(p);
+ return;
+ }
+ sum += s->Freq;
+ }
+ while (--i);
+
+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats - 1;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_EncodeBit_0(rc, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ p->FoundState = s;
+ Ppmd7_UpdateBin(p);
+ return;
+ }
+ else
+ {
+ RangeEnc_EncodeBit_1(rc, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ }
+ for (;;)
+ {
+ UInt32 escFreq;
+ CPpmd_See *see;
+ CPpmd_State *s;
+ UInt32 sum;
+ unsigned i, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return; /* EndMarker (symbol = -1) */
+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
+ s = Ppmd7_GetStats(p, p->MinContext);
+ sum = 0;
+ i = p->MinContext->NumStats;
+ do
+ {
+ int cur = s->Symbol;
+ if (cur == symbol)
+ {
+ UInt32 low = sum;
+ CPpmd_State *s1 = s;
+ do
+ {
+ sum += (s->Freq & (int)(MASK(s->Symbol)));
+ s++;
+ }
+ while (--i);
+ RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq);
+ Ppmd_See_Update(see);
+ p->FoundState = s1;
+ Ppmd7_Update2(p);
+ return;
+ }
+ sum += (s->Freq & (int)(MASK(cur)));
+ MASK(cur) = 0;
+ s++;
+ }
+ while (--i);
+
+ RangeEnc_Encode(rc, sum, escFreq, sum + escFreq);
+ see->Summ = (UInt16)(see->Summ + sum + escFreq);
+ }
+}
diff --git a/src/libs/7zip/unix/C/Ppmd8.c b/src/libs/7zip/unix/C/Ppmd8.c
new file mode 100644
index 000000000..9187a88ef
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd8.c
@@ -0,0 +1,1120 @@
+/* Ppmd8.c -- PPMdI codec
+2010-03-24 : Igor Pavlov : Public domain
+This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */
+
+#include <memory.h>
+
+#include "Ppmd8.h"
+
+const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(nu) - 1])
+#define I2U(indx) (p->Indx2Units[indx])
+
+#ifdef PPMD_32BIT
+ #define REF(ptr) (ptr)
+#else
+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
+#endif
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref))
+#define STATS(ctx) Ppmd8_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+typedef CPpmd8_Context * CTX_PTR;
+
+struct CPpmd8_Node_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd8_Node_ *
+ #else
+ UInt32
+ #endif
+ CPpmd8_Node_Ref;
+
+typedef struct CPpmd8_Node_
+{
+ UInt32 Stamp;
+ CPpmd8_Node_Ref Next;
+ UInt32 NU;
+} CPpmd8_Node;
+
+#ifdef PPMD_32BIT
+ #define NODE(ptr) (ptr)
+#else
+ #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs)))
+#endif
+
+#define EMPTY_NODE 0xFFFFFFFF
+
+void Ppmd8_Construct(CPpmd8 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = 0;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while(--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 5; i++)
+ p->NS2Indx[i] = (Byte)i;
+ for (m = i, k = 1; i < 260; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 4;
+ }
+}
+
+void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = 0;
+}
+
+Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc)
+{
+ if (p->Base == 0 || p->Size != size)
+ {
+ Ppmd8_Free(p, alloc);
+ p->AlignOffset =
+ #ifdef PPMD_32BIT
+ (4 - size) & 3;
+ #else
+ 4 - (size & 3);
+ #endif
+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size)) == 0)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+static void InsertNode(CPpmd8 *p, void *node, unsigned indx)
+{
+ ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE;
+ ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx];
+ ((CPpmd8_Node *)node)->NU = I2U(indx);
+ p->FreeList[indx] = REF(node);
+ p->Stamps[indx]++;
+}
+
+static void *RemoveNode(CPpmd8 *p, unsigned indx)
+{
+ CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]);
+ p->FreeList[indx] = node->Next;
+ p->Stamps[indx]--;
+ return node;
+}
+
+static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ InsertNode(p, ptr, i);
+}
+
+static void GlueFreeBlocks(CPpmd8 *p)
+{
+ CPpmd8_Node_Ref head = 0;
+ CPpmd8_Node_Ref *prev = &head;
+ unsigned i;
+
+ p->GlueCount = 1 << 13;
+ memset(p->Stamps, 0, sizeof(p->Stamps));
+
+ /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end.
+ All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd8_Node *)p->LoUnit)->Stamp = 0;
+
+ /* Glue free blocks */
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ CPpmd8_Node *node = NODE(next);
+ if (node->NU != 0)
+ {
+ CPpmd8_Node *node2;
+ *prev = next;
+ prev = &(node->Next);
+ while ((node2 = node + node->NU)->Stamp == EMPTY_NODE)
+ {
+ node->NU += node2->NU;
+ node2->NU = 0;
+ }
+ }
+ next = node->Next;
+ }
+ }
+ *prev = 0;
+
+ /* Fill lists of free blocks */
+ while (head != 0)
+ {
+ CPpmd8_Node *node = NODE(head);
+ unsigned nu;
+ head = node->Next;
+ nu = node->NU;
+ if (nu == 0)
+ continue;
+ for (; nu > 128; nu -= 128, node += 128)
+ InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, node + k, nu - k - 1);
+ }
+ InsertNode(p, node, i);
+ }
+}
+
+static void *AllocUnitsRare(CPpmd8 *p, unsigned indx)
+{
+ unsigned i;
+ void *retVal;
+ if (p->GlueCount == 0)
+ {
+ GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ }
+ i = indx;
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ p->GlueCount--;
+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
+ }
+ }
+ while (p->FreeList[i] == 0);
+ retVal = RemoveNode(p, i);
+ SplitBlock(p, retVal, i, indx);
+ return retVal;
+}
+
+static void *AllocUnits(CPpmd8 *p, unsigned indx)
+{
+ UInt32 numBytes;
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ numBytes = U2B(I2U(indx));
+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
+ {
+ void *retVal = p->LoUnit;
+ p->LoUnit += numBytes;
+ return retVal;
+ }
+ return AllocUnitsRare(p, indx);
+}
+
+#define MyMem12Cpy(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }
+
+static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = RemoveNode(p, i1);
+ MyMem12Cpy(ptr, oldPtr, newNU);
+ InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+
+static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu)
+{
+ InsertNode(p, ptr, U2I(nu));
+}
+
+static void SpecialFreeUnit(CPpmd8 *p, void *ptr)
+{
+ if ((Byte *)ptr != p->UnitsStart)
+ InsertNode(p, ptr, 0);
+ else
+ {
+ #ifdef PPMD8_FREEZE_SUPPORT
+ *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */
+ #endif
+ p->UnitsStart += UNIT_SIZE;
+ }
+}
+
+static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu)
+{
+ unsigned indx = U2I(nu);
+ void *ptr;
+ if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx])
+ return oldPtr;
+ ptr = RemoveNode(p, indx);
+ MyMem12Cpy(ptr, oldPtr, nu);
+ if ((Byte*)oldPtr != p->UnitsStart)
+ InsertNode(p, oldPtr, indx);
+ else
+ p->UnitsStart += U2B(I2U(indx));
+ return ptr;
+}
+
+static void ExpandTextArea(CPpmd8 *p)
+{
+ UInt32 count[PPMD_NUM_INDEXES];
+ unsigned i;
+ memset(count, 0, sizeof(count));
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd8_Node *)p->LoUnit)->Stamp = 0;
+
+ {
+ CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart;
+ for (; node->Stamp == EMPTY_NODE; node += node->NU)
+ {
+ node->Stamp = 0;
+ count[U2I(node->NU)]++;
+ }
+ p->UnitsStart = (Byte *)node;
+ }
+
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i];
+ while (count[i] != 0)
+ {
+ CPpmd8_Node *node = NODE(*next);
+ while (node->Stamp == 0)
+ {
+ *next = node->Next;
+ node = NODE(*next);
+ p->Stamps[i]--;
+ if (--count[i] == 0)
+ break;
+ }
+ next = &node->Next;
+ }
+ }
+}
+
+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
+
+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
+}
+
+#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); }
+
+static void RestartModel(CPpmd8 *p)
+{
+ unsigned i, k, m, r;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+ memset(p->Stamps, 0, sizeof(p->Stamps));
+ RESET_TEXT(0);
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ p->MinContext->Suffix = 0;
+ p->MinContext->NumStats = 255;
+ p->MinContext->Flags = 0;
+ p->MinContext->SummFreq = 256 + 1;
+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+ p->LoUnit += U2B(256 / 2);
+ p->MinContext->Stats = REF(p->FoundState);
+ for (i = 0; i < 256; i++)
+ {
+ CPpmd_State *s = &p->FoundState[i];
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ SetSuccessor(s, 0);
+ }
+
+ for (i = m = 0; m < 25; m++)
+ {
+ while (p->NS2Indx[i] == m)
+ i++;
+ for (k = 0; k < 8; k++)
+ {
+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1));
+ UInt16 *dest = p->BinSumm[m] + k;
+ for (r = 0; r < 64; r += 8)
+ dest[r] = val;
+ }
+ }
+
+ for (i = m = 0; m < 24; m++)
+ {
+ while (p->NS2Indx[i + 3] == m + 3)
+ i++;
+ for (k = 0; k < 32; k++)
+ {
+ CPpmd_See *s = &p->See[m][k];
+ s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4));
+ s->Count = 7;
+ }
+ }
+}
+
+void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
+{
+ p->MaxOrder = maxOrder;
+ p->RestoreMethod = restoreMethod;
+ RestartModel(p);
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Count = 64; /* unused */
+}
+
+static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale)
+{
+ unsigned i = ctx->NumStats, escFreq, sumFreq, flags;
+ CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1);
+ ctx->Stats = REF(s);
+ #ifdef PPMD8_FREEZE_SUPPORT
+ /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */
+ scale |= (ctx->SummFreq >= ((UInt32)1 << 15));
+ #endif
+ flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40);
+ escFreq = ctx->SummFreq - s->Freq;
+ sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale));
+ do
+ {
+ escFreq -= (++s)->Freq;
+ sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale));
+ flags |= 0x08 * (s->Symbol >= 0x40);
+ }
+ while (--i);
+ ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale));
+ ctx->Flags = (Byte)flags;
+}
+
+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
+{
+ CPpmd_State tmp = *t1;
+ *t1 = *t2;
+ *t2 = tmp;
+}
+
+static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order)
+{
+ int i;
+ unsigned tmp;
+ CPpmd_State *s;
+
+ if (!ctx->NumStats)
+ {
+ s = ONE_STATE(ctx);
+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart)
+ {
+ if (order < p->MaxOrder)
+ SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1));
+ else
+ SetSuccessor(s, 0);
+ if (SUCCESSOR(s) || order <= 9) /* O_BOUND */
+ return REF(ctx);
+ }
+ SpecialFreeUnit(p, ctx);
+ return 0;
+ }
+
+ ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1));
+
+ for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--)
+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart)
+ {
+ CPpmd_State *s2 = STATS(ctx) + (i--);
+ SetSuccessor(s, 0);
+ SwapStates(s, s2);
+ }
+ else if (order < p->MaxOrder)
+ SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1));
+ else
+ SetSuccessor(s, 0);
+
+ if (i != ctx->NumStats && order)
+ {
+ ctx->NumStats = (Byte)i;
+ s = STATS(ctx);
+ if (i < 0)
+ {
+ FreeUnits(p, s, tmp);
+ SpecialFreeUnit(p, ctx);
+ return 0;
+ }
+ if (i == 0)
+ {
+ ctx->Flags = (ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40);
+ *ONE_STATE(ctx) = *s;
+ FreeUnits(p, s, tmp);
+ ONE_STATE(ctx)->Freq = (Byte)((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3;
+ }
+ else
+ Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i);
+ }
+ return REF(ctx);
+}
+
+#ifdef PPMD8_FREEZE_SUPPORT
+static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order)
+{
+ CPpmd_State *s;
+ if (!ctx->NumStats)
+ {
+ s = ONE_STATE(ctx);
+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder)
+ SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1));
+ else
+ SetSuccessor(s, 0);
+ /* Suffix context can be removed already, since different (high-order)
+ Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */
+ if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF))
+ {
+ FreeUnits(p, ctx, 1);
+ return 0;
+ }
+ else
+ return REF(ctx);
+ }
+
+ for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--)
+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder)
+ SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1));
+ else
+ SetSuccessor(s, 0);
+
+ return REF(ctx);
+}
+#endif
+
+static UInt32 GetUsedMemory(const CPpmd8 *p)
+{
+ UInt32 v = 0;
+ unsigned i;
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ v += p->Stamps[i] * I2U(i);
+ return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v);
+}
+
+#ifdef PPMD8_FREEZE_SUPPORT
+ #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor)
+#else
+ #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1)
+#endif
+
+static void RestoreModel(CPpmd8 *p, CTX_PTR c1
+ #ifdef PPMD8_FREEZE_SUPPORT
+ , CTX_PTR fSuccessor
+ #endif
+ )
+{
+ CTX_PTR c;
+ CPpmd_State *s;
+ RESET_TEXT(0);
+ for (c = p->MaxContext; c != c1; c = SUFFIX(c))
+ if (--(c->NumStats) == 0)
+ {
+ s = STATS(c);
+ c->Flags = (c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40);
+ *ONE_STATE(c) = *s;
+ SpecialFreeUnit(p, s);
+ ONE_STATE(c)->Freq = (ONE_STATE(c)->Freq + 11) >> 3;
+ }
+ else
+ Refresh(p, c, (c->NumStats+3) >> 1, 0);
+
+ for (; c != p->MinContext; c = SUFFIX(c))
+ if (!c->NumStats)
+ ONE_STATE(c)->Freq -= ONE_STATE(c)->Freq >> 1;
+ else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats)
+ Refresh(p, c, (c->NumStats + 2) >> 1, 1);
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ p->MaxContext = fSuccessor;
+ p->GlueCount += !(p->Stamps[1] & 1);
+ }
+ else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ while (p->MaxContext->Suffix)
+ p->MaxContext = SUFFIX(p->MaxContext);
+ RemoveBinContexts(p, p->MaxContext, 0);
+ p->RestoreMethod++;
+ p->GlueCount = 0;
+ p->OrderFall = p->MaxOrder;
+ }
+ else
+ #endif
+ if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1))
+ RestartModel(p);
+ else
+ {
+ while (p->MaxContext->Suffix)
+ p->MaxContext = SUFFIX(p->MaxContext);
+ do
+ {
+ CutOff(p, p->MaxContext, 0);
+ ExpandTextArea(p);
+ }
+ while (GetUsedMemory(p) > 3 * (p->Size >> 2));
+ p->GlueCount = 0;
+ p->OrderFall = p->MaxOrder;
+ }
+}
+
+static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c)
+{
+ CPpmd_State upState;
+ Byte flags;
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ /* fixed over Shkarin's code. Maybe it could work without + 1 too. */
+ CPpmd_State *ps[PPMD8_MAX_ORDER + 1];
+ unsigned numPs = 0;
+
+ if (!skip)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+ if (s1)
+ {
+ s = s1;
+ s1 = NULL;
+ }
+ else if (c->NumStats != 0)
+ {
+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq++;
+ c->SummFreq++;
+ }
+ }
+ else
+ {
+ s = ONE_STATE(c);
+ s->Freq += (!SUFFIX(c)->NumStats & (s->Freq < 24));
+ }
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+ c = CTX(successor);
+ if (numPs == 0)
+ return c;
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+ upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch);
+ SetSuccessor(&upState, upBranch + 1);
+ flags = 0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40);
+
+ if (c->NumStats == 0)
+ upState.Freq = ONE_STATE(c)->Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != upState.Symbol; s++);
+ cf = s->Freq - 1;
+ s0 = c->SummFreq - c->NumStats - cf;
+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0)));
+ }
+
+ do
+ {
+ /* Create Child */
+ CTX_PTR c1; /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (CTX_PTR)RemoveNode(p, 0);
+ else
+ {
+ c1 = (CTX_PTR)AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+ c1->NumStats = 0;
+ c1->Flags = flags;
+ *ONE_STATE(c1) = upState;
+ c1->Suffix = REF(c);
+ SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c)
+{
+ CPpmd_State *s = NULL;
+ CTX_PTR c1 = c;
+ CPpmd_Void_Ref upBranch = REF(p->Text);
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */
+ CPpmd_State *ps[PPMD8_MAX_ORDER + 1];
+ unsigned numPs = 0;
+ ps[numPs++] = p->FoundState;
+ #endif
+
+ SetSuccessor(p->FoundState, upBranch);
+ p->OrderFall++;
+
+ for (;;)
+ {
+ if (s1)
+ {
+ c = SUFFIX(c);
+ s = s1;
+ s1 = NULL;
+ }
+ else
+ {
+ if (!c->Suffix)
+ {
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
+ RESET_TEXT(1);
+ p->OrderFall = 1;
+ }
+ #endif
+ return c;
+ }
+ c = SUFFIX(c);
+ if (c->NumStats)
+ {
+ if ((s = STATS(c))->Symbol != p->FoundState->Symbol)
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ else
+ {
+ s = ONE_STATE(c);
+ s->Freq += (s->Freq < 32);
+ }
+ }
+ if (SUCCESSOR(s))
+ break;
+ #ifdef PPMD8_FREEZE_SUPPORT
+ ps[numPs++] = s;
+ #endif
+ SetSuccessor(s, upBranch);
+ p->OrderFall++;
+ }
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ c = CTX(SUCCESSOR(s));
+ do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
+ RESET_TEXT(1);
+ p->OrderFall = 1;
+ return c;
+ }
+ else
+ #endif
+ if (SUCCESSOR(s) <= upBranch)
+ {
+ CTX_PTR successor;
+ CPpmd_State *s1 = p->FoundState;
+ p->FoundState = s;
+
+ successor = CreateSuccessors(p, False, NULL, c);
+ if (successor == NULL)
+ SetSuccessor(s, 0);
+ else
+ SetSuccessor(s, REF(successor));
+ p->FoundState = s1;
+ }
+
+ if (p->OrderFall == 1 && c1 == p->MaxContext)
+ {
+ SetSuccessor(p->FoundState, SUCCESSOR(s));
+ p->Text--;
+ }
+ if (SUCCESSOR(s) == 0)
+ return NULL;
+ return CTX(SUCCESSOR(s));
+}
+
+static void UpdateModel(CPpmd8 *p)
+{
+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
+ CTX_PTR c;
+ unsigned s0, ns, fFreq = p->FoundState->Freq;
+ Byte flag, fSymbol = p->FoundState->Symbol;
+ CPpmd_State *s = NULL;
+
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 0)
+ {
+ s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ s = STATS(c);
+ if (s->Symbol != p->FoundState->Symbol)
+ {
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ s--;
+ }
+ }
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ }
+
+ c = p->MaxContext;
+ if (p->OrderFall == 0 && fSuccessor)
+ {
+ CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext);
+ if (cs == 0)
+ {
+ SetSuccessor(p->FoundState, 0);
+ RESTORE_MODEL(c, CTX(fSuccessor));
+ }
+ else
+ {
+ SetSuccessor(p->FoundState, REF(cs));
+ p->MaxContext = cs;
+ }
+ return;
+ }
+
+ *p->Text++ = p->FoundState->Symbol;
+ successor = REF(p->Text);
+ if (p->Text >= p->UnitsStart)
+ {
+ RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */
+ return;
+ }
+
+ if (!fSuccessor)
+ {
+ CTX_PTR cs = ReduceOrder(p, s, p->MinContext);
+ if (cs == NULL)
+ {
+ RESTORE_MODEL(c, 0);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+ else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart)
+ {
+ CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext);
+ if (cs == NULL)
+ {
+ RESTORE_MODEL(c, 0);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+
+ if (--p->OrderFall == 0)
+ {
+ successor = fSuccessor;
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ #ifdef PPMD8_FREEZE_SUPPORT
+ else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ successor = fSuccessor;
+ RESET_TEXT(0);
+ p->OrderFall = 0;
+ }
+ #endif
+
+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq;
+ flag = 0x08 * (fSymbol >= 0x40);
+
+ for (; c != p->MinContext; c = SUFFIX(c))
+ {
+ unsigned ns1;
+ UInt32 cf, sf;
+ if ((ns1 = c->NumStats) != 0)
+ {
+ if ((ns1 & 1) != 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = (ns1 + 1) >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I(oldNU + 1))
+ {
+ void *ptr = AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ RESTORE_MODEL(c, CTX(fSuccessor));
+ return;
+ }
+ oldPtr = STATS(c);
+ MyMem12Cpy(ptr, oldPtr, oldNU);
+ InsertNode(p, oldPtr, i);
+ c->Stats = STATS_REF(ptr);
+ }
+ }
+ c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns));
+ }
+ else
+ {
+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
+ if (!s)
+ {
+ RESTORE_MODEL(c, CTX(fSuccessor));
+ return;
+ }
+ *s = *ONE_STATE(c);
+ c->Stats = REF(s);
+ if (s->Freq < MAX_FREQ / 4 - 1)
+ s->Freq <<= 1;
+ else
+ s->Freq = MAX_FREQ - 4;
+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 2));
+ }
+ cf = 2 * fFreq * (c->SummFreq + 6);
+ sf = (UInt32)s0 + c->SummFreq;
+ if (cf < 6 * sf)
+ {
+ cf = 1 + (cf > sf) + (cf >= 4 * sf);
+ c->SummFreq += 4;
+ }
+ else
+ {
+ cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf);
+ c->SummFreq = (UInt16)(c->SummFreq + cf);
+ }
+ {
+ CPpmd_State *s = STATS(c) + ns1 + 1;
+ SetSuccessor(s, successor);
+ s->Symbol = fSymbol;
+ s->Freq = (Byte)cf;
+ c->Flags |= flag;
+ c->NumStats = (Byte)(ns1 + 1);
+ }
+ }
+ p->MaxContext = p->MinContext = CTX(fSuccessor);
+}
+
+static void Rescale(CPpmd8 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+ {
+ CPpmd_State tmp = *s;
+ for (; s != stats; s--)
+ s[0] = s[-1];
+ *s = tmp;
+ }
+ escFreq = p->MinContext->SummFreq - s->Freq;
+ s->Freq += 4;
+ adder = (p->OrderFall != 0
+ #ifdef PPMD8_FREEZE_SUPPORT
+ || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE
+ #endif
+ );
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq = s->Freq;
+
+ i = p->MinContext->NumStats;
+ do
+ {
+ escFreq -= (++s)->Freq;
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq += s->Freq;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ CPpmd_State *s1 = s;
+ CPpmd_State tmp = *s1;
+ do
+ s1[0] = s1[-1];
+ while (--s1 != stats && tmp.Freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ unsigned numStats = p->MinContext->NumStats;
+ unsigned n0, n1;
+ do { i++; } while ((--s)->Freq == 0);
+ escFreq += i;
+ p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i);
+ if (p->MinContext->NumStats == 0)
+ {
+ CPpmd_State tmp = *stats;
+ tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq);
+ if (tmp.Freq > MAX_FREQ / 3)
+ tmp.Freq = MAX_FREQ / 3;
+ InsertNode(p, stats, U2I((numStats + 2) >> 1));
+ p->MinContext->Flags = (p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40);
+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
+ return;
+ }
+ n0 = (numStats + 2) >> 1;
+ n1 = (p->MinContext->NumStats + 2) >> 1;
+ if (n0 != n1)
+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ p->MinContext->Flags &= ~0x08;
+ p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40);
+ i = p->MinContext->NumStats;
+ do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i);
+ }
+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ p->MinContext->Flags |= 0x4;
+ p->FoundState = STATS(p->MinContext);
+}
+
+CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ if (p->MinContext->NumStats != 0xFF)
+ {
+ see = p->See[p->NS2Indx[p->MinContext->NumStats + 2] - 3] +
+ (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) +
+ 2 * (2 * (unsigned)p->MinContext->NumStats <
+ ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) +
+ p->MinContext->Flags;
+ {
+ unsigned r = (see->Summ >> see->Shift);
+ see->Summ = (UInt16)(see->Summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+static void NextContext(CPpmd8 *p)
+{
+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart)
+ p->MinContext = p->MaxContext = c;
+ else
+ {
+ UpdateModel(p);
+ p->MinContext = p->MaxContext;
+ }
+}
+
+void Ppmd8_Update1(CPpmd8 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ s->Freq += 4;
+ p->MinContext->SummFreq += 4;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ p->FoundState = --s;
+ if (s->Freq > MAX_FREQ)
+ Rescale(p);
+ }
+ NextContext(p);
+}
+
+void Ppmd8_Update1_0(CPpmd8 *p)
+{
+ p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq);
+ p->RunLength += p->PrevSuccess;
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ NextContext(p);
+}
+
+void Ppmd8_UpdateBin(CPpmd8 *p)
+{
+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196));
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ NextContext(p);
+}
+
+void Ppmd8_Update2(CPpmd8 *p)
+{
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ p->RunLength = p->InitRL;
+ UpdateModel(p);
+ p->MinContext = p->MaxContext;
+}
+
+/* H->I changes:
+ NS2Indx
+ GlewCount, and Glue method
+ BinSum
+ See / EscFreq
+ CreateSuccessors updates more suffix contexts
+ UpdateModel consts.
+ PrevSuccess Update
+*/
diff --git a/src/libs/7zip/unix/C/Ppmd8.h b/src/libs/7zip/unix/C/Ppmd8.h
new file mode 100644
index 000000000..870dc9dd8
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd8.h
@@ -0,0 +1,133 @@
+/* Ppmd8.h -- PPMdI codec
+2010-03-24 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#ifndef __PPMD8_H
+#define __PPMD8_H
+
+#include "Ppmd.h"
+
+EXTERN_C_BEGIN
+
+#define PPMD8_MIN_ORDER 2
+#define PPMD8_MAX_ORDER 16
+
+struct CPpmd8_Context_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd8_Context_ *
+ #else
+ UInt32
+ #endif
+ CPpmd8_Context_Ref;
+
+typedef struct CPpmd8_Context_
+{
+ Byte NumStats;
+ Byte Flags;
+ UInt16 SummFreq;
+ CPpmd_State_Ref Stats;
+ CPpmd8_Context_Ref Suffix;
+} CPpmd8_Context;
+
+#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
+
+/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed
+ code is not compatible with original code for some files compressed
+ in FREEZE mode. So we disable FREEZE mode support. */
+
+enum
+{
+ PPMD8_RESTORE_METHOD_RESTART,
+ PPMD8_RESTORE_METHOD_CUT_OFF
+ #ifdef PPMD8_FREEZE_SUPPORT
+ , PPMD8_RESTORE_METHOD_FREEZE
+ #endif
+};
+
+typedef struct
+{
+ CPpmd8_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+ UInt32 AlignOffset;
+ unsigned RestoreMethod;
+
+ /* Range Coder */
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ union
+ {
+ IByteIn *In;
+ IByteOut *Out;
+ } Stream;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES];
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+ UInt32 Stamps[PPMD_NUM_INDEXES];
+
+ Byte NS2BSIndx[256], NS2Indx[260];
+ CPpmd_See DummySee, See[24][32];
+ UInt16 BinSumm[25][64];
+} CPpmd8;
+
+void Ppmd8_Construct(CPpmd8 *p);
+Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc);
+void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc);
+void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod);
+#define Ppmd8_WasAllocated(p) ((p)->Base != NULL)
+
+
+/* ---------- Internal Functions ---------- */
+
+extern const Byte PPMD8_kExpEscape[16];
+
+#ifdef PPMD_32BIT
+ #define Ppmd8_GetPtr(p, ptr) (ptr)
+ #define Ppmd8_GetContext(p, ptr) (ptr)
+ #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats)
+#else
+ #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
+ #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs)))
+ #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats)))
+#endif
+
+void Ppmd8_Update1(CPpmd8 *p);
+void Ppmd8_Update1_0(CPpmd8 *p);
+void Ppmd8_Update2(CPpmd8 *p);
+void Ppmd8_UpdateBin(CPpmd8 *p);
+
+#define Ppmd8_GetBinSumm(p) \
+ &p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \
+ p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \
+ p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)]
+
+CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale);
+
+
+/* ---------- Decode ---------- */
+
+Bool Ppmd8_RangeDec_Init(CPpmd8 *p);
+#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */
+
+
+/* ---------- Encode ---------- */
+
+#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; }
+void Ppmd8_RangeEnc_FlushData(CPpmd8 *p);
+void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/Ppmd8Dec.c b/src/libs/7zip/unix/C/Ppmd8Dec.c
new file mode 100644
index 000000000..c54e02ab2
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd8Dec.c
@@ -0,0 +1,155 @@
+/* Ppmd8Dec.c -- PPMdI Decoder
+2010-04-16 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "Ppmd8.h"
+
+#define kTop (1 << 24)
+#define kBot (1 << 15)
+
+Bool Ppmd8_RangeDec_Init(CPpmd8 *p)
+{
+ unsigned i;
+ p->Low = 0;
+ p->Range = 0xFFFFFFFF;
+ p->Code = 0;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total)
+{
+ return p->Code / (p->Range /= total);
+}
+
+static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size)
+{
+ start *= p->Range;
+ p->Low += start;
+ p->Code -= start;
+ p->Range *= size;
+
+ while ((p->Low ^ (p->Low + p->Range)) < kTop ||
+ (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))
+ {
+ p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);
+ p->Range <<= 8;
+ p->Low <<= 8;
+ }
+}
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+int Ppmd8_DecodeSymbol(CPpmd8 *p)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 0)
+ {
+ CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
+ {
+ Byte symbol;
+ RangeDec_Decode(p, 0, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd8_Update1_0(p);
+ return symbol;
+ }
+ p->PrevSuccess = 0;
+ i = p->MinContext->NumStats;
+ do
+ {
+ if ((hiCnt += (++s)->Freq) > count)
+ {
+ Byte symbol;
+ RangeDec_Decode(p, hiCnt - s->Freq, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd8_Update1(p);
+ return symbol;
+ }
+ }
+ while (--i);
+ if (count >= p->MinContext->SummFreq)
+ return -2;
+ RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt);
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd8_GetBinSumm(p);
+ if (((p->Code / (p->Range >>= 14)) < *prob))
+ {
+ Byte symbol;
+ RangeDec_Decode(p, 0, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol;
+ Ppmd8_UpdateBin(p);
+ return symbol;
+ }
+ RangeDec_Decode(p, *prob, (1 << 14) - *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD8_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ for (;;)
+ {
+ CPpmd_State *ps[256], *s;
+ UInt32 freqSum, count, hiCnt;
+ CPpmd_See *see;
+ unsigned i, num, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return -1;
+ p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+ hiCnt = 0;
+ s = Ppmd8_GetStats(p, p->MinContext);
+ i = 0;
+ num = p->MinContext->NumStats - numMasked;
+ do
+ {
+ int k = (int)(MASK(s->Symbol));
+ hiCnt += (s->Freq & k);
+ ps[i] = s++;
+ i -= k;
+ }
+ while (i != num);
+
+ see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+ count = RangeDec_GetThreshold(p, freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte symbol;
+ CPpmd_State **pps = ps;
+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
+ s = *pps;
+ RangeDec_Decode(p, hiCnt - s->Freq, s->Freq);
+ Ppmd_See_Update(see);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd8_Update2(p);
+ return symbol;
+ }
+ if (count >= freqSum)
+ return -2;
+ RangeDec_Decode(p, hiCnt, freqSum - hiCnt);
+ see->Summ = (UInt16)(see->Summ + freqSum);
+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
+ }
+}
diff --git a/src/libs/7zip/unix/C/Ppmd8Enc.c b/src/libs/7zip/unix/C/Ppmd8Enc.c
new file mode 100644
index 000000000..8da727eb2
--- /dev/null
+++ b/src/libs/7zip/unix/C/Ppmd8Enc.c
@@ -0,0 +1,161 @@
+/* Ppmd8Enc.c -- PPMdI Encoder
+2010-04-16 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "Ppmd8.h"
+
+#define kTop (1 << 24)
+#define kBot (1 << 15)
+
+void Ppmd8_RangeEnc_FlushData(CPpmd8 *p)
+{
+ unsigned i;
+ for (i = 0; i < 4; i++, p->Low <<= 8 )
+ p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24));
+}
+
+static void RangeEnc_Normalize(CPpmd8 *p)
+{
+ while ((p->Low ^ (p->Low + p->Range)) < kTop ||
+ (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))
+ {
+ p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24));
+ p->Range <<= 8;
+ p->Low <<= 8;
+ }
+}
+
+static void RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total)
+{
+ p->Low += start * (p->Range /= total);
+ p->Range *= size;
+ RangeEnc_Normalize(p);
+}
+
+static void RangeEnc_EncodeBit_0(CPpmd8 *p, UInt32 size0)
+{
+ p->Range >>= 14;
+ p->Range *= size0;
+ RangeEnc_Normalize(p);
+}
+
+static void RangeEnc_EncodeBit_1(CPpmd8 *p, UInt32 size0)
+{
+ p->Low += size0 * (p->Range >>= 14);
+ p->Range *= ((1 << 14) - size0);
+ RangeEnc_Normalize(p);
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 0)
+ {
+ CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);
+ UInt32 sum;
+ unsigned i;
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_Encode(p, 0, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd8_Update1_0(p);
+ return;
+ }
+ p->PrevSuccess = 0;
+ sum = s->Freq;
+ i = p->MinContext->NumStats;
+ do
+ {
+ if ((++s)->Symbol == symbol)
+ {
+ RangeEnc_Encode(p, sum, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd8_Update1(p);
+ return;
+ }
+ sum += s->Freq;
+ }
+ while (--i);
+
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ RangeEnc_Encode(p, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd8_GetBinSumm(p);
+ CPpmd_State *s = Ppmd8Context_OneState(p->MinContext);
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_EncodeBit_0(p, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ p->FoundState = s;
+ Ppmd8_UpdateBin(p);
+ return;
+ }
+ else
+ {
+ RangeEnc_EncodeBit_1(p, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD8_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ }
+ for (;;)
+ {
+ UInt32 escFreq;
+ CPpmd_See *see;
+ CPpmd_State *s;
+ UInt32 sum;
+ unsigned i, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return; /* EndMarker (symbol = -1) */
+ p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+
+ see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq);
+ s = Ppmd8_GetStats(p, p->MinContext);
+ sum = 0;
+ i = p->MinContext->NumStats + 1;
+ do
+ {
+ int cur = s->Symbol;
+ if (cur == symbol)
+ {
+ UInt32 low = sum;
+ CPpmd_State *s1 = s;
+ do
+ {
+ sum += (s->Freq & (int)(MASK(s->Symbol)));
+ s++;
+ }
+ while (--i);
+ RangeEnc_Encode(p, low, s1->Freq, sum + escFreq);
+ Ppmd_See_Update(see);
+ p->FoundState = s1;
+ Ppmd8_Update2(p);
+ return;
+ }
+ sum += (s->Freq & (int)(MASK(cur)));
+ MASK(cur) = 0;
+ s++;
+ }
+ while (--i);
+
+ RangeEnc_Encode(p, sum, escFreq, sum + escFreq);
+ see->Summ = (UInt16)(see->Summ + sum + escFreq);
+ }
+}
diff --git a/src/libs/7zip/unix/C/RotateDefs.h b/src/libs/7zip/unix/C/RotateDefs.h
new file mode 100644
index 000000000..c3a1385ce
--- /dev/null
+++ b/src/libs/7zip/unix/C/RotateDefs.h
@@ -0,0 +1,20 @@
+/* RotateDefs.h -- Rotate functions
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __ROTATE_DEFS_H
+#define __ROTATE_DEFS_H
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+#define rotlFixed(x, n) _rotl((x), (n))
+#define rotrFixed(x, n) _rotr((x), (n))
+
+#else
+
+#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
+
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/Sha256.c b/src/libs/7zip/unix/C/Sha256.c
new file mode 100644
index 000000000..eb4fc61fc
--- /dev/null
+++ b/src/libs/7zip/unix/C/Sha256.c
@@ -0,0 +1,204 @@
+/* Crypto/Sha256.c -- SHA-256 Hash
+2010-06-11 : Igor Pavlov : Public domain
+This code is based on public domain code from Wei Dai's Crypto++ library. */
+
+#include "RotateDefs.h"
+#include "Sha256.h"
+
+/* define it for speed optimization */
+/* #define _SHA256_UNROLL */
+/* #define _SHA256_UNROLL2 */
+
+void Sha256_Init(CSha256 *p)
+{
+ p->state[0] = 0x6a09e667;
+ p->state[1] = 0xbb67ae85;
+ p->state[2] = 0x3c6ef372;
+ p->state[3] = 0xa54ff53a;
+ p->state[4] = 0x510e527f;
+ p->state[5] = 0x9b05688c;
+ p->state[6] = 0x1f83d9ab;
+ p->state[7] = 0x5be0cd19;
+ p->count = 0;
+}
+
+#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22))
+#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25))
+#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3))
+#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10))
+
+#define blk0(i) (W[i] = data[i])
+#define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15]))
+
+#define Ch(x,y,z) (z^(x&(y^z)))
+#define Maj(x,y,z) ((x&y)|(z&(x|y)))
+
+#define a(i) T[(0-(i))&7]
+#define b(i) T[(1-(i))&7]
+#define c(i) T[(2-(i))&7]
+#define d(i) T[(3-(i))&7]
+#define e(i) T[(4-(i))&7]
+#define f(i) T[(5-(i))&7]
+#define g(i) T[(6-(i))&7]
+#define h(i) T[(7-(i))&7]
+
+
+#ifdef _SHA256_UNROLL2
+
+#define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\
+ d += h; h += S0(a) + Maj(a, b, c)
+
+#define RX_8(i) \
+ R(a,b,c,d,e,f,g,h, i); \
+ R(h,a,b,c,d,e,f,g, i+1); \
+ R(g,h,a,b,c,d,e,f, i+2); \
+ R(f,g,h,a,b,c,d,e, i+3); \
+ R(e,f,g,h,a,b,c,d, i+4); \
+ R(d,e,f,g,h,a,b,c, i+5); \
+ R(c,d,e,f,g,h,a,b, i+6); \
+ R(b,c,d,e,f,g,h,a, i+7)
+
+#else
+
+#define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\
+ d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i))
+
+#ifdef _SHA256_UNROLL
+
+#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7);
+
+#endif
+
+#endif
+
+static const UInt32 K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+static void Sha256_Transform(UInt32 *state, const UInt32 *data)
+{
+ UInt32 W[16];
+ unsigned j;
+ #ifdef _SHA256_UNROLL2
+ UInt32 a,b,c,d,e,f,g,h;
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ f = state[5];
+ g = state[6];
+ h = state[7];
+ #else
+ UInt32 T[8];
+ for (j = 0; j < 8; j++)
+ T[j] = state[j];
+ #endif
+
+ for (j = 0; j < 64; j += 16)
+ {
+ #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2)
+ RX_8(0); RX_8(8);
+ #else
+ unsigned i;
+ for (i = 0; i < 16; i++) { R(i); }
+ #endif
+ }
+
+ #ifdef _SHA256_UNROLL2
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ state[5] += f;
+ state[6] += g;
+ state[7] += h;
+ #else
+ for (j = 0; j < 8; j++)
+ state[j] += T[j];
+ #endif
+
+ /* Wipe variables */
+ /* memset(W, 0, sizeof(W)); */
+ /* memset(T, 0, sizeof(T)); */
+}
+
+#undef S0
+#undef S1
+#undef s0
+#undef s1
+
+static void Sha256_WriteByteBlock(CSha256 *p)
+{
+ UInt32 data32[16];
+ unsigned i;
+ for (i = 0; i < 16; i++)
+ data32[i] =
+ ((UInt32)(p->buffer[i * 4 ]) << 24) +
+ ((UInt32)(p->buffer[i * 4 + 1]) << 16) +
+ ((UInt32)(p->buffer[i * 4 + 2]) << 8) +
+ ((UInt32)(p->buffer[i * 4 + 3]));
+ Sha256_Transform(p->state, data32);
+}
+
+void Sha256_Update(CSha256 *p, const Byte *data, size_t size)
+{
+ UInt32 curBufferPos = (UInt32)p->count & 0x3F;
+ while (size > 0)
+ {
+ p->buffer[curBufferPos++] = *data++;
+ p->count++;
+ size--;
+ if (curBufferPos == 64)
+ {
+ curBufferPos = 0;
+ Sha256_WriteByteBlock(p);
+ }
+ }
+}
+
+void Sha256_Final(CSha256 *p, Byte *digest)
+{
+ UInt64 lenInBits = (p->count << 3);
+ UInt32 curBufferPos = (UInt32)p->count & 0x3F;
+ unsigned i;
+ p->buffer[curBufferPos++] = 0x80;
+ while (curBufferPos != (64 - 8))
+ {
+ curBufferPos &= 0x3F;
+ if (curBufferPos == 0)
+ Sha256_WriteByteBlock(p);
+ p->buffer[curBufferPos++] = 0;
+ }
+ for (i = 0; i < 8; i++)
+ {
+ p->buffer[curBufferPos++] = (Byte)(lenInBits >> 56);
+ lenInBits <<= 8;
+ }
+ Sha256_WriteByteBlock(p);
+
+ for (i = 0; i < 8; i++)
+ {
+ *digest++ = (Byte)(p->state[i] >> 24);
+ *digest++ = (Byte)(p->state[i] >> 16);
+ *digest++ = (Byte)(p->state[i] >> 8);
+ *digest++ = (Byte)(p->state[i]);
+ }
+ Sha256_Init(p);
+}
diff --git a/src/libs/7zip/unix/C/Sha256.h b/src/libs/7zip/unix/C/Sha256.h
new file mode 100644
index 000000000..530f513ec
--- /dev/null
+++ b/src/libs/7zip/unix/C/Sha256.h
@@ -0,0 +1,26 @@
+/* Sha256.h -- SHA-256 Hash
+2010-06-11 : Igor Pavlov : Public domain */
+
+#ifndef __CRYPTO_SHA256_H
+#define __CRYPTO_SHA256_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+#define SHA256_DIGEST_SIZE 32
+
+typedef struct
+{
+ UInt32 state[8];
+ UInt64 count;
+ Byte buffer[64];
+} CSha256;
+
+void Sha256_Init(CSha256 *p);
+void Sha256_Update(CSha256 *p, const Byte *data, size_t size);
+void Sha256_Final(CSha256 *p, Byte *digest);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/Sort.c b/src/libs/7zip/unix/C/Sort.c
new file mode 100644
index 000000000..388d22893
--- /dev/null
+++ b/src/libs/7zip/unix/C/Sort.c
@@ -0,0 +1,93 @@
+/* Sort.c -- Sort functions
+2010-09-17 : Igor Pavlov : Public domain */
+
+#include "Sort.h"
+
+#define HeapSortDown(p, k, size, temp) \
+ { for (;;) { \
+ UInt32 s = (k << 1); \
+ if (s > size) break; \
+ if (s < size && p[s + 1] > p[s]) s++; \
+ if (temp >= p[s]) break; \
+ p[k] = p[s]; k = s; \
+ } p[k] = temp; }
+
+void HeapSort(UInt32 *p, UInt32 size)
+{
+ if (size <= 1)
+ return;
+ p--;
+ {
+ UInt32 i = size / 2;
+ do
+ {
+ UInt32 temp = p[i];
+ UInt32 k = i;
+ HeapSortDown(p, k, size, temp)
+ }
+ while (--i != 0);
+ }
+ /*
+ do
+ {
+ UInt32 k = 1;
+ UInt32 temp = p[size];
+ p[size--] = p[1];
+ HeapSortDown(p, k, size, temp)
+ }
+ while (size > 1);
+ */
+ while (size > 3)
+ {
+ UInt32 temp = p[size];
+ UInt32 k = (p[3] > p[2]) ? 3 : 2;
+ p[size--] = p[1];
+ p[1] = p[k];
+ HeapSortDown(p, k, size, temp)
+ }
+ {
+ UInt32 temp = p[size];
+ p[size] = p[1];
+ if (size > 2 && p[2] < temp)
+ {
+ p[1] = p[2];
+ p[2] = temp;
+ }
+ else
+ p[1] = temp;
+ }
+}
+
+/*
+#define HeapSortRefDown(p, vals, n, size, temp) \
+ { UInt32 k = n; UInt32 val = vals[temp]; for (;;) { \
+ UInt32 s = (k << 1); \
+ if (s > size) break; \
+ if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \
+ if (val >= vals[p[s]]) break; \
+ p[k] = p[s]; k = s; \
+ } p[k] = temp; }
+
+void HeapSortRef(UInt32 *p, UInt32 *vals, UInt32 size)
+{
+ if (size <= 1)
+ return;
+ p--;
+ {
+ UInt32 i = size / 2;
+ do
+ {
+ UInt32 temp = p[i];
+ HeapSortRefDown(p, vals, i, size, temp);
+ }
+ while (--i != 0);
+ }
+ do
+ {
+ UInt32 temp = p[size];
+ p[size--] = p[1];
+ HeapSortRefDown(p, vals, 1, size, temp);
+ }
+ while (size > 1);
+}
+*/
diff --git a/src/libs/7zip/unix/C/Sort.h b/src/libs/7zip/unix/C/Sort.h
new file mode 100644
index 000000000..65dfc6f6a
--- /dev/null
+++ b/src/libs/7zip/unix/C/Sort.h
@@ -0,0 +1,20 @@
+/* Sort.h -- Sort functions
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_SORT_H
+#define __7Z_SORT_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HeapSort(UInt32 *p, UInt32 size);
+/* void HeapSortRef(UInt32 *p, UInt32 *vals, UInt32 size); */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/Threads.c b/src/libs/7zip/unix/C/Threads.c
new file mode 100644
index 000000000..1b8203f68
--- /dev/null
+++ b/src/libs/7zip/unix/C/Threads.c
@@ -0,0 +1,582 @@
+/* Threads.c */
+
+#include "Threads.h"
+
+#ifdef ENV_BEOS
+#include <kernel/OS.h>
+#else
+#include <pthread.h>
+#include <stdlib.h>
+#endif
+
+#include <errno.h>
+
+#if defined(__linux__)
+#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
+#endif
+
+#ifdef ENV_BEOS
+
+/* TODO : optimize the code and verify the returned values */
+
+WRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
+{
+ thread->_tid = spawn_thread((int32 (*)(void *))startAddress, "CThread", B_LOW_PRIORITY, parameter);
+ if (thread->_tid >= B_OK) {
+ resume_thread(thread->_tid);
+ } else {
+ thread->_tid = B_BAD_THREAD_ID;
+ }
+ thread->_created = 1;
+ return 0; // SZ_OK;
+}
+
+WRes Thread_Wait(CThread *thread)
+{
+ int ret;
+
+ if (thread->_created == 0)
+ return EINVAL;
+
+ if (thread->_tid >= B_OK)
+ {
+ status_t exit_value;
+ wait_for_thread(thread->_tid, &exit_value);
+ thread->_tid = B_BAD_THREAD_ID;
+ } else {
+ return EINVAL;
+ }
+
+ thread->_created = 0;
+
+ return 0;
+}
+
+WRes Thread_Close(CThread *thread)
+{
+ if (!thread->_created) return SZ_OK;
+
+ thread->_tid = B_BAD_THREAD_ID;
+ thread->_created = 0;
+ return SZ_OK;
+}
+
+
+WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled)
+{
+ p->_index_waiting = 0;
+ p->_manual_reset = manualReset;
+ p->_state = (initialSignaled ? TRUE : FALSE);
+ p->_created = 1;
+ p->_sem = create_sem(1,"event");
+ return 0;
+}
+
+WRes Event_Set(CEvent *p) {
+ int index;
+ acquire_sem(p->_sem);
+ p->_state = TRUE;
+ for(index = 0 ; index < p->_index_waiting ; index++)
+ {
+ send_data(p->_waiting[index], '7zCN', NULL, 0);
+ }
+ p->_index_waiting = 0;
+ release_sem(p->_sem);
+ return 0;
+}
+
+WRes Event_Reset(CEvent *p) {
+ acquire_sem(p->_sem);
+ p->_state = FALSE;
+ release_sem(p->_sem);
+ return 0;
+}
+
+WRes Event_Wait(CEvent *p) {
+ acquire_sem(p->_sem);
+ while (p->_state == FALSE)
+ {
+ thread_id sender;
+ p->_waiting[p->_index_waiting++] = find_thread(NULL);
+ release_sem(p->_sem);
+ /* int msg = */ receive_data(&sender, NULL, 0);
+ acquire_sem(p->_sem);
+ }
+ if (p->_manual_reset == FALSE)
+ {
+ p->_state = FALSE;
+ }
+ release_sem(p->_sem);
+ return 0;
+}
+
+WRes Event_Close(CEvent *p) {
+ if (p->_created)
+ {
+ p->_created = 0;
+ delete_sem(p->_sem);
+ }
+ return 0;
+}
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount)
+{
+ p->_index_waiting = 0;
+ p->_count = initiallyCount;
+ p->_maxCount = maxCount;
+ p->_created = 1;
+ p->_sem = create_sem(1,"sem");
+ return 0;
+}
+
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
+{
+ UInt32 newCount;
+ int index;
+
+ if (releaseCount < 1) return EINVAL;
+
+ acquire_sem(p->_sem);
+ newCount = p->_count + releaseCount;
+ if (newCount > p->_maxCount)
+ {
+ release_sem(p->_sem);
+ return EINVAL;
+ }
+ p->_count = newCount;
+ for(index = 0 ; index < p->_index_waiting ; index++)
+ {
+ send_data(p->_waiting[index], '7zCN', NULL, 0);
+ }
+ p->_index_waiting = 0;
+ release_sem(p->_sem);
+ return 0;
+}
+
+WRes Semaphore_Wait(CSemaphore *p) {
+ acquire_sem(p->_sem);
+ while (p->_count < 1)
+ {
+ thread_id sender;
+ p->_waiting[p->_index_waiting++] = find_thread(NULL);
+ release_sem(p->_sem);
+ /* int msg = */ receive_data(&sender, NULL, 0);
+ acquire_sem(p->_sem);
+ }
+ p->_count--;
+ release_sem(p->_sem);
+ return 0;
+}
+
+WRes Semaphore_Close(CSemaphore *p) {
+ if (p->_created)
+ {
+ p->_created = 0;
+ delete_sem(p->_sem);
+ }
+ return 0;
+}
+
+WRes CriticalSection_Init(CCriticalSection * lpCriticalSection)
+{
+ lpCriticalSection->_sem = create_sem(1,"cc");
+ return 0;
+}
+
+#else /* !ENV_BEOS */
+
+WRes Thread_Create(CThread *thread, THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
+{
+ pthread_attr_t attr;
+ int ret;
+
+ thread->_created = 0;
+
+ ret = pthread_attr_init(&attr);
+ if (ret) return ret;
+
+ ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
+ if (ret) return ret;
+
+ ret = pthread_create(&thread->_tid, &attr, (void * (*)(void *))startAddress, parameter);
+
+ /* ret2 = */ pthread_attr_destroy(&attr);
+
+ if (ret) return ret;
+
+ thread->_created = 1;
+
+ return 0; // SZ_OK;
+}
+
+WRes Thread_Wait(CThread *thread)
+{
+ void *thread_return;
+ int ret;
+
+ if (thread->_created == 0)
+ return EINVAL;
+
+ ret = pthread_join(thread->_tid,&thread_return);
+ thread->_created = 0;
+
+ return ret;
+}
+
+WRes Thread_Close(CThread *thread)
+{
+ if (!thread->_created) return SZ_OK;
+
+ pthread_detach(thread->_tid);
+ thread->_tid = 0;
+ thread->_created = 0;
+ return SZ_OK;
+}
+
+#ifdef DEBUG_SYNCHRO
+
+#include <stdio.h>
+
+static void dump_error(int ligne,int ret,const char *text,void *param)
+{
+ printf("\n##T%d#ERROR2 (l=%d) %s : param=%p ret = %d (%s)##\n",(int)pthread_self(),ligne,text,param,ret,strerror(ret));
+ // abort();
+}
+
+WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled)
+{
+ int ret;
+ pthread_mutexattr_t mutexattr;
+ memset(&mutexattr,0,sizeof(mutexattr));
+ ret = pthread_mutexattr_init(&mutexattr);
+ if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_init",&mutexattr);
+ ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK);
+ if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_settype",&mutexattr);
+ ret = pthread_mutex_init(&p->_mutex,&mutexattr);
+ if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_mutexattr_init",&p->_mutex);
+ if (ret == 0)
+ {
+ ret = pthread_cond_init(&p->_cond,0);
+ if (ret != 0) dump_error(__LINE__,ret,"Event_Create::pthread_cond_init",&p->_cond);
+ p->_manual_reset = manualReset;
+ p->_state = (initialSignaled ? TRUE : FALSE);
+ p->_created = 1;
+ }
+ return ret;
+}
+
+WRes Event_Set(CEvent *p) {
+ int ret = pthread_mutex_lock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_mutex_lock",&p->_mutex);
+ if (ret == 0)
+ {
+ p->_state = TRUE;
+ ret = pthread_cond_broadcast(&p->_cond);
+ if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_cond_broadcast",&p->_cond);
+ if (ret == 0)
+ {
+ ret = pthread_mutex_unlock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"ES::pthread_mutex_unlock",&p->_mutex);
+ }
+ }
+ return ret;
+}
+
+WRes Event_Reset(CEvent *p) {
+ int ret = pthread_mutex_lock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"ER::pthread_mutex_lock",&p->_mutex);
+ if (ret == 0)
+ {
+ p->_state = FALSE;
+ ret = pthread_mutex_unlock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"ER::pthread_mutex_unlock",&p->_mutex);
+ }
+ return ret;
+}
+
+WRes Event_Wait(CEvent *p) {
+ int ret = pthread_mutex_lock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_mutex_lock",&p->_mutex);
+ if (ret == 0)
+ {
+ while ((p->_state == FALSE) && (ret == 0))
+ {
+ ret = pthread_cond_wait(&p->_cond, &p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_cond_wait",&p->_mutex);
+ }
+ if (ret == 0)
+ {
+ if (p->_manual_reset == FALSE)
+ {
+ p->_state = FALSE;
+ }
+ ret = pthread_mutex_unlock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"EW::pthread_mutex_unlock",&p->_mutex);
+ }
+ }
+ return ret;
+}
+
+WRes Event_Close(CEvent *p) {
+ if (p->_created)
+ {
+ int ret;
+ p->_created = 0;
+ ret = pthread_mutex_destroy(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"EC::pthread_mutex_destroy",&p->_mutex);
+ ret = pthread_cond_destroy(&p->_cond);
+ if (ret != 0) dump_error(__LINE__,ret,"EC::pthread_cond_destroy",&p->_cond);
+ }
+ return 0;
+}
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount)
+{
+ int ret;
+ pthread_mutexattr_t mutexattr;
+ memset(&mutexattr,0,sizeof(mutexattr));
+ ret = pthread_mutexattr_init(&mutexattr);
+ if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_init",&mutexattr);
+ ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK);
+ if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_settype",&mutexattr);
+ ret = pthread_mutex_init(&p->_mutex,&mutexattr);
+ if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_mutexattr_init",&p->_mutex);
+ if (ret == 0)
+ {
+ ret = pthread_cond_init(&p->_cond,0);
+ if (ret != 0) dump_error(__LINE__,ret,"SemC::pthread_cond_init",&p->_mutex);
+ p->_count = initiallyCount;
+ p->_maxCount = maxCount;
+ p->_created = 1;
+ }
+ return ret;
+}
+
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
+{
+ int ret;
+ if (releaseCount < 1) return EINVAL;
+
+ ret = pthread_mutex_lock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_lock",&p->_mutex);
+ if (ret == 0)
+ {
+ UInt32 newCount = p->_count + releaseCount;
+ if (newCount > p->_maxCount)
+ {
+ ret = pthread_mutex_unlock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_unlock",&p->_mutex);
+ return EINVAL;
+ }
+ p->_count = newCount;
+ ret = pthread_cond_broadcast(&p->_cond);
+ if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_cond_broadcast",&p->_cond);
+ if (ret == 0)
+ {
+ ret = pthread_mutex_unlock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"SemR::pthread_mutex_unlock",&p->_mutex);
+ }
+ }
+ return ret;
+}
+
+WRes Semaphore_Wait(CSemaphore *p) {
+ int ret = pthread_mutex_lock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_mutex_lock",&p->_mutex);
+ if (ret == 0)
+ {
+ while ((p->_count < 1) && (ret == 0))
+ {
+ ret = pthread_cond_wait(&p->_cond, &p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_cond_wait",&p->_mutex);
+ }
+ if (ret == 0)
+ {
+ p->_count--;
+ ret = pthread_mutex_unlock(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"SemW::pthread_mutex_unlock",&p->_mutex);
+ }
+ }
+ return ret;
+}
+
+WRes Semaphore_Close(CSemaphore *p) {
+ if (p->_created)
+ {
+ int ret;
+ p->_created = 0;
+ ret = pthread_mutex_destroy(&p->_mutex);
+ if (ret != 0) dump_error(__LINE__,ret,"Semc::pthread_mutex_destroy",&p->_mutex);
+ ret = pthread_cond_destroy(&p->_cond);
+ if (ret != 0) dump_error(__LINE__,ret,"Semc::pthread_cond_destroy",&p->_cond);
+ }
+ return 0;
+}
+
+WRes CriticalSection_Init(CCriticalSection * lpCriticalSection)
+{
+ if (lpCriticalSection)
+ {
+ int ret;
+ pthread_mutexattr_t mutexattr;
+ memset(&mutexattr,0,sizeof(mutexattr));
+ ret = pthread_mutexattr_init(&mutexattr);
+ if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_init",&mutexattr);
+ ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK);
+ if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_settype",&mutexattr);
+ ret = pthread_mutex_init(&lpCriticalSection->_mutex,&mutexattr);
+ if (ret != 0) dump_error(__LINE__,ret,"CS I::pthread_mutexattr_init",&lpCriticalSection->_mutex);
+ return ret;
+ }
+ return EINTR;
+}
+
+void CriticalSection_Enter(CCriticalSection * lpCriticalSection)
+{
+ if (lpCriticalSection)
+ {
+ int ret = pthread_mutex_lock(&(lpCriticalSection->_mutex));
+ if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_lock",&(lpCriticalSection->_mutex));
+ }
+}
+
+void CriticalSection_Leave(CCriticalSection * lpCriticalSection)
+{
+ if (lpCriticalSection)
+ {
+ int ret = pthread_mutex_unlock(&(lpCriticalSection->_mutex));
+ if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_unlock",&(lpCriticalSection->_mutex));
+ }
+}
+
+void CriticalSection_Delete(CCriticalSection * lpCriticalSection)
+{
+ if (lpCriticalSection)
+ {
+ int ret = pthread_mutex_destroy(&(lpCriticalSection->_mutex));
+ if (ret != 0) dump_error(__LINE__,ret,"CS::pthread_mutex_destroy",&(lpCriticalSection->_mutex));
+ }
+}
+
+#else
+
+WRes Event_Create(CEvent *p, BOOL manualReset, int initialSignaled)
+{
+ pthread_mutex_init(&p->_mutex,0);
+ pthread_cond_init(&p->_cond,0);
+ p->_manual_reset = manualReset;
+ p->_state = (initialSignaled ? TRUE : FALSE);
+ p->_created = 1;
+ return 0;
+}
+
+WRes Event_Set(CEvent *p) {
+ pthread_mutex_lock(&p->_mutex);
+ p->_state = TRUE;
+ pthread_cond_broadcast(&p->_cond);
+ pthread_mutex_unlock(&p->_mutex);
+ return 0;
+}
+
+WRes Event_Reset(CEvent *p) {
+ pthread_mutex_lock(&p->_mutex);
+ p->_state = FALSE;
+ pthread_mutex_unlock(&p->_mutex);
+ return 0;
+}
+
+WRes Event_Wait(CEvent *p) {
+ pthread_mutex_lock(&p->_mutex);
+ while (p->_state == FALSE)
+ {
+ pthread_cond_wait(&p->_cond, &p->_mutex);
+ }
+ if (p->_manual_reset == FALSE)
+ {
+ p->_state = FALSE;
+ }
+ pthread_mutex_unlock(&p->_mutex);
+ return 0;
+}
+
+WRes Event_Close(CEvent *p) {
+ if (p->_created)
+ {
+ p->_created = 0;
+ pthread_mutex_destroy(&p->_mutex);
+ pthread_cond_destroy(&p->_cond);
+ }
+ return 0;
+}
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount)
+{
+ pthread_mutex_init(&p->_mutex,0);
+ pthread_cond_init(&p->_cond,0);
+ p->_count = initiallyCount;
+ p->_maxCount = maxCount;
+ p->_created = 1;
+ return 0;
+}
+
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
+{
+ UInt32 newCount;
+
+ if (releaseCount < 1) return EINVAL;
+
+ pthread_mutex_lock(&p->_mutex);
+
+ newCount = p->_count + releaseCount;
+ if (newCount > p->_maxCount)
+ {
+ pthread_mutex_unlock(&p->_mutex);
+ return EINVAL;
+ }
+ p->_count = newCount;
+ pthread_cond_broadcast(&p->_cond);
+ pthread_mutex_unlock(&p->_mutex);
+ return 0;
+}
+
+WRes Semaphore_Wait(CSemaphore *p) {
+ pthread_mutex_lock(&p->_mutex);
+ while (p->_count < 1)
+ {
+ pthread_cond_wait(&p->_cond, &p->_mutex);
+ }
+ p->_count--;
+ pthread_mutex_unlock(&p->_mutex);
+ return 0;
+}
+
+WRes Semaphore_Close(CSemaphore *p) {
+ if (p->_created)
+ {
+ p->_created = 0;
+ pthread_mutex_destroy(&p->_mutex);
+ pthread_cond_destroy(&p->_cond);
+ }
+ return 0;
+}
+
+WRes CriticalSection_Init(CCriticalSection * lpCriticalSection)
+{
+ return pthread_mutex_init(&(lpCriticalSection->_mutex),0);
+}
+
+#endif /* DEBUG_SYNCHRO */
+
+#endif /* ENV_BEOS */
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int initialSignaled)
+ { return Event_Create(p, TRUE, initialSignaled); }
+
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
+ { return ManualResetEvent_Create(p, 0); }
+
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int initialSignaled)
+ { return Event_Create(p, FALSE, initialSignaled); }
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
+ { return AutoResetEvent_Create(p, 0); }
+
diff --git a/src/libs/7zip/unix/C/Threads.h b/src/libs/7zip/unix/C/Threads.h
new file mode 100644
index 000000000..07b05be0c
--- /dev/null
+++ b/src/libs/7zip/unix/C/Threads.h
@@ -0,0 +1,123 @@
+/* Threads.h -- multithreading library
+2008-11-22 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_THRESDS_H
+#define __7Z_THRESDS_H
+
+#include "Types.h"
+#include "windows.h"
+
+#ifdef ENV_BEOS
+#include <kernel/OS.h>
+#define MAX_THREAD 256
+#else
+#include <pthread.h>
+#endif
+
+/* #define DEBUG_SYNCHRO 1 */
+
+typedef struct _CThread
+{
+#ifdef ENV_BEOS
+ thread_id _tid;
+#else
+ pthread_t _tid;
+#endif
+ int _created;
+
+} CThread;
+
+#define Thread_Construct(thread) (thread)->_created = 0
+#define Thread_WasCreated(thread) ((thread)->_created != 0)
+
+typedef unsigned THREAD_FUNC_RET_TYPE;
+#define THREAD_FUNC_CALL_TYPE MY_STD_CALL
+#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
+
+typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
+
+WRes Thread_Create(CThread *thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter);
+WRes Thread_Wait(CThread *thread);
+WRes Thread_Close(CThread *thread);
+
+typedef struct _CEvent
+{
+ int _created;
+ int _manual_reset;
+ int _state;
+#ifdef ENV_BEOS
+ thread_id _waiting[MAX_THREAD];
+ int _index_waiting;
+ sem_id _sem;
+#else
+ pthread_mutex_t _mutex;
+ pthread_cond_t _cond;
+#endif
+} CEvent;
+
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+
+#define Event_Construct(event) (event)->_created = 0
+#define Event_IsCreated(event) ((event)->_created)
+
+WRes ManualResetEvent_Create(CManualResetEvent *event, int initialSignaled);
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *event);
+WRes AutoResetEvent_Create(CAutoResetEvent *event, int initialSignaled);
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *event);
+WRes Event_Set(CEvent *event);
+WRes Event_Reset(CEvent *event);
+WRes Event_Wait(CEvent *event);
+WRes Event_Close(CEvent *event);
+
+
+typedef struct _CSemaphore
+{
+ int _created;
+ UInt32 _count;
+ UInt32 _maxCount;
+#ifdef ENV_BEOS
+ thread_id _waiting[MAX_THREAD];
+ int _index_waiting;
+ sem_id _sem;
+#else
+ pthread_mutex_t _mutex;
+ pthread_cond_t _cond;
+#endif
+} CSemaphore;
+
+#define Semaphore_Construct(p) (p)->_created = 0
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initiallyCount, UInt32 maxCount);
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1)
+WRes Semaphore_Wait(CSemaphore *p);
+WRes Semaphore_Close(CSemaphore *p);
+
+typedef struct {
+#ifdef ENV_BEOS
+ sem_id _sem;
+#else
+ pthread_mutex_t _mutex;
+#endif
+} CCriticalSection;
+
+WRes CriticalSection_Init(CCriticalSection *p);
+#ifdef ENV_BEOS
+#define CriticalSection_Delete(p) delete_sem((p)->_sem)
+#define CriticalSection_Enter(p) acquire_sem((p)->_sem)
+#define CriticalSection_Leave(p) release_sem((p)->_sem)
+#else
+#ifdef DEBUG_SYNCHRO
+void CriticalSection_Delete(CCriticalSection *);
+void CriticalSection_Enter(CCriticalSection *);
+void CriticalSection_Leave(CCriticalSection *);
+#else
+#define CriticalSection_Delete(p) pthread_mutex_destroy(&((p)->_mutex))
+#define CriticalSection_Enter(p) pthread_mutex_lock(&((p)->_mutex))
+#define CriticalSection_Leave(p) pthread_mutex_unlock(&((p)->_mutex))
+#endif
+#endif
+
+#endif
+
diff --git a/src/libs/7zip/unix/C/Types.h b/src/libs/7zip/unix/C/Types.h
new file mode 100644
index 000000000..7732c240c
--- /dev/null
+++ b/src/libs/7zip/unix/C/Types.h
@@ -0,0 +1,254 @@
+/* Types.h -- Basic types
+2010-10-09 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#include <stddef.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+#ifdef _WIN32
+typedef DWORD WRes;
+#else
+typedef int WRes;
+#endif
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#define UINT64_CONST(n) n
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#define UINT64_CONST(n) n ## ULL
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+
+#ifdef _WIN32
+#define MY_STD_CALL __stdcall
+#else
+#define MY_STD_CALL
+#endif
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else
+
+#define MY_CDECL
+#define MY_FAST_CALL
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
+} IByteIn;
+
+typedef struct
+{
+ void (*Write)(void *p, Byte b);
+} IByteOut;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+} ISeqInStream;
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
+
+typedef struct
+{
+ size_t (*Write)(void *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+} ISeqOutStream;
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ISeekInStream;
+
+typedef struct
+{
+ SRes (*Look)(void *p, const void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(void *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ILookInStream;
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
+
+#define LookToRead_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ ILookInStream s;
+ ISeekInStream *realStream;
+ size_t pos;
+ size_t size;
+ Byte buf[LookToRead_BUF_SIZE];
+} CLookToRead;
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
+void LookToRead_Init(CLookToRead *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+typedef struct
+{
+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+} ICompressProgress;
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
+#define IAlloc_Free(p, a) (p)->Free((p), a)
+
+#ifdef _WIN32
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/Xz.c b/src/libs/7zip/unix/C/Xz.c
new file mode 100644
index 000000000..18caba2c1
--- /dev/null
+++ b/src/libs/7zip/unix/C/Xz.c
@@ -0,0 +1,88 @@
+/* Xz.c - Xz
+2009-04-15 : Igor Pavlov : Public domain */
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+#include "Xz.h"
+#include "XzCrc64.h"
+
+Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 };
+Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' };
+
+unsigned Xz_WriteVarInt(Byte *buf, UInt64 v)
+{
+ unsigned i = 0;
+ do
+ {
+ buf[i++] = (Byte)((v & 0x7F) | 0x80);
+ v >>= 7;
+ }
+ while (v != 0);
+ buf[i - 1] &= 0x7F;
+ return i;
+}
+
+void Xz_Construct(CXzStream *p)
+{
+ p->numBlocks = p->numBlocksAllocated = 0;
+ p->blocks = 0;
+ p->flags = 0;
+}
+
+void Xz_Free(CXzStream *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->blocks);
+ p->numBlocks = p->numBlocksAllocated = 0;
+ p->blocks = 0;
+}
+
+unsigned XzFlags_GetCheckSize(CXzStreamFlags f)
+{
+ int t = XzFlags_GetCheckType(f);
+ return (t == 0) ? 0 : (4 << ((t - 1) / 3));
+}
+
+void XzCheck_Init(CXzCheck *p, int mode)
+{
+ p->mode = mode;
+ switch (mode)
+ {
+ case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
+ case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
+ case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break;
+ }
+}
+
+void XzCheck_Update(CXzCheck *p, const void *data, size_t size)
+{
+ switch (p->mode)
+ {
+ case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break;
+ case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break;
+ case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break;
+ }
+}
+
+int XzCheck_Final(CXzCheck *p, Byte *digest)
+{
+ switch (p->mode)
+ {
+ case XZ_CHECK_CRC32:
+ SetUi32(digest, CRC_GET_DIGEST(p->crc));
+ break;
+ case XZ_CHECK_CRC64:
+ {
+ int i;
+ UInt64 v = CRC64_GET_DIGEST(p->crc64);
+ for (i = 0; i < 8; i++, v >>= 8)
+ digest[i] = (Byte)(v & 0xFF);
+ break;
+ }
+ case XZ_CHECK_SHA256:
+ Sha256_Final(&p->sha, digest);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/libs/7zip/unix/C/Xz.h b/src/libs/7zip/unix/C/Xz.h
new file mode 100644
index 000000000..2cfa1b789
--- /dev/null
+++ b/src/libs/7zip/unix/C/Xz.h
@@ -0,0 +1,252 @@
+/* Xz.h - Xz interface
+2010-09-17 : Igor Pavlov : Public domain */
+
+#ifndef __XZ_H
+#define __XZ_H
+
+#include "Sha256.h"
+
+EXTERN_C_BEGIN
+
+#define XZ_ID_Subblock 1
+#define XZ_ID_Delta 3
+#define XZ_ID_X86 4
+#define XZ_ID_PPC 5
+#define XZ_ID_IA64 6
+#define XZ_ID_ARM 7
+#define XZ_ID_ARMT 8
+#define XZ_ID_SPARC 9
+#define XZ_ID_LZMA2 0x21
+
+unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value);
+unsigned Xz_WriteVarInt(Byte *buf, UInt64 v);
+
+/* ---------- xz block ---------- */
+
+#define XZ_BLOCK_HEADER_SIZE_MAX 1024
+
+#define XZ_NUM_FILTERS_MAX 4
+#define XZ_BF_NUM_FILTERS_MASK 3
+#define XZ_BF_PACK_SIZE (1 << 6)
+#define XZ_BF_UNPACK_SIZE (1 << 7)
+
+#define XZ_FILTER_PROPS_SIZE_MAX 20
+
+typedef struct
+{
+ UInt64 id;
+ UInt32 propsSize;
+ Byte props[XZ_FILTER_PROPS_SIZE_MAX];
+} CXzFilter;
+
+typedef struct
+{
+ UInt64 packSize;
+ UInt64 unpackSize;
+ Byte flags;
+ CXzFilter filters[XZ_NUM_FILTERS_MAX];
+} CXzBlock;
+
+#define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1)
+#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0)
+#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0)
+
+SRes XzBlock_Parse(CXzBlock *p, const Byte *header);
+SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes);
+
+/* ---------- xz stream ---------- */
+
+#define XZ_SIG_SIZE 6
+#define XZ_FOOTER_SIG_SIZE 2
+
+extern Byte XZ_SIG[XZ_SIG_SIZE];
+extern Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE];
+
+#define XZ_STREAM_FLAGS_SIZE 2
+#define XZ_STREAM_CRC_SIZE 4
+
+#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE)
+#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4)
+
+#define XZ_CHECK_MASK 0xF
+#define XZ_CHECK_NO 0
+#define XZ_CHECK_CRC32 1
+#define XZ_CHECK_CRC64 4
+#define XZ_CHECK_SHA256 10
+
+typedef struct
+{
+ int mode;
+ UInt32 crc;
+ UInt64 crc64;
+ CSha256 sha;
+} CXzCheck;
+
+void XzCheck_Init(CXzCheck *p, int mode);
+void XzCheck_Update(CXzCheck *p, const void *data, size_t size);
+int XzCheck_Final(CXzCheck *p, Byte *digest);
+
+typedef UInt16 CXzStreamFlags;
+
+#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK)
+#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK)
+#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32)
+unsigned XzFlags_GetCheckSize(CXzStreamFlags f);
+
+SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf);
+SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream);
+
+typedef struct
+{
+ UInt64 unpackSize;
+ UInt64 totalSize;
+} CXzBlockSizes;
+
+typedef struct
+{
+ CXzStreamFlags flags;
+ size_t numBlocks;
+ size_t numBlocksAllocated;
+ CXzBlockSizes *blocks;
+ UInt64 startOffset;
+} CXzStream;
+
+void Xz_Construct(CXzStream *p);
+void Xz_Free(CXzStream *p, ISzAlloc *alloc);
+
+#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1)
+
+UInt64 Xz_GetUnpackSize(const CXzStream *p);
+UInt64 Xz_GetPackSize(const CXzStream *p);
+
+typedef struct
+{
+ size_t num;
+ size_t numAllocated;
+ CXzStream *streams;
+} CXzs;
+
+void Xzs_Construct(CXzs *p);
+void Xzs_Free(CXzs *p, ISzAlloc *alloc);
+SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc);
+
+UInt64 Xzs_GetNumBlocks(const CXzs *p);
+UInt64 Xzs_GetUnpackSize(const CXzs *p);
+
+typedef enum
+{
+ CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ CODER_STATUS_NOT_FINISHED, /* stream was not finished */
+ CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
+} ECoderStatus;
+
+typedef enum
+{
+ CODER_FINISH_ANY, /* finish at any point */
+ CODER_FINISH_END /* block must be finished at the end */
+} ECoderFinishMode;
+
+typedef struct _IStateCoder
+{
+ void *p;
+ void (*Free)(void *p, ISzAlloc *alloc);
+ SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc);
+ void (*Init)(void *p);
+ SRes (*Code)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished);
+} IStateCoder;
+
+#define MIXCODER_NUM_FILTERS_MAX 4
+
+typedef struct
+{
+ ISzAlloc *alloc;
+ Byte *buf;
+ int numCoders;
+ int finished[MIXCODER_NUM_FILTERS_MAX - 1];
+ size_t pos[MIXCODER_NUM_FILTERS_MAX - 1];
+ size_t size[MIXCODER_NUM_FILTERS_MAX - 1];
+ UInt64 ids[MIXCODER_NUM_FILTERS_MAX];
+ IStateCoder coders[MIXCODER_NUM_FILTERS_MAX];
+} CMixCoder;
+
+void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc);
+void MixCoder_Free(CMixCoder *p);
+void MixCoder_Init(CMixCoder *p);
+SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId);
+SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status);
+
+typedef enum
+{
+ XZ_STATE_STREAM_HEADER,
+ XZ_STATE_STREAM_INDEX,
+ XZ_STATE_STREAM_INDEX_CRC,
+ XZ_STATE_STREAM_FOOTER,
+ XZ_STATE_STREAM_PADDING,
+ XZ_STATE_BLOCK_HEADER,
+ XZ_STATE_BLOCK,
+ XZ_STATE_BLOCK_FOOTER
+} EXzState;
+
+typedef struct
+{
+ EXzState state;
+ UInt32 pos;
+ unsigned alignPos;
+ unsigned indexPreSize;
+
+ CXzStreamFlags streamFlags;
+
+ UInt32 blockHeaderSize;
+ UInt64 packSize;
+ UInt64 unpackSize;
+
+ UInt64 numBlocks;
+ UInt64 indexSize;
+ UInt64 indexPos;
+ UInt64 padSize;
+
+ UInt64 numStreams;
+
+ UInt32 crc;
+ CMixCoder decoder;
+ CXzBlock block;
+ CXzCheck check;
+ CSha256 sha;
+ Byte shaDigest[SHA256_DIGEST_SIZE];
+ Byte buf[XZ_BLOCK_HEADER_SIZE_MAX];
+} CXzUnpacker;
+
+SRes XzUnpacker_Create(CXzUnpacker *p, ISzAlloc *alloc);
+void XzUnpacker_Free(CXzUnpacker *p);
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+
+SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, /* int srcWasFinished, */ int finishMode,
+ ECoderStatus *status);
+
+Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/XzCrc64.c b/src/libs/7zip/unix/C/XzCrc64.c
new file mode 100644
index 000000000..0369554b7
--- /dev/null
+++ b/src/libs/7zip/unix/C/XzCrc64.c
@@ -0,0 +1,33 @@
+/* XzCrc64.c -- CRC64 calculation
+2010-04-16 : Igor Pavlov : Public domain */
+
+#include "XzCrc64.h"
+
+#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
+UInt64 g_Crc64Table[256];
+
+void MY_FAST_CALL Crc64GenerateTable(void)
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt64 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ ((UInt64)kCrc64Poly & ~((r & 1) - 1));
+ g_Crc64Table[i] = r;
+ }
+}
+
+UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 ; size--, p++)
+ v = CRC64_UPDATE_BYTE(v, *p);
+ return v;
+}
+
+UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size)
+{
+ return CRC64_GET_DIGEST(Crc64Update(CRC64_INIT_VAL, data, size));
+}
diff --git a/src/libs/7zip/unix/C/XzCrc64.h b/src/libs/7zip/unix/C/XzCrc64.h
new file mode 100644
index 000000000..0e8efd7ea
--- /dev/null
+++ b/src/libs/7zip/unix/C/XzCrc64.h
@@ -0,0 +1,26 @@
+/* XzCrc64.h -- CRC64 calculation
+2010-04-16 : Igor Pavlov : Public domain */
+
+#ifndef __XZ_CRC64_H
+#define __XZ_CRC64_H
+
+#include <stddef.h>
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+extern UInt64 g_Crc64Table[];
+
+void MY_FAST_CALL Crc64GenerateTable(void);
+
+#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF)
+#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL)
+#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size);
+UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/C/XzDec.c b/src/libs/7zip/unix/C/XzDec.c
new file mode 100644
index 000000000..40f1a2a45
--- /dev/null
+++ b/src/libs/7zip/unix/C/XzDec.c
@@ -0,0 +1,875 @@
+/* XzDec.c -- Xz Decode
+2010-04-16 : Igor Pavlov : Public domain */
+
+/* #define XZ_DUMP */
+
+#ifdef XZ_DUMP
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Alloc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "Delta.h"
+#include "Lzma2Dec.h"
+
+#ifdef USE_SUBBLOCK
+#include "SbDec.h"
+#endif
+
+#include "Xz.h"
+
+#define XZ_CHECK_SIZE_MAX 64
+
+#define CODER_BUF_SIZE (1 << 17)
+
+unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
+{
+ int i, limit;
+ *value = 0;
+ limit = (maxSize > 9) ? 9 : (int)maxSize;
+
+ for (i = 0; i < limit;)
+ {
+ Byte b = p[i];
+ *value |= (UInt64)(b & 0x7F) << (7 * i++);
+ if ((b & 0x80) == 0)
+ return (b == 0 && i != 1) ? 0 : i;
+ }
+ return 0;
+}
+
+/* ---------- BraState ---------- */
+
+#define BRA_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ size_t bufPos;
+ size_t bufConv;
+ size_t bufTotal;
+
+ UInt32 methodId;
+ int encodeMode;
+ UInt32 delta;
+ UInt32 ip;
+ UInt32 x86State;
+ Byte deltaState[DELTA_STATE_SIZE];
+
+ Byte buf[BRA_BUF_SIZE];
+} CBraState;
+
+void BraState_Free(void *pp, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, pp);
+}
+
+SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ CBraState *p = ((CBraState *)pp);
+ alloc = alloc;
+ p->encodeMode = 0;
+ p->ip = 0;
+ if (p->methodId == XZ_ID_Delta)
+ {
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ p->delta = (unsigned)props[0] + 1;
+ }
+ else
+ {
+ if (propSize == 4)
+ {
+ UInt32 v = GetUi32(props);
+ switch(p->methodId)
+ {
+ case XZ_ID_PPC:
+ case XZ_ID_ARM:
+ case XZ_ID_SPARC:
+ if ((v & 3) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ case XZ_ID_ARMT:
+ if ((v & 1) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ case XZ_ID_IA64:
+ if ((v & 0xF) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ }
+ p->ip = v;
+ }
+ else if (propSize != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ return SZ_OK;
+}
+
+void BraState_Init(void *pp)
+{
+ CBraState *p = ((CBraState *)pp);
+ p->bufPos = p->bufConv = p->bufTotal = 0;
+ x86_Convert_Init(p->x86State);
+ if (p->methodId == XZ_ID_Delta)
+ Delta_Init(p->deltaState);
+}
+
+#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break;
+
+static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ CBraState *p = ((CBraState *)pp);
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ finishMode = finishMode;
+ *wasFinished = 0;
+ while (destLenOrig > 0)
+ {
+ if (p->bufPos != p->bufConv)
+ {
+ size_t curSize = p->bufConv - p->bufPos;
+ if (curSize > destLenOrig)
+ curSize = destLenOrig;
+ memcpy(dest, p->buf + p->bufPos, curSize);
+ p->bufPos += curSize;
+ *destLen += curSize;
+ dest += curSize;
+ destLenOrig -= curSize;
+ continue;
+ }
+ p->bufTotal -= p->bufPos;
+ memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
+ p->bufPos = 0;
+ p->bufConv = 0;
+ {
+ size_t curSize = BRA_BUF_SIZE - p->bufTotal;
+ if (curSize > srcLenOrig)
+ curSize = srcLenOrig;
+ memcpy(p->buf + p->bufTotal, src, curSize);
+ *srcLen += curSize;
+ src += curSize;
+ srcLenOrig -= curSize;
+ p->bufTotal += curSize;
+ }
+ if (p->bufTotal == 0)
+ break;
+ switch(p->methodId)
+ {
+ case XZ_ID_Delta:
+ if (p->encodeMode)
+ Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal);
+ else
+ Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal);
+ p->bufConv = p->bufTotal;
+ break;
+ case XZ_ID_X86:
+ p->bufConv = x86_Convert(p->buf, p->bufTotal, p->ip, &p->x86State, p->encodeMode);
+ break;
+ CASE_BRA_CONV(PPC)
+ CASE_BRA_CONV(IA64)
+ CASE_BRA_CONV(ARM)
+ CASE_BRA_CONV(ARMT)
+ CASE_BRA_CONV(SPARC)
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ p->ip += (UInt32)p->bufConv;
+
+ if (p->bufConv == 0)
+ {
+ if (!srcWasFinished)
+ break;
+ p->bufConv = p->bufTotal;
+ }
+ }
+ if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished)
+ *wasFinished = 1;
+ return SZ_OK;
+}
+
+SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, ISzAlloc *alloc)
+{
+ CBraState *decoder;
+ if (id != XZ_ID_Delta &&
+ id != XZ_ID_X86 &&
+ id != XZ_ID_PPC &&
+ id != XZ_ID_IA64 &&
+ id != XZ_ID_ARM &&
+ id != XZ_ID_ARMT &&
+ id != XZ_ID_SPARC)
+ return SZ_ERROR_UNSUPPORTED;
+ p->p = 0;
+ decoder = alloc->Alloc(alloc, sizeof(CBraState));
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ decoder->methodId = (UInt32)id;
+ p->p = decoder;
+ p->Free = BraState_Free;
+ p->SetProps = BraState_SetProps;
+ p->Init = BraState_Init;
+ p->Code = BraState_Code;
+ return SZ_OK;
+}
+
+/* ---------- SbState ---------- */
+
+#ifdef USE_SUBBLOCK
+
+static void SbState_Free(void *pp, ISzAlloc *alloc)
+{
+ CSubblockDec *p = (CSubblockDec *)pp;
+ SubblockDec_Free(p, alloc);
+ alloc->Free(alloc, pp);
+}
+
+static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ pp = pp;
+ props = props;
+ alloc = alloc;
+ return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static void SbState_Init(void *pp)
+{
+ SubblockDec_Init((CSubblockDec *)pp);
+}
+
+static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ ECoderStatus status;
+ SRes res = SubblockDec_Decode((CSubblockDec *)pp, dest, destLen, src, srcLen, finishMode, &status);
+ srcWasFinished = srcWasFinished;
+ *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
+ return res;
+}
+
+SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
+{
+ CSubblockDec *decoder;
+ p->p = 0;
+ decoder = alloc->Alloc(alloc, sizeof(CSubblockDec));
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ p->p = decoder;
+ p->Free = SbState_Free;
+ p->SetProps = SbState_SetProps;
+ p->Init = SbState_Init;
+ p->Code = SbState_Code;
+ SubblockDec_Construct(decoder);
+ return SZ_OK;
+}
+#endif
+
+/* ---------- Lzma2State ---------- */
+
+static void Lzma2State_Free(void *pp, ISzAlloc *alloc)
+{
+ Lzma2Dec_Free((CLzma2Dec *)pp, alloc);
+ alloc->Free(alloc, pp);
+}
+
+static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc);
+}
+
+static void Lzma2State_Init(void *pp)
+{
+ Lzma2Dec_Init((CLzma2Dec *)pp);
+}
+
+static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ ELzmaStatus status;
+ /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
+ SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, finishMode, &status);
+ srcWasFinished = srcWasFinished;
+ *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
+ return res;
+}
+
+static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
+{
+ CLzma2Dec *decoder = alloc->Alloc(alloc, sizeof(CLzma2Dec));
+ p->p = decoder;
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ p->Free = Lzma2State_Free;
+ p->SetProps = Lzma2State_SetProps;
+ p->Init = Lzma2State_Init;
+ p->Code = Lzma2State_Code;
+ Lzma2Dec_Construct(decoder);
+ return SZ_OK;
+}
+
+
+void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc)
+{
+ int i;
+ p->alloc = alloc;
+ p->buf = 0;
+ p->numCoders = 0;
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
+ p->coders[i].p = NULL;
+}
+
+void MixCoder_Free(CMixCoder *p)
+{
+ int i;
+ for (i = 0; i < p->numCoders; i++)
+ {
+ IStateCoder *sc = &p->coders[i];
+ if (p->alloc && sc->p)
+ sc->Free(sc->p, p->alloc);
+ }
+ p->numCoders = 0;
+ if (p->buf)
+ p->alloc->Free(p->alloc, p->buf);
+}
+
+void MixCoder_Init(CMixCoder *p)
+{
+ int i;
+ for (i = 0; i < p->numCoders - 1; i++)
+ {
+ p->size[i] = 0;
+ p->pos[i] = 0;
+ p->finished[i] = 0;
+ }
+ for (i = 0; i < p->numCoders; i++)
+ {
+ IStateCoder *coder = &p->coders[i];
+ coder->Init(coder->p);
+ }
+}
+
+SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId)
+{
+ IStateCoder *sc = &p->coders[coderIndex];
+ p->ids[coderIndex] = methodId;
+ switch(methodId)
+ {
+ case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, p->alloc);
+ #ifdef USE_SUBBLOCK
+ case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);
+ #endif
+ }
+ if (coderIndex == 0)
+ return SZ_ERROR_UNSUPPORTED;
+ return BraState_SetFromMethod(sc, methodId, p->alloc);
+}
+
+SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ Bool allFinished = True;
+ *destLen = 0;
+ *srcLen = 0;
+ *status = CODER_STATUS_NOT_FINISHED;
+
+ if (p->buf == 0)
+ {
+ p->buf = p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
+ if (p->buf == 0)
+ return SZ_ERROR_MEM;
+ }
+
+ if (p->numCoders != 1)
+ finishMode = CODER_FINISH_ANY;
+
+ for (;;)
+ {
+ Bool processed = False;
+ int i;
+ /*
+ if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY)
+ break;
+ */
+
+ for (i = 0; i < p->numCoders; i++)
+ {
+ SRes res;
+ IStateCoder *coder = &p->coders[i];
+ Byte *destCur;
+ SizeT destLenCur, srcLenCur;
+ const Byte *srcCur;
+ int srcFinishedCur;
+ int encodingWasFinished;
+
+ if (i == 0)
+ {
+ srcCur = src;
+ srcLenCur = srcLenOrig - *srcLen;
+ srcFinishedCur = srcWasFinished;
+ }
+ else
+ {
+ srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1];
+ srcLenCur = p->size[i - 1] - p->pos[i - 1];
+ srcFinishedCur = p->finished[i - 1];
+ }
+
+ if (i == p->numCoders - 1)
+ {
+ destCur = dest;
+ destLenCur = destLenOrig - *destLen;
+ }
+ else
+ {
+ if (p->pos[i] != p->size[i])
+ continue;
+ destCur = p->buf + (CODER_BUF_SIZE * i);
+ destLenCur = CODER_BUF_SIZE;
+ }
+
+ res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished);
+
+ if (!encodingWasFinished)
+ allFinished = False;
+
+ if (i == 0)
+ {
+ *srcLen += srcLenCur;
+ src += srcLenCur;
+ }
+ else
+ {
+ p->pos[i - 1] += srcLenCur;
+ }
+
+ if (i == p->numCoders - 1)
+ {
+ *destLen += destLenCur;
+ dest += destLenCur;
+ }
+ else
+ {
+ p->size[i] = destLenCur;
+ p->pos[i] = 0;
+ p->finished[i] = encodingWasFinished;
+ }
+
+ if (res != SZ_OK)
+ return res;
+
+ if (destLenCur != 0 || srcLenCur != 0)
+ processed = True;
+ }
+ if (!processed)
+ break;
+ }
+ if (allFinished)
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+}
+
+SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
+{
+ *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
+ if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) !=
+ GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE))
+ return SZ_ERROR_NO_ARCHIVE;
+ return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
+{
+ return
+ indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) &&
+ (GetUi32(buf) == CrcCalc(buf + 4, 6) &&
+ flags == GetBe16(buf + 8) &&
+ memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0);
+}
+
+#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
+ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
+ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
+
+
+SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
+{
+ unsigned pos;
+ int numFilters, i;
+ UInt32 headerSize = (UInt32)header[0] << 2;
+
+ if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
+ return SZ_ERROR_ARCHIVE;
+
+ pos = 1;
+ if (pos == headerSize)
+ return SZ_ERROR_ARCHIVE;
+ p->flags = header[pos++];
+
+ if (XzBlock_HasPackSize(p))
+ {
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize);
+ if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ if (XzBlock_HasUnpackSize(p))
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize);
+
+ numFilters = XzBlock_GetNumFilters(p);
+ for (i = 0; i < numFilters; i++)
+ {
+ CXzFilter *filter = p->filters + i;
+ UInt64 size;
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id);
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &size);
+ if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX)
+ return SZ_ERROR_ARCHIVE;
+ filter->propsSize = (UInt32)size;
+ memcpy(filter->props, header + pos, (size_t)size);
+ pos += (unsigned)size;
+
+ #ifdef XZ_DUMP
+ printf("\nf[%d] = %2X: ", i, filter->id);
+ {
+ int i;
+ for (i = 0; i < size; i++)
+ printf(" %2X", filter->props[i]);
+ }
+ #endif
+ }
+
+ while (pos < headerSize)
+ if (header[pos++] != 0)
+ return SZ_ERROR_ARCHIVE;
+ return SZ_OK;
+}
+
+SRes XzDec_Init(CMixCoder *p, const CXzBlock *block)
+{
+ int i;
+ Bool needReInit = True;
+ int numFilters = XzBlock_GetNumFilters(block);
+ if (numFilters == p->numCoders)
+ {
+ for (i = 0; i < numFilters; i++)
+ if (p->ids[i] != block->filters[numFilters - 1 - i].id)
+ break;
+ needReInit = (i != numFilters);
+ }
+ if (needReInit)
+ {
+ MixCoder_Free(p);
+ p->numCoders = numFilters;
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &block->filters[numFilters - 1 - i];
+ RINOK(MixCoder_SetFromMethod(p, i, f->id));
+ }
+ }
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &block->filters[numFilters - 1 - i];
+ IStateCoder *sc = &p->coders[i];
+ RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc));
+ }
+ MixCoder_Init(p);
+ return SZ_OK;
+}
+
+SRes XzUnpacker_Create(CXzUnpacker *p, ISzAlloc *alloc)
+{
+ MixCoder_Construct(&p->decoder, alloc);
+ p->state = XZ_STATE_STREAM_HEADER;
+ p->pos = 0;
+ p->numStreams = 0;
+ return SZ_OK;
+}
+
+void XzUnpacker_Free(CXzUnpacker *p)
+{
+ MixCoder_Free(&p->decoder);
+}
+
+SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int finishMode, ECoderStatus *status)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ *status = CODER_STATUS_NOT_SPECIFIED;
+ for (;;)
+ {
+ SizeT srcRem = srcLenOrig - *srcLen;
+
+ if (p->state == XZ_STATE_BLOCK)
+ {
+ SizeT destLen2 = destLenOrig - *destLen;
+ SizeT srcLen2 = srcLenOrig - *srcLen;
+ SRes res;
+ if (srcLen2 == 0 && destLen2 == 0)
+ {
+ *status = CODER_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+
+ res = MixCoder_Code(&p->decoder, dest, &destLen2, src, &srcLen2, False, finishMode, status);
+ XzCheck_Update(&p->check, dest, destLen2);
+
+ (*srcLen) += srcLen2;
+ src += srcLen2;
+ p->packSize += srcLen2;
+
+ (*destLen) += destLen2;
+ dest += destLen2;
+ p->unpackSize += destLen2;
+
+ RINOK(res);
+
+ if (*status == CODER_STATUS_FINISHED_WITH_MARK)
+ {
+ Byte temp[32];
+ unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags));
+ num += Xz_WriteVarInt(temp + num, p->unpackSize);
+ Sha256_Update(&p->sha, temp, num);
+ p->indexSize += num;
+ p->numBlocks++;
+
+ p->state = XZ_STATE_BLOCK_FOOTER;
+ p->pos = 0;
+ p->alignPos = 0;
+ }
+ else if (srcLen2 == 0 && destLen2 == 0)
+ return SZ_OK;
+
+ continue;
+ }
+
+ if (srcRem == 0)
+ {
+ *status = CODER_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ switch(p->state)
+ {
+ case XZ_STATE_STREAM_HEADER:
+ {
+ if (p->pos < XZ_STREAM_HEADER_SIZE)
+ {
+ if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos])
+ return SZ_ERROR_NO_ARCHIVE;
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ }
+ else
+ {
+ RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
+ p->state = XZ_STATE_BLOCK_HEADER;
+ Sha256_Init(&p->sha);
+ p->indexSize = 0;
+ p->numBlocks = 0;
+ p->pos = 0;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_HEADER:
+ {
+ if (p->pos == 0)
+ {
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ if (p->buf[0] == 0)
+ {
+ p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks);
+ p->indexPos = p->indexPreSize;
+ p->indexSize += p->indexPreSize;
+ Sha256_Final(&p->sha, p->shaDigest);
+ Sha256_Init(&p->sha);
+ p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
+ p->state = XZ_STATE_STREAM_INDEX;
+ }
+ p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
+ }
+ else if (p->pos != p->blockHeaderSize)
+ {
+ UInt32 cur = p->blockHeaderSize - p->pos;
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ }
+ else
+ {
+ RINOK(XzBlock_Parse(&p->block, p->buf));
+ p->state = XZ_STATE_BLOCK;
+ p->packSize = 0;
+ p->unpackSize = 0;
+ XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
+ RINOK(XzDec_Init(&p->decoder, &p->block));
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_FOOTER:
+ {
+ if (((p->packSize + p->alignPos) & 3) != 0)
+ {
+ (*srcLen)++;
+ p->alignPos++;
+ if (*src++ != 0)
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
+ UInt32 cur = checkSize - p->pos;
+ if (cur != 0)
+ {
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ }
+ else
+ {
+ Byte digest[XZ_CHECK_SIZE_MAX];
+ p->state = XZ_STATE_BLOCK_HEADER;
+ p->pos = 0;
+ if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
+ return SZ_ERROR_CRC;
+ }
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_INDEX:
+ {
+ if (p->pos < p->indexPreSize)
+ {
+ (*srcLen)++;
+ if (*src++ != p->buf[p->pos++])
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ if (p->indexPos < p->indexSize)
+ {
+ UInt64 cur = p->indexSize - p->indexPos;
+ if (srcRem > cur)
+ srcRem = (SizeT)cur;
+ p->crc = CrcUpdate(p->crc, src, srcRem);
+ Sha256_Update(&p->sha, src, srcRem);
+ (*srcLen) += srcRem;
+ src += srcRem;
+ p->indexPos += srcRem;
+ }
+ else if ((p->indexPos & 3) != 0)
+ {
+ Byte b = *src++;
+ p->crc = CRC_UPDATE_BYTE(p->crc, b);
+ (*srcLen)++;
+ p->indexPos++;
+ p->indexSize++;
+ if (b != 0)
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ Byte digest[SHA256_DIGEST_SIZE];
+ p->state = XZ_STATE_STREAM_INDEX_CRC;
+ p->indexSize += 4;
+ p->pos = 0;
+ Sha256_Final(&p->sha, digest);
+ if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
+ return SZ_ERROR_CRC;
+ }
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_INDEX_CRC:
+ {
+ if (p->pos < 4)
+ {
+ (*srcLen)++;
+ p->buf[p->pos++] = *src++;
+ }
+ else
+ {
+ p->state = XZ_STATE_STREAM_FOOTER;
+ p->pos = 0;
+ if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))
+ return SZ_ERROR_CRC;
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_FOOTER:
+ {
+ UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ if (p->pos == XZ_STREAM_FOOTER_SIZE)
+ {
+ p->state = XZ_STATE_STREAM_PADDING;
+ p->numStreams++;
+ p->padSize = 0;
+ if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf))
+ return SZ_ERROR_CRC;
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_PADDING:
+ {
+ if (*src != 0)
+ {
+ if (((UInt32)p->padSize & 3) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ p->pos = 0;
+ p->state = XZ_STATE_STREAM_HEADER;
+ }
+ else
+ {
+ (*srcLen)++;
+ src++;
+ p->padSize++;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK: break; /* to disable GCC warning */
+ }
+ }
+ /*
+ if (p->state == XZ_STATE_FINISHED)
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ */
+}
+
+Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p)
+{
+ return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
+}
diff --git a/src/libs/7zip/unix/C/XzEnc.c b/src/libs/7zip/unix/C/XzEnc.c
new file mode 100644
index 000000000..721b4e765
--- /dev/null
+++ b/src/libs/7zip/unix/C/XzEnc.c
@@ -0,0 +1,497 @@
+/* XzEnc.c -- Xz Encode
+2009-06-04 : Igor Pavlov : Public domain */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Alloc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#ifdef USE_SUBBLOCK
+#include "SbEnc.h"
+#endif
+
+#include "XzEnc.h"
+
+static void *SzBigAlloc(void *p, size_t size) { p = p; return BigAlloc(size); }
+static void SzBigFree(void *p, void *address) { p = p; BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+#define XzBlock_ClearFlags(p) (p)->flags = 0;
+#define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1);
+#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE;
+#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE;
+
+static SRes WriteBytes(ISeqOutStream *s, const void *buf, UInt32 size)
+{
+ return (s->Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
+}
+
+static SRes WriteBytesAndCrc(ISeqOutStream *s, const void *buf, UInt32 size, UInt32 *crc)
+{
+ *crc = CrcUpdate(*crc, buf, size);
+ return WriteBytes(s, buf, size);
+}
+
+SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
+{
+ UInt32 crc;
+ Byte header[XZ_STREAM_HEADER_SIZE];
+ memcpy(header, XZ_SIG, XZ_SIG_SIZE);
+ header[XZ_SIG_SIZE] = (Byte)(f >> 8);
+ header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
+ crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
+ SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc);
+ return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
+}
+
+SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
+{
+ Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
+
+ unsigned pos = 1;
+ int numFilters, i;
+ header[pos++] = p->flags;
+
+ if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
+ if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
+ numFilters = XzBlock_GetNumFilters(p);
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &p->filters[i];
+ pos += Xz_WriteVarInt(header + pos, f->id);
+ pos += Xz_WriteVarInt(header + pos, f->propsSize);
+ memcpy(header + pos, f->props, f->propsSize);
+ pos += f->propsSize;
+ }
+ while((pos & 3) != 0)
+ header[pos++] = 0;
+ header[0] = (Byte)(pos >> 2);
+ SetUi32(header + pos, CrcCalc(header, pos));
+ return WriteBytes(s, header, pos + 4);
+}
+
+SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
+{
+ Byte buf[32];
+ UInt64 globalPos;
+ {
+ UInt32 crc = CRC_INIT_VAL;
+ unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
+ size_t i;
+
+ globalPos = pos;
+ buf[0] = 0;
+ RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
+ for (i = 0; i < p->numBlocks; i++)
+ {
+ const CXzBlockSizes *block = &p->blocks[i];
+ pos = Xz_WriteVarInt(buf, block->totalSize);
+ pos += Xz_WriteVarInt(buf + pos, block->unpackSize);
+ globalPos += pos;
+ RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
+ }
+ pos = ((unsigned)globalPos & 3);
+ if (pos != 0)
+ {
+ buf[0] = buf[1] = buf[2] = 0;
+ RINOK(WriteBytesAndCrc(s, buf, 4 - pos, &crc));
+ globalPos += 4 - pos;
+ }
+ {
+ SetUi32(buf, CRC_GET_DIGEST(crc));
+ RINOK(WriteBytes(s, buf, 4));
+ globalPos += 4;
+ }
+ }
+
+ {
+ UInt32 indexSize = (UInt32)((globalPos >> 2) - 1);
+ SetUi32(buf + 4, indexSize);
+ buf[8] = (Byte)(p->flags >> 8);
+ buf[9] = (Byte)(p->flags & 0xFF);
+ SetUi32(buf, CrcCalc(buf + 4, 6));
+ memcpy(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE);
+ return WriteBytes(s, buf, 12);
+ }
+}
+
+SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc)
+{
+ if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks)
+ {
+ size_t num = (p->numBlocks + 1) * 2;
+ size_t newSize = sizeof(CXzBlockSizes) * num;
+ CXzBlockSizes *blocks;
+ if (newSize / sizeof(CXzBlockSizes) != num)
+ return SZ_ERROR_MEM;
+ blocks = alloc->Alloc(alloc, newSize);
+ if (blocks == 0)
+ return SZ_ERROR_MEM;
+ if (p->numBlocks != 0)
+ {
+ memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes));
+ Xz_Free(p, alloc);
+ }
+ p->blocks = blocks;
+ p->numBlocksAllocated = num;
+ }
+ {
+ CXzBlockSizes *block = &p->blocks[p->numBlocks++];
+ block->totalSize = totalSize;
+ block->unpackSize = unpackSize;
+ }
+ return SZ_OK;
+}
+
+/* ---------- CSeqCheckInStream ---------- */
+
+typedef struct
+{
+ ISeqInStream p;
+ ISeqInStream *realStream;
+ UInt64 processed;
+ CXzCheck check;
+} CSeqCheckInStream;
+
+void SeqCheckInStream_Init(CSeqCheckInStream *p, int mode)
+{
+ p->processed = 0;
+ XzCheck_Init(&p->check, mode);
+}
+
+void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
+{
+ XzCheck_Final(&p->check, digest);
+}
+
+static SRes SeqCheckInStream_Read(void *pp, void *data, size_t *size)
+{
+ CSeqCheckInStream *p = (CSeqCheckInStream *)pp;
+ SRes res = p->realStream->Read(p->realStream, data, size);
+ XzCheck_Update(&p->check, data, *size);
+ p->processed += *size;
+ return res;
+}
+
+/* ---------- CSeqSizeOutStream ---------- */
+
+typedef struct
+{
+ ISeqOutStream p;
+ ISeqOutStream *realStream;
+ UInt64 processed;
+} CSeqSizeOutStream;
+
+static size_t MyWrite(void *pp, const void *data, size_t size)
+{
+ CSeqSizeOutStream *p = (CSeqSizeOutStream *)pp;
+ size = p->realStream->Write(p->realStream, data, size);
+ p->processed += size;
+ return size;
+}
+
+/* ---------- CSeqInFilter ---------- */
+
+/*
+typedef struct _IFilter
+{
+ void *p;
+ void (*Free)(void *p, ISzAlloc *alloc);
+ SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc);
+ void (*Init)(void *p);
+ size_t (*Filter)(void *p, Byte *data, SizeT destLen);
+} IFilter;
+
+#define FILT_BUF_SIZE (1 << 19)
+
+typedef struct
+{
+ ISeqInStream p;
+ ISeqInStream *realStream;
+ UInt32 x86State;
+ UInt32 ip;
+ UInt64 processed;
+ CXzCheck check;
+ Byte buf[FILT_BUF_SIZE];
+ UInt32 bufferPos;
+ UInt32 convertedPosBegin;
+ UInt32 convertedPosEnd;
+ IFilter *filter;
+} CSeqInFilter;
+
+static SRes SeqInFilter_Read(void *pp, void *data, size_t *size)
+{
+ CSeqInFilter *p = (CSeqInFilter *)pp;
+ size_t remSize = *size;
+ *size = 0;
+
+ while (remSize > 0)
+ {
+ int i;
+ if (p->convertedPosBegin != p->convertedPosEnd)
+ {
+ UInt32 sizeTemp = p->convertedPosEnd - p->convertedPosBegin;
+ if (remSize < sizeTemp)
+ sizeTemp = (UInt32)remSize;
+ memmove(data, p->buf + p->convertedPosBegin, sizeTemp);
+ p->convertedPosBegin += sizeTemp;
+ data = (void *)((Byte *)data + sizeTemp);
+ remSize -= sizeTemp;
+ *size += sizeTemp;
+ break;
+ }
+ for (i = 0; p->convertedPosEnd + i < p->bufferPos; i++)
+ p->buf[i] = p->buf[i + p->convertedPosEnd];
+ p->bufferPos = i;
+ p->convertedPosBegin = p->convertedPosEnd = 0;
+ {
+ size_t processedSizeTemp = FILT_BUF_SIZE - p->bufferPos;
+ RINOK(p->realStream->Read(p->realStream, p->buf + p->bufferPos, &processedSizeTemp));
+ p->bufferPos = p->bufferPos + (UInt32)processedSizeTemp;
+ }
+ p->convertedPosEnd = (UInt32)p->filter->Filter(p->filter->p, p->buf, p->bufferPos);
+ if (p->convertedPosEnd == 0)
+ {
+ if (p->bufferPos == 0)
+ break;
+ else
+ {
+ p->convertedPosEnd = p->bufferPos;
+ continue;
+ }
+ }
+ if (p->convertedPosEnd > p->bufferPos)
+ {
+ for (; p->bufferPos < p->convertedPosEnd; p->bufferPos++)
+ p->buf[p->bufferPos] = 0;
+ p->convertedPosEnd = (UInt32)p->filter->Filter(p->filter->p, p->buf, p->bufferPos);
+ }
+ }
+ return SZ_OK;
+}
+*/
+
+/*
+typedef struct
+{
+ ISeqInStream p;
+ ISeqInStream *realStream;
+ CMixCoder mixCoder;
+ Byte buf[FILT_BUF_SIZE];
+ UInt32 bufPos;
+ UInt32 bufSize;
+} CMixCoderSeqInStream;
+
+static SRes CMixCoderSeqInStream_Read(void *pp, void *data, size_t *size)
+{
+ CMixCoderSeqInStream *p = (CMixCoderSeqInStream *)pp;
+ SRes res = SZ_OK;
+ size_t remSize = *size;
+ *size = 0;
+ while (remSize > 0)
+ {
+ if (p->bufPos == p->bufSize)
+ {
+ size_t curSize;
+ p->bufPos = p->bufSize = 0;
+ if (*size != 0)
+ break;
+ curSize = FILT_BUF_SIZE;
+ RINOK(p->realStream->Read(p->realStream, p->buf, &curSize));
+ p->bufSize = (UInt32)curSize;
+ }
+ {
+ SizeT destLen = remSize;
+ SizeT srcLen = p->bufSize - p->bufPos;
+ res = MixCoder_Code(&p->mixCoder, data, &destLen, p->buf + p->bufPos, &srcLen, 0);
+ data = (void *)((Byte *)data + destLen);
+ remSize -= destLen;
+ *size += destLen;
+ p->bufPos += srcLen;
+ }
+ }
+ return res;
+}
+*/
+
+#ifdef USE_SUBBLOCK
+typedef struct
+{
+ ISeqInStream p;
+ CSubblockEnc sb;
+ UInt64 processed;
+} CSbEncInStream;
+
+void SbEncInStream_Init(CSbEncInStream *p)
+{
+ p->processed = 0;
+ SubblockEnc_Init(&p->sb);
+}
+
+static SRes SbEncInStream_Read(void *pp, void *data, size_t *size)
+{
+ CSbEncInStream *p = (CSbEncInStream *)pp;
+ SRes res = SubblockEnc_Read(&p->sb, data, size);
+ p->processed += *size;
+ return res;
+}
+#endif
+
+typedef struct
+{
+ /* CMixCoderSeqInStream inStream; */
+ CLzma2EncHandle lzma2;
+ #ifdef USE_SUBBLOCK
+ CSbEncInStream sb;
+ #endif
+ ISzAlloc *alloc;
+ ISzAlloc *bigAlloc;
+} CLzma2WithFilters;
+
+
+static void Lzma2WithFilters_Construct(CLzma2WithFilters *p, ISzAlloc *alloc, ISzAlloc *bigAlloc)
+{
+ p->alloc = alloc;
+ p->bigAlloc = bigAlloc;
+ p->lzma2 = NULL;
+ #ifdef USE_SUBBLOCK
+ p->sb.p.Read = SbEncInStream_Read;
+ SubblockEnc_Construct(&p->sb.sb, p->alloc);
+ #endif
+}
+
+static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p)
+{
+ p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc);
+ if (p->lzma2 == 0)
+ return SZ_ERROR_MEM;
+ return SZ_OK;
+}
+
+static void Lzma2WithFilters_Free(CLzma2WithFilters *p)
+{
+ #ifdef USE_SUBBLOCK
+ SubblockEnc_Free(&p->sb.sb);
+ #endif
+ if (p->lzma2)
+ {
+ Lzma2Enc_Destroy(p->lzma2);
+ p->lzma2 = NULL;
+ }
+}
+
+static SRes Xz_Compress(CXzStream *xz,
+ CLzma2WithFilters *lzmaf,
+ ISeqOutStream *outStream,
+ ISeqInStream *inStream,
+ const CLzma2EncProps *lzma2Props,
+ Bool useSubblock,
+ ICompressProgress *progress)
+{
+ xz->flags = XZ_CHECK_CRC32;
+
+ RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, lzma2Props));
+ RINOK(Xz_WriteHeader(xz->flags, outStream));
+
+ {
+ CSeqCheckInStream checkInStream;
+ CSeqSizeOutStream seqSizeOutStream;
+ CXzBlock block;
+ int filterIndex = 0;
+
+ XzBlock_ClearFlags(&block);
+ XzBlock_SetNumFilters(&block, 1 + (useSubblock ? 1 : 0));
+
+ if (useSubblock)
+ {
+ CXzFilter *f = &block.filters[filterIndex++];
+ f->id = XZ_ID_Subblock;
+ f->propsSize = 0;
+ }
+
+ {
+ CXzFilter *f = &block.filters[filterIndex++];
+ f->id = XZ_ID_LZMA2;
+ f->propsSize = 1;
+ f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
+ }
+
+ seqSizeOutStream.p.Write = MyWrite;
+ seqSizeOutStream.realStream = outStream;
+ seqSizeOutStream.processed = 0;
+
+ RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.p));
+
+ checkInStream.p.Read = SeqCheckInStream_Read;
+ checkInStream.realStream = inStream;
+ SeqCheckInStream_Init(&checkInStream, XzFlags_GetCheckType(xz->flags));
+
+ #ifdef USE_SUBBLOCK
+ if (useSubblock)
+ {
+ lzmaf->sb.sb.inStream = &checkInStream.p;
+ SubblockEnc_Init(&lzmaf->sb.sb);
+ }
+ #endif
+
+ {
+ UInt64 packPos = seqSizeOutStream.processed;
+ SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p,
+ #ifdef USE_SUBBLOCK
+ useSubblock ? &lzmaf->sb.p:
+ #endif
+ &checkInStream.p,
+ progress);
+ RINOK(res);
+ block.unpackSize = checkInStream.processed;
+ block.packSize = seqSizeOutStream.processed - packPos;
+ }
+
+ {
+ unsigned padSize = 0;
+ Byte buf[128];
+ while((((unsigned)block.packSize + padSize) & 3) != 0)
+ buf[padSize++] = 0;
+ SeqCheckInStream_GetDigest(&checkInStream, buf + padSize);
+ RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags)));
+ RINOK(Xz_AddIndexRecord(xz, block.unpackSize, seqSizeOutStream.processed - padSize, &g_Alloc));
+ }
+ }
+ return Xz_WriteFooter(xz, outStream);
+}
+
+SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
+ const CLzma2EncProps *lzma2Props, Bool useSubblock,
+ ICompressProgress *progress)
+{
+ SRes res;
+ CXzStream xz;
+ CLzma2WithFilters lzmaf;
+ Xz_Construct(&xz);
+ Lzma2WithFilters_Construct(&lzmaf, &g_Alloc, &g_BigAlloc);
+ res = Lzma2WithFilters_Create(&lzmaf);
+ if (res == SZ_OK)
+ res = Xz_Compress(&xz, &lzmaf, outStream, inStream,
+ lzma2Props, useSubblock, progress);
+ Lzma2WithFilters_Free(&lzmaf);
+ Xz_Free(&xz, &g_Alloc);
+ return res;
+}
+
+SRes Xz_EncodeEmpty(ISeqOutStream *outStream)
+{
+ SRes res;
+ CXzStream xz;
+ Xz_Construct(&xz);
+ res = Xz_WriteHeader(xz.flags, outStream);
+ if (res == SZ_OK)
+ res = Xz_WriteFooter(&xz, outStream);
+ Xz_Free(&xz, &g_Alloc);
+ return res;
+}
diff --git a/src/libs/7zip/unix/C/XzEnc.h b/src/libs/7zip/unix/C/XzEnc.h
new file mode 100644
index 000000000..13390df8b
--- /dev/null
+++ b/src/libs/7zip/unix/C/XzEnc.h
@@ -0,0 +1,25 @@
+/* XzEnc.h -- Xz Encode
+2009-04-15 : Igor Pavlov : Public domain */
+
+#ifndef __XZ_ENC_H
+#define __XZ_ENC_H
+
+#include "Lzma2Enc.h"
+
+#include "Xz.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
+ const CLzma2EncProps *lzma2Props, Bool useSubblock,
+ ICompressProgress *progress);
+
+SRes Xz_EncodeEmpty(ISeqOutStream *outStream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/C/XzIn.c b/src/libs/7zip/unix/C/XzIn.c
new file mode 100644
index 000000000..f8ea86315
--- /dev/null
+++ b/src/libs/7zip/unix/C/XzIn.c
@@ -0,0 +1,306 @@
+/* XzIn.c - Xz input
+2009-06-19 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+#include "Xz.h"
+
+SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream)
+{
+ Byte sig[XZ_STREAM_HEADER_SIZE];
+ RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE));
+ if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ return Xz_ParseHeader(p, sig);
+}
+
+#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
+ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
+ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
+
+SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes)
+{
+ Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
+ unsigned headerSize;
+ *headerSizeRes = 0;
+ RINOK(SeqInStream_ReadByte(inStream, &header[0]));
+ headerSize = ((unsigned)header[0] << 2) + 4;
+ if (headerSize == 0)
+ {
+ *headerSizeRes = 1;
+ *isIndex = True;
+ return SZ_OK;
+ }
+
+ *isIndex = False;
+ *headerSizeRes = headerSize;
+ RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));
+ return XzBlock_Parse(p, header);
+}
+
+#define ADD_SIZE_CHECH(size, val) \
+ { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
+
+UInt64 Xz_GetUnpackSize(const CXzStream *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->numBlocks; i++)
+ ADD_SIZE_CHECH(size, p->blocks[i].unpackSize);
+ return size;
+}
+
+UInt64 Xz_GetPackSize(const CXzStream *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->numBlocks; i++)
+ ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3);
+ return size;
+}
+
+/*
+SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream)
+{
+ return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
+}
+*/
+
+static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc)
+{
+ size_t i, numBlocks, crcStartPos, pos = 1;
+ UInt32 crc;
+
+ if (size < 5 || buf[0] != 0)
+ return SZ_ERROR_ARCHIVE;
+
+ size -= 4;
+ crc = CrcCalc(buf, size);
+ if (crc != GetUi32(buf + size))
+ return SZ_ERROR_ARCHIVE;
+
+ {
+ UInt64 numBlocks64;
+ READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64);
+ numBlocks = (size_t)numBlocks64;
+ if (numBlocks != numBlocks64 || numBlocks * 2 > size)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ crcStartPos = pos;
+ Xz_Free(p, alloc);
+ if (numBlocks != 0)
+ {
+ p->numBlocks = numBlocks;
+ p->numBlocksAllocated = numBlocks;
+ p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
+ if (p->blocks == 0)
+ return SZ_ERROR_MEM;
+ for (i = 0; i < numBlocks; i++)
+ {
+ CXzBlockSizes *block = &p->blocks[i];
+ READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize);
+ READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize);
+ if (block->totalSize == 0)
+ return SZ_ERROR_ARCHIVE;
+ }
+ }
+ while ((pos & 3) != 0)
+ if (buf[pos++] != 0)
+ return SZ_ERROR_ARCHIVE;
+ return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+}
+
+static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc)
+{
+ SRes res;
+ size_t size;
+ Byte *buf;
+ if (indexSize > ((UInt32)1 << 31))
+ return SZ_ERROR_UNSUPPORTED;
+ size = (size_t)indexSize;
+ if (size != indexSize)
+ return SZ_ERROR_UNSUPPORTED;
+ buf = alloc->Alloc(alloc, size);
+ if (buf == 0)
+ return SZ_ERROR_MEM;
+ res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
+ if (res == SZ_OK)
+ res = Xz_ReadIndex2(p, buf, size, alloc);
+ alloc->Free(alloc, buf);
+ return res;
+}
+
+static SRes SeekFromCur(ILookInStream *inStream, Int64 *res)
+{
+ return inStream->Seek(inStream, res, SZ_SEEK_CUR);
+}
+
+static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc)
+{
+ UInt64 indexSize;
+ Byte buf[XZ_STREAM_FOOTER_SIZE];
+
+ if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset = -XZ_STREAM_FOOTER_SIZE;
+ RINOK(SeekFromCur(stream, startOffset));
+
+ RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
+
+ if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
+ {
+ Int64 i = 0;
+ *startOffset += XZ_STREAM_FOOTER_SIZE;
+ for (;;)
+ {
+ int j;
+ size_t processedSize;
+ #define TEMP_BUF_SIZE (1 << 10)
+ Byte tempBuf[TEMP_BUF_SIZE];
+ if (*startOffset < XZ_STREAM_FOOTER_SIZE || i > (1 << 16))
+ return SZ_ERROR_NO_ARCHIVE;
+ processedSize = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset;
+ i += processedSize;
+ *startOffset = -(Int64)processedSize;
+ RINOK(SeekFromCur(stream, startOffset));
+ RINOK(LookInStream_Read2(stream, tempBuf, processedSize, SZ_ERROR_NO_ARCHIVE));
+ for (j = (int)processedSize; j >= 1; j--) // FIXED j >= 0 => j >= 1
+ if (tempBuf[j -1] != 0)
+ break;
+ if (j != 0)
+ {
+ if ((j & 3) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset += j;
+ if (*startOffset < XZ_STREAM_FOOTER_SIZE)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset -= XZ_STREAM_FOOTER_SIZE;
+ RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
+ RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
+ if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ break;
+ }
+ }
+ }
+
+ p->flags = (CXzStreamFlags)GetBe16(buf + 8);
+
+ if (!XzFlags_IsSupported(p->flags))
+ return SZ_ERROR_UNSUPPORTED;
+
+ if (GetUi32(buf) != CrcCalc(buf + 4, 6))
+ return SZ_ERROR_ARCHIVE;
+
+ indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2;
+
+ *startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE);
+ RINOK(SeekFromCur(stream, startOffset));
+
+ RINOK(Xz_ReadIndex(p, stream, indexSize, alloc));
+
+ {
+ UInt64 totalSize = Xz_GetPackSize(p);
+ UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize;
+ if (totalSize == XZ_SIZE_OVERFLOW ||
+ sum >= ((UInt64)1 << 63) ||
+ totalSize >= ((UInt64)1 << 63))
+ return SZ_ERROR_ARCHIVE;
+ *startOffset = -(Int64)sum;
+ RINOK(SeekFromCur(stream, startOffset));
+ }
+ {
+ CXzStreamFlags headerFlags;
+ CSecToRead secToRead;
+ SecToRead_CreateVTable(&secToRead);
+ secToRead.realStream = stream;
+
+ RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s));
+ return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
+ }
+}
+
+
+/* ---------- Xz Streams ---------- */
+
+void Xzs_Construct(CXzs *p)
+{
+ p->num = p->numAllocated = 0;
+ p->streams = 0;
+}
+
+void Xzs_Free(CXzs *p, ISzAlloc *alloc)
+{
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ Xz_Free(&p->streams[i], alloc);
+ alloc->Free(alloc, p->streams);
+ p->num = p->numAllocated = 0;
+ p->streams = 0;
+}
+
+UInt64 Xzs_GetNumBlocks(const CXzs *p)
+{
+ UInt64 num = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ num += p->streams[i].numBlocks;
+ return num;
+}
+
+UInt64 Xzs_GetUnpackSize(const CXzs *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ ADD_SIZE_CHECH(size, Xz_GetUnpackSize(&p->streams[i]));
+ return size;
+}
+
+/*
+UInt64 Xzs_GetPackSize(const CXzs *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ ADD_SIZE_CHECH(size, Xz_GetTotalSize(&p->streams[i]));
+ return size;
+}
+*/
+
+SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc)
+{
+ Int64 endOffset = 0;
+ RINOK(stream->Seek(stream, &endOffset, SZ_SEEK_END));
+ *startOffset = endOffset;
+ for (;;)
+ {
+ CXzStream st;
+ SRes res;
+ Xz_Construct(&st);
+ res = Xz_ReadBackward(&st, stream, startOffset, alloc);
+ st.startOffset = *startOffset;
+ RINOK(res);
+ if (p->num == p->numAllocated)
+ {
+ size_t newNum = p->num + p->num / 4 + 1;
+ Byte *data = (Byte *)alloc->Alloc(alloc, newNum * sizeof(CXzStream));
+ if (data == 0)
+ return SZ_ERROR_MEM;
+ p->numAllocated = newNum;
+ memcpy(data, p->streams, p->num * sizeof(CXzStream));
+ alloc->Free(alloc, p->streams);
+ p->streams = (CXzStream *)data;
+ }
+ p->streams[p->num++] = st;
+ if (*startOffset == 0)
+ break;
+ RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
+ if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
+ return SZ_ERROR_PROGRESS;
+ }
+ return SZ_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.cpp
new file mode 100644
index 000000000..6774fc482
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.cpp
@@ -0,0 +1,3 @@
+// CompressionMethod.cpp
+
+#include "StdAfx.h"
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.h
new file mode 100644
index 000000000..55bbc68ee
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zCompressionMode.h
@@ -0,0 +1,50 @@
+// 7zCompressionMode.h
+
+#ifndef __7Z_COMPRESSION_MODE_H
+#define __7Z_COMPRESSION_MODE_H
+
+#include "../../../Common/MyString.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CMethodFull: public CMethod
+{
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+ bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBind
+{
+ UInt32 InCoder;
+ UInt32 InStream;
+ UInt32 OutCoder;
+ UInt32 OutStream;
+};
+
+struct CCompressionMethodMode
+{
+ CObjectVector<CMethodFull> Methods;
+ CRecordVector<CBind> Binds;
+ #ifndef _7ZIP_ST
+ UInt32 NumThreads;
+ #endif
+ bool PasswordIsDefined;
+ UString Password;
+
+ bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
+ CCompressionMethodMode(): PasswordIsDefined(false)
+ #ifndef _7ZIP_ST
+ , NumThreads(1)
+ #endif
+ {}
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp
new file mode 100644
index 000000000..425a34157
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp
@@ -0,0 +1,332 @@
+// 7zDecode.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/LockedStream.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+
+#include "7zDecode.h"
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,
+ CBindInfoEx &bindInfo)
+{
+ bindInfo.Clear();
+ int i;
+ for (i = 0; i < folder.BindPairs.Size(); i++)
+ {
+ NCoderMixer::CBindPair bindPair;
+ bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;
+ bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;
+ bindInfo.BindPairs.Add(bindPair);
+ }
+ UInt32 outStreamIndex = 0;
+ for (i = 0; i < folder.Coders.Size(); i++)
+ {
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ const CCoderInfo &coderInfo = folder.Coders[i];
+ coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;
+ coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;
+ bindInfo.Coders.Add(coderStreamsInfo);
+ bindInfo.CoderMethodIDs.Add(coderInfo.MethodID);
+ for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)
+ if (folder.FindBindPairForOutStream(outStreamIndex) < 0)
+ bindInfo.OutStreams.Add(outStreamIndex);
+ }
+ for (i = 0; i < folder.PackStreams.Size(); i++)
+ bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]);
+}
+
+static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1,
+ const NCoderMixer::CCoderStreamsInfo &a2)
+{
+ return (a1.NumInStreams == a2.NumInStreams) &&
+ (a1.NumOutStreams == a2.NumOutStreams);
+}
+
+static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2)
+{
+ return (a1.InIndex == a2.InIndex) &&
+ (a1.OutIndex == a2.OutIndex);
+}
+
+static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
+{
+ if (a1.Coders.Size() != a2.Coders.Size())
+ return false;
+ int i;
+ for (i = 0; i < a1.Coders.Size(); i++)
+ if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
+ return false;
+ if (a1.BindPairs.Size() != a2.BindPairs.Size())
+ return false;
+ for (i = 0; i < a1.BindPairs.Size(); i++)
+ if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i]))
+ return false;
+ for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
+ if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
+ return false;
+ if (a1.InStreams.Size() != a2.InStreams.Size())
+ return false;
+ if (a1.OutStreams.Size() != a2.OutStreams.Size())
+ return false;
+ return true;
+}
+
+CDecoder::CDecoder(bool multiThread)
+{
+ #ifndef _ST_MODE
+ multiThread = true;
+ #endif
+ _multiThread = multiThread;
+ _bindInfoExPrevIsDefined = false;
+}
+
+HRESULT CDecoder::Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ UInt64 startPos,
+ const UInt64 *packSizes,
+ const CFolder &folderInfo,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *compressProgress
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , bool mtMode, UInt32 numThreads
+ #endif
+ )
+{
+ if (!folderInfo.CheckStructure())
+ return E_NOTIMPL;
+ #ifndef _NO_CRYPTO
+ passwordIsDefined = false;
+ #endif
+ CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
+
+ CLockedInStream lockedInStream;
+ lockedInStream.Init(inStream);
+
+ for (int j = 0; j < folderInfo.PackStreams.Size(); j++)
+ {
+ CLockedSequentialInStreamImp *lockedStreamImpSpec = new
+ CLockedSequentialInStreamImp;
+ CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;
+ lockedStreamImpSpec->Init(&lockedInStream, startPos);
+ startPos += packSizes[j];
+
+ CLimitedSequentialInStream *streamSpec = new
+ CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream = streamSpec;
+ streamSpec->SetStream(lockedStreamImp);
+ streamSpec->Init(packSizes[j]);
+ inStreams.Add(inStream);
+ }
+
+ int numCoders = folderInfo.Coders.Size();
+
+ CBindInfoEx bindInfo;
+ ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);
+ bool createNewCoders;
+ if (!_bindInfoExPrevIsDefined)
+ createNewCoders = true;
+ else
+ createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);
+ if (createNewCoders)
+ {
+ int i;
+ _decoders.Clear();
+ // _decoders2.Clear();
+
+ _mixerCoder.Release();
+
+ if (_multiThread)
+ {
+ _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT;
+ _mixerCoder = _mixerCoderMTSpec;
+ _mixerCoderCommon = _mixerCoderMTSpec;
+ }
+ else
+ {
+ #ifdef _ST_MODE
+ _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST;
+ _mixerCoder = _mixerCoderSTSpec;
+ _mixerCoderCommon = _mixerCoderSTSpec;
+ #endif
+ }
+ RINOK(_mixerCoderCommon->SetBindInfo(bindInfo));
+
+ for (i = 0; i < numCoders; i++)
+ {
+ const CCoderInfo &coderInfo = folderInfo.Coders[i];
+
+
+ CMyComPtr<ICompressCoder> decoder;
+ CMyComPtr<ICompressCoder2> decoder2;
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ coderInfo.MethodID, decoder, decoder2, false));
+ CMyComPtr<IUnknown> decoderUnknown;
+ if (coderInfo.IsSimpleCoder())
+ {
+ if (decoder == 0)
+ return E_NOTIMPL;
+
+ decoderUnknown = (IUnknown *)decoder;
+
+ if (_multiThread)
+ _mixerCoderMTSpec->AddCoder(decoder);
+ #ifdef _ST_MODE
+ else
+ _mixerCoderSTSpec->AddCoder(decoder, false);
+ #endif
+ }
+ else
+ {
+ if (decoder2 == 0)
+ return E_NOTIMPL;
+ decoderUnknown = (IUnknown *)decoder2;
+ if (_multiThread)
+ _mixerCoderMTSpec->AddCoder2(decoder2);
+ #ifdef _ST_MODE
+ else
+ _mixerCoderSTSpec->AddCoder2(decoder2, false);
+ #endif
+ }
+ _decoders.Add(decoderUnknown);
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+ }
+ #endif
+ }
+ _bindInfoExPrev = bindInfo;
+ _bindInfoExPrevIsDefined = true;
+ }
+ int i;
+ _mixerCoderCommon->ReInit();
+
+ UInt32 packStreamIndex = 0, unpackStreamIndex = 0;
+ UInt32 coderIndex = 0;
+ // UInt32 coder2Index = 0;
+
+ for (i = 0; i < numCoders; i++)
+ {
+ const CCoderInfo &coderInfo = folderInfo.Coders[i];
+ CMyComPtr<IUnknown> &decoder = _decoders[coderIndex];
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ const CByteBuffer &props = coderInfo.Props;
+ size_t size = props.GetCapacity();
+ if (size > 0xFFFFFFFF)
+ return E_NOTIMPL;
+ // if (size > 0)
+ {
+ RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size));
+ }
+ }
+ }
+
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ if (mtMode)
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(numThreads));
+ }
+ }
+ #endif
+
+ #ifndef _NO_CRYPTO
+ {
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+ if (cryptoSetPassword)
+ {
+ if (getTextPassword == 0)
+ return E_FAIL;
+ CMyComBSTR passwordBSTR;
+ RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR));
+ CByteBuffer buffer;
+ passwordIsDefined = true;
+ const UString password(passwordBSTR);
+ const UInt32 sizeInBytes = password.Length() * 2;
+ buffer.SetCapacity(sizeInBytes);
+ for (int i = 0; i < password.Length(); i++)
+ {
+ wchar_t c = password[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+ }
+ }
+ #endif
+
+ coderIndex++;
+
+ UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;
+ UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;
+ CRecordVector<const UInt64 *> packSizesPointers;
+ CRecordVector<const UInt64 *> unpackSizesPointers;
+ packSizesPointers.Reserve(numInStreams);
+ unpackSizesPointers.Reserve(numOutStreams);
+ UInt32 j;
+ for (j = 0; j < numOutStreams; j++, unpackStreamIndex++)
+ unpackSizesPointers.Add(&folderInfo.UnpackSizes[unpackStreamIndex]);
+
+ for (j = 0; j < numInStreams; j++, packStreamIndex++)
+ {
+ int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);
+ if (bindPairIndex >= 0)
+ packSizesPointers.Add(
+ &folderInfo.UnpackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]);
+ else
+ {
+ int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);
+ if (index < 0)
+ return E_FAIL;
+ packSizesPointers.Add(&packSizes[index]);
+ }
+ }
+
+ _mixerCoderCommon->SetCoderInfo(i,
+ &packSizesPointers.Front(),
+ &unpackSizesPointers.Front());
+ }
+ UInt32 mainCoder, temp;
+ bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);
+
+ if (_multiThread)
+ _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder);
+ /*
+ else
+ _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);;
+ */
+
+ if (numCoders == 0)
+ return 0;
+ CRecordVector<ISequentialInStream *> inStreamPointers;
+ inStreamPointers.Reserve(inStreams.Size());
+ for (i = 0; i < inStreams.Size(); i++)
+ inStreamPointers.Add(inStreams[i]);
+ ISequentialOutStream *outStreamPointer = outStream;
+ return _mixerCoder->Code(&inStreamPointers.Front(), NULL,
+ inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress);
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.h
new file mode 100644
index 000000000..d8a424a36
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zDecode.h
@@ -0,0 +1,68 @@
+// 7zDecode.h
+
+#ifndef __7Z_DECODE_H
+#define __7Z_DECODE_H
+
+#include "../../IStream.h"
+#include "../../IPassword.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+
+#include "../../Common/CreateCoder.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CBindInfoEx: public NCoderMixer::CBindInfo
+{
+ CRecordVector<CMethodId> CoderMethodIDs;
+ void Clear()
+ {
+ CBindInfo::Clear();
+ CoderMethodIDs.Clear();
+ }
+};
+
+class CDecoder
+{
+ bool _bindInfoExPrevIsDefined;
+ CBindInfoEx _bindInfoExPrev;
+
+ bool _multiThread;
+ #ifdef _ST_MODE
+ NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec;
+ #endif
+ NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec;
+ NCoderMixer::CCoderMixer2 *_mixerCoderCommon;
+
+ CMyComPtr<ICompressCoder2> _mixerCoder;
+ CObjectVector<CMyComPtr<IUnknown> > _decoders;
+ // CObjectVector<CMyComPtr<ICompressCoder2> > _decoders2;
+public:
+ CDecoder(bool multiThread);
+ HRESULT Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ UInt64 startPos,
+ const UInt64 *packSizes,
+ const CFolder &folder,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *compressProgress
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPasswordSpec, bool &passwordIsDefined
+ #endif
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , bool mtMode, UInt32 numThreads
+ #endif
+ );
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.cpp
new file mode 100644
index 000000000..87996bc0e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.cpp
@@ -0,0 +1,444 @@
+// 7zEncode.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/InOutTempBuffer.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+
+#include "7zEncode.h"
+#include "7zSpecStream.h"
+
+static const UInt64 k_Delta = 0x03;
+static const UInt64 k_BCJ = 0x03030103;
+static const UInt64 k_BCJ2 = 0x0303011B;
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo,
+ const CRecordVector<CMethodId> decompressionMethods,
+ CFolder &folder)
+{
+ folder.Coders.Clear();
+ // bindInfo.CoderMethodIDs.Clear();
+ // folder.OutStreams.Clear();
+ folder.PackStreams.Clear();
+ folder.BindPairs.Clear();
+ int i;
+ for (i = 0; i < bindInfo.BindPairs.Size(); i++)
+ {
+ CBindPair bindPair;
+ bindPair.InIndex = bindInfo.BindPairs[i].InIndex;
+ bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex;
+ folder.BindPairs.Add(bindPair);
+ }
+ for (i = 0; i < bindInfo.Coders.Size(); i++)
+ {
+ CCoderInfo coderInfo;
+ const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
+ coderInfo.NumInStreams = coderStreamsInfo.NumInStreams;
+ coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams;
+ coderInfo.MethodID = decompressionMethods[i];
+ folder.Coders.Add(coderInfo);
+ }
+ for (i = 0; i < bindInfo.InStreams.Size(); i++)
+ folder.PackStreams.Add(bindInfo.InStreams[i]);
+}
+
+HRESULT CEncoder::CreateMixerCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const UInt64 *inSizeForReduce)
+{
+ _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT;
+ _mixerCoder = _mixerCoderSpec;
+ RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo));
+ for (int i = 0; i < _options.Methods.Size(); i++)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ _codersInfo.Add(CCoderInfo());
+ CCoderInfo &encodingInfo = _codersInfo.Back();
+ encodingInfo.MethodID = methodFull.Id;
+ CMyComPtr<ICompressCoder> encoder;
+ CMyComPtr<ICompressCoder2> encoder2;
+
+
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodFull.Id, encoder, encoder2, true));
+
+ if (!encoder && !encoder2)
+ return E_FAIL;
+
+ CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2;
+
+ #ifndef _7ZIP_ST
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
+ }
+ }
+ #endif
+
+
+ RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon));
+
+ /*
+ CMyComPtr<ICryptoResetSalt> resetSalt;
+ encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
+ if (resetSalt != NULL)
+ {
+ resetSalt->ResetSalt();
+ }
+ */
+
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+ }
+ #endif
+
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+
+ if (cryptoSetPassword)
+ {
+ CByteBuffer buffer;
+ const UInt32 sizeInBytes = _options.Password.Length() * 2;
+ buffer.SetCapacity(sizeInBytes);
+ for (int i = 0; i < _options.Password.Length(); i++)
+ {
+ wchar_t c = _options.Password[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+ }
+
+ if (encoder)
+ _mixerCoderSpec->AddCoder(encoder);
+ else
+ _mixerCoderSpec->AddCoder2(encoder2);
+ }
+ return S_OK;
+}
+
+HRESULT CEncoder::Encode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream,
+ const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
+ CFolder &folderItem,
+ ISequentialOutStream *outStream,
+ CRecordVector<UInt64> &packSizes,
+ ICompressProgressInfo *compressProgress)
+{
+ RINOK(EncoderConstr());
+
+ if (_mixerCoderSpec == NULL)
+ {
+ RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
+ }
+ _mixerCoderSpec->ReInit();
+ // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress);
+
+ CObjectVector<CInOutTempBuffer> inOutTempBuffers;
+ CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs;
+ CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
+ int numMethods = _bindInfo.Coders.Size();
+ int i;
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ inOutTempBuffers.Add(CInOutTempBuffer());
+ inOutTempBuffers.Back().Create();
+ inOutTempBuffers.Back().InitWriting();
+ }
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ CSequentialOutTempBufferImp *tempBufferSpec = new CSequentialOutTempBufferImp;
+ CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
+ tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
+ tempBuffers.Add(tempBuffer);
+ tempBufferSpecs.Add(tempBufferSpec);
+ }
+
+ for (i = 0; i < numMethods; i++)
+ _mixerCoderSpec->SetCoderInfo(i, NULL, NULL);
+
+ if (_bindInfo.InStreams.IsEmpty())
+ return E_FAIL;
+ UInt32 mainCoderIndex, mainStreamIndex;
+ _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex);
+
+ if (inStreamSize != NULL)
+ {
+ CRecordVector<const UInt64 *> sizePointers;
+ for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++)
+ if (i == mainStreamIndex)
+ sizePointers.Add(inStreamSize);
+ else
+ sizePointers.Add(NULL);
+ _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL);
+ }
+
+
+ // UInt64 outStreamStartPos;
+ // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
+
+ CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
+ CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+ CSequentialOutStreamSizeCount *outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
+ CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
+
+ inStreamSizeCountSpec->Init(inStream);
+ outStreamSizeCountSpec->SetStream(outStream);
+ outStreamSizeCountSpec->Init();
+
+ CRecordVector<ISequentialInStream *> inStreamPointers;
+ CRecordVector<ISequentialOutStream *> outStreamPointers;
+ inStreamPointers.Add(inStreamSizeCount);
+ outStreamPointers.Add(outStreamSizeCount);
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ outStreamPointers.Add(tempBuffers[i - 1]);
+
+ for (i = 0; i < _codersInfo.Size(); i++)
+ {
+ CCoderInfo &encodingInfo = _codersInfo[i];
+
+ CMyComPtr<ICryptoResetInitVector> resetInitVector;
+ _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
+ if (resetInitVector != NULL)
+ {
+ resetInitVector->ResetInitVector();
+ }
+
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+ _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+ if (writeCoderProperties != NULL)
+ {
+ CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init();
+ writeCoderProperties->WriteCoderProperties(outStream);
+ outStreamSpec->CopyToBuffer(encodingInfo.Props);
+ }
+ }
+
+ UInt32 progressIndex = mainCoderIndex;
+
+ for (i = 0; i + 1 < _codersInfo.Size(); i++)
+ {
+ UInt64 m = _codersInfo[i].MethodID;
+ if (m == k_Delta || m == k_BCJ || m == k_BCJ2)
+ progressIndex = i + 1;
+ }
+
+ _mixerCoderSpec->SetProgressCoderIndex(progressIndex);
+
+ RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
+ &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
+
+ ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem);
+
+ packSizes.Add(outStreamSizeCountSpec->GetSize());
+
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
+ RINOK(inOutTempBuffer.WriteToStream(outStream));
+ packSizes.Add(inOutTempBuffer.GetDataSize());
+ }
+
+ for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++)
+ {
+ int binder = _bindInfo.FindBinderForInStream(
+ _bindReverseConverter->DestOutToSrcInMap[i]);
+ UInt64 streamSize;
+ if (binder < 0)
+ streamSize = inStreamSizeCountSpec->GetSize();
+ else
+ streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder);
+ folderItem.UnpackSizes.Add(streamSize);
+ }
+ for (i = numMethods - 1; i >= 0; i--)
+ folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props;
+ return S_OK;
+}
+
+
+CEncoder::CEncoder(const CCompressionMethodMode &options):
+ _bindReverseConverter(0),
+ _constructed(false)
+{
+ if (options.IsEmpty())
+ throw 1;
+
+ _options = options;
+ _mixerCoderSpec = NULL;
+}
+
+HRESULT CEncoder::EncoderConstr()
+{
+ if (_constructed)
+ return S_OK;
+ if (_options.Methods.IsEmpty())
+ {
+ // it has only password method;
+ if (!_options.PasswordIsDefined)
+ throw 1;
+ if (!_options.Binds.IsEmpty())
+ throw 1;
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ CMethodFull method;
+
+ method.NumInStreams = 1;
+ method.NumOutStreams = 1;
+ coderStreamsInfo.NumInStreams = 1;
+ coderStreamsInfo.NumOutStreams = 1;
+ method.Id = k_AES;
+
+ _options.Methods.Add(method);
+ _bindInfo.Coders.Add(coderStreamsInfo);
+
+ _bindInfo.InStreams.Add(0);
+ _bindInfo.OutStreams.Add(0);
+ }
+ else
+ {
+
+ UInt32 numInStreams = 0, numOutStreams = 0;
+ int i;
+ for (i = 0; i < _options.Methods.Size(); i++)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ coderStreamsInfo.NumInStreams = methodFull.NumOutStreams;
+ coderStreamsInfo.NumOutStreams = methodFull.NumInStreams;
+ if (_options.Binds.IsEmpty())
+ {
+ if (i < _options.Methods.Size() - 1)
+ {
+ NCoderMixer::CBindPair bindPair;
+ bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams;
+ bindPair.OutIndex = numOutStreams;
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ else
+ _bindInfo.OutStreams.Insert(0, numOutStreams);
+ for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++)
+ _bindInfo.OutStreams.Add(numOutStreams + j);
+ }
+
+ numInStreams += coderStreamsInfo.NumInStreams;
+ numOutStreams += coderStreamsInfo.NumOutStreams;
+
+ _bindInfo.Coders.Add(coderStreamsInfo);
+ }
+
+ if (!_options.Binds.IsEmpty())
+ {
+ for (i = 0; i < _options.Binds.Size(); i++)
+ {
+ NCoderMixer::CBindPair bindPair;
+ const CBind &bind = _options.Binds[i];
+ bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream;
+ bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream;
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ for (i = 0; i < (int)numOutStreams; i++)
+ if (_bindInfo.FindBinderForOutStream(i) == -1)
+ _bindInfo.OutStreams.Add(i);
+ }
+
+ for (i = 0; i < (int)numInStreams; i++)
+ if (_bindInfo.FindBinderForInStream(i) == -1)
+ _bindInfo.InStreams.Add(i);
+
+ if (_bindInfo.InStreams.IsEmpty())
+ throw 1; // this is error
+
+ // Make main stream first in list
+ int inIndex = _bindInfo.InStreams[0];
+ for (;;)
+ {
+ UInt32 coderIndex, coderStreamIndex;
+ _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex);
+ UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
+ int binder = _bindInfo.FindBinderForOutStream(outIndex);
+ if (binder >= 0)
+ {
+ inIndex = _bindInfo.BindPairs[binder].InIndex;
+ continue;
+ }
+ for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
+ if (_bindInfo.OutStreams[i] == outIndex)
+ {
+ _bindInfo.OutStreams.Delete(i);
+ _bindInfo.OutStreams.Insert(0, outIndex);
+ break;
+ }
+ break;
+ }
+
+ if (_options.PasswordIsDefined)
+ {
+ int numCryptoStreams = _bindInfo.OutStreams.Size();
+
+ for (i = 0; i < numCryptoStreams; i++)
+ {
+ NCoderMixer::CBindPair bindPair;
+ bindPair.InIndex = numInStreams + i;
+ bindPair.OutIndex = _bindInfo.OutStreams[i];
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ _bindInfo.OutStreams.Clear();
+
+ /*
+ if (numCryptoStreams == 0)
+ numCryptoStreams = 1;
+ */
+
+ for (i = 0; i < numCryptoStreams; i++)
+ {
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ CMethodFull method;
+ method.NumInStreams = 1;
+ method.NumOutStreams = 1;
+ coderStreamsInfo.NumInStreams = method.NumOutStreams;
+ coderStreamsInfo.NumOutStreams = method.NumInStreams;
+ method.Id = k_AES;
+
+ _options.Methods.Add(method);
+ _bindInfo.Coders.Add(coderStreamsInfo);
+ _bindInfo.OutStreams.Add(numOutStreams + i);
+ }
+ }
+
+ }
+
+ for (int i = _options.Methods.Size() - 1; i >= 0; i--)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ _decompressionMethods.Add(methodFull.Id);
+ }
+
+ _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo);
+ _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo);
+ _constructed = true;
+ return S_OK;
+}
+
+CEncoder::~CEncoder()
+{
+ delete _bindReverseConverter;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.h
new file mode 100644
index 000000000..4909a6e89
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zEncode.h
@@ -0,0 +1,55 @@
+// 7zEncode.h
+
+#ifndef __7Z_ENCODE_H
+#define __7Z_ENCODE_H
+
+// #include "../../Common/StreamObjects.h"
+
+#include "7zCompressionMode.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+#include "7zItem.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CEncoder
+{
+ NCoderMixer::CCoderMixer2MT *_mixerCoderSpec;
+ CMyComPtr<ICompressCoder2> _mixerCoder;
+
+ CObjectVector<CCoderInfo> _codersInfo;
+
+ CCompressionMethodMode _options;
+ NCoderMixer::CBindInfo _bindInfo;
+ NCoderMixer::CBindInfo _decompressBindInfo;
+ NCoderMixer::CBindReverseConverter *_bindReverseConverter;
+ CRecordVector<CMethodId> _decompressionMethods;
+
+ HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS
+ const UInt64 *inSizeForReduce);
+
+ bool _constructed;
+public:
+ CEncoder(const CCompressionMethodMode &options);
+ ~CEncoder();
+ HRESULT EncoderConstr();
+ HRESULT Encode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream,
+ const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
+ CFolder &folderItem,
+ ISequentialOutStream *outStream,
+ CRecordVector<UInt64> &packSizes,
+ ICompressProgressInfo *compressProgress);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zExtract.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zExtract.cpp
new file mode 100644
index 000000000..d55f38e13
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zExtract.cpp
@@ -0,0 +1,270 @@
+// 7zExtract.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../Common/ProgressUtils.h"
+
+#include "7zDecode.h"
+// #include "7z1Decode.h"
+#include "7zFolderOutStream.h"
+#include "7zHandler.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CExtractFolderInfo
+{
+ #ifdef _7Z_VOL
+ int VolumeIndex;
+ #endif
+ CNum FileIndex;
+ CNum FolderIndex;
+ CBoolVector ExtractStatuses;
+ UInt64 UnpackSize;
+ CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ int volumeIndex,
+ #endif
+ CNum fileIndex, CNum folderIndex):
+ #ifdef _7Z_VOL
+ VolumeIndex(volumeIndex),
+ #endif
+ FileIndex(fileIndex),
+ FolderIndex(folderIndex),
+ UnpackSize(0)
+ {
+ if (fileIndex != kNumNoIndex)
+ {
+ ExtractStatuses.Reserve(1);
+ ExtractStatuses.Add(true);
+ }
+ };
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
+{
+ COM_TRY_BEGIN
+ bool testMode = (testModeSpec != 0);
+ CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+ UInt64 importantTotalUnpacked = 0;
+
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems =
+ #ifdef _7Z_VOL
+ _refs.Size();
+ #else
+ _db.Files.Size();
+ #endif
+
+ if(numItems == 0)
+ return S_OK;
+
+ /*
+ if(_volumes.Size() != 1)
+ return E_FAIL;
+ const CVolume &volume = _volumes.Front();
+ const CArchiveDatabaseEx &_db = volume.Database;
+ IInStream *_inStream = volume.Stream;
+ */
+
+ CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
+ for (UInt32 ii = 0; ii < numItems; ii++)
+ {
+ // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
+ UInt32 ref2Index = allFilesMode ? ii : indices[ii];
+ // const CRef2 &ref2 = _refs[ref2Index];
+
+ // for (UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
+ {
+ #ifdef _7Z_VOL
+ // const CRef &ref = ref2.Refs[ri];
+ const CRef &ref = _refs[ref2Index];
+
+ int volumeIndex = ref.VolumeIndex;
+ const CVolume &volume = _volumes[volumeIndex];
+ const CArchiveDatabaseEx &db = volume.Database;
+ UInt32 fileIndex = ref.ItemIndex;
+ #else
+ const CArchiveDatabaseEx &db = _db;
+ UInt32 fileIndex = ref2Index;
+ #endif
+
+ CNum folderIndex = db.FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex == kNumNoIndex)
+ {
+ extractFolderInfoVector.Add(CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ volumeIndex,
+ #endif
+ fileIndex, kNumNoIndex));
+ continue;
+ }
+ if (extractFolderInfoVector.IsEmpty() ||
+ folderIndex != extractFolderInfoVector.Back().FolderIndex
+ #ifdef _7Z_VOL
+ || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
+ #endif
+ )
+ {
+ extractFolderInfoVector.Add(CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ volumeIndex,
+ #endif
+ kNumNoIndex, folderIndex));
+ const CFolder &folderInfo = db.Folders[folderIndex];
+ UInt64 unpackSize = folderInfo.GetUnpackSize();
+ importantTotalUnpacked += unpackSize;
+ extractFolderInfoVector.Back().UnpackSize = unpackSize;
+ }
+
+ CExtractFolderInfo &efi = extractFolderInfoVector.Back();
+
+ // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
+ CNum startIndex = db.FolderStartFileIndex[folderIndex];
+ for (CNum index = efi.ExtractStatuses.Size();
+ index <= fileIndex - startIndex; index++)
+ {
+ // UInt64 unpackSize = _db.Files[startIndex + index].UnpackSize;
+ // Count partial_folder_size
+ // efi.UnpackSize += unpackSize;
+ // importantTotalUnpacked += unpackSize;
+ efi.ExtractStatuses.Add(index == fileIndex - startIndex);
+ }
+ }
+ }
+
+ RINOK(extractCallback->SetTotal(importantTotalUnpacked));
+
+ CDecoder decoder(
+ #ifdef _ST_MODE
+ false
+ #else
+ true
+ #endif
+ );
+ // CDecoder1 decoder;
+
+ UInt64 totalPacked = 0;
+ UInt64 totalUnpacked = 0;
+ UInt64 curPacked, curUnpacked;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (int i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
+ {
+ lps->OutSize = totalUnpacked;
+ lps->InSize = totalPacked;
+ RINOK(lps->SetCur());
+
+ if (i >= extractFolderInfoVector.Size())
+ break;
+
+ const CExtractFolderInfo &efi = extractFolderInfoVector[i];
+ curUnpacked = efi.UnpackSize;
+ curPacked = 0;
+
+ CFolderOutStream *folderOutStream = new CFolderOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
+
+ #ifdef _7Z_VOL
+ const CVolume &volume = _volumes[efi.VolumeIndex];
+ const CArchiveDatabaseEx &db = volume.Database;
+ #else
+ const CArchiveDatabaseEx &db = _db;
+ #endif
+
+ CNum startIndex;
+ if (efi.FileIndex != kNumNoIndex)
+ startIndex = efi.FileIndex;
+ else
+ startIndex = db.FolderStartFileIndex[efi.FolderIndex];
+
+ HRESULT result = folderOutStream->Init(&db,
+ #ifdef _7Z_VOL
+ volume.StartRef2Index,
+ #else
+ 0,
+ #endif
+ startIndex,
+ &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0);
+
+ RINOK(result);
+
+ if (efi.FileIndex != kNumNoIndex)
+ continue;
+
+ CNum folderIndex = efi.FolderIndex;
+ const CFolder &folderInfo = db.Folders[folderIndex];
+
+ curPacked = _db.GetFolderFullPackSize(folderIndex);
+
+ CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex];
+ UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0);
+
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ if (extractCallback)
+ extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ #endif
+
+ try
+ {
+ #ifndef _NO_CRYPTO
+ bool passwordIsDefined;
+ #endif
+
+ HRESULT result = decoder.Decode(
+ EXTERNAL_CODECS_VARS
+ #ifdef _7Z_VOL
+ volume.Stream,
+ #else
+ _inStream,
+ #endif
+ folderStartPackPos,
+ &db.PackSizes[packStreamIndex],
+ folderInfo,
+ outStream,
+ progress
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , true, _numThreads
+ #endif
+ );
+
+ if (result == S_FALSE)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ if (result == E_NOTIMPL)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ if (result != S_OK)
+ return result;
+ if (folderOutStream->WasWritingFinished() != S_OK)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ }
+ catch(...)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.cpp
new file mode 100644
index 000000000..edd276bc1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.cpp
@@ -0,0 +1,123 @@
+// 7zFolderInStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderInStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderInStream::CFolderInStream()
+{
+ _inStreamWithHashSpec = new CSequentialInStreamWithCRC;
+ _inStreamWithHash = _inStreamWithHashSpec;
+}
+
+void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
+ const UInt32 *fileIndices, UInt32 numFiles)
+{
+ _updateCallback = updateCallback;
+ _numFiles = numFiles;
+ _fileIndex = 0;
+ _fileIndices = fileIndices;
+ Processed.Clear();
+ CRCs.Clear();
+ Sizes.Clear();
+ _fileIsOpen = false;
+ _currentSizeIsDefined = false;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+ _filePos = 0;
+ while (_fileIndex < _numFiles)
+ {
+ CMyComPtr<ISequentialInStream> stream;
+ HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream);
+ if (result != S_OK && result != S_FALSE)
+ return result;
+ _fileIndex++;
+ _inStreamWithHashSpec->SetStream(stream);
+ _inStreamWithHashSpec->Init();
+ if (stream)
+ {
+ _fileIsOpen = true;
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+ if (streamGetSize)
+ {
+ RINOK(streamGetSize->GetSize(&_currentSize));
+ _currentSizeIsDefined = true;
+ }
+ return S_OK;
+ }
+ RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ Sizes.Add(0);
+ Processed.Add(result == S_OK);
+ AddDigest();
+ }
+ return S_OK;
+}
+
+void CFolderInStream::AddDigest()
+{
+ CRCs.Add(_inStreamWithHashSpec->GetCRC());
+}
+
+HRESULT CFolderInStream::CloseStream()
+{
+ RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ _inStreamWithHashSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentSizeIsDefined = false;
+ Processed.Add(true);
+ Sizes.Add(_filePos);
+ AddDigest();
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != 0)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 processed2;
+ RINOK(_inStreamWithHash->Read(data, size, &processed2));
+ if (processed2 == 0)
+ {
+ RINOK(CloseStream());
+ continue;
+ }
+ if (processedSize != 0)
+ *processedSize = processed2;
+ _filePos += processed2;
+ break;
+ }
+ if (_fileIndex >= _numFiles)
+ break;
+ RINOK(OpenStream());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
+{
+ *value = 0;
+ int index2 = (int)subStream;
+ if (index2 < 0 || subStream > Sizes.Size())
+ return E_FAIL;
+ if (index2 < Sizes.Size())
+ {
+ *value = Sizes[index2];
+ return S_OK;
+ }
+ if (!_currentSizeIsDefined)
+ return S_FALSE;
+ *value = _currentSize;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.h
new file mode 100644
index 000000000..6df3672a1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderInStream.h
@@ -0,0 +1,58 @@
+// 7zFolderInStream.h
+
+#ifndef __7Z_FOLDER_IN_STREAM_H
+#define __7Z_FOLDER_IN_STREAM_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+#include "../Common/InStreamWithCRC.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderInStream:
+ public ISequentialInStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ CSequentialInStreamWithCRC *_inStreamWithHashSpec;
+ CMyComPtr<ISequentialInStream> _inStreamWithHash;
+ CMyComPtr<IArchiveUpdateCallback> _updateCallback;
+
+ bool _currentSizeIsDefined;
+ bool _fileIsOpen;
+ UInt64 _currentSize;
+ UInt64 _filePos;
+ const UInt32 *_fileIndices;
+ UInt32 _numFiles;
+ UInt32 _fileIndex;
+
+ HRESULT OpenStream();
+ HRESULT CloseStream();
+ void AddDigest();
+
+public:
+ CRecordVector<bool> Processed;
+ CRecordVector<UInt32> CRCs;
+ CRecordVector<UInt64> Sizes;
+
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+
+ CFolderInStream();
+ void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles);
+ UInt64 GetFullSize() const
+ {
+ UInt64 size = 0;
+ for (int i = 0; i < Sizes.Size(); i++)
+ size += Sizes[i];
+ return size;
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
new file mode 100644
index 000000000..22c4600ec
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
@@ -0,0 +1,149 @@
+// 7zFolderOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderOutStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderOutStream::CFolderOutStream()
+{
+ _crcStreamSpec = new COutStreamWithCRC;
+ _crcStream = _crcStreamSpec;
+}
+
+HRESULT CFolderOutStream::Init(
+ const CArchiveDatabaseEx *db,
+ UInt32 ref2Offset, UInt32 startIndex,
+ const CBoolVector *extractStatuses,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode, bool checkCrc)
+{
+ _db = db;
+ _ref2Offset = ref2Offset;
+ _startIndex = startIndex;
+
+ _extractStatuses = extractStatuses;
+ _extractCallback = extractCallback;
+ _testMode = testMode;
+ _checkCrc = checkCrc;
+
+ _currentIndex = 0;
+ _fileIsOpen = false;
+ return ProcessEmptyFiles();
+}
+
+HRESULT CFolderOutStream::OpenFile()
+{
+ Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract) :
+ NExtract::NAskMode::kSkip;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ UInt32 index = _startIndex + _currentIndex;
+ RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
+ _crcStreamSpec->SetStream(realOutStream);
+ _crcStreamSpec->Init(_checkCrc);
+ _fileIsOpen = true;
+ const CFileItem &fi = _db->Files[index];
+ _rem = fi.Size;
+ if (askMode == NExtract::NAskMode::kExtract && !realOutStream &&
+ !_db->IsItemAnti(index) && !fi.IsDir)
+ askMode = NExtract::NAskMode::kSkip;
+ return _extractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res)
+{
+ _crcStreamSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentIndex++;
+ return _extractCallback->SetOperationResult(res);
+}
+
+HRESULT CFolderOutStream::CloseFileAndSetResult()
+{
+ const CFileItem &fi = _db->Files[_startIndex + _currentIndex];
+ return CloseFileAndSetResult(
+ (fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kCRCError);
+}
+
+HRESULT CFolderOutStream::ProcessEmptyFiles()
+{
+ while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
+ {
+ RINOK(OpenFile());
+ RINOK(CloseFileAndSetResult());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = size < _rem ? size : (UInt32)_rem;
+ RINOK(_crcStream->Write(data, cur, &cur));
+ if (cur == 0)
+ break;
+ data = (const Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (processedSize != NULL)
+ *processedSize += cur;
+ if (_rem == 0)
+ {
+ RINOK(CloseFileAndSetResult());
+ RINOK(ProcessEmptyFiles());
+ continue;
+ }
+ }
+ else
+ {
+ RINOK(ProcessEmptyFiles());
+ if (_currentIndex == _extractStatuses->Size())
+ {
+ // we support partial extracting
+ if (processedSize != NULL)
+ *processedSize += size;
+ break;
+ }
+ RINOK(OpenFile());
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
+{
+ *value = 0;
+ if ((int)subStream >= _extractStatuses->Size())
+ return S_FALSE;
+ *value = _db->Files[_startIndex + (int)subStream].Size;
+ return S_OK;
+}
+
+HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
+{
+ while (_currentIndex < _extractStatuses->Size())
+ {
+ if (_fileIsOpen)
+ {
+ RINOK(CloseFileAndSetResult(resultEOperationResult));
+ }
+ else
+ {
+ RINOK(OpenFile());
+ }
+ }
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.h
new file mode 100644
index 000000000..f9bb1af42
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zFolderOutStream.h
@@ -0,0 +1,58 @@
+// 7zFolderOutStream.h
+
+#ifndef __7Z_FOLDER_OUT_STREAM_H
+#define __7Z_FOLDER_OUT_STREAM_H
+
+#include "../../IStream.h"
+#include "../IArchive.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderOutStream:
+ public ISequentialOutStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ COutStreamWithCRC *_crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> _crcStream;
+ const CArchiveDatabaseEx *_db;
+ const CBoolVector *_extractStatuses;
+ CMyComPtr<IArchiveExtractCallback> _extractCallback;
+ UInt32 _ref2Offset;
+ UInt32 _startIndex;
+ int _currentIndex;
+ bool _testMode;
+ bool _checkCrc;
+ bool _fileIsOpen;
+ UInt64 _rem;
+
+ HRESULT OpenFile();
+ HRESULT CloseFileAndSetResult(Int32 res);
+ HRESULT CloseFileAndSetResult();
+ HRESULT ProcessEmptyFiles();
+public:
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+ CFolderOutStream();
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+
+ HRESULT Init(
+ const CArchiveDatabaseEx *db,
+ UInt32 ref2Offset, UInt32 startIndex,
+ const CBoolVector *extractStatuses,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode, bool checkCrc);
+ HRESULT FlushCorrupted(Int32 resultEOperationResult);
+ HRESULT WasWritingFinished() const
+ { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.cpp
new file mode 100644
index 000000000..4ab7afa87
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.cpp
@@ -0,0 +1,482 @@
+// 7zHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+
+#ifndef __7Z_SET_PROPERTIES
+#include "../../../Windows/System.h"
+#endif
+
+#include "../Common/ItemNameUtils.h"
+
+#include "7zHandler.h"
+#include "7zProperties.h"
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+#include "../Common/ParseProperties.h"
+#endif
+#endif
+
+using namespace NWindows;
+
+extern UString ConvertMethodIdToString(UInt64 id);
+
+namespace NArchive {
+namespace N7z {
+
+CHandler::CHandler()
+{
+ _crcSize = 4;
+
+ #ifndef _NO_CRYPTO
+ _passwordIsDefined = false;
+ #endif
+
+ #ifdef EXTRACT_ONLY
+ #ifdef __7Z_SET_PROPERTIES
+ _numThreads = NSystem::GetNumberOfProcessors();
+ #endif
+ #else
+ Init();
+ #endif
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.Files.Size();
+ return S_OK;
+}
+
+#ifdef _SFX
+
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
+ BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
+{
+ return E_NOTIMPL;
+}
+
+
+#else
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidSolid, VT_BOOL},
+ { NULL, kpidNumBlocks, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8}
+};
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ UString resString;
+ CRecordVector<UInt64> ids;
+ int i;
+ for (i = 0; i < _db.Folders.Size(); i++)
+ {
+ const CFolder &f = _db.Folders[i];
+ for (int j = f.Coders.Size() - 1; j >= 0; j--)
+ ids.AddToUniqueSorted(f.Coders[j].MethodID);
+ }
+
+ for (i = 0; i < ids.Size(); i++)
+ {
+ UInt64 id = ids[i];
+ UString methodName;
+ /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
+ if (methodName.IsEmpty())
+ methodName = ConvertMethodIdToString(id);
+ if (!resString.IsEmpty())
+ resString += L' ';
+ resString += methodName;
+ }
+ prop = resString;
+ break;
+ }
+ case kpidSolid: prop = _db.IsSolid(); break;
+ case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break;
+ case kpidHeadersSize: prop = _db.HeadersSize; break;
+ case kpidPhySize: prop = _db.PhySize; break;
+ case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+IMP_IInArchive_ArcProps
+
+#endif
+
+static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop)
+{
+ UInt64 value;
+ if (v.GetItem(index, value))
+ {
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)value;
+ ft.dwHighDateTime = (DWORD)(value >> 32);
+ prop = ft;
+ }
+}
+
+#ifndef _SFX
+
+static UString ConvertUInt32ToString(UInt32 value)
+{
+ wchar_t buffer[32];
+ ConvertUInt64ToString(value, buffer);
+ return buffer;
+}
+
+static UString GetStringForSizeValue(UInt32 value)
+{
+ for (int i = 31; i >= 0; i--)
+ if ((UInt32(1) << i) == value)
+ return ConvertUInt32ToString(i);
+ UString result;
+ if (value % (1 << 20) == 0)
+ {
+ result += ConvertUInt32ToString(value >> 20);
+ result += L"m";
+ }
+ else if (value % (1 << 10) == 0)
+ {
+ result += ConvertUInt32ToString(value >> 10);
+ result += L"k";
+ }
+ else
+ {
+ result += ConvertUInt32ToString(value);
+ result += L"b";
+ }
+ return result;
+}
+
+static const UInt64 k_Copy = 0x0;
+static const UInt64 k_Delta = 3;
+static const UInt64 k_LZMA2 = 0x21;
+static const UInt64 k_LZMA = 0x030101;
+static const UInt64 k_PPMD = 0x030401;
+
+static wchar_t GetHex(Byte value)
+{
+ return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
+}
+static inline void AddHexToString(UString &res, Byte value)
+{
+ res += GetHex((Byte)(value >> 4));
+ res += GetHex((Byte)(value & 0xF));
+}
+
+#endif
+
+bool CHandler::IsEncrypted(UInt32 index2) const
+{
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ return _db.Folders[folderIndex].IsEncrypted();
+ return false;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ /*
+ const CRef2 &ref2 = _refs[index];
+ if (ref2.Refs.IsEmpty())
+ return E_FAIL;
+ const CRef &ref = ref2.Refs.Front();
+ */
+
+ const CFileItem &item = _db.Files[index];
+ UInt32 index2 = index;
+
+ switch(propID)
+ {
+ case kpidPath:
+ if (!item.Name.IsEmpty())
+ prop = NItemName::GetOSName(item.Name);
+ break;
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidSize:
+ {
+ prop = item.Size;
+ // prop = ref2.Size;
+ break;
+ }
+ case kpidPackSize:
+ {
+ // prop = ref2.PackSize;
+ {
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ {
+ if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
+ prop = _db.GetFolderFullPackSize(folderIndex);
+ /*
+ else
+ prop = (UInt64)0;
+ */
+ }
+ else
+ prop = (UInt64)0;
+ }
+ break;
+ }
+ case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; }
+ case kpidCTime: SetPropFromUInt64Def(_db.CTime, index2, prop); break;
+ case kpidATime: SetPropFromUInt64Def(_db.ATime, index2, prop); break;
+ case kpidMTime: SetPropFromUInt64Def(_db.MTime, index2, prop); break;
+ case kpidAttrib: if (item.AttribDefined) prop = item.Attrib; break;
+ case kpidCRC: if (item.CrcDefined) prop = item.Crc; break;
+ case kpidEncrypted: prop = IsEncrypted(index2); break;
+ case kpidIsAnti: prop = _db.IsItemAnti(index2); break;
+ #ifndef _SFX
+ case kpidMethod:
+ {
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ {
+ const CFolder &folderInfo = _db.Folders[folderIndex];
+ UString methodsString;
+ for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
+ {
+ const CCoderInfo &coder = folderInfo.Coders[i];
+ if (!methodsString.IsEmpty())
+ methodsString += L' ';
+
+ UString methodName, propsString;
+ bool methodIsKnown = FindMethod(
+ EXTERNAL_CODECS_VARS
+ coder.MethodID, methodName);
+
+ if (!methodIsKnown)
+ methodsString += ConvertMethodIdToString(coder.MethodID);
+ else
+ {
+ methodsString += methodName;
+ if (coder.MethodID == k_Delta && coder.Props.GetCapacity() == 1)
+ propsString = ConvertUInt32ToString((UInt32)coder.Props[0] + 1);
+ else if (coder.MethodID == k_LZMA && coder.Props.GetCapacity() == 5)
+ {
+ UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
+ propsString = GetStringForSizeValue(dicSize);
+ }
+ else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1)
+ {
+ Byte p = coder.Props[0];
+ UInt32 dicSize = (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11));
+ propsString = GetStringForSizeValue(dicSize);
+ }
+ else if (coder.MethodID == k_PPMD && coder.Props.GetCapacity() == 5)
+ {
+ Byte order = *(const Byte *)coder.Props;
+ propsString = L'o';
+ propsString += ConvertUInt32ToString(order);
+ propsString += L":mem";
+ UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
+ propsString += GetStringForSizeValue(dicSize);
+ }
+ else if (coder.MethodID == k_AES && coder.Props.GetCapacity() >= 1)
+ {
+ const Byte *data = (const Byte *)coder.Props;
+ Byte firstByte = *data++;
+ UInt32 numCyclesPower = firstByte & 0x3F;
+ propsString = ConvertUInt32ToString(numCyclesPower);
+ /*
+ if ((firstByte & 0xC0) != 0)
+ {
+ UInt32 saltSize = (firstByte >> 7) & 1;
+ UInt32 ivSize = (firstByte >> 6) & 1;
+ if (coder.Props.GetCapacity() >= 2)
+ {
+ Byte secondByte = *data++;
+ saltSize += (secondByte >> 4);
+ ivSize += (secondByte & 0x0F);
+ }
+ }
+ */
+ }
+ }
+ if (!propsString.IsEmpty())
+ {
+ methodsString += L':';
+ methodsString += propsString;
+ }
+ else if (coder.Props.GetCapacity() > 0)
+ {
+ methodsString += L":[";
+ for (size_t bi = 0; bi < coder.Props.GetCapacity(); bi++)
+ {
+ if (bi > 5 && bi + 1 < coder.Props.GetCapacity())
+ {
+ methodsString += L"..";
+ break;
+ }
+ else
+ AddHexToString(methodsString, coder.Props[bi]);
+ }
+ methodsString += L']';
+ }
+ }
+ prop = methodsString;
+ }
+ }
+ break;
+ case kpidBlock:
+ {
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ prop = (UInt32)folderIndex;
+ }
+ break;
+ case kpidPackedSize0:
+ case kpidPackedSize1:
+ case kpidPackedSize2:
+ case kpidPackedSize3:
+ case kpidPackedSize4:
+ {
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ {
+ const CFolder &folderInfo = _db.Folders[folderIndex];
+ if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
+ folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
+ {
+ prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
+ }
+ else
+ prop = (UInt64)0;
+ }
+ else
+ prop = (UInt64)0;
+ }
+ break;
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ Close();
+ #ifndef _SFX
+ _fileInfoPopIDs.Clear();
+ #endif
+ try
+ {
+ CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
+
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ if (openArchiveCallback)
+ {
+ openArchiveCallbackTemp.QueryInterface(
+ IID_ICryptoGetTextPassword, &getTextPassword);
+ }
+ #endif
+ CInArchive archive;
+ RINOK(archive.Open(stream, maxCheckStartPosition));
+ #ifndef _NO_CRYPTO
+ _passwordIsDefined = false;
+ UString password;
+ #endif
+ HRESULT result = archive.ReadDatabase(
+ EXTERNAL_CODECS_VARS
+ _db
+ #ifndef _NO_CRYPTO
+ , getTextPassword, _passwordIsDefined
+ #endif
+ );
+ RINOK(result);
+ _db.Fill();
+ _inStream = stream;
+ }
+ catch(...)
+ {
+ Close();
+ return S_FALSE;
+ }
+ // _inStream = stream;
+ #ifndef _SFX
+ FillPopIDs();
+ #endif
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ COM_TRY_BEGIN
+ _inStream.Release();
+ _db.Clear();
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+ COM_TRY_BEGIN
+ const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+ _numThreads = numProcessors;
+
+ for (int i = 0; i < numProperties; i++)
+ {
+ UString name = names[i];
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &value = values[i];
+ UInt32 number;
+ int index = ParseStringToUInt32(name, number);
+ if (index == 0)
+ {
+ if(name.Left(2).CompareNoCase(L"MT") == 0)
+ {
+ RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
+ continue;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+#endif
+#endif
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.h
new file mode 100644
index 000000000..56062d464
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandler.h
@@ -0,0 +1,119 @@
+// 7z/Handler.h
+
+#ifndef __7Z_HANDLER_H
+#define __7Z_HANDLER_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#ifndef EXTRACT_ONLY
+#include "../Common/HandlerOut.h"
+#endif
+
+#include "7zCompressionMode.h"
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+#ifndef __7Z_SET_PROPERTIES
+
+#ifdef EXTRACT_ONLY
+#if !defined(_7ZIP_ST) && !defined(_SFX)
+#define __7Z_SET_PROPERTIES
+#endif
+#else
+#define __7Z_SET_PROPERTIES
+#endif
+
+#endif
+
+
+class CHandler:
+ #ifndef EXTRACT_ONLY
+ public NArchive::COutHandler,
+ #endif
+ public IInArchive,
+ #ifdef __7Z_SET_PROPERTIES
+ public ISetProperties,
+ #endif
+ #ifndef EXTRACT_ONLY
+ public IOutArchive,
+ #endif
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ #ifdef __7Z_SET_PROPERTIES
+ MY_QUERYINTERFACE_ENTRY(ISetProperties)
+ #endif
+ #ifndef EXTRACT_ONLY
+ MY_QUERYINTERFACE_ENTRY(IOutArchive)
+ #endif
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+
+ #ifdef __7Z_SET_PROPERTIES
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+ #endif
+
+ #ifndef EXTRACT_ONLY
+ INTERFACE_IOutArchive(;)
+ #endif
+
+ DECL_ISetCompressCodecsInfo
+
+ CHandler();
+
+private:
+ CMyComPtr<IInStream> _inStream;
+ NArchive::N7z::CArchiveDatabaseEx _db;
+ #ifndef _NO_CRYPTO
+ bool _passwordIsDefined;
+ #endif
+
+ #ifdef EXTRACT_ONLY
+
+ #ifdef __7Z_SET_PROPERTIES
+ UInt32 _numThreads;
+ #endif
+
+ UInt32 _crcSize;
+
+ #else
+
+ CRecordVector<CBind> _binds;
+
+ HRESULT SetCompressionMethod(CCompressionMethodMode &method,
+ CObjectVector<COneMethodInfo> &methodsInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ );
+
+ HRESULT SetCompressionMethod(
+ CCompressionMethodMode &method,
+ CCompressionMethodMode &headerMethod);
+
+ #endif
+
+ bool IsEncrypted(UInt32 index2) const;
+ #ifndef _SFX
+
+ CRecordVector<UInt64> _fileInfoPopIDs;
+ void FillPopIDs();
+
+ #endif
+
+ DECL_EXTERNAL_CODECS_VARS
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp
new file mode 100644
index 000000000..a8ccab6df
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp
@@ -0,0 +1,483 @@
+// 7zHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../ICoder.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/ParseProperties.h"
+
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace N7z {
+
+static const wchar_t *kLZMAMethodName = L"LZMA";
+static const wchar_t *kCopyMethod = L"Copy";
+static const wchar_t *kDefaultMethodName = kLZMAMethodName;
+
+static const UInt32 kLzmaAlgorithmX5 = 1;
+static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
+static const UInt32 kDictionaryForHeaders =
+ #ifdef UNDER_CE
+ 1 << 18
+ #else
+ 1 << 20
+ #endif
+;
+static const UInt32 kNumFastBytesForHeaders = 273;
+static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5;
+
+static inline bool IsCopyMethod(const UString &methodName)
+ { return (methodName.CompareNoCase(kCopyMethod) == 0); }
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+{
+ *type = NFileTimeType::kWindows;
+ return S_OK;
+}
+
+HRESULT CHandler::SetCompressionMethod(
+ CCompressionMethodMode &methodMode,
+ CCompressionMethodMode &headerMethod)
+{
+ HRESULT res = SetCompressionMethod(methodMode, _methods
+ #ifndef _7ZIP_ST
+ , _numThreads
+ #endif
+ );
+ RINOK(res);
+ methodMode.Binds = _binds;
+
+ if (_compressHeaders)
+ {
+ // headerMethod.Methods.Add(methodMode.Methods.Back());
+
+ CObjectVector<COneMethodInfo> headerMethodInfoVector;
+ COneMethodInfo oneMethodInfo;
+ oneMethodInfo.MethodName = kLZMAMethodName;
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kMatchFinder;
+ prop.Value = kLzmaMatchFinderForHeaders;
+ oneMethodInfo.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kAlgorithm;
+ prop.Value = kAlgorithmForHeaders;
+ oneMethodInfo.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kNumFastBytes;
+ prop.Value = (UInt32)kNumFastBytesForHeaders;
+ oneMethodInfo.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kDictionarySize;
+ prop.Value = (UInt32)kDictionaryForHeaders;
+ oneMethodInfo.Props.Add(prop);
+ }
+ headerMethodInfoVector.Add(oneMethodInfo);
+ HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector
+ #ifndef _7ZIP_ST
+ , 1
+ #endif
+ );
+ RINOK(res);
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::SetCompressionMethod(
+ CCompressionMethodMode &methodMode,
+ CObjectVector<COneMethodInfo> &methodsInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ )
+{
+ UInt32 level = _level;
+
+ if (methodsInfo.IsEmpty())
+ {
+ COneMethodInfo oneMethodInfo;
+ oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName);
+ methodsInfo.Add(oneMethodInfo);
+ }
+
+ bool needSolid = false;
+ for(int i = 0; i < methodsInfo.Size(); i++)
+ {
+ COneMethodInfo &oneMethodInfo = methodsInfo[i];
+ SetCompressionMethod2(oneMethodInfo
+ #ifndef _7ZIP_ST
+ , numThreads
+ #endif
+ );
+
+ if (!IsCopyMethod(oneMethodInfo.MethodName))
+ needSolid = true;
+
+ CMethodFull methodFull;
+
+ if (!FindMethod(
+ EXTERNAL_CODECS_VARS
+ oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams))
+ return E_INVALIDARG;
+ methodFull.Props = oneMethodInfo.Props;
+ methodMode.Methods.Add(methodFull);
+
+ if (!_numSolidBytesDefined)
+ {
+ for (int j = 0; j < methodFull.Props.Size(); j++)
+ {
+ const CProp &prop = methodFull.Props[j];
+ if ((prop.Id == NCoderPropID::kDictionarySize ||
+ prop.Id == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4)
+ {
+ _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7;
+ const UInt64 kMinSize = (1 << 24);
+ if (_numSolidBytes < kMinSize)
+ _numSolidBytes = kMinSize;
+ _numSolidBytesDefined = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!needSolid && !_numSolidBytesDefined)
+ {
+ _numSolidBytesDefined = true;
+ _numSolidBytes = 0;
+ }
+ return S_OK;
+}
+
+static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool writeTime, PROPID propID, UInt64 &ft, bool &ftDefined)
+{
+ ft = 0;
+ ftDefined = false;
+ if (!writeTime)
+ return S_OK;
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ {
+ ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
+ ftDefined = true;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ COM_TRY_BEGIN
+
+ const CArchiveDatabaseEx *db = 0;
+ #ifdef _7Z_VOL
+ if (_volumes.Size() > 1)
+ return E_FAIL;
+ const CVolume *volume = 0;
+ if (_volumes.Size() == 1)
+ {
+ volume = &_volumes.Front();
+ db = &volume->Database;
+ }
+ #else
+ if (_inStream != 0)
+ db = &_db;
+ #endif
+
+ CObjectVector<CUpdateItem> updateItems;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+ CUpdateItem ui;
+ ui.NewProps = IntToBool(newProps);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArchive = indexInArchive;
+ ui.IndexInClient = i;
+ ui.IsAnti = false;
+ ui.Size = 0;
+
+ if (ui.IndexInArchive != -1)
+ {
+ if (db == 0 || ui.IndexInArchive >= db->Files.Size())
+ return E_INVALIDARG;
+ const CFileItem &fi = db->Files[ui.IndexInArchive];
+ ui.Name = fi.Name;
+ ui.IsDir = fi.IsDir;
+ ui.Size = fi.Size;
+ ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);
+
+ ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);
+ ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);
+ ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
+ }
+
+ if (ui.NewProps)
+ {
+ bool nameIsDefined;
+ bool folderStatusIsDefined;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.AttribDefined = false;
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ {
+ ui.Attrib = prop.ulVal;
+ ui.AttribDefined = true;
+ }
+ }
+
+ // we need MTime to sort files.
+ RINOK(GetTime(updateCallback, i, WriteCTime, kpidCTime, ui.CTime, ui.CTimeDefined));
+ RINOK(GetTime(updateCallback, i, WriteATime, kpidATime, ui.ATime, ui.ATimeDefined));
+ RINOK(GetTime(updateCallback, i, true, kpidMTime, ui.MTime, ui.MTimeDefined));
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidPath, &prop));
+ if (prop.vt == VT_EMPTY)
+ nameIsDefined = false;
+ else if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ else
+ {
+ ui.Name = NItemName::MakeLegalName(prop.bstrVal);
+ nameIsDefined = true;
+ }
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop));
+ if (prop.vt == VT_EMPTY)
+ folderStatusIsDefined = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ {
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ folderStatusIsDefined = true;
+ }
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.IsAnti = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ if (ui.IsAnti)
+ {
+ ui.AttribDefined = false;
+
+ ui.CTimeDefined = false;
+ ui.ATimeDefined = false;
+ ui.MTimeDefined = false;
+
+ ui.Size = 0;
+ }
+
+ if (!folderStatusIsDefined && ui.AttribDefined)
+ ui.SetDirStatusFromAttrib();
+ }
+
+ if (ui.NewData)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ ui.Size = (UInt64)prop.uhVal.QuadPart;
+ if (ui.Size != 0 && ui.IsAnti)
+ return E_INVALIDARG;
+ }
+ updateItems.Add(ui);
+ }
+
+ CCompressionMethodMode methodMode, headerMethod;
+ RINOK(SetCompressionMethod(methodMode, headerMethod));
+ #ifndef _7ZIP_ST
+ methodMode.NumThreads = _numThreads;
+ headerMethod.NumThreads = 1;
+ #endif
+
+ CMyComPtr<ICryptoGetTextPassword2> getPassword2;
+ updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
+
+ if (getPassword2)
+ {
+ CMyComBSTR password;
+ Int32 passwordIsDefined;
+ RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
+ methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
+ if (methodMode.PasswordIsDefined)
+ methodMode.Password = password;
+ }
+ else
+ methodMode.PasswordIsDefined = false;
+
+ bool compressMainHeader = _compressHeaders; // check it
+
+ bool encryptHeaders = false;
+
+ if (methodMode.PasswordIsDefined)
+ {
+ if (_encryptHeadersSpecified)
+ encryptHeaders = _encryptHeaders;
+ #ifndef _NO_CRYPTO
+ else
+ encryptHeaders = _passwordIsDefined;
+ #endif
+ compressMainHeader = true;
+ if (encryptHeaders)
+ {
+ headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
+ headerMethod.Password = methodMode.Password;
+ }
+ }
+
+ if (numItems < 2)
+ compressMainHeader = false;
+
+ CUpdateOptions options;
+ options.Method = &methodMode;
+ options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0;
+ options.UseFilters = _level != 0 && _autoFilter;
+ options.MaxFilter = _level >= 8;
+
+ options.HeaderOptions.CompressMainHeader = compressMainHeader;
+ options.HeaderOptions.WriteCTime = WriteCTime;
+ options.HeaderOptions.WriteATime = WriteATime;
+ options.HeaderOptions.WriteMTime = WriteMTime;
+
+ options.NumSolidFiles = _numSolidFiles;
+ options.NumSolidBytes = _numSolidBytes;
+ options.SolidExtension = _solidExtension;
+ options.RemoveSfxBlock = _removeSfxBlock;
+ options.VolumeMode = _volumeMode;
+
+ COutArchive archive;
+ CArchiveDatabase newDatabase;
+
+ CMyComPtr<ICryptoGetTextPassword> getPassword;
+ updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
+
+ HRESULT res = Update(
+ EXTERNAL_CODECS_VARS
+ #ifdef _7Z_VOL
+ volume ? volume->Stream: 0,
+ volume ? db : 0,
+ #else
+ _inStream,
+ db,
+ #endif
+ updateItems,
+ archive, newDatabase, outStream, updateCallback, options
+ #ifndef _NO_CRYPTO
+ , getPassword
+ #endif
+ );
+
+ RINOK(res);
+
+ updateItems.ClearAndFree();
+
+ return archive.WriteDatabase(EXTERNAL_CODECS_VARS
+ newDatabase, options.HeaderMethod, options.HeaderOptions);
+
+ COM_TRY_END
+}
+
+static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
+{
+ stream = 0;
+ int index = ParseStringToUInt32(srcString, coder);
+ if (index == 0)
+ return E_INVALIDARG;
+ srcString.Delete(0, index);
+ if (srcString[0] == 'S')
+ {
+ srcString.Delete(0);
+ int index = ParseStringToUInt32(srcString, stream);
+ if (index == 0)
+ return E_INVALIDARG;
+ srcString.Delete(0, index);
+ }
+ return S_OK;
+}
+
+static HRESULT GetBindInfo(UString &srcString, CBind &bind)
+{
+ RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream));
+ if (srcString[0] != ':')
+ return E_INVALIDARG;
+ srcString.Delete(0);
+ RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream));
+ if (!srcString.IsEmpty())
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+ COM_TRY_BEGIN
+ _binds.Clear();
+ BeforeSetProperty();
+
+ for (int i = 0; i < numProperties; i++)
+ {
+ UString name = names[i];
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &value = values[i];
+
+ if (name[0] == 'B')
+ {
+ name.Delete(0);
+ CBind bind;
+ RINOK(GetBindInfo(name, bind));
+ _binds.Add(bind);
+ continue;
+ }
+
+ RINOK(SetProperty(name, value));
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.cpp
new file mode 100644
index 000000000..5b5f2fb37
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.cpp
@@ -0,0 +1,14 @@
+// 7zHeader.cpp
+
+#include "StdAfx.h"
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+#ifdef _7Z_VOL
+Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1};
+#endif
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.h
new file mode 100644
index 000000000..30622b90e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHeader.h
@@ -0,0 +1,97 @@
+// 7z/7zHeader.h
+
+#ifndef __7Z_HEADER_H
+#define __7Z_HEADER_H
+
+#include "../../../Common/Types.h"
+
+namespace NArchive {
+namespace N7z {
+
+const int kSignatureSize = 6;
+extern Byte kSignature[kSignatureSize];
+
+// #define _7Z_VOL
+// 7z-MultiVolume is not finished yet.
+// It can work already, but I still do not like some
+// things of that new multivolume format.
+// So please keep it commented.
+
+#ifdef _7Z_VOL
+extern Byte kFinishSignature[kSignatureSize];
+#endif
+
+struct CArchiveVersion
+{
+ Byte Major;
+ Byte Minor;
+};
+
+const Byte kMajorVersion = 0;
+
+struct CStartHeader
+{
+ UInt64 NextHeaderOffset;
+ UInt64 NextHeaderSize;
+ UInt32 NextHeaderCRC;
+};
+
+const UInt32 kStartHeaderSize = 20;
+
+#ifdef _7Z_VOL
+struct CFinishHeader: public CStartHeader
+{
+ UInt64 ArchiveStartOffset; // data offset from end if that struct
+ UInt64 AdditionalStartBlockSize; // start signature & start header size
+};
+
+const UInt32 kFinishHeaderSize = kStartHeaderSize + 16;
+#endif
+
+namespace NID
+{
+ enum EEnum
+ {
+ kEnd,
+
+ kHeader,
+
+ kArchiveProperties,
+
+ kAdditionalStreamsInfo,
+ kMainStreamsInfo,
+ kFilesInfo,
+
+ kPackInfo,
+ kUnpackInfo,
+ kSubStreamsInfo,
+
+ kSize,
+ kCRC,
+
+ kFolder,
+
+ kCodersUnpackSize,
+ kNumUnpackStream,
+
+ kEmptyStream,
+ kEmptyFile,
+ kAnti,
+
+ kName,
+ kCTime,
+ kATime,
+ kMTime,
+ kWinAttributes,
+ kComment,
+
+ kEncodedHeader,
+
+ kStartPos,
+ kDummy
+ };
+}
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.cpp
new file mode 100644
index 000000000..0feb81d2c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.cpp
@@ -0,0 +1,1276 @@
+// 7zIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "7zDecode.h"
+#include "7zIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+// define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader
+#ifndef _SFX
+#define FORMAT_7Z_RECOVERY
+#endif
+
+namespace NArchive {
+namespace N7z {
+
+static void BoolVector_Fill_False(CBoolVector &v, int size)
+{
+ v.Clear();
+ v.Reserve(size);
+ for (int i = 0; i < size; i++)
+ v.Add(false);
+}
+
+static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index)
+{
+ if (index >= (UInt32)v.Size())
+ return true;
+ bool res = v[index];
+ v[index] = true;
+ return res;
+}
+
+bool CFolder::CheckStructure() const
+{
+ const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it
+ const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax
+ const int kNumBindsMax = 32;
+
+ if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax)
+ return false;
+
+ {
+ CBoolVector v;
+ BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size());
+
+ int i;
+ for (i = 0; i < BindPairs.Size(); i++)
+ if (BoolVector_GetAndSet(v, BindPairs[i].InIndex))
+ return false;
+ for (i = 0; i < PackStreams.Size(); i++)
+ if (BoolVector_GetAndSet(v, PackStreams[i]))
+ return false;
+
+ BoolVector_Fill_False(v, UnpackSizes.Size());
+ for (i = 0; i < BindPairs.Size(); i++)
+ if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex))
+ return false;
+ }
+
+ UInt32 mask[kMaskSize];
+ int i;
+ for (i = 0; i < kMaskSize; i++)
+ mask[i] = 0;
+
+ {
+ CIntVector inStreamToCoder, outStreamToCoder;
+ for (i = 0; i < Coders.Size(); i++)
+ {
+ CNum j;
+ const CCoderInfo &coder = Coders[i];
+ for (j = 0; j < coder.NumInStreams; j++)
+ inStreamToCoder.Add(i);
+ for (j = 0; j < coder.NumOutStreams; j++)
+ outStreamToCoder.Add(i);
+ }
+
+ for (i = 0; i < BindPairs.Size(); i++)
+ {
+ const CBindPair &bp = BindPairs[i];
+ mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]);
+ }
+ }
+
+ for (i = 0; i < kMaskSize; i++)
+ for (int j = 0; j < kMaskSize; j++)
+ if (((1 << j) & mask[i]) != 0)
+ mask[i] |= mask[j];
+
+ for (i = 0; i < kMaskSize; i++)
+ if (((1 << i) & mask[i]) != 0)
+ return false;
+
+ return true;
+}
+
+class CInArchiveException {};
+
+static void ThrowException() { throw CInArchiveException(); }
+static inline void ThrowEndOfData() { ThrowException(); }
+static inline void ThrowUnsupported() { ThrowException(); }
+static inline void ThrowIncorrect() { ThrowException(); }
+static inline void ThrowUnsupportedVersion() { ThrowException(); }
+
+/*
+class CInArchiveException
+{
+public:
+ enum CCauseType
+ {
+ kUnsupportedVersion = 0,
+ kUnsupported,
+ kIncorrect,
+ kEndOfData
+ } Cause;
+ CInArchiveException(CCauseType cause): Cause(cause) {};
+};
+
+static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
+static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); }
+static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
+static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); }
+static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
+*/
+
+class CStreamSwitch
+{
+ CInArchive *_archive;
+ bool _needRemove;
+public:
+ CStreamSwitch(): _needRemove(false) {}
+ ~CStreamSwitch() { Remove(); }
+ void Remove();
+ void Set(CInArchive *archive, const Byte *data, size_t size);
+ void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
+ void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
+};
+
+void CStreamSwitch::Remove()
+{
+ if (_needRemove)
+ {
+ _archive->DeleteByteStream();
+ _needRemove = false;
+ }
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
+{
+ Remove();
+ _archive = archive;
+ _archive->AddByteStream(data, size);
+ _needRemove = true;
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
+{
+ Set(archive, byteBuffer, byteBuffer.GetCapacity());
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
+{
+ Remove();
+ Byte external = archive->ReadByte();
+ if (external != 0)
+ {
+ int dataIndex = (int)archive->ReadNum();
+ if (dataIndex < 0 || dataIndex >= dataVector->Size())
+ ThrowIncorrect();
+ Set(archive, (*dataVector)[dataIndex]);
+ }
+}
+
+Byte CInByte2::ReadByte()
+{
+ if (_pos >= _size)
+ ThrowEndOfData();
+ return _buffer[_pos++];
+}
+
+void CInByte2::ReadBytes(Byte *data, size_t size)
+{
+ if (size > _size - _pos)
+ ThrowEndOfData();
+ for (size_t i = 0; i < size; i++)
+ data[i] = _buffer[_pos++];
+}
+
+void CInByte2::SkipData(UInt64 size)
+{
+ if (size > _size - _pos)
+ ThrowEndOfData();
+ _pos += (size_t)size;
+}
+
+void CInByte2::SkipData()
+{
+ SkipData(ReadNumber());
+}
+
+UInt64 CInByte2::ReadNumber()
+{
+ if (_pos >= _size)
+ ThrowEndOfData();
+ Byte firstByte = _buffer[_pos++];
+ Byte mask = 0x80;
+ UInt64 value = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if ((firstByte & mask) == 0)
+ {
+ UInt64 highPart = firstByte & (mask - 1);
+ value += (highPart << (i * 8));
+ return value;
+ }
+ if (_pos >= _size)
+ ThrowEndOfData();
+ value |= ((UInt64)_buffer[_pos++] << (8 * i));
+ mask >>= 1;
+ }
+ return value;
+}
+
+CNum CInByte2::ReadNum()
+{
+ UInt64 value = ReadNumber();
+ if (value > kNumMax)
+ ThrowUnsupported();
+ return (CNum)value;
+}
+
+UInt32 CInByte2::ReadUInt32()
+{
+ if (_pos + 4 > _size)
+ ThrowEndOfData();
+ UInt32 res = Get32(_buffer + _pos);
+ _pos += 4;
+ return res;
+}
+
+UInt64 CInByte2::ReadUInt64()
+{
+ if (_pos + 8 > _size)
+ ThrowEndOfData();
+ UInt64 res = Get64(_buffer + _pos);
+ _pos += 8;
+ return res;
+}
+
+void CInByte2::ReadString(UString &s)
+{
+ const Byte *buf = _buffer + _pos;
+ size_t rem = (_size - _pos) / 2 * 2;
+ {
+ size_t i;
+ for (i = 0; i < rem; i += 2)
+ if (buf[i] == 0 && buf[i + 1] == 0)
+ break;
+ if (i == rem)
+ ThrowEndOfData();
+ rem = i;
+ }
+ int len = (int)(rem / 2);
+ if (len < 0 || (size_t)len * 2 != rem)
+ ThrowUnsupported();
+ wchar_t *p = s.GetBuffer(len);
+ int i;
+ for (i = 0; i < len; i++, buf += 2)
+ p[i] = (wchar_t)Get16(buf);
+ s.ReleaseBuffer(len);
+ _pos += rem + 2;
+}
+
+static inline bool TestSignature(const Byte *p)
+{
+ for (int i = 0; i < kSignatureSize; i++)
+ if (p[i] != kSignature[i])
+ return false;
+ return CrcCalc(p + 12, 20) == GetUi32(p + 8);
+}
+
+#ifdef FORMAT_7Z_RECOVERY
+static inline bool TestSignature2(const Byte *p)
+{
+ int i;
+ for (i = 0; i < kSignatureSize; i++)
+ if (p[i] != kSignature[i])
+ return false;
+ if (CrcCalc(p + 12, 20) == GetUi32(p + 8))
+ return true;
+ for (i = 8; i < kHeaderSize; i++)
+ if (p[i] != 0)
+ return false;
+ return (p[6] != 0 || p[7] != 0);
+}
+#else
+#define TestSignature2(p) TestSignature(p)
+#endif
+
+HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ RINOK(ReadStream_FALSE(stream, _header, kHeaderSize));
+
+ if (TestSignature2(_header))
+ return S_OK;
+
+ CByteBuffer byteBuffer;
+ const UInt32 kBufferSize = (1 << 16);
+ byteBuffer.SetCapacity(kBufferSize);
+ Byte *buffer = byteBuffer;
+ UInt32 numPrevBytes = kHeaderSize;
+ memcpy(buffer, _header, kHeaderSize);
+ UInt64 curTestPos = _arhiveBeginStreamPosition;
+ for (;;)
+ {
+ if (searchHeaderSizeLimit != NULL)
+ if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
+ break;
+ do
+ {
+ UInt32 numReadBytes = kBufferSize - numPrevBytes;
+ UInt32 processedSize;
+ RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
+ numPrevBytes += processedSize;
+ if (processedSize == 0)
+ return S_FALSE;
+ }
+ while (numPrevBytes <= kHeaderSize);
+ UInt32 numTests = numPrevBytes - kHeaderSize;
+ for (UInt32 pos = 0; pos < numTests; pos++)
+ {
+ for (; buffer[pos] != '7' && pos < numTests; pos++);
+ if (pos == numTests)
+ break;
+ if (TestSignature(buffer + pos))
+ {
+ memcpy(_header, buffer + pos, kHeaderSize);
+ curTestPos += pos;
+ _arhiveBeginStreamPosition = curTestPos;
+ return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
+ }
+ }
+ curTestPos += numTests;
+ numPrevBytes -= numTests;
+ memmove(buffer, buffer + numTests, numPrevBytes);
+ }
+ return S_FALSE;
+}
+
+// S_FALSE means that file is not archive
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ HeadersSize = 0;
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
+ RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
+ _stream = stream;
+ return S_OK;
+}
+
+void CInArchive::Close()
+{
+ _stream.Release();
+}
+
+void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
+{
+ for (;;)
+ {
+ if (ReadID() == NID::kEnd)
+ break;
+ SkipData();
+ }
+}
+
+void CInArchive::GetNextFolderItem(CFolder &folder)
+{
+ CNum numCoders = ReadNum();
+
+ folder.Coders.Clear();
+ folder.Coders.Reserve((int)numCoders);
+ CNum numInStreams = 0;
+ CNum numOutStreams = 0;
+ CNum i;
+ for (i = 0; i < numCoders; i++)
+ {
+ folder.Coders.Add(CCoderInfo());
+ CCoderInfo &coder = folder.Coders.Back();
+
+ {
+ Byte mainByte = ReadByte();
+ int idSize = (mainByte & 0xF);
+ Byte longID[15];
+ ReadBytes(longID, idSize);
+ if (idSize > 8)
+ ThrowUnsupported();
+ UInt64 id = 0;
+ for (int j = 0; j < idSize; j++)
+ id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
+ coder.MethodID = id;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ coder.NumInStreams = ReadNum();
+ coder.NumOutStreams = ReadNum();
+ }
+ else
+ {
+ coder.NumInStreams = 1;
+ coder.NumOutStreams = 1;
+ }
+ if ((mainByte & 0x20) != 0)
+ {
+ CNum propsSize = ReadNum();
+ coder.Props.SetCapacity((size_t)propsSize);
+ ReadBytes((Byte *)coder.Props, (size_t)propsSize);
+ }
+ if ((mainByte & 0x80) != 0)
+ ThrowUnsupported();
+ }
+ numInStreams += coder.NumInStreams;
+ numOutStreams += coder.NumOutStreams;
+ }
+
+ CNum numBindPairs = numOutStreams - 1;
+ folder.BindPairs.Clear();
+ folder.BindPairs.Reserve(numBindPairs);
+ for (i = 0; i < numBindPairs; i++)
+ {
+ CBindPair bp;
+ bp.InIndex = ReadNum();
+ bp.OutIndex = ReadNum();
+ folder.BindPairs.Add(bp);
+ }
+
+ if (numInStreams < numBindPairs)
+ ThrowUnsupported();
+ CNum numPackStreams = numInStreams - numBindPairs;
+ folder.PackStreams.Reserve(numPackStreams);
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams; i++)
+ if (folder.FindBindPairForInStream(i) < 0)
+ {
+ folder.PackStreams.Add(i);
+ break;
+ }
+ if (folder.PackStreams.Size() != 1)
+ ThrowUnsupported();
+ }
+ else
+ for (i = 0; i < numPackStreams; i++)
+ folder.PackStreams.Add(ReadNum());
+}
+
+void CInArchive::WaitAttribute(UInt64 attribute)
+{
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type == attribute)
+ return;
+ if (type == NID::kEnd)
+ ThrowIncorrect();
+ SkipData();
+ }
+}
+
+void CInArchive::ReadHashDigests(int numItems,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests)
+{
+ ReadBoolVector2(numItems, digestsDefined);
+ digests.Clear();
+ digests.Reserve(numItems);
+ for (int i = 0; i < numItems; i++)
+ {
+ UInt32 crc = 0;
+ if (digestsDefined[i])
+ crc = ReadUInt32();
+ digests.Add(crc);
+ }
+}
+
+void CInArchive::ReadPackInfo(
+ UInt64 &dataOffset,
+ CRecordVector<UInt64> &packSizes,
+ CBoolVector &packCRCsDefined,
+ CRecordVector<UInt32> &packCRCs)
+{
+ dataOffset = ReadNumber();
+ CNum numPackStreams = ReadNum();
+
+ WaitAttribute(NID::kSize);
+ packSizes.Clear();
+ packSizes.Reserve(numPackStreams);
+ for (CNum i = 0; i < numPackStreams; i++)
+ packSizes.Add(ReadNumber());
+
+ UInt64 type;
+ for (;;)
+ {
+ type = ReadID();
+ if (type == NID::kEnd)
+ break;
+ if (type == NID::kCRC)
+ {
+ ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs);
+ continue;
+ }
+ SkipData();
+ }
+ if (packCRCsDefined.IsEmpty())
+ {
+ BoolVector_Fill_False(packCRCsDefined, numPackStreams);
+ packCRCs.Reserve(numPackStreams);
+ packCRCs.Clear();
+ for (CNum i = 0; i < numPackStreams; i++)
+ packCRCs.Add(0);
+ }
+}
+
+void CInArchive::ReadUnpackInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ CObjectVector<CFolder> &folders)
+{
+ WaitAttribute(NID::kFolder);
+ CNum numFolders = ReadNum();
+
+ {
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, dataVector);
+ folders.Clear();
+ folders.Reserve(numFolders);
+ for (CNum i = 0; i < numFolders; i++)
+ {
+ folders.Add(CFolder());
+ GetNextFolderItem(folders.Back());
+ }
+ }
+
+ WaitAttribute(NID::kCodersUnpackSize);
+
+ CNum i;
+ for (i = 0; i < numFolders; i++)
+ {
+ CFolder &folder = folders[i];
+ CNum numOutStreams = folder.GetNumOutStreams();
+ folder.UnpackSizes.Reserve(numOutStreams);
+ for (CNum j = 0; j < numOutStreams; j++)
+ folder.UnpackSizes.Add(ReadNumber());
+ }
+
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type == NID::kEnd)
+ return;
+ if (type == NID::kCRC)
+ {
+ CBoolVector crcsDefined;
+ CRecordVector<UInt32> crcs;
+ ReadHashDigests(numFolders, crcsDefined, crcs);
+ for (i = 0; i < numFolders; i++)
+ {
+ CFolder &folder = folders[i];
+ folder.UnpackCRCDefined = crcsDefined[i];
+ folder.UnpackCRC = crcs[i];
+ }
+ continue;
+ }
+ SkipData();
+ }
+}
+
+void CInArchive::ReadSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CRecordVector<UInt64> &unpackSizes,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests)
+{
+ numUnpackStreamsInFolders.Clear();
+ numUnpackStreamsInFolders.Reserve(folders.Size());
+ UInt64 type;
+ for (;;)
+ {
+ type = ReadID();
+ if (type == NID::kNumUnpackStream)
+ {
+ for (int i = 0; i < folders.Size(); i++)
+ numUnpackStreamsInFolders.Add(ReadNum());
+ continue;
+ }
+ if (type == NID::kCRC || type == NID::kSize)
+ break;
+ if (type == NID::kEnd)
+ break;
+ SkipData();
+ }
+
+ if (numUnpackStreamsInFolders.IsEmpty())
+ for (int i = 0; i < folders.Size(); i++)
+ numUnpackStreamsInFolders.Add(1);
+
+ int i;
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ {
+ // v3.13 incorrectly worked with empty folders
+ // v4.07: we check that folder is empty
+ CNum numSubstreams = numUnpackStreamsInFolders[i];
+ if (numSubstreams == 0)
+ continue;
+ UInt64 sum = 0;
+ for (CNum j = 1; j < numSubstreams; j++)
+ if (type == NID::kSize)
+ {
+ UInt64 size = ReadNumber();
+ unpackSizes.Add(size);
+ sum += size;
+ }
+ unpackSizes.Add(folders[i].GetUnpackSize() - sum);
+ }
+ if (type == NID::kSize)
+ type = ReadID();
+
+ int numDigests = 0;
+ int numDigestsTotal = 0;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ CNum numSubstreams = numUnpackStreamsInFolders[i];
+ if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
+ numDigests += numSubstreams;
+ numDigestsTotal += numSubstreams;
+ }
+
+ for (;;)
+ {
+ if (type == NID::kCRC)
+ {
+ CBoolVector digestsDefined2;
+ CRecordVector<UInt32> digests2;
+ ReadHashDigests(numDigests, digestsDefined2, digests2);
+ int digestIndex = 0;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ CNum numSubstreams = numUnpackStreamsInFolders[i];
+ const CFolder &folder = folders[i];
+ if (numSubstreams == 1 && folder.UnpackCRCDefined)
+ {
+ digestsDefined.Add(true);
+ digests.Add(folder.UnpackCRC);
+ }
+ else
+ for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
+ {
+ digestsDefined.Add(digestsDefined2[digestIndex]);
+ digests.Add(digests2[digestIndex]);
+ }
+ }
+ }
+ else if (type == NID::kEnd)
+ {
+ if (digestsDefined.IsEmpty())
+ {
+ BoolVector_Fill_False(digestsDefined, numDigestsTotal);
+ digests.Clear();
+ for (int i = 0; i < numDigestsTotal; i++)
+ digests.Add(0);
+ }
+ return;
+ }
+ else
+ SkipData();
+ type = ReadID();
+ }
+}
+
+void CInArchive::ReadStreamsInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ UInt64 &dataOffset,
+ CRecordVector<UInt64> &packSizes,
+ CBoolVector &packCRCsDefined,
+ CRecordVector<UInt32> &packCRCs,
+ CObjectVector<CFolder> &folders,
+ CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CRecordVector<UInt64> &unpackSizes,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests)
+{
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type > ((UInt32)1 << 30))
+ ThrowIncorrect();
+ switch((UInt32)type)
+ {
+ case NID::kEnd:
+ return;
+ case NID::kPackInfo:
+ {
+ ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
+ break;
+ }
+ case NID::kUnpackInfo:
+ {
+ ReadUnpackInfo(dataVector, folders);
+ break;
+ }
+ case NID::kSubStreamsInfo:
+ {
+ ReadSubStreamsInfo(folders, numUnpackStreamsInFolders,
+ unpackSizes, digestsDefined, digests);
+ break;
+ }
+ default:
+ ThrowIncorrect();
+ }
+ }
+}
+
+void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
+{
+ v.Clear();
+ v.Reserve(numItems);
+ Byte b = 0;
+ Byte mask = 0;
+ for (int i = 0; i < numItems; i++)
+ {
+ if (mask == 0)
+ {
+ b = ReadByte();
+ mask = 0x80;
+ }
+ v.Add((b & mask) != 0);
+ mask >>= 1;
+ }
+}
+
+void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
+{
+ Byte allAreDefined = ReadByte();
+ if (allAreDefined == 0)
+ {
+ ReadBoolVector(numItems, v);
+ return;
+ }
+ v.Clear();
+ v.Reserve(numItems);
+ for (int i = 0; i < numItems; i++)
+ v.Add(true);
+}
+
+void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
+ CUInt64DefVector &v, int numFiles)
+{
+ ReadBoolVector2(numFiles, v.Defined);
+
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ v.Values.Reserve(numFiles);
+
+ for (int i = 0; i < numFiles; i++)
+ {
+ UInt64 t = 0;
+ if (v.Defined[i])
+ t = ReadUInt64();
+ v.Values.Add(t);
+ }
+}
+
+HRESULT CInArchive::ReadAndDecodePackedStreams(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 baseOffset,
+ UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ )
+{
+ CRecordVector<UInt64> packSizes;
+ CBoolVector packCRCsDefined;
+ CRecordVector<UInt32> packCRCs;
+ CObjectVector<CFolder> folders;
+
+ CRecordVector<CNum> numUnpackStreamsInFolders;
+ CRecordVector<UInt64> unpackSizes;
+ CBoolVector digestsDefined;
+ CRecordVector<UInt32> digests;
+
+ ReadStreamsInfo(NULL,
+ dataOffset,
+ packSizes,
+ packCRCsDefined,
+ packCRCs,
+ folders,
+ numUnpackStreamsInFolders,
+ unpackSizes,
+ digestsDefined,
+ digests);
+
+ // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
+
+ CNum packIndex = 0;
+ CDecoder decoder(
+ #ifdef _ST_MODE
+ false
+ #else
+ true
+ #endif
+ );
+ UInt64 dataStartPos = baseOffset + dataOffset;
+ for (int i = 0; i < folders.Size(); i++)
+ {
+ const CFolder &folder = folders[i];
+ dataVector.Add(CByteBuffer());
+ CByteBuffer &data = dataVector.Back();
+ UInt64 unpackSize64 = folder.GetUnpackSize();
+ size_t unpackSize = (size_t)unpackSize64;
+ if (unpackSize != unpackSize64)
+ ThrowUnsupported();
+ data.SetCapacity(unpackSize);
+
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->Init(data, unpackSize);
+
+ HRESULT result = decoder.Decode(
+ EXTERNAL_CODECS_LOC_VARS
+ _stream, dataStartPos,
+ &packSizes[packIndex], folder, outStream, NULL
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , false, 1
+ #endif
+ );
+ RINOK(result);
+
+ if (folder.UnpackCRCDefined)
+ if (CrcCalc(data, unpackSize) != folder.UnpackCRC)
+ ThrowIncorrect();
+ for (int j = 0; j < folder.PackStreams.Size(); j++)
+ {
+ UInt64 packSize = packSizes[packIndex++];
+ dataStartPos += packSize;
+ HeadersSize += packSize;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadHeader(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ )
+{
+ UInt64 type = ReadID();
+
+ if (type == NID::kArchiveProperties)
+ {
+ ReadArchiveProperties(db.ArchiveInfo);
+ type = ReadID();
+ }
+
+ CObjectVector<CByteBuffer> dataVector;
+
+ if (type == NID::kAdditionalStreamsInfo)
+ {
+ HRESULT result = ReadAndDecodePackedStreams(
+ EXTERNAL_CODECS_LOC_VARS
+ db.ArchiveInfo.StartPositionAfterHeader,
+ db.ArchiveInfo.DataStartPosition2,
+ dataVector
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ );
+ RINOK(result);
+ db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
+ type = ReadID();
+ }
+
+ CRecordVector<UInt64> unpackSizes;
+ CBoolVector digestsDefined;
+ CRecordVector<UInt32> digests;
+
+ if (type == NID::kMainStreamsInfo)
+ {
+ ReadStreamsInfo(&dataVector,
+ db.ArchiveInfo.DataStartPosition,
+ db.PackSizes,
+ db.PackCRCsDefined,
+ db.PackCRCs,
+ db.Folders,
+ db.NumUnpackStreamsVector,
+ unpackSizes,
+ digestsDefined,
+ digests);
+ db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader;
+ type = ReadID();
+ }
+ else
+ {
+ for (int i = 0; i < db.Folders.Size(); i++)
+ {
+ db.NumUnpackStreamsVector.Add(1);
+ CFolder &folder = db.Folders[i];
+ unpackSizes.Add(folder.GetUnpackSize());
+ digestsDefined.Add(folder.UnpackCRCDefined);
+ digests.Add(folder.UnpackCRC);
+ }
+ }
+
+ db.Files.Clear();
+
+ if (type == NID::kEnd)
+ return S_OK;
+ if (type != NID::kFilesInfo)
+ ThrowIncorrect();
+
+ CNum numFiles = ReadNum();
+ db.Files.Reserve(numFiles);
+ CNum i;
+ for (i = 0; i < numFiles; i++)
+ db.Files.Add(CFileItem());
+
+ db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
+ if (!db.PackSizes.IsEmpty())
+ db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
+ if (numFiles > 0 && !digests.IsEmpty())
+ db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
+
+ CBoolVector emptyStreamVector;
+ BoolVector_Fill_False(emptyStreamVector, (int)numFiles);
+ CBoolVector emptyFileVector;
+ CBoolVector antiFileVector;
+ CNum numEmptyStreams = 0;
+
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type == NID::kEnd)
+ break;
+ UInt64 size = ReadNumber();
+ size_t ppp = _inByteBack->_pos;
+ bool addPropIdToList = true;
+ bool isKnownType = true;
+ if (type > ((UInt32)1 << 30))
+ isKnownType = false;
+ else switch((UInt32)type)
+ {
+ case NID::kName:
+ {
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ for (int i = 0; i < db.Files.Size(); i++)
+ _inByteBack->ReadString(db.Files[i].Name);
+ break;
+ }
+ case NID::kWinAttributes:
+ {
+ CBoolVector boolVector;
+ ReadBoolVector2(db.Files.Size(), boolVector);
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ for (i = 0; i < numFiles; i++)
+ {
+ CFileItem &file = db.Files[i];
+ file.AttribDefined = boolVector[i];
+ if (file.AttribDefined)
+ file.Attrib = ReadUInt32();
+ }
+ break;
+ }
+ case NID::kEmptyStream:
+ {
+ ReadBoolVector(numFiles, emptyStreamVector);
+ for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
+ if (emptyStreamVector[i])
+ numEmptyStreams++;
+
+ BoolVector_Fill_False(emptyFileVector, numEmptyStreams);
+ BoolVector_Fill_False(antiFileVector, numEmptyStreams);
+
+ break;
+ }
+ case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break;
+ case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break;
+ case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break;
+ case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break;
+ case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break;
+ case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break;
+ case NID::kDummy:
+ {
+ for (UInt64 j = 0; j < size; j++)
+ if (ReadByte() != 0)
+ ThrowIncorrect();
+ addPropIdToList = false;
+ break;
+ }
+ default:
+ addPropIdToList = isKnownType = false;
+ }
+ if (isKnownType)
+ {
+ if(addPropIdToList)
+ db.ArchiveInfo.FileInfoPopIDs.Add(type);
+ }
+ else
+ SkipData(size);
+ bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 ||
+ db.ArchiveInfo.Version.Minor > 2);
+ if (checkRecordsSize && _inByteBack->_pos - ppp != size)
+ ThrowIncorrect();
+ }
+
+ CNum emptyFileIndex = 0;
+ CNum sizeIndex = 0;
+
+ CNum numAntiItems = 0;
+ for (i = 0; i < numEmptyStreams; i++)
+ if (antiFileVector[i])
+ numAntiItems++;
+
+ for (i = 0; i < numFiles; i++)
+ {
+ CFileItem &file = db.Files[i];
+ bool isAnti;
+ file.HasStream = !emptyStreamVector[i];
+ if (file.HasStream)
+ {
+ file.IsDir = false;
+ isAnti = false;
+ file.Size = unpackSizes[sizeIndex];
+ file.Crc = digests[sizeIndex];
+ file.CrcDefined = digestsDefined[sizeIndex];
+ sizeIndex++;
+ }
+ else
+ {
+ file.IsDir = !emptyFileVector[emptyFileIndex];
+ isAnti = antiFileVector[emptyFileIndex];
+ emptyFileIndex++;
+ file.Size = 0;
+ file.CrcDefined = false;
+ }
+ if (numAntiItems != 0)
+ db.IsAnti.Add(isAnti);
+ }
+ return S_OK;
+}
+
+
+void CArchiveDatabaseEx::FillFolderStartPackStream()
+{
+ FolderStartPackStreamIndex.Clear();
+ FolderStartPackStreamIndex.Reserve(Folders.Size());
+ CNum startPos = 0;
+ for (int i = 0; i < Folders.Size(); i++)
+ {
+ FolderStartPackStreamIndex.Add(startPos);
+ startPos += (CNum)Folders[i].PackStreams.Size();
+ }
+}
+
+void CArchiveDatabaseEx::FillStartPos()
+{
+ PackStreamStartPositions.Clear();
+ PackStreamStartPositions.Reserve(PackSizes.Size());
+ UInt64 startPos = 0;
+ for (int i = 0; i < PackSizes.Size(); i++)
+ {
+ PackStreamStartPositions.Add(startPos);
+ startPos += PackSizes[i];
+ }
+}
+
+void CArchiveDatabaseEx::FillFolderStartFileIndex()
+{
+ FolderStartFileIndex.Clear();
+ FolderStartFileIndex.Reserve(Folders.Size());
+ FileIndexToFolderIndexMap.Clear();
+ FileIndexToFolderIndexMap.Reserve(Files.Size());
+
+ int folderIndex = 0;
+ CNum indexInFolder = 0;
+ for (int i = 0; i < Files.Size(); i++)
+ {
+ const CFileItem &file = Files[i];
+ bool emptyStream = !file.HasStream;
+ if (emptyStream && indexInFolder == 0)
+ {
+ FileIndexToFolderIndexMap.Add(kNumNoIndex);
+ continue;
+ }
+ if (indexInFolder == 0)
+ {
+ // v3.13 incorrectly worked with empty folders
+ // v4.07: Loop for skipping empty folders
+ for (;;)
+ {
+ if (folderIndex >= Folders.Size())
+ ThrowIncorrect();
+ FolderStartFileIndex.Add(i); // check it
+ if (NumUnpackStreamsVector[folderIndex] != 0)
+ break;
+ folderIndex++;
+ }
+ }
+ FileIndexToFolderIndexMap.Add(folderIndex);
+ if (emptyStream)
+ continue;
+ indexInFolder++;
+ if (indexInFolder >= NumUnpackStreamsVector[folderIndex])
+ {
+ folderIndex++;
+ indexInFolder = 0;
+ }
+ }
+}
+
+HRESULT CInArchive::ReadDatabase2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ )
+{
+ db.Clear();
+ db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+
+ db.ArchiveInfo.Version.Major = _header[6];
+ db.ArchiveInfo.Version.Minor = _header[7];
+
+ if (db.ArchiveInfo.Version.Major != kMajorVersion)
+ ThrowUnsupportedVersion();
+
+ UInt32 crcFromArchive = Get32(_header + 8);
+ UInt64 nextHeaderOffset = Get64(_header + 0xC);
+ UInt64 nextHeaderSize = Get64(_header + 0x14);
+ UInt32 nextHeaderCRC = Get32(_header + 0x1C);
+ UInt32 crc = CrcCalc(_header + 0xC, 20);
+
+ #ifdef FORMAT_7Z_RECOVERY
+ if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
+ {
+ UInt64 cur, cur2;
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
+ const int kCheckSize = 500;
+ Byte buf[kCheckSize];
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
+ int checkSize = kCheckSize;
+ if (cur2 - cur < kCheckSize)
+ checkSize = (int)(cur2 - cur);
+ RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
+
+ RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));
+
+ int i;
+ for (i = (int)checkSize - 2; i >= 0; i--)
+ if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
+ break;
+ if (i < 0)
+ return S_FALSE;
+ nextHeaderSize = checkSize - i;
+ nextHeaderOffset = cur2 - cur + i;
+ nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
+ RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
+ }
+ else
+ #endif
+ {
+ if (crc != crcFromArchive)
+ ThrowIncorrect();
+ }
+
+ db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
+
+ if (nextHeaderSize == 0)
+ return S_OK;
+
+ if (nextHeaderSize > (UInt64)0xFFFFFFFF)
+ return S_FALSE;
+
+ if ((Int64)nextHeaderOffset < 0)
+ return S_FALSE;
+
+ RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
+
+ CByteBuffer buffer2;
+ buffer2.SetCapacity((size_t)nextHeaderSize);
+
+ RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize));
+ HeadersSize += kHeaderSize + nextHeaderSize;
+ db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
+
+ if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
+ ThrowIncorrect();
+
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, buffer2);
+
+ CObjectVector<CByteBuffer> dataVector;
+
+ UInt64 type = ReadID();
+ if (type != NID::kHeader)
+ {
+ if (type != NID::kEncodedHeader)
+ ThrowIncorrect();
+ HRESULT result = ReadAndDecodePackedStreams(
+ EXTERNAL_CODECS_LOC_VARS
+ db.ArchiveInfo.StartPositionAfterHeader,
+ db.ArchiveInfo.DataStartPosition2,
+ dataVector
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ );
+ RINOK(result);
+ if (dataVector.Size() == 0)
+ return S_OK;
+ if (dataVector.Size() > 1)
+ ThrowIncorrect();
+ streamSwitch.Remove();
+ streamSwitch.Set(this, dataVector.Front());
+ if (ReadID() != NID::kHeader)
+ ThrowIncorrect();
+ }
+
+ db.HeadersSize = HeadersSize;
+
+ return ReadHeader(
+ EXTERNAL_CODECS_LOC_VARS
+ db
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ );
+}
+
+HRESULT CInArchive::ReadDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ )
+{
+ try
+ {
+ return ReadDatabase2(
+ EXTERNAL_CODECS_LOC_VARS db
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ );
+ }
+ catch(CInArchiveException &) { return S_FALSE; }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.h
new file mode 100644
index 000000000..971f27b2a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zIn.h
@@ -0,0 +1,245 @@
+// 7zIn.h
+
+#ifndef __7Z_IN_H
+#define __7Z_IN_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IPassword.h"
+#include "../../IStream.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/InBuffer.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CInArchiveInfo
+{
+ CArchiveVersion Version;
+ UInt64 StartPosition;
+ UInt64 StartPositionAfterHeader;
+ UInt64 DataStartPosition;
+ UInt64 DataStartPosition2;
+ CRecordVector<UInt64> FileInfoPopIDs;
+ void Clear()
+ {
+ FileInfoPopIDs.Clear();
+ }
+};
+
+struct CArchiveDatabaseEx: public CArchiveDatabase
+{
+ CInArchiveInfo ArchiveInfo;
+ CRecordVector<UInt64> PackStreamStartPositions;
+ CRecordVector<CNum> FolderStartPackStreamIndex;
+ CRecordVector<CNum> FolderStartFileIndex;
+ CRecordVector<CNum> FileIndexToFolderIndexMap;
+
+ UInt64 HeadersSize;
+ UInt64 PhySize;
+
+ void Clear()
+ {
+ CArchiveDatabase::Clear();
+ ArchiveInfo.Clear();
+ PackStreamStartPositions.Clear();
+ FolderStartPackStreamIndex.Clear();
+ FolderStartFileIndex.Clear();
+ FileIndexToFolderIndexMap.Clear();
+
+ HeadersSize = 0;
+ PhySize = 0;
+ }
+
+ void FillFolderStartPackStream();
+ void FillStartPos();
+ void FillFolderStartFileIndex();
+
+ void Fill()
+ {
+ FillFolderStartPackStream();
+ FillStartPos();
+ FillFolderStartFileIndex();
+ }
+
+ UInt64 GetFolderStreamPos(int folderIndex, int indexInFolder) const
+ {
+ return ArchiveInfo.DataStartPosition +
+ PackStreamStartPositions[FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+ }
+
+ UInt64 GetFolderFullPackSize(int folderIndex) const
+ {
+ CNum packStreamIndex = FolderStartPackStreamIndex[folderIndex];
+ const CFolder &folder = Folders[folderIndex];
+ UInt64 size = 0;
+ for (int i = 0; i < folder.PackStreams.Size(); i++)
+ size += PackSizes[packStreamIndex + i];
+ return size;
+ }
+
+ UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
+ {
+ return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+ }
+
+ UInt64 GetFilePackSize(CNum fileIndex) const
+ {
+ CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex != kNumNoIndex)
+ if (FolderStartFileIndex[folderIndex] == fileIndex)
+ return GetFolderFullPackSize(folderIndex);
+ return 0;
+ }
+};
+
+class CInByte2
+{
+ const Byte *_buffer;
+ size_t _size;
+public:
+ size_t _pos;
+ void Init(const Byte *buffer, size_t size)
+ {
+ _buffer = buffer;
+ _size = size;
+ _pos = 0;
+ }
+ Byte ReadByte();
+ void ReadBytes(Byte *data, size_t size);
+ void SkipData(UInt64 size);
+ void SkipData();
+ UInt64 ReadNumber();
+ CNum ReadNum();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ void ReadString(UString &s);
+};
+
+class CStreamSwitch;
+
+const UInt32 kHeaderSize = 32;
+
+class CInArchive
+{
+ friend class CStreamSwitch;
+
+ CMyComPtr<IInStream> _stream;
+
+ CObjectVector<CInByte2> _inByteVector;
+ CInByte2 *_inByteBack;
+
+ UInt64 _arhiveBeginStreamPosition;
+
+ Byte _header[kHeaderSize];
+
+ UInt64 HeadersSize;
+
+ void AddByteStream(const Byte *buffer, size_t size)
+ {
+ _inByteVector.Add(CInByte2());
+ _inByteBack = &_inByteVector.Back();
+ _inByteBack->Init(buffer, size);
+ }
+
+ void DeleteByteStream()
+ {
+ _inByteVector.DeleteBack();
+ if (!_inByteVector.IsEmpty())
+ _inByteBack = &_inByteVector.Back();
+ }
+
+private:
+ HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+
+ void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); }
+ Byte ReadByte() { return _inByteBack->ReadByte(); }
+ UInt64 ReadNumber() { return _inByteBack->ReadNumber(); }
+ CNum ReadNum() { return _inByteBack->ReadNum(); }
+ UInt64 ReadID() { return _inByteBack->ReadNumber(); }
+ UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); }
+ UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
+ void SkipData(UInt64 size) { _inByteBack->SkipData(size); }
+ void SkipData() { _inByteBack->SkipData(); }
+ void WaitAttribute(UInt64 attribute);
+
+ void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
+ void GetNextFolderItem(CFolder &itemInfo);
+ void ReadHashDigests(int numItems,
+ CBoolVector &digestsDefined, CRecordVector<UInt32> &digests);
+
+ void ReadPackInfo(
+ UInt64 &dataOffset,
+ CRecordVector<UInt64> &packSizes,
+ CBoolVector &packCRCsDefined,
+ CRecordVector<UInt32> &packCRCs);
+
+ void ReadUnpackInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ CObjectVector<CFolder> &folders);
+
+ void ReadSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CRecordVector<UInt64> &unpackSizes,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests);
+
+ void ReadStreamsInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ UInt64 &dataOffset,
+ CRecordVector<UInt64> &packSizes,
+ CBoolVector &packCRCsDefined,
+ CRecordVector<UInt32> &packCRCs,
+ CObjectVector<CFolder> &folders,
+ CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CRecordVector<UInt64> &unpackSizes,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests);
+
+
+ void ReadBoolVector(int numItems, CBoolVector &v);
+ void ReadBoolVector2(int numItems, CBoolVector &v);
+ void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
+ CUInt64DefVector &v, int numFiles);
+ HRESULT ReadAndDecodePackedStreams(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 baseOffset, UInt64 &dataOffset,
+ CObjectVector<CByteBuffer> &dataVector
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ );
+ HRESULT ReadHeader(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ );
+ HRESULT ReadDatabase2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ );
+public:
+ HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
+ void Close();
+
+ HRESULT ReadDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ );
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zItem.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zItem.h
new file mode 100644
index 000000000..34f10775c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zItem.h
@@ -0,0 +1,268 @@
+// 7zItem.h
+
+#ifndef __7Z_ITEM_H
+#define __7Z_ITEM_H
+
+#include "../../../Common/Buffer.h"
+#include "../../../Common/MyString.h"
+
+#include "../../Common/MethodId.h"
+
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+const UInt64 k_AES = 0x06F10701;
+
+typedef UInt32 CNum;
+const CNum kNumMax = 0x7FFFFFFF;
+const CNum kNumNoIndex = 0xFFFFFFFF;
+
+struct CCoderInfo
+{
+ CMethodId MethodID;
+ CByteBuffer Props;
+ CNum NumInStreams;
+ CNum NumOutStreams;
+ bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBindPair
+{
+ CNum InIndex;
+ CNum OutIndex;
+};
+
+struct CFolder
+{
+ CObjectVector<CCoderInfo> Coders;
+ CRecordVector<CBindPair> BindPairs;
+ CRecordVector<CNum> PackStreams;
+ CRecordVector<UInt64> UnpackSizes;
+ UInt32 UnpackCRC;
+ bool UnpackCRCDefined;
+
+ CFolder(): UnpackCRCDefined(false) {}
+
+ UInt64 GetUnpackSize() const // test it
+ {
+ if (UnpackSizes.IsEmpty())
+ return 0;
+ for (int i = UnpackSizes.Size() - 1; i >= 0; i--)
+ if (FindBindPairForOutStream(i) < 0)
+ return UnpackSizes[i];
+ throw 1;
+ }
+
+ CNum GetNumOutStreams() const
+ {
+ CNum result = 0;
+ for (int i = 0; i < Coders.Size(); i++)
+ result += Coders[i].NumOutStreams;
+ return result;
+ }
+
+ int FindBindPairForInStream(CNum inStreamIndex) const
+ {
+ for(int i = 0; i < BindPairs.Size(); i++)
+ if (BindPairs[i].InIndex == inStreamIndex)
+ return i;
+ return -1;
+ }
+ int FindBindPairForOutStream(CNum outStreamIndex) const
+ {
+ for(int i = 0; i < BindPairs.Size(); i++)
+ if (BindPairs[i].OutIndex == outStreamIndex)
+ return i;
+ return -1;
+ }
+ int FindPackStreamArrayIndex(CNum inStreamIndex) const
+ {
+ for(int i = 0; i < PackStreams.Size(); i++)
+ if (PackStreams[i] == inStreamIndex)
+ return i;
+ return -1;
+ }
+
+ bool IsEncrypted() const
+ {
+ for (int i = Coders.Size() - 1; i >= 0; i--)
+ if (Coders[i].MethodID == k_AES)
+ return true;
+ return false;
+ }
+
+ bool CheckStructure() const;
+};
+
+struct CUInt64DefVector
+{
+ CRecordVector<UInt64> Values;
+ CRecordVector<bool> Defined;
+
+ void Clear()
+ {
+ Values.Clear();
+ Defined.Clear();
+ }
+
+ void ReserveDown()
+ {
+ Values.ReserveDown();
+ Values.ReserveDown();
+ }
+
+ bool GetItem(int index, UInt64 &value) const
+ {
+ if (index < Defined.Size() && Defined[index])
+ {
+ value = Values[index];
+ return true;
+ }
+ value = 0;
+ return false;
+ }
+
+ void SetItem(int index, bool defined, UInt64 value)
+ {
+ while (index >= Defined.Size())
+ Defined.Add(false);
+ Defined[index] = defined;
+ if (!defined)
+ return;
+ while (index >= Values.Size())
+ Values.Add(0);
+ Values[index] = value;
+ }
+
+ bool CheckSize(int size) const { return Defined.Size() == size || Defined.Size() == 0; }
+};
+
+struct CFileItem
+{
+ UInt64 Size;
+ UInt32 Attrib;
+ UInt32 Crc;
+ UString Name;
+
+ bool HasStream; // Test it !!! it means that there is
+ // stream in some folder. It can be empty stream
+ bool IsDir;
+ bool CrcDefined;
+ bool AttribDefined;
+
+ CFileItem():
+ HasStream(true),
+ IsDir(false),
+ CrcDefined(false),
+ AttribDefined(false)
+ {}
+ void SetAttrib(UInt32 attrib)
+ {
+ AttribDefined = true;
+ Attrib = attrib;
+ }
+};
+
+struct CFileItem2
+{
+ UInt64 CTime;
+ UInt64 ATime;
+ UInt64 MTime;
+ UInt64 StartPos;
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+ bool StartPosDefined;
+ bool IsAnti;
+};
+
+struct CArchiveDatabase
+{
+ CRecordVector<UInt64> PackSizes;
+ CRecordVector<bool> PackCRCsDefined;
+ CRecordVector<UInt32> PackCRCs;
+ CObjectVector<CFolder> Folders;
+ CRecordVector<CNum> NumUnpackStreamsVector;
+ CObjectVector<CFileItem> Files;
+
+ CUInt64DefVector CTime;
+ CUInt64DefVector ATime;
+ CUInt64DefVector MTime;
+ CUInt64DefVector StartPos;
+ CRecordVector<bool> IsAnti;
+
+ void Clear()
+ {
+ PackSizes.Clear();
+ PackCRCsDefined.Clear();
+ PackCRCs.Clear();
+ Folders.Clear();
+ NumUnpackStreamsVector.Clear();
+ Files.Clear();
+ CTime.Clear();
+ ATime.Clear();
+ MTime.Clear();
+ StartPos.Clear();
+ IsAnti.Clear();
+ }
+
+ void ReserveDown()
+ {
+ PackSizes.ReserveDown();
+ PackCRCsDefined.ReserveDown();
+ PackCRCs.ReserveDown();
+ Folders.ReserveDown();
+ NumUnpackStreamsVector.ReserveDown();
+ Files.ReserveDown();
+ CTime.ReserveDown();
+ ATime.ReserveDown();
+ MTime.ReserveDown();
+ StartPos.ReserveDown();
+ IsAnti.ReserveDown();
+ }
+
+ bool IsEmpty() const
+ {
+ return (PackSizes.IsEmpty() &&
+ PackCRCsDefined.IsEmpty() &&
+ PackCRCs.IsEmpty() &&
+ Folders.IsEmpty() &&
+ NumUnpackStreamsVector.IsEmpty() &&
+ Files.IsEmpty());
+ }
+
+ bool CheckNumFiles() const
+ {
+ int size = Files.Size();
+ return (
+ CTime.CheckSize(size) &&
+ ATime.CheckSize(size) &&
+ MTime.CheckSize(size) &&
+ StartPos.CheckSize(size) &&
+ (size == IsAnti.Size() || IsAnti.Size() == 0));
+ }
+
+ bool IsSolid() const
+ {
+ for (int i = 0; i < NumUnpackStreamsVector.Size(); i++)
+ if (NumUnpackStreamsVector[i] > 1)
+ return true;
+ return false;
+ }
+ bool IsItemAnti(int index) const { return (index < IsAnti.Size() && IsAnti[index]); }
+ void SetItemAnti(int index, bool isAnti)
+ {
+ while (index >= IsAnti.Size())
+ IsAnti.Add(false);
+ IsAnti[index] = isAnti;
+ }
+
+ void GetFile(int index, CFileItem &file, CFileItem2 &file2) const;
+ void AddFile(const CFileItem &file, const CFileItem2 &file2);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp
new file mode 100644
index 000000000..0c8aa7e8c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.cpp
@@ -0,0 +1,866 @@
+// 7zOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/AutoPtr.h"
+
+#include "../../Common/StreamObjects.h"
+
+#include "7zOut.h"
+
+static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size)
+{
+ while (size > 0)
+ {
+ UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF);
+ UInt32 processedSize;
+ RINOK(stream->Write(data, curSize, &processedSize));
+ if (processedSize == 0)
+ return E_FAIL;
+ data = (const void *)((const Byte *)data + processedSize);
+ size -= processedSize;
+ }
+ return S_OK;
+}
+
+namespace NArchive {
+namespace N7z {
+
+HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
+{
+ return ::WriteBytes(SeqStream, data, size);
+}
+
+HRESULT COutArchive::WriteSignature()
+{
+ Byte buf[8];
+ memcpy(buf, kSignature, kSignatureSize);
+ buf[kSignatureSize] = kMajorVersion;
+ buf[kSignatureSize + 1] = 3;
+ return WriteDirect(buf, 8);
+}
+
+#ifdef _7Z_VOL
+HRESULT COutArchive::WriteFinishSignature()
+{
+ RINOK(WriteDirect(kFinishSignature, kSignatureSize));
+ CArchiveVersion av;
+ av.Major = kMajorVersion;
+ av.Minor = 2;
+ RINOK(WriteDirectByte(av.Major));
+ return WriteDirectByte(av.Minor);
+}
+#endif
+
+static void SetUInt32(Byte *p, UInt32 d)
+{
+ for (int i = 0; i < 4; i++, d >>= 8)
+ p[i] = (Byte)d;
+}
+
+static void SetUInt64(Byte *p, UInt64 d)
+{
+ for (int i = 0; i < 8; i++, d >>= 8)
+ p[i] = (Byte)d;
+}
+
+HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
+{
+ Byte buf[24];
+ SetUInt64(buf + 4, h.NextHeaderOffset);
+ SetUInt64(buf + 12, h.NextHeaderSize);
+ SetUInt32(buf + 20, h.NextHeaderCRC);
+ SetUInt32(buf, CrcCalc(buf + 4, 20));
+ return WriteDirect(buf, 24);
+}
+
+#ifdef _7Z_VOL
+HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h)
+{
+ CCRC crc;
+ crc.UpdateUInt64(h.NextHeaderOffset);
+ crc.UpdateUInt64(h.NextHeaderSize);
+ crc.UpdateUInt32(h.NextHeaderCRC);
+ crc.UpdateUInt64(h.ArchiveStartOffset);
+ crc.UpdateUInt64(h.AdditionalStartBlockSize);
+ RINOK(WriteDirectUInt32(crc.GetDigest()));
+ RINOK(WriteDirectUInt64(h.NextHeaderOffset));
+ RINOK(WriteDirectUInt64(h.NextHeaderSize));
+ RINOK(WriteDirectUInt32(h.NextHeaderCRC));
+ RINOK(WriteDirectUInt64(h.ArchiveStartOffset));
+ return WriteDirectUInt64(h.AdditionalStartBlockSize);
+}
+#endif
+
+HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
+{
+ Close();
+ #ifdef _7Z_VOL
+ // endMarker = false;
+ _endMarker = endMarker;
+ #endif
+ SeqStream = stream;
+ if (!endMarker)
+ {
+ SeqStream.QueryInterface(IID_IOutStream, &Stream);
+ if (!Stream)
+ {
+ return E_NOTIMPL;
+ // endMarker = true;
+ }
+ }
+ #ifdef _7Z_VOL
+ if (endMarker)
+ {
+ /*
+ CStartHeader sh;
+ sh.NextHeaderOffset = (UInt32)(Int32)-1;
+ sh.NextHeaderSize = (UInt32)(Int32)-1;
+ sh.NextHeaderCRC = 0;
+ WriteStartHeader(sh);
+ */
+ }
+ else
+ #endif
+ {
+ if (!Stream)
+ return E_FAIL;
+ RINOK(WriteSignature());
+ RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
+ }
+ return S_OK;
+}
+
+void COutArchive::Close()
+{
+ SeqStream.Release();
+ Stream.Release();
+}
+
+HRESULT COutArchive::SkipPrefixArchiveHeader()
+{
+ #ifdef _7Z_VOL
+ if (_endMarker)
+ return S_OK;
+ #endif
+ return Stream->Seek(24, STREAM_SEEK_CUR, NULL);
+}
+
+UInt64 COutArchive::GetPos() const
+{
+ if (_countMode)
+ return _countSize;
+ if (_writeToStream)
+ return _outByte.GetProcessedSize();
+ return _outByte2.GetPos();
+}
+
+void COutArchive::WriteBytes(const void *data, size_t size)
+{
+ if (_countMode)
+ _countSize += size;
+ else if (_writeToStream)
+ {
+ _outByte.WriteBytes(data, size);
+ _crc = CrcUpdate(_crc, data, size);
+ }
+ else
+ _outByte2.WriteBytes(data, size);
+}
+
+void COutArchive::WriteByte(Byte b)
+{
+ if (_countMode)
+ _countSize++;
+ else if (_writeToStream)
+ {
+ _outByte.WriteByte(b);
+ _crc = CRC_UPDATE_BYTE(_crc, b);
+ }
+ else
+ _outByte2.WriteByte(b);
+}
+
+void COutArchive::WriteUInt32(UInt32 value)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteUInt64(UInt64 value)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteNumber(UInt64 value)
+{
+ Byte firstByte = 0;
+ Byte mask = 0x80;
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ if (value < ((UInt64(1) << ( 7 * (i + 1)))))
+ {
+ firstByte |= Byte(value >> (8 * i));
+ break;
+ }
+ firstByte |= mask;
+ mask >>= 1;
+ }
+ WriteByte(firstByte);
+ for (;i > 0; i--)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+static UInt32 GetBigNumberSize(UInt64 value)
+{
+ int i;
+ for (i = 1; i < 9; i++)
+ if (value < (((UInt64)1 << (i * 7))))
+ break;
+ return i;
+}
+
+#ifdef _7Z_VOL
+UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
+{
+ UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
+ if (nameLength != 0)
+ {
+ nameLength = (nameLength + 1) * 2;
+ result += nameLength + GetBigNumberSize(nameLength) + 2;
+ }
+ if (props)
+ {
+ result += 20;
+ }
+ if (result >= 128)
+ result++;
+ result += kSignatureSize + 2 + kFinishHeaderSize;
+ return result;
+}
+
+UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
+{
+ UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
+ int testSize;
+ if (volSize > headersSizeBase)
+ testSize = volSize - headersSizeBase;
+ else
+ testSize = 1;
+ UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
+ UInt64 pureSize = 1;
+ if (volSize > headersSize)
+ pureSize = volSize - headersSize;
+ return pureSize;
+}
+#endif
+
+void COutArchive::WriteFolder(const CFolder &folder)
+{
+ WriteNumber(folder.Coders.Size());
+ int i;
+ for (i = 0; i < folder.Coders.Size(); i++)
+ {
+ const CCoderInfo &coder = folder.Coders[i];
+ {
+ size_t propsSize = coder.Props.GetCapacity();
+
+ UInt64 id = coder.MethodID;
+ int idSize;
+ for (idSize = 1; idSize < sizeof(id); idSize++)
+ if ((id >> (8 * idSize)) == 0)
+ break;
+ BYTE longID[15];
+ for (int t = idSize - 1; t >= 0 ; t--, id >>= 8)
+ longID[t] = (Byte)(id & 0xFF);
+ Byte b;
+ b = (Byte)(idSize & 0xF);
+ bool isComplex = !coder.IsSimpleCoder();
+ b |= (isComplex ? 0x10 : 0);
+ b |= ((propsSize != 0) ? 0x20 : 0 );
+ WriteByte(b);
+ WriteBytes(longID, idSize);
+ if (isComplex)
+ {
+ WriteNumber(coder.NumInStreams);
+ WriteNumber(coder.NumOutStreams);
+ }
+ if (propsSize == 0)
+ continue;
+ WriteNumber(propsSize);
+ WriteBytes(coder.Props, propsSize);
+ }
+ }
+ for (i = 0; i < folder.BindPairs.Size(); i++)
+ {
+ const CBindPair &bindPair = folder.BindPairs[i];
+ WriteNumber(bindPair.InIndex);
+ WriteNumber(bindPair.OutIndex);
+ }
+ if (folder.PackStreams.Size() > 1)
+ for (i = 0; i < folder.PackStreams.Size(); i++)
+ {
+ WriteNumber(folder.PackStreams[i]);
+ }
+}
+
+void COutArchive::WriteBoolVector(const CBoolVector &boolVector)
+{
+ Byte b = 0;
+ Byte mask = 0x80;
+ for (int i = 0; i < boolVector.Size(); i++)
+ {
+ if (boolVector[i])
+ b |= mask;
+ mask >>= 1;
+ if (mask == 0)
+ {
+ WriteByte(b);
+ mask = 0x80;
+ b = 0;
+ }
+ }
+ if (mask != 0x80)
+ WriteByte(b);
+}
+
+
+void COutArchive::WriteHashDigests(
+ const CRecordVector<bool> &digestsDefined,
+ const CRecordVector<UInt32> &digests)
+{
+ int numDefined = 0;
+ int i;
+ for (i = 0; i < digestsDefined.Size(); i++)
+ if (digestsDefined[i])
+ numDefined++;
+ if (numDefined == 0)
+ return;
+
+ WriteByte(NID::kCRC);
+ if (numDefined == digestsDefined.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(digestsDefined);
+ }
+ for (i = 0; i < digests.Size(); i++)
+ if (digestsDefined[i])
+ WriteUInt32(digests[i]);
+}
+
+void COutArchive::WritePackInfo(
+ UInt64 dataOffset,
+ const CRecordVector<UInt64> &packSizes,
+ const CRecordVector<bool> &packCRCsDefined,
+ const CRecordVector<UInt32> &packCRCs)
+{
+ if (packSizes.IsEmpty())
+ return;
+ WriteByte(NID::kPackInfo);
+ WriteNumber(dataOffset);
+ WriteNumber(packSizes.Size());
+ WriteByte(NID::kSize);
+ for (int i = 0; i < packSizes.Size(); i++)
+ WriteNumber(packSizes[i]);
+
+ WriteHashDigests(packCRCsDefined, packCRCs);
+
+ WriteByte(NID::kEnd);
+}
+
+void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders)
+{
+ if (folders.IsEmpty())
+ return;
+
+ WriteByte(NID::kUnpackInfo);
+
+ WriteByte(NID::kFolder);
+ WriteNumber(folders.Size());
+ {
+ WriteByte(0);
+ for (int i = 0; i < folders.Size(); i++)
+ WriteFolder(folders[i]);
+ }
+
+ WriteByte(NID::kCodersUnpackSize);
+ int i;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ const CFolder &folder = folders[i];
+ for (int j = 0; j < folder.UnpackSizes.Size(); j++)
+ WriteNumber(folder.UnpackSizes[j]);
+ }
+
+ CRecordVector<bool> unpackCRCsDefined;
+ CRecordVector<UInt32> unpackCRCs;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ const CFolder &folder = folders[i];
+ unpackCRCsDefined.Add(folder.UnpackCRCDefined);
+ unpackCRCs.Add(folder.UnpackCRC);
+ }
+ WriteHashDigests(unpackCRCsDefined, unpackCRCs);
+
+ WriteByte(NID::kEnd);
+}
+
+void COutArchive::WriteSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ const CRecordVector<CNum> &numUnpackStreamsInFolders,
+ const CRecordVector<UInt64> &unpackSizes,
+ const CRecordVector<bool> &digestsDefined,
+ const CRecordVector<UInt32> &digests)
+{
+ WriteByte(NID::kSubStreamsInfo);
+
+ int i;
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ {
+ if (numUnpackStreamsInFolders[i] != 1)
+ {
+ WriteByte(NID::kNumUnpackStream);
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ WriteNumber(numUnpackStreamsInFolders[i]);
+ break;
+ }
+ }
+
+
+ bool needFlag = true;
+ CNum index = 0;
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ for (CNum j = 0; j < numUnpackStreamsInFolders[i]; j++)
+ {
+ if (j + 1 != numUnpackStreamsInFolders[i])
+ {
+ if (needFlag)
+ WriteByte(NID::kSize);
+ needFlag = false;
+ WriteNumber(unpackSizes[index]);
+ }
+ index++;
+ }
+
+ CRecordVector<bool> digestsDefined2;
+ CRecordVector<UInt32> digests2;
+
+ int digestIndex = 0;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ int numSubStreams = (int)numUnpackStreamsInFolders[i];
+ if (numSubStreams == 1 && folders[i].UnpackCRCDefined)
+ digestIndex++;
+ else
+ for (int j = 0; j < numSubStreams; j++, digestIndex++)
+ {
+ digestsDefined2.Add(digestsDefined[digestIndex]);
+ digests2.Add(digests[digestIndex]);
+ }
+ }
+ WriteHashDigests(digestsDefined2, digests2);
+ WriteByte(NID::kEnd);
+}
+
+void COutArchive::SkipAlign(unsigned /* pos */, unsigned /* alignSize */)
+{
+ return;
+}
+
+/*
+7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
+
+void COutArchive::SkipAlign(unsigned pos, unsigned alignSize)
+{
+ pos += (unsigned)GetPos();
+ pos &= (alignSize - 1);
+ if (pos == 0)
+ return;
+ unsigned skip = alignSize - pos;
+ if (skip < 2)
+ skip += alignSize;
+ skip -= 2;
+ WriteByte(NID::kDummy);
+ WriteByte((Byte)skip);
+ for (unsigned i = 0; i < skip; i++)
+ WriteByte(0);
+}
+*/
+
+static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
+
+void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize)
+{
+ const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
+ const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
+ SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
+
+ WriteByte(type);
+ WriteNumber(dataSize);
+ if (numDefined == v.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(v);
+ }
+ WriteByte(0);
+}
+
+void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
+{
+ int numDefined = 0;
+
+ int i;
+ for (i = 0; i < v.Defined.Size(); i++)
+ if (v.Defined[i])
+ numDefined++;
+
+ if (numDefined == 0)
+ return;
+
+ WriteAlignedBoolHeader(v.Defined, numDefined, type, 8);
+
+ for (i = 0; i < v.Defined.Size(); i++)
+ if (v.Defined[i])
+ WriteUInt64(v.Values[i]);
+}
+
+HRESULT COutArchive::EncodeStream(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CEncoder &encoder, const CByteBuffer &data,
+ CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
+{
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> stream = streamSpec;
+ streamSpec->Init(data, data.GetCapacity());
+ CFolder folderItem;
+ folderItem.UnpackCRCDefined = true;
+ folderItem.UnpackCRC = CrcCalc(data, data.GetCapacity());
+ UInt64 dataSize64 = data.GetCapacity();
+ RINOK(encoder.Encode(
+ EXTERNAL_CODECS_LOC_VARS
+ stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
+ folders.Add(folderItem);
+ return S_OK;
+}
+
+void COutArchive::WriteHeader(
+ const CArchiveDatabase &db,
+ const CHeaderOptions &headerOptions,
+ UInt64 &headerOffset)
+{
+ int i;
+
+ UInt64 packedSize = 0;
+ for (i = 0; i < db.PackSizes.Size(); i++)
+ packedSize += db.PackSizes[i];
+
+ headerOffset = packedSize;
+
+ WriteByte(NID::kHeader);
+
+ // Archive Properties
+
+ if (db.Folders.Size() > 0)
+ {
+ WriteByte(NID::kMainStreamsInfo);
+ WritePackInfo(0, db.PackSizes,
+ db.PackCRCsDefined,
+ db.PackCRCs);
+
+ WriteUnpackInfo(db.Folders);
+
+ CRecordVector<UInt64> unpackSizes;
+ CRecordVector<bool> digestsDefined;
+ CRecordVector<UInt32> digests;
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ if (!file.HasStream)
+ continue;
+ unpackSizes.Add(file.Size);
+ digestsDefined.Add(file.CrcDefined);
+ digests.Add(file.Crc);
+ }
+
+ WriteSubStreamsInfo(
+ db.Folders,
+ db.NumUnpackStreamsVector,
+ unpackSizes,
+ digestsDefined,
+ digests);
+ WriteByte(NID::kEnd);
+ }
+
+ if (db.Files.IsEmpty())
+ {
+ WriteByte(NID::kEnd);
+ return;
+ }
+
+ WriteByte(NID::kFilesInfo);
+ WriteNumber(db.Files.Size());
+
+ {
+ /* ---------- Empty Streams ---------- */
+ CBoolVector emptyStreamVector;
+ emptyStreamVector.Reserve(db.Files.Size());
+ int numEmptyStreams = 0;
+ for (i = 0; i < db.Files.Size(); i++)
+ if (db.Files[i].HasStream)
+ emptyStreamVector.Add(false);
+ else
+ {
+ emptyStreamVector.Add(true);
+ numEmptyStreams++;
+ }
+ if (numEmptyStreams > 0)
+ {
+ WriteByte(NID::kEmptyStream);
+ WriteNumber(Bv_GetSizeInBytes(emptyStreamVector));
+ WriteBoolVector(emptyStreamVector);
+
+ CBoolVector emptyFileVector, antiVector;
+ emptyFileVector.Reserve(numEmptyStreams);
+ antiVector.Reserve(numEmptyStreams);
+ CNum numEmptyFiles = 0, numAntiItems = 0;
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ if (!file.HasStream)
+ {
+ emptyFileVector.Add(!file.IsDir);
+ if (!file.IsDir)
+ numEmptyFiles++;
+ bool isAnti = db.IsItemAnti(i);
+ antiVector.Add(isAnti);
+ if (isAnti)
+ numAntiItems++;
+ }
+ }
+
+ if (numEmptyFiles > 0)
+ {
+ WriteByte(NID::kEmptyFile);
+ WriteNumber(Bv_GetSizeInBytes(emptyFileVector));
+ WriteBoolVector(emptyFileVector);
+ }
+
+ if (numAntiItems > 0)
+ {
+ WriteByte(NID::kAnti);
+ WriteNumber(Bv_GetSizeInBytes(antiVector));
+ WriteBoolVector(antiVector);
+ }
+ }
+ }
+
+
+ {
+ /* ---------- Names ---------- */
+
+ int numDefined = 0;
+ size_t namesDataSize = 0;
+ for (int i = 0; i < db.Files.Size(); i++)
+ {
+ const UString &name = db.Files[i].Name;
+ if (!name.IsEmpty())
+ numDefined++;
+ namesDataSize += (name.Length() + 1) * 2;
+ }
+
+ if (numDefined > 0)
+ {
+ namesDataSize++;
+ SkipAlign(2 + GetBigNumberSize(namesDataSize), 2);
+
+ WriteByte(NID::kName);
+ WriteNumber(namesDataSize);
+ WriteByte(0);
+ for (int i = 0; i < db.Files.Size(); i++)
+ {
+ const UString &name = db.Files[i].Name;
+ for (int t = 0; t <= name.Length(); t++)
+ {
+ wchar_t c = name[t];
+ WriteByte((Byte)c);
+ WriteByte((Byte)(c >> 8));
+ }
+ }
+ }
+ }
+
+ if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime);
+ if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime);
+ if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime);
+ WriteUInt64DefVector(db.StartPos, NID::kStartPos);
+
+ {
+ /* ---------- Write Attrib ---------- */
+ CBoolVector boolVector;
+ boolVector.Reserve(db.Files.Size());
+ int numDefined = 0;
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ bool defined = db.Files[i].AttribDefined;
+ boolVector.Add(defined);
+ if (defined)
+ numDefined++;
+ }
+ if (numDefined > 0)
+ {
+ WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4);
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ if (file.AttribDefined)
+ WriteUInt32(file.Attrib);
+ }
+ }
+ }
+
+ WriteByte(NID::kEnd); // for files
+ WriteByte(NID::kEnd); // for headers
+}
+
+HRESULT COutArchive::WriteDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CArchiveDatabase &db,
+ const CCompressionMethodMode *options,
+ const CHeaderOptions &headerOptions)
+{
+ if (!db.CheckNumFiles())
+ return E_FAIL;
+
+ UInt64 headerOffset;
+ UInt32 headerCRC;
+ UInt64 headerSize;
+ if (db.IsEmpty())
+ {
+ headerSize = 0;
+ headerOffset = 0;
+ headerCRC = CrcCalc(0, 0);
+ }
+ else
+ {
+ bool encodeHeaders = false;
+ if (options != 0)
+ if (options->IsEmpty())
+ options = 0;
+ if (options != 0)
+ if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
+ encodeHeaders = true;
+
+ _outByte.SetStream(SeqStream);
+ _outByte.Init();
+ _crc = CRC_INIT_VAL;
+ _countMode = encodeHeaders;
+ _writeToStream = true;
+ _countSize = 0;
+ WriteHeader(db, headerOptions, headerOffset);
+
+ if (encodeHeaders)
+ {
+ CByteBuffer buf;
+ buf.SetCapacity(_countSize);
+ _outByte2.Init((Byte *)buf, _countSize);
+
+ _countMode = false;
+ _writeToStream = false;
+ WriteHeader(db, headerOptions, headerOffset);
+
+ if (_countSize != _outByte2.GetPos())
+ return E_FAIL;
+
+ CCompressionMethodMode encryptOptions;
+ encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
+ encryptOptions.Password = options->Password;
+ CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
+ CRecordVector<UInt64> packSizes;
+ CObjectVector<CFolder> folders;
+ RINOK(EncodeStream(
+ EXTERNAL_CODECS_LOC_VARS
+ encoder, buf,
+ packSizes, folders));
+
+ _writeToStream = true;
+
+ if (folders.Size() == 0)
+ throw 1;
+
+ WriteID(NID::kEncodedHeader);
+ WritePackInfo(headerOffset, packSizes,
+ CRecordVector<bool>(), CRecordVector<UInt32>());
+ WriteUnpackInfo(folders);
+ WriteByte(NID::kEnd);
+ for (int i = 0; i < packSizes.Size(); i++)
+ headerOffset += packSizes[i];
+ }
+ RINOK(_outByte.Flush());
+ headerCRC = CRC_GET_DIGEST(_crc);
+ headerSize = _outByte.GetProcessedSize();
+ }
+ #ifdef _7Z_VOL
+ if (_endMarker)
+ {
+ CFinishHeader h;
+ h.NextHeaderSize = headerSize;
+ h.NextHeaderCRC = headerCRC;
+ h.NextHeaderOffset =
+ UInt64(0) - (headerSize +
+ 4 + kFinishHeaderSize);
+ h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
+ h.AdditionalStartBlockSize = 0;
+ RINOK(WriteFinishHeader(h));
+ return WriteFinishSignature();
+ }
+ else
+ #endif
+ {
+ CStartHeader h;
+ h.NextHeaderSize = headerSize;
+ h.NextHeaderCRC = headerCRC;
+ h.NextHeaderOffset = headerOffset;
+ RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
+ return WriteStartHeader(h);
+ }
+}
+
+void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const
+{
+ file = Files[index];
+ file2.CTimeDefined = CTime.GetItem(index, file2.CTime);
+ file2.ATimeDefined = ATime.GetItem(index, file2.ATime);
+ file2.MTimeDefined = MTime.GetItem(index, file2.MTime);
+ file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos);
+ file2.IsAnti = IsItemAnti(index);
+}
+
+void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2)
+{
+ int index = Files.Size();
+ CTime.SetItem(index, file2.CTimeDefined, file2.CTime);
+ ATime.SetItem(index, file2.ATimeDefined, file2.ATime);
+ MTime.SetItem(index, file2.MTimeDefined, file2.MTime);
+ StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos);
+ SetItemAnti(index, file2.IsAnti);
+ Files.Add(file);
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.h
new file mode 100644
index 000000000..7b1b528e6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zOut.h
@@ -0,0 +1,152 @@
+// 7zOut.h
+
+#ifndef __7Z_OUT_H
+#define __7Z_OUT_H
+
+#include "7zCompressionMode.h"
+#include "7zEncode.h"
+#include "7zHeader.h"
+#include "7zItem.h"
+
+#include "../../Common/OutBuffer.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CWriteBufferLoc
+{
+ Byte *_data;
+ size_t _size;
+ size_t _pos;
+public:
+ CWriteBufferLoc(): _size(0), _pos(0) {}
+ void Init(Byte *data, size_t size)
+ {
+ _data = data;
+ _size = size;
+ _pos = 0;
+ }
+ void WriteBytes(const void *data, size_t size)
+ {
+ if (size > _size - _pos)
+ throw 1;
+ memcpy(_data + _pos, data, size);
+ _pos += size;
+ }
+ void WriteByte(Byte b)
+ {
+ if (_size == _pos)
+ throw 1;
+ _data[_pos++] = b;
+ }
+ size_t GetPos() const { return _pos; }
+};
+
+struct CHeaderOptions
+{
+ bool CompressMainHeader;
+ bool WriteCTime;
+ bool WriteATime;
+ bool WriteMTime;
+
+ CHeaderOptions():
+ CompressMainHeader(true),
+ WriteCTime(false),
+ WriteATime(false),
+ WriteMTime(true)
+ {}
+};
+
+class COutArchive
+{
+ UInt64 _prefixHeaderPos;
+
+ HRESULT WriteDirect(const void *data, UInt32 size);
+
+ UInt64 GetPos() const;
+ void WriteBytes(const void *data, size_t size);
+ void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.GetCapacity()); }
+ void WriteByte(Byte b);
+ void WriteUInt32(UInt32 value);
+ void WriteUInt64(UInt64 value);
+ void WriteNumber(UInt64 value);
+ void WriteID(UInt64 value) { WriteNumber(value); }
+
+ void WriteFolder(const CFolder &folder);
+ HRESULT WriteFileHeader(const CFileItem &itemInfo);
+ void WriteBoolVector(const CBoolVector &boolVector);
+ void WriteHashDigests(
+ const CRecordVector<bool> &digestsDefined,
+ const CRecordVector<UInt32> &hashDigests);
+
+ void WritePackInfo(
+ UInt64 dataOffset,
+ const CRecordVector<UInt64> &packSizes,
+ const CRecordVector<bool> &packCRCsDefined,
+ const CRecordVector<UInt32> &packCRCs);
+
+ void WriteUnpackInfo(const CObjectVector<CFolder> &folders);
+
+ void WriteSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ const CRecordVector<CNum> &numUnpackStreamsInFolders,
+ const CRecordVector<UInt64> &unpackSizes,
+ const CRecordVector<bool> &digestsDefined,
+ const CRecordVector<UInt32> &hashDigests);
+
+ void SkipAlign(unsigned pos, unsigned alignSize);
+ void WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize);
+ void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type);
+
+ HRESULT EncodeStream(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CEncoder &encoder, const CByteBuffer &data,
+ CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders);
+ void WriteHeader(
+ const CArchiveDatabase &db,
+ const CHeaderOptions &headerOptions,
+ UInt64 &headerOffset);
+
+ bool _countMode;
+ bool _writeToStream;
+ size_t _countSize;
+ UInt32 _crc;
+ COutBuffer _outByte;
+ CWriteBufferLoc _outByte2;
+
+ #ifdef _7Z_VOL
+ bool _endMarker;
+ #endif
+
+ HRESULT WriteSignature();
+ #ifdef _7Z_VOL
+ HRESULT WriteFinishSignature();
+ #endif
+ HRESULT WriteStartHeader(const CStartHeader &h);
+ #ifdef _7Z_VOL
+ HRESULT WriteFinishHeader(const CFinishHeader &h);
+ #endif
+ CMyComPtr<IOutStream> Stream;
+public:
+
+ COutArchive() { _outByte.Create(1 << 16); }
+ CMyComPtr<ISequentialOutStream> SeqStream;
+ HRESULT Create(ISequentialOutStream *stream, bool endMarker);
+ void Close();
+ HRESULT SkipPrefixArchiveHeader();
+ HRESULT WriteDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CArchiveDatabase &db,
+ const CCompressionMethodMode *options,
+ const CHeaderOptions &headerOptions);
+
+ #ifdef _7Z_VOL
+ static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false);
+ static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false);
+ #endif
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.cpp
new file mode 100644
index 000000000..fd4af49c7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.cpp
@@ -0,0 +1,164 @@
+// 7zProperties.cpp
+
+#include "StdAfx.h"
+
+#include "7zProperties.h"
+#include "7zHeader.h"
+#include "7zHandler.h"
+
+// #define _MULTI_PACK
+
+namespace NArchive {
+namespace N7z {
+
+struct CPropMap
+{
+ UInt64 FilePropID;
+ STATPROPSTG StatPROPSTG;
+};
+
+CPropMap kPropMap[] =
+{
+ { NID::kName, { NULL, kpidPath, VT_BSTR } },
+ { NID::kSize, { NULL, kpidSize, VT_UI8 } },
+ { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },
+
+ #ifdef _MULTI_PACK
+ { 100, { L"Pack0", kpidPackedSize0, VT_UI8 } },
+ { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } },
+ { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } },
+ { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } },
+ { 104, { L"Pack4", kpidPackedSize4, VT_UI8 } },
+ #endif
+
+ { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
+ { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },
+ { NID::kATime, { NULL, kpidATime, VT_FILETIME } },
+ { NID::kWinAttributes, { NULL, kpidAttrib, VT_UI4 } },
+ { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } },
+
+ { NID::kCRC, { NULL, kpidCRC, VT_UI4 } },
+
+ { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } }
+
+ #ifndef _SFX
+ ,
+ { 97, { NULL,kpidEncrypted, VT_BOOL } },
+ { 98, { NULL,kpidMethod, VT_BSTR } },
+ { 99, { NULL,kpidBlock, VT_UI4 } }
+ #endif
+};
+
+static const int kPropMapSize = sizeof(kPropMap) / sizeof(kPropMap[0]);
+
+static int FindPropInMap(UInt64 filePropID)
+{
+ for (int i = 0; i < kPropMapSize; i++)
+ if (kPropMap[i].FilePropID == filePropID)
+ return i;
+ return -1;
+}
+
+static void CopyOneItem(CRecordVector<UInt64> &src,
+ CRecordVector<UInt64> &dest, UInt32 item)
+{
+ for (int i = 0; i < src.Size(); i++)
+ if (src[i] == item)
+ {
+ dest.Add(item);
+ src.Delete(i);
+ return;
+ }
+}
+
+static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
+{
+ for (int i = 0; i < src.Size(); i++)
+ if (src[i] == item)
+ {
+ src.Delete(i);
+ return;
+ }
+}
+
+static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
+{
+ for (int i = 0; i < dest.Size(); i++)
+ if (dest[i] == item)
+ {
+ dest.Delete(i);
+ break;
+ }
+ dest.Insert(0, item);
+}
+
+void CHandler::FillPopIDs()
+{
+ _fileInfoPopIDs.Clear();
+
+ #ifdef _7Z_VOL
+ if(_volumes.Size() < 1)
+ return;
+ const CVolume &volume = _volumes.Front();
+ const CArchiveDatabaseEx &_db = volume.Database;
+ #endif
+
+ CRecordVector<UInt64> fileInfoPopIDs = _db.ArchiveInfo.FileInfoPopIDs;
+
+ RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
+ RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
+
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kName);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kAnti);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kSize);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kPackInfo);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCTime);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kMTime);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kATime);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kWinAttributes);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCRC);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kComment);
+ _fileInfoPopIDs += fileInfoPopIDs;
+
+ #ifndef _SFX
+ _fileInfoPopIDs.Add(97);
+ _fileInfoPopIDs.Add(98);
+ _fileInfoPopIDs.Add(99);
+ #endif
+ #ifdef _MULTI_PACK
+ _fileInfoPopIDs.Add(100);
+ _fileInfoPopIDs.Add(101);
+ _fileInfoPopIDs.Add(102);
+ _fileInfoPopIDs.Add(103);
+ _fileInfoPopIDs.Add(104);
+ #endif
+
+ #ifndef _SFX
+ InsertToHead(_fileInfoPopIDs, NID::kMTime);
+ InsertToHead(_fileInfoPopIDs, NID::kPackInfo);
+ InsertToHead(_fileInfoPopIDs, NID::kSize);
+ InsertToHead(_fileInfoPopIDs, NID::kName);
+ #endif
+}
+
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
+{
+ *numProperties = _fileInfoPopIDs.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)
+{
+ if ((int)index >= _fileInfoPopIDs.Size())
+ return E_INVALIDARG;
+ int indexInMap = FindPropInMap(_fileInfoPopIDs[index]);
+ if (indexInMap == -1)
+ return E_INVALIDARG;
+ const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG;
+ *propID = srcItem.propid;
+ *varType = srcItem.vt;
+ *name = 0;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.h
new file mode 100644
index 000000000..661817954
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zProperties.h
@@ -0,0 +1,22 @@
+// 7zProperties.h
+
+#ifndef __7Z_PROPERTIES_H
+#define __7Z_PROPERTIES_H
+
+#include "../../PropID.h"
+
+namespace NArchive {
+namespace N7z {
+
+enum
+{
+ kpidPackedSize0 = kpidUserDefined,
+ kpidPackedSize1,
+ kpidPackedSize2,
+ kpidPackedSize3,
+ kpidPackedSize4
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zRegister.cpp
new file mode 100644
index 000000000..6e9bf6b99
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zRegister.cpp
@@ -0,0 +1,18 @@
+// 7zRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "7zHandler.h"
+static IInArchive *CreateArc() { return new NArchive::N7z::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::N7z::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"7z", L"7z", 0, 7, {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}, 6, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(7z)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.cpp
new file mode 100644
index 000000000..06969636d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.cpp
@@ -0,0 +1,24 @@
+// 7zSpecStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zSpecStream.h"
+
+STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize != 0)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(
+ UInt64 subStream, UInt64 *value)
+{
+ if (_getSubStreamSize == NULL)
+ return E_NOTIMPL;
+ return _getSubStreamSize->GetSubStreamSize(subStream, value);
+}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.h
new file mode 100644
index 000000000..2e26efd5c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zSpecStream.h
@@ -0,0 +1,35 @@
+// 7zSpecStream.h
+
+#ifndef __7Z_SPEC_STREAM_H
+#define __7Z_SPEC_STREAM_H
+
+#include "../../IStream.h"
+#include "../../ICoder.h"
+#include "../../../Common/MyCom.h"
+
+class CSequentialInStreamSizeCount2:
+ public ISequentialInStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
+ UInt64 _size;
+public:
+ void Init(ISequentialInStream *stream)
+ {
+ _stream = stream;
+ _getSubStreamSize = 0;
+ _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);
+ _size = 0;
+ }
+ UInt64 GetSize() const { return _size; }
+
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.cpp
new file mode 100644
index 000000000..f07efc178
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -0,0 +1,1216 @@
+// 7zUpdate.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "7zDecode.h"
+#include "7zEncode.h"
+#include "7zFolderInStream.h"
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+#ifndef WIN32
+#include "Windows/FileIO.h"
+#endif
+
+namespace NArchive {
+namespace N7z {
+
+static const UInt64 k_LZMA = 0x030101;
+static const UInt64 k_BCJ = 0x03030103;
+static const UInt64 k_BCJ2 = 0x0303011B;
+
+static const wchar_t *kMatchFinderForBCJ2_LZMA = L"BT2";
+static const UInt32 kDictionaryForBCJ2_LZMA = 1 << 20;
+static const UInt32 kAlgorithmForBCJ2_LZMA = 1;
+static const UInt32 kNumFastBytesForBCJ2_LZMA = 64;
+
+#ifdef MY_CPU_X86_OR_AMD64
+#define USE_86_FILTER
+#endif
+
+static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream,
+ UInt64 position, UInt64 size, ICompressProgressInfo *progress)
+{
+ RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0));
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(size);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
+ return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL);
+}
+
+static int GetReverseSlashPos(const UString &name)
+{
+ int slashPos = name.ReverseFind(L'/');
+ #ifdef _WIN32
+ int slash1Pos = name.ReverseFind(L'\\');
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+ return slashPos;
+}
+
+int CUpdateItem::GetExtensionPos() const
+{
+ int slashPos = GetReverseSlashPos(Name);
+ int dotPos = Name.ReverseFind(L'.');
+ if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+ return Name.Length();
+ return dotPos + 1;
+}
+
+UString CUpdateItem::GetExtension() const
+{
+ return Name.Mid(GetExtensionPos());
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+#define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b))
+
+static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2)
+{
+ size_t c1 = a1.GetCapacity();
+ size_t c2 = a2.GetCapacity();
+ RINOZ_COMP(c1, c2);
+ for (size_t i = 0; i < c1; i++)
+ RINOZ_COMP(a1[i], a2[i]);
+ return 0;
+}
+
+static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2)
+{
+ RINOZ_COMP(c1.NumInStreams, c2.NumInStreams);
+ RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams);
+ RINOZ_COMP(c1.MethodID, c2.MethodID);
+ return CompareBuffers(c1.Props, c2.Props);
+}
+
+static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2)
+{
+ RINOZ_COMP(b1.InIndex, b2.InIndex);
+ return MyCompare(b1.OutIndex, b2.OutIndex);
+}
+
+static int CompareFolders(const CFolder &f1, const CFolder &f2)
+{
+ int s1 = f1.Coders.Size();
+ int s2 = f2.Coders.Size();
+ RINOZ_COMP(s1, s2);
+ int i;
+ for (i = 0; i < s1; i++)
+ RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i]));
+ s1 = f1.BindPairs.Size();
+ s2 = f2.BindPairs.Size();
+ RINOZ_COMP(s1, s2);
+ for (i = 0; i < s1; i++)
+ RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i]));
+ return 0;
+}
+
+/*
+static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
+{
+ return MyStringCompareNoCase(f1.Name, f2.Name);
+}
+*/
+
+struct CFolderRepack
+{
+ int FolderIndex;
+ int Group;
+ CNum NumCopyFiles;
+};
+
+static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *param)
+{
+ RINOZ_COMP(p1->Group, p2->Group);
+ int i1 = p1->FolderIndex;
+ int i2 = p2->FolderIndex;
+ const CArchiveDatabaseEx &db = *(const CArchiveDatabaseEx *)param;
+ RINOZ(CompareFolders(
+ db.Folders[i1],
+ db.Folders[i2]));
+ return MyCompare(i1, i2);
+ /*
+ RINOZ_COMP(
+ db.NumUnpackStreamsVector[i1],
+ db.NumUnpackStreamsVector[i2]);
+ if (db.NumUnpackStreamsVector[i1] == 0)
+ return 0;
+ return CompareFiles(
+ db.Files[db.FolderStartFileIndex[i1]],
+ db.Files[db.FolderStartFileIndex[i2]]);
+ */
+}
+
+////////////////////////////////////////////////////////////
+
+static int CompareEmptyItems(const int *p1, const int *p2, void *param)
+{
+ const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
+ const CUpdateItem &u1 = updateItems[*p1];
+ const CUpdateItem &u2 = updateItems[*p2];
+ if (u1.IsDir != u2.IsDir)
+ return (u1.IsDir) ? 1 : -1;
+ if (u1.IsDir)
+ {
+ if (u1.IsAnti != u2.IsAnti)
+ return (u1.IsAnti ? 1 : -1);
+ int n = MyStringCompareNoCase(u1.Name, u2.Name);
+ return -n;
+ }
+ if (u1.IsAnti != u2.IsAnti)
+ return (u1.IsAnti ? 1 : -1);
+ return MyStringCompareNoCase(u1.Name, u2.Name);
+}
+
+static const char *g_Exts =
+ " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo"
+ " zip jar ear war msi"
+ " 3gp avi mov mpeg mpg mpe wmv"
+ " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav"
+ " swf "
+ " chm hxi hxs"
+ " gif jpeg jpg jp2 png tiff bmp ico psd psp"
+ " awg ps eps cgm dxf svg vrml wmf emf ai md"
+ " cad dwg pps key sxi"
+ " max 3ds"
+ " iso bin nrg mdf img pdi tar cpio xpi"
+ " vfd vhd vud vmc vsv"
+ " vmdk dsk nvram vmem vmsd vmsn vmss vmtm"
+ " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def"
+ " f77 f f90 f95"
+ " asm sql manifest dep "
+ " mak clw csproj vcproj sln dsp dsw "
+ " class "
+ " bat cmd"
+ " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
+ " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs"
+ " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf"
+ " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf"
+ " abw afp cwk lwp wpd wps wpt wrf wri"
+ " abf afm bdf fon mgf otf pcf pfa snf ttf"
+ " dbf mdb nsf ntf wdb db fdb gdb"
+ " exe dll ocx vbx sfx sys tlb awx com obj lib out o so "
+ " pdb pch idb ncb opt";
+
+int GetExtIndex(const char *ext)
+{
+ int extIndex = 1;
+ const char *p = g_Exts;
+ for (;;)
+ {
+ char c = *p++;
+ if (c == 0)
+ return extIndex;
+ if (c == ' ')
+ continue;
+ int pos = 0;
+ for (;;)
+ {
+ char c2 = ext[pos++];
+ if (c2 == 0 && (c == 0 || c == ' '))
+ return extIndex;
+ if (c != c2)
+ break;
+ c = *p++;
+ }
+ extIndex++;
+ for (;;)
+ {
+ if (c == 0)
+ return extIndex;
+ if (c == ' ')
+ break;
+ c = *p++;
+ }
+ }
+}
+
+struct CRefItem
+{
+ const CUpdateItem *UpdateItem;
+ UInt32 Index;
+ UInt32 ExtensionPos;
+ UInt32 NamePos;
+ int ExtensionIndex;
+ CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType):
+ UpdateItem(&ui),
+ Index(index),
+ ExtensionPos(0),
+ NamePos(0),
+ ExtensionIndex(0)
+ {
+ if (sortByType)
+ {
+ int slashPos = GetReverseSlashPos(ui.Name);
+ NamePos = ((slashPos >= 0) ? (slashPos + 1) : 0);
+ int dotPos = ui.Name.ReverseFind(L'.');
+ if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+ ExtensionPos = ui.Name.Length();
+ else
+ {
+ ExtensionPos = dotPos + 1;
+ UString us = ui.Name.Mid(ExtensionPos);
+ if (!us.IsEmpty())
+ {
+ us.MakeLower();
+ int i;
+ AString s;
+ for (i = 0; i < us.Length(); i++)
+ {
+ wchar_t c = us[i];
+ if (c >= 0x80)
+ break;
+ s += (char)c;
+ }
+ if (i == us.Length())
+ ExtensionIndex = GetExtIndex(s);
+ else
+ ExtensionIndex = 0;
+ }
+ }
+ }
+ }
+};
+
+static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param)
+{
+ const CRefItem &a1 = *p1;
+ const CRefItem &a2 = *p2;
+ const CUpdateItem &u1 = *a1.UpdateItem;
+ const CUpdateItem &u2 = *a2.UpdateItem;
+ int n;
+ if (u1.IsDir != u2.IsDir)
+ return (u1.IsDir) ? 1 : -1;
+ if (u1.IsDir)
+ {
+ if (u1.IsAnti != u2.IsAnti)
+ return (u1.IsAnti ? 1 : -1);
+ n = MyStringCompareNoCase(u1.Name, u2.Name);
+ return -n;
+ }
+ bool sortByType = *(bool *)param;
+ if (sortByType)
+ {
+ RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex);
+ RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos));
+ RINOZ(MyStringCompareNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos));
+ if (!u1.MTimeDefined && u2.MTimeDefined) return 1;
+ if (u1.MTimeDefined && !u2.MTimeDefined) return -1;
+ if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime);
+ RINOZ_COMP(u1.Size, u2.Size);
+ }
+ return MyStringCompareNoCase(u1.Name, u2.Name);
+}
+
+struct CSolidGroup
+{
+ CRecordVector<UInt32> Indices;
+};
+
+#ifdef _WIN32
+static wchar_t *g_ExeExts[] =
+{
+ L"dll",
+ L"exe",
+ L"ocx",
+ L"sfx",
+ L"sys"
+};
+
+static bool IsExeExt(const UString &ext)
+{
+ for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++)
+ if (ext.CompareNoCase(g_ExeExts[i]) == 0)
+ return true;
+ return false;
+}
+#else
+static bool IsExeFile(const CUpdateItem &ui)
+{
+ if (ui.Attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) {
+ unsigned short st_mode = ui.Attrib >> 16;
+ if ((st_mode & 00111) && (ui.Size >= 2048))
+ {
+ // file has the execution flag and it's big enought
+ // try to find if the file is a script
+ NWindows::NFile::NIO::CInFile file;
+ if (file.Open(ui.Name))
+ {
+ char buffer[512];
+ UINT32 processedSize;
+ if (file.Read(buffer,sizeof(buffer),processedSize))
+ {
+ for(UInt32 i = 0; i < processedSize ; i++)
+ {
+ if (buffer[i] == 0)
+ {
+ return true; // this file is not a text (ascii, utf8, ...) !
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+#endif
+
+#ifdef USE_86_FILTER
+
+static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &methodResult)
+{
+ methodResult.Id = methodID;
+ methodResult.NumInStreams = numInStreams;
+ methodResult.NumOutStreams = 1;
+}
+
+static void MakeExeMethod(const CCompressionMethodMode &method,
+ bool bcj2Filter, CCompressionMethodMode &exeMethod)
+{
+ exeMethod = method;
+ if (bcj2Filter)
+ {
+ CMethodFull methodFull;
+ GetMethodFull(k_BCJ2, 4, methodFull);
+ exeMethod.Methods.Insert(0, methodFull);
+ GetMethodFull(k_LZMA, 1, methodFull);
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kAlgorithm;
+ prop.Value = kAlgorithmForBCJ2_LZMA;
+ methodFull.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kMatchFinder;
+ prop.Value = kMatchFinderForBCJ2_LZMA;
+ methodFull.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kDictionarySize;
+ prop.Value = kDictionaryForBCJ2_LZMA;
+ methodFull.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kNumFastBytes;
+ prop.Value = kNumFastBytesForBCJ2_LZMA;
+ methodFull.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kNumThreads;
+ prop.Value = (UInt32)1;
+ methodFull.Props.Add(prop);
+ }
+
+ exeMethod.Methods.Add(methodFull);
+ exeMethod.Methods.Add(methodFull);
+ CBind bind;
+
+ bind.OutCoder = 0;
+ bind.InStream = 0;
+
+ bind.InCoder = 1;
+ bind.OutStream = 0;
+ exeMethod.Binds.Add(bind);
+
+ bind.InCoder = 2;
+ bind.OutStream = 1;
+ exeMethod.Binds.Add(bind);
+
+ bind.InCoder = 3;
+ bind.OutStream = 2;
+ exeMethod.Binds.Add(bind);
+ }
+ else
+ {
+ CMethodFull methodFull;
+ GetMethodFull(k_BCJ, 1, methodFull);
+ exeMethod.Methods.Insert(0, methodFull);
+ CBind bind;
+ bind.OutCoder = 0;
+ bind.InStream = 0;
+ bind.InCoder = 1;
+ bind.OutStream = 0;
+ exeMethod.Binds.Add(bind);
+ }
+}
+
+#endif
+
+static void FromUpdateItemToFileItem(const CUpdateItem &ui,
+ CFileItem &file, CFileItem2 &file2)
+{
+ file.Name = NItemName::MakeLegalName(ui.Name);
+ if (ui.AttribDefined)
+ file.SetAttrib(ui.Attrib);
+
+ file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined;
+ file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined;
+ file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined;
+ file2.IsAnti = ui.IsAnti;
+ file2.StartPosDefined = false;
+
+ file.Size = ui.Size;
+ file.IsDir = ui.IsDir;
+ file.HasStream = ui.HasStream();
+}
+
+class CFolderOutStream2:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ COutStreamWithCRC *_crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> _crcStream;
+ const CArchiveDatabaseEx *_db;
+ const CBoolVector *_extractStatuses;
+ CMyComPtr<ISequentialOutStream> _outStream;
+ UInt32 _startIndex;
+ int _currentIndex;
+ bool _fileIsOpen;
+ UInt64 _rem;
+
+ void OpenFile();
+ void CloseFile();
+ HRESULT CloseFileAndSetResult();
+ HRESULT ProcessEmptyFiles();
+public:
+ MY_UNKNOWN_IMP
+
+ CFolderOutStream2()
+ {
+ _crcStreamSpec = new COutStreamWithCRC;
+ _crcStream = _crcStreamSpec;
+ }
+
+ HRESULT Init(const CArchiveDatabaseEx *db, UInt32 startIndex,
+ const CBoolVector *extractStatuses, ISequentialOutStream *outStream);
+ void ReleaseOutStream();
+ HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+HRESULT CFolderOutStream2::Init(const CArchiveDatabaseEx *db, UInt32 startIndex,
+ const CBoolVector *extractStatuses, ISequentialOutStream *outStream)
+{
+ _db = db;
+ _startIndex = startIndex;
+ _extractStatuses = extractStatuses;
+ _outStream = outStream;
+
+ _currentIndex = 0;
+ _fileIsOpen = false;
+ return ProcessEmptyFiles();
+}
+
+void CFolderOutStream2::ReleaseOutStream()
+{
+ _outStream.Release();
+ _crcStreamSpec->ReleaseStream();
+}
+
+void CFolderOutStream2::OpenFile()
+{
+ _crcStreamSpec->SetStream((*_extractStatuses)[_currentIndex] ? (ISequentialOutStream *)_outStream : NULL); // FIXED for gcc 2.95
+ _crcStreamSpec->Init(true);
+ _fileIsOpen = true;
+ _rem = _db->Files[_startIndex + _currentIndex].Size;
+}
+
+void CFolderOutStream2::CloseFile()
+{
+ _crcStreamSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentIndex++;
+}
+
+HRESULT CFolderOutStream2::CloseFileAndSetResult()
+{
+ const CFileItem &file = _db->Files[_startIndex + _currentIndex];
+ CloseFile();
+ return (file.IsDir || !file.CrcDefined || file.Crc == _crcStreamSpec->GetCRC()) ? S_OK: S_FALSE;
+}
+
+HRESULT CFolderOutStream2::ProcessEmptyFiles()
+{
+ while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
+ {
+ OpenFile();
+ RINOK(CloseFileAndSetResult());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = size < _rem ? size : (UInt32)_rem;
+ RINOK(_crcStream->Write(data, cur, &cur));
+ if (cur == 0)
+ break;
+ data = (const Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (processedSize != NULL)
+ *processedSize += cur;
+ if (_rem == 0)
+ {
+ RINOK(CloseFileAndSetResult());
+ RINOK(ProcessEmptyFiles());
+ continue;
+ }
+ }
+ else
+ {
+ RINOK(ProcessEmptyFiles());
+ if (_currentIndex == _extractStatuses->Size())
+ {
+ // we don't support partial extracting
+ return E_FAIL;
+ }
+ OpenFile();
+ }
+ }
+ return S_OK;
+}
+
+class CThreadDecoder: public CVirtThread
+{
+public:
+ HRESULT Result;
+ CMyComPtr<IInStream> InStream;
+
+ CFolderOutStream2 *FosSpec;
+ CMyComPtr<ISequentialOutStream> Fos;
+
+ UInt64 StartPos;
+ const UInt64 *PackSizes;
+ const CFolder *Folder;
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> GetTextPassword;
+ #endif
+
+ DECL_EXTERNAL_CODECS_VARS
+ CDecoder Decoder;
+
+ #ifndef _7ZIP_ST
+ bool MtMode;
+ UInt32 NumThreads;
+ #endif
+
+ CThreadDecoder():
+ Decoder(true)
+ {
+ #ifndef _7ZIP_ST
+ MtMode = false;
+ NumThreads = 1;
+ #endif
+ FosSpec = new CFolderOutStream2;
+ Fos = FosSpec;
+ Result = E_FAIL;
+ }
+ virtual void Execute();
+};
+
+void CThreadDecoder::Execute()
+{
+ try
+ {
+ #ifndef _NO_CRYPTO
+ bool passwordIsDefined;
+ #endif
+ Result = Decoder.Decode(
+ EXTERNAL_CODECS_VARS
+ InStream,
+ StartPos,
+ PackSizes,
+ *Folder,
+ Fos,
+ NULL
+ #ifndef _NO_CRYPTO
+ , GetTextPassword, passwordIsDefined
+ #endif
+ #ifndef _7ZIP_ST
+ , MtMode, NumThreads
+ #endif
+ );
+ }
+ catch(...)
+ {
+ Result = E_FAIL;
+ }
+ if (Result == S_OK)
+ Result = FosSpec->CheckFinishedState();
+ FosSpec->ReleaseOutStream();
+}
+
+bool static Is86FilteredFolder(const CFolder &f)
+{
+ for (int i = 0; i < f.Coders.Size(); i++)
+ {
+ CMethodId m = f.Coders[i].MethodID;
+ if (m == k_BCJ || m == k_BCJ2)
+ return true;
+ }
+ return false;
+}
+
+#ifndef _NO_CRYPTO
+
+class CCryptoGetTextPassword:
+ public ICryptoGetTextPassword,
+ public CMyUnknownImp
+{
+public:
+ UString Password;
+
+ MY_UNKNOWN_IMP
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+};
+
+STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password)
+{
+ return StringToBstr(Password, password);
+}
+
+#endif
+
+static const int kNumGroupsMax = 4;
+
+#ifdef USE_86_FILTER
+static bool Is86Group(int group) { return (group & 1) != 0; }
+#endif
+static bool IsEncryptedGroup(int group) { return (group & 2) != 0; }
+static int GetGroupIndex(bool encrypted, int bcjFiltered)
+ { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); }
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ const CArchiveDatabaseEx *db,
+ const CObjectVector<CUpdateItem> &updateItems,
+ COutArchive &archive,
+ CArchiveDatabase &newDatabase,
+ ISequentialOutStream *seqOutStream,
+ IArchiveUpdateCallback *updateCallback,
+ const CUpdateOptions &options
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getDecoderPassword
+ #endif
+ )
+{
+ UInt64 numSolidFiles = options.NumSolidFiles;
+ if (numSolidFiles == 0)
+ numSolidFiles = 1;
+ /*
+ CMyComPtr<IOutStream> outStream;
+ RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
+ if (!outStream)
+ return E_NOTIMPL;
+ */
+
+ UInt64 startBlockSize = db != 0 ? db->ArchiveInfo.StartPosition: 0;
+ if (startBlockSize > 0 && !options.RemoveSfxBlock)
+ {
+ RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
+ }
+
+ CRecordVector<int> fileIndexToUpdateIndexMap;
+ CRecordVector<CFolderRepack> folderRefs;
+ UInt64 complexity = 0;
+ UInt64 inSizeForReduce2 = 0;
+ bool needEncryptedRepack = false;
+ if (db != 0)
+ {
+ fileIndexToUpdateIndexMap.Reserve(db->Files.Size());
+ int i;
+ for (i = 0; i < db->Files.Size(); i++)
+ fileIndexToUpdateIndexMap.Add(-1);
+
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ int index = updateItems[i].IndexInArchive;
+ if (index != -1)
+ fileIndexToUpdateIndexMap[index] = i;
+ }
+
+ for (i = 0; i < db->Folders.Size(); i++)
+ {
+ CNum indexInFolder = 0;
+ CNum numCopyItems = 0;
+ CNum numUnpackStreams = db->NumUnpackStreamsVector[i];
+ UInt64 repackSize = 0;
+ for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++)
+ {
+ const CFileItem &file = db->Files[fi];
+ if (file.HasStream)
+ {
+ indexInFolder++;
+ int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0 && !updateItems[updateIndex].NewData)
+ {
+ numCopyItems++;
+ repackSize += file.Size;
+ }
+ }
+ }
+
+ if (numCopyItems == 0)
+ continue;
+
+ CFolderRepack rep;
+ rep.FolderIndex = i;
+ rep.NumCopyFiles = numCopyItems;
+ const CFolder &f = db->Folders[i];
+ bool isEncrypted = f.IsEncrypted();
+ rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f));
+ folderRefs.Add(rep);
+ if (numCopyItems == numUnpackStreams)
+ complexity += db->GetFolderFullPackSize(i);
+ else
+ {
+ complexity += repackSize;
+ if (repackSize > inSizeForReduce2)
+ inSizeForReduce2 = repackSize;
+ if (isEncrypted)
+ needEncryptedRepack = true;
+ }
+ }
+ folderRefs.Sort(CompareFolderRepacks, (void *)db);
+ }
+
+ UInt64 inSizeForReduce = 0;
+ int i;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ complexity += ui.Size;
+ if (numSolidFiles != 1)
+ inSizeForReduce += ui.Size;
+ else if (ui.Size > inSizeForReduce)
+ inSizeForReduce = ui.Size;
+ }
+ }
+
+ if (inSizeForReduce2 > inSizeForReduce)
+ inSizeForReduce = inSizeForReduce2;
+
+ const UInt32 kMinReduceSize = (1 << 16);
+ if (inSizeForReduce < kMinReduceSize)
+ inSizeForReduce = kMinReduceSize;
+
+ RINOK(updateCallback->SetTotal(complexity));
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CThreadDecoder threadDecoder;
+ if (!folderRefs.IsEmpty())
+ {
+ #ifdef EXTERNAL_CODECS
+ threadDecoder._codecsInfo = codecsInfo;
+ threadDecoder._externalCodecs = *externalCodecs;
+ #endif
+ RINOK(threadDecoder.Create());
+ }
+
+ CObjectVector<CSolidGroup> groups;
+ for (i = 0; i < kNumGroupsMax; i++)
+ groups.Add(CSolidGroup());
+
+ {
+ // ---------- Split files to 2 groups ----------
+
+ bool useFilters = options.UseFilters;
+ const CCompressionMethodMode &method = *options.Method;
+ if (method.Methods.Size() != 1 || method.Binds.Size() != 0)
+ useFilters = false;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (!ui.NewData || !ui.HasStream())
+ continue;
+ bool filteredGroup = false;
+ if (useFilters)
+ {
+#ifdef _WIN32
+ int dotPos = ui.Name.ReverseFind(L'.');
+ if (dotPos >= 0)
+ filteredGroup = IsExeExt(ui.Name.Mid(dotPos + 1));
+#else
+ filteredGroup = IsExeFile(ui);
+#endif
+ }
+ groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i);
+ }
+ }
+
+ #ifndef _NO_CRYPTO
+
+ CCryptoGetTextPassword *getPasswordSpec = NULL;
+ if (needEncryptedRepack)
+ {
+ getPasswordSpec = new CCryptoGetTextPassword;
+ threadDecoder.GetTextPassword = getPasswordSpec;
+
+ if (options.Method->PasswordIsDefined)
+ getPasswordSpec->Password = options.Method->Password;
+ else
+ {
+ if (!getDecoderPassword)
+ return E_NOTIMPL;
+ CMyComBSTR password;
+ RINOK(getDecoderPassword->CryptoGetTextPassword(&password));
+ getPasswordSpec->Password = password;
+ }
+ }
+
+ #endif
+
+ // ---------- Compress ----------
+
+ RINOK(archive.Create(seqOutStream, false));
+ RINOK(archive.SkipPrefixArchiveHeader());
+
+ int folderRefIndex = 0;
+ lps->ProgressOffset = 0;
+
+ for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++)
+ {
+ const CSolidGroup &group = groups[groupIndex];
+
+ CCompressionMethodMode method;
+ #ifdef USE_86_FILTER
+ if (Is86Group(groupIndex))
+ MakeExeMethod(*options.Method, options.MaxFilter, method);
+ else
+ #endif
+ method = *options.Method;
+
+ if (IsEncryptedGroup(groupIndex))
+ {
+ if (!method.PasswordIsDefined)
+ {
+ #ifndef _NO_CRYPTO
+ if (getPasswordSpec)
+ method.Password = getPasswordSpec->Password;
+ #endif
+ method.PasswordIsDefined = true;
+ }
+ }
+ else
+ {
+ method.PasswordIsDefined = false;
+ method.Password.Empty();
+ }
+
+ CEncoder encoder(method);
+
+ for (; folderRefIndex < folderRefs.Size(); folderRefIndex++)
+ {
+ const CFolderRepack &rep = folderRefs[folderRefIndex];
+ if (rep.Group != groupIndex)
+ break;
+ int folderIndex = rep.FolderIndex;
+
+ if (rep.NumCopyFiles == db->NumUnpackStreamsVector[folderIndex])
+ {
+ UInt64 packSize = db->GetFolderFullPackSize(folderIndex);
+ RINOK(WriteRange(inStream, archive.SeqStream,
+ db->GetFolderStreamPos(folderIndex, 0), packSize, progress));
+ lps->ProgressOffset += packSize;
+
+ const CFolder &folder = db->Folders[folderIndex];
+ CNum startIndex = db->FolderStartPackStreamIndex[folderIndex];
+ for (int j = 0; j < folder.PackStreams.Size(); j++)
+ {
+ newDatabase.PackSizes.Add(db->PackSizes[startIndex + j]);
+ // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);
+ // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);
+ }
+ newDatabase.Folders.Add(folder);
+ }
+ else
+ {
+ CStreamBinder sb;
+ RINOK(sb.CreateEvents());
+ CMyComPtr<ISequentialOutStream> sbOutStream;
+ CMyComPtr<ISequentialInStream> sbInStream;
+ sb.CreateStreams(&sbInStream, &sbOutStream);
+ CBoolVector extractStatuses;
+
+ CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
+ CNum indexInFolder = 0;
+
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ bool needExtract = false;
+ if (db->Files[fi].HasStream)
+ {
+ indexInFolder++;
+ int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0 && !updateItems[updateIndex].NewData)
+ needExtract = true;
+ }
+ extractStatuses.Add(needExtract);
+ }
+
+ RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream));
+ sbOutStream.Release();
+
+ threadDecoder.InStream = inStream;
+ threadDecoder.Folder = &db->Folders[folderIndex];
+ threadDecoder.StartPos = db->GetFolderStreamPos(folderIndex, 0);
+ threadDecoder.PackSizes = &db->PackSizes[db->FolderStartPackStreamIndex[folderIndex]];
+
+ threadDecoder.Start();
+
+ int startPackIndex = newDatabase.PackSizes.Size();
+ CFolder newFolder;
+ RINOK(encoder.Encode(
+ EXTERNAL_CODECS_LOC_VARS
+ sbInStream, NULL, &inSizeForReduce, newFolder,
+ archive.SeqStream, newDatabase.PackSizes, progress));
+
+ threadDecoder.WaitFinish();
+
+ RINOK(threadDecoder.Result);
+
+ for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+ lps->OutSize += newDatabase.PackSizes[startPackIndex];
+ lps->InSize += newFolder.GetUnpackSize();
+
+ newDatabase.Folders.Add(newFolder);
+ }
+
+ newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles);
+
+ CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
+
+ CNum indexInFolder = 0;
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ CFileItem file;
+ CFileItem2 file2;
+ db->GetFile(fi, file, file2);
+ if (file.HasStream)
+ {
+ indexInFolder++;
+ int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0)
+ {
+ const CUpdateItem &ui = updateItems[updateIndex];
+ if (ui.NewData)
+ continue;
+ if (ui.NewProps)
+ {
+ CFileItem uf;
+ FromUpdateItemToFileItem(ui, uf, file2);
+ uf.Size = file.Size;
+ uf.Crc = file.Crc;
+ uf.CrcDefined = file.CrcDefined;
+ uf.HasStream = file.HasStream;
+ file = uf;
+ }
+ newDatabase.AddFile(file, file2);
+ }
+ }
+ }
+ }
+
+ int numFiles = group.Indices.Size();
+ if (numFiles == 0)
+ continue;
+ CRecordVector<CRefItem> refItems;
+ refItems.Reserve(numFiles);
+ bool sortByType = (numSolidFiles > 1);
+ for (i = 0; i < numFiles; i++)
+ refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType));
+ refItems.Sort(CompareUpdateItems, (void *)&sortByType);
+
+ CRecordVector<UInt32> indices;
+ indices.Reserve(numFiles);
+
+ for (i = 0; i < numFiles; i++)
+ {
+ UInt32 index = refItems[i].Index;
+ indices.Add(index);
+ /*
+ const CUpdateItem &ui = updateItems[index];
+ CFileItem file;
+ if (ui.NewProps)
+ FromUpdateItemToFileItem(ui, file);
+ else
+ file = db.Files[ui.IndexInArchive];
+ if (file.IsAnti || file.IsDir)
+ return E_FAIL;
+ newDatabase.Files.Add(file);
+ */
+ }
+
+ for (i = 0; i < numFiles;)
+ {
+ UInt64 totalSize = 0;
+ int numSubFiles;
+ UString prevExtension;
+ for (numSubFiles = 0; i + numSubFiles < numFiles &&
+ numSubFiles < numSolidFiles; numSubFiles++)
+ {
+ const CUpdateItem &ui = updateItems[indices[i + numSubFiles]];
+ totalSize += ui.Size;
+ if (totalSize > options.NumSolidBytes)
+ break;
+ if (options.SolidExtension)
+ {
+ UString ext = ui.GetExtension();
+ if (numSubFiles == 0)
+ prevExtension = ext;
+ else
+ if (ext.CompareNoCase(prevExtension) != 0)
+ break;
+ }
+ }
+ if (numSubFiles < 1)
+ numSubFiles = 1;
+
+ CFolderInStream *inStreamSpec = new CFolderInStream;
+ CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
+ inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
+
+ CFolder folderItem;
+
+ int startPackIndex = newDatabase.PackSizes.Size();
+ RINOK(encoder.Encode(
+ EXTERNAL_CODECS_LOC_VARS
+ solidInStream, NULL, &inSizeForReduce, folderItem,
+ archive.SeqStream, newDatabase.PackSizes, progress));
+
+ for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+ lps->OutSize += newDatabase.PackSizes[startPackIndex];
+
+ lps->InSize += folderItem.GetUnpackSize();
+ // for ()
+ // newDatabase.PackCRCsDefined.Add(false);
+ // newDatabase.PackCRCs.Add(0);
+
+ newDatabase.Folders.Add(folderItem);
+
+ CNum numUnpackStreams = 0;
+ for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
+ {
+ const CUpdateItem &ui = updateItems[indices[i + subIndex]];
+ CFileItem file;
+ CFileItem2 file2;
+ if (ui.NewProps)
+ FromUpdateItemToFileItem(ui, file, file2);
+ else
+ db->GetFile(ui.IndexInArchive, file, file2);
+ if (file2.IsAnti || file.IsDir)
+ return E_FAIL;
+
+ /*
+ CFileItem &file = newDatabase.Files[
+ startFileIndexInDatabase + i + subIndex];
+ */
+ if (!inStreamSpec->Processed[subIndex])
+ {
+ continue;
+ // file.Name += L".locked";
+ }
+
+ file.Crc = inStreamSpec->CRCs[subIndex];
+ file.Size = inStreamSpec->Sizes[subIndex];
+ if (file.Size != 0)
+ {
+ file.CrcDefined = true;
+ file.HasStream = true;
+ numUnpackStreams++;
+ }
+ else
+ {
+ file.CrcDefined = false;
+ file.HasStream = false;
+ }
+ newDatabase.AddFile(file, file2);
+ }
+ // numUnpackStreams = 0 is very bad case for locked files
+ // v3.13 doesn't understand it.
+ newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
+ i += numSubFiles;
+ }
+ }
+
+ if (folderRefIndex != folderRefs.Size())
+ return E_FAIL;
+
+ /*
+ folderRefs.ClearAndFree();
+ fileIndexToUpdateIndexMap.ClearAndFree();
+ groups.ClearAndFree();
+ */
+
+ {
+ // ---------- Write Folders & Empty Files ----------
+
+ CRecordVector<int> emptyRefs;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ if (ui.HasStream())
+ continue;
+ }
+ else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream)
+ continue;
+ emptyRefs.Add(i);
+ }
+ emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);
+ for (i = 0; i < emptyRefs.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[emptyRefs[i]];
+ CFileItem file;
+ CFileItem2 file2;
+ if (ui.NewProps)
+ FromUpdateItemToFileItem(ui, file, file2);
+ else
+ db->GetFile(ui.IndexInArchive, file, file2);
+ newDatabase.AddFile(file, file2);
+ }
+ }
+
+ newDatabase.ReserveDown();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.h b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.h
new file mode 100644
index 000000000..31e362246
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zUpdate.h
@@ -0,0 +1,88 @@
+// 7zUpdate.h
+
+#ifndef __7Z_UPDATE_H
+#define __7Z_UPDATE_H
+
+#include "7zCompressionMode.h"
+#include "7zIn.h"
+#include "7zOut.h"
+
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CUpdateItem
+{
+ int IndexInArchive;
+ int IndexInClient;
+
+ UInt64 CTime;
+ UInt64 ATime;
+ UInt64 MTime;
+
+ UInt64 Size;
+ UString Name;
+
+ UInt32 Attrib;
+
+ bool NewData;
+ bool NewProps;
+
+ bool IsAnti;
+ bool IsDir;
+
+ bool AttribDefined;
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+
+ bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
+
+ CUpdateItem():
+ IsAnti(false),
+ IsDir(false),
+ AttribDefined(false),
+ CTimeDefined(false),
+ ATimeDefined(false),
+ MTimeDefined(false)
+ {}
+ void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); };
+
+ int GetExtensionPos() const;
+ UString GetExtension() const;
+};
+
+struct CUpdateOptions
+{
+ const CCompressionMethodMode *Method;
+ const CCompressionMethodMode *HeaderMethod;
+ bool UseFilters;
+ bool MaxFilter;
+
+ CHeaderOptions HeaderOptions;
+
+ UInt64 NumSolidFiles;
+ UInt64 NumSolidBytes;
+ bool SolidExtension;
+ bool RemoveSfxBlock;
+ bool VolumeMode;
+};
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ const CArchiveDatabaseEx *db,
+ const CObjectVector<CUpdateItem> &updateItems,
+ COutArchive &archive,
+ CArchiveDatabase &newDatabase,
+ ISequentialOutStream *seqOutStream,
+ IArchiveUpdateCallback *updateCallback,
+ const CUpdateOptions &options
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getDecoderPassword
+ #endif
+ );
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/ApmHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/ApmHandler.cpp
new file mode 100644
index 000000000..a3b5e19b9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/ApmHandler.cpp
@@ -0,0 +1,356 @@
+// ApmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NApm {
+
+struct CItem
+{
+ UInt32 StartBlock;
+ UInt32 NumBlocks;
+ char Name[32];
+ char Type[32];
+ /*
+ UInt32 DataStartBlock;
+ UInt32 NumDataBlocks;
+ UInt32 Status;
+ UInt32 BootStartBlock;
+ UInt32 BootSize;
+ UInt32 BootAddr;
+ UInt32 BootEntry;
+ UInt32 BootChecksum;
+ char Processor[16];
+ */
+
+ bool Parse(const Byte *p, UInt32 &numBlocksInMap)
+ {
+ if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0)
+ return false;
+ numBlocksInMap = Get32(p + 4);
+ StartBlock = Get32(p + 8);
+ NumBlocks = Get32(p + 0xC);
+ memcpy(Name, p + 0x10, 32);
+ memcpy(Type, p + 0x30, 32);
+ /*
+ DataStartBlock = Get32(p + 0x50);
+ NumDataBlocks = Get32(p + 0x54);
+ Status = Get32(p + 0x58);
+ BootStartBlock = Get32(p + 0x5C);
+ BootSize = Get32(p + 0x60);
+ BootAddr = Get32(p + 0x64);
+ if (Get32(p + 0x68) != 0)
+ return false;
+ BootEntry = Get32(p + 0x6C);
+ if (Get32(p + 0x70) != 0)
+ return false;
+ BootChecksum = Get32(p + 0x74);
+ memcpy(Processor, p + 0x78, 16);
+ */
+ return true;
+ }
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CRecordVector<CItem> _items;
+
+ int _blockSizeLog;
+ UInt32 _numBlocks;
+
+ HRESULT ReadTables(IInStream *stream);
+ UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; }
+ UInt64 GetItemSize(const CItem &item) { return BlocksToBytes(item.NumBlocks); }
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+static inline int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+HRESULT CHandler::ReadTables(IInStream *stream)
+{
+ const UInt32 kSectorSize = 512;
+ Byte buf[kSectorSize];
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+ if (buf[0] != 0x45 || buf[1] != 0x52)
+ return S_FALSE;
+ _blockSizeLog = GetLog(Get16(buf + 2));
+ if (_blockSizeLog < 9 || _blockSizeLog > 14)
+ return S_FALSE;
+ _numBlocks = Get32(buf + 4);
+ for (int i = 8; i < 16; i++)
+ if (buf[i] != 0)
+ return S_FALSE;
+ }
+
+ unsigned numSkips = (unsigned)1 << (_blockSizeLog - 9);
+ for (unsigned j = 1; j < numSkips; j++)
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+ }
+
+ UInt32 numBlocksInMap = 0;
+ for (unsigned i = 0;;)
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+
+ CItem item;
+
+ UInt32 numBlocksInMap2;
+ if (!item.Parse(buf, numBlocksInMap2))
+ return S_FALSE;
+ if (i == 0)
+ {
+ numBlocksInMap = numBlocksInMap2;
+ if (numBlocksInMap > (1 << 8))
+ return S_FALSE;
+ }
+ else if (numBlocksInMap2 != numBlocksInMap)
+ return S_FALSE;
+
+ UInt32 finish = item.StartBlock + item.NumBlocks;
+ if (finish < item.StartBlock)
+ return S_FALSE;
+ _numBlocks = MyMax(_numBlocks, finish);
+
+ _items.Add(item);
+ for (unsigned j = 1; j < numSkips; j++)
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+ }
+ if (++i == numBlocksInMap)
+ break;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(ReadTables(stream));
+ _stream = stream;
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static AString GetString(const char *s)
+{
+ AString res;
+ for (int i = 0; i < 32 && s[i] != 0; i++)
+ res += s[i];
+ return res;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMainSubfile:
+ {
+ int mainIndex = -1;
+ for (int i = 0; i < _items.Size(); i++)
+ {
+ AString s = GetString(_items[i].Type);
+ if (s != "Apple_Free" &&
+ s != "Apple_partition_map")
+ {
+ if (mainIndex >= 0)
+ {
+ mainIndex = -1;
+ break;
+ }
+ mainIndex = i;
+ }
+ }
+ if (mainIndex >= 0)
+ prop = (UInt32)mainIndex;
+ break;
+ }
+ case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
+ case kpidPhySize: prop = BlocksToBytes(_numBlocks); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ AString s = GetString(item.Name);
+ if (s.IsEmpty())
+ {
+ char s2[32];
+ ConvertUInt32ToString(index, s2);
+ s = s2;
+ }
+ AString type = GetString(item.Type);
+ if (type == "Apple_HFS")
+ type = "hfs";
+ if (!type.IsEmpty())
+ {
+ s += '.';
+ s += type;
+ }
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = GetItemSize(item);
+ break;
+ case kpidOffset: prop = BlocksToBytes(item.StartBlock); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += GetItemSize(_items[allFilesMode ? i : indices[i]]);
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ UInt64 size = GetItemSize(item);
+ totalSize += size;
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ RINOK(_stream->Seek(BlocksToBytes(item.StartBlock), STREAM_SEEK_SET, NULL));
+ streamSpec->Init(size);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == size ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ return CreateLimitedInStream(_stream, BlocksToBytes(item.StartBlock), GetItemSize(item), stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"APM", L"", 0, 0xD4, { 0x50, 0x4D, 0, 0, 0, 0, 0 }, 7, false, CreateArc, 0 };
+
+REGISTER_ARC(Apm)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/ArchiveExports.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/ArchiveExports.cpp
new file mode 100644
index 000000000..c7908b591
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/ArchiveExports.cpp
@@ -0,0 +1,135 @@
+// ArchiveExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+
+static const unsigned int kNumArcsMax = 48;
+static unsigned int g_NumArcs = 0;
+static unsigned int g_DefaultArcIndex = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax];
+void RegisterArc(const CArcInfo *arcInfo)
+{
+ if (g_NumArcs < kNumArcsMax)
+ {
+ const wchar_t *p = arcInfo->Name;
+ if (p[0] == '7' && p[1] == 'z' && p[2] == 0)
+ g_DefaultArcIndex = g_NumArcs;
+ g_Arcs[g_NumArcs++] = arcInfo;
+ }
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler,
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
+
+static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value)
+{
+ if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
+ value->vt = VT_BSTR;
+ return S_OK;
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
+{
+ return SetPropString((const char *)&guid, sizeof(GUID), value);
+}
+
+int FindFormatCalssId(const GUID *clsID)
+{
+ GUID cls = *clsID;
+ CLS_ARC_ID_ITEM(cls) = 0;
+ if (cls != CLSID_CArchiveHandler)
+ return -1;
+ Byte id = CLS_ARC_ID_ITEM(*clsID);
+ for (unsigned i = 0; i < g_NumArcs; i++)
+ if (g_Arcs[i]->ClassId == id)
+ return (int)i;
+ return -1;
+}
+
+STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ COM_TRY_BEGIN
+ {
+ int needIn = (*iid == IID_IInArchive);
+ int needOut = (*iid == IID_IOutArchive);
+ if (!needIn && !needOut)
+ return E_NOINTERFACE;
+ int formatIndex = FindFormatCalssId(clsid);
+ if (formatIndex < 0)
+ return CLASS_E_CLASSNOTAVAILABLE;
+
+ const CArcInfo &arc = *g_Arcs[formatIndex];
+ if (needIn)
+ {
+ *outObject = arc.CreateInArchive();
+ ((IInArchive *)*outObject)->AddRef();
+ }
+ else
+ {
+ if (!arc.CreateOutArchive)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ *outObject = arc.CreateOutArchive();
+ ((IOutArchive *)*outObject)->AddRef();
+ }
+ }
+ COM_TRY_END
+ return S_OK;
+}
+
+STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ if (formatIndex >= g_NumArcs)
+ return E_INVALIDARG;
+ const CArcInfo &arc = *g_Arcs[formatIndex];
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case NArchive::kName:
+ prop = arc.Name;
+ break;
+ case NArchive::kClassID:
+ {
+ GUID clsId = CLSID_CArchiveHandler;
+ CLS_ARC_ID_ITEM(clsId) = arc.ClassId;
+ return SetPropGUID(clsId, value);
+ }
+ case NArchive::kExtension:
+ if (arc.Ext != 0)
+ prop = arc.Ext;
+ break;
+ case NArchive::kAddExtension:
+ if (arc.AddExt != 0)
+ prop = arc.AddExt;
+ break;
+ case NArchive::kUpdate:
+ prop = (bool)(arc.CreateOutArchive != 0);
+ break;
+ case NArchive::kKeepName:
+ prop = arc.KeepName;
+ break;
+ case NArchive::kStartSignature:
+ return SetPropString((const char *)arc.Signature, arc.SignatureSize, value);
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
+{
+ return GetHandlerProperty2(g_DefaultArcIndex, propID, value);
+}
+
+STDAPI GetNumberOfFormats(UINT32 *numFormats)
+{
+ *numFormats = g_NumArcs;
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/ArjHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/ArjHandler.cpp
new file mode 100644
index 000000000..4dd686ec0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/ArjHandler.cpp
@@ -0,0 +1,798 @@
+// ArjHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/ArjDecoder1.h"
+#include "../Compress/ArjDecoder2.h"
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+#include "Common/OutStreamWithCRC.h"
+
+using namespace NWindows;
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NArj {
+
+const int kBlockSizeMin = 30;
+const int kBlockSizeMax = 2600;
+
+namespace NSignature
+{
+ const Byte kSig0 = 0x60;
+ const Byte kSig1 = 0xEA;
+}
+
+namespace NFileHeader
+{
+ namespace NCompressionMethod
+ {
+ enum
+ {
+ kStored = 0,
+ kCompressed1a = 1,
+ kCompressed1b = 2,
+ kCompressed1c = 3,
+ kCompressed2 = 4,
+ kNoDataNoCRC = 8,
+ kNoData = 9
+ };
+ }
+
+ namespace NFileType
+ {
+ enum
+ {
+ kBinary = 0,
+ k7BitText = 1,
+ kArchiveHeader = 2,
+ kDirectory = 3,
+ kVolumeLablel = 4,
+ kChapterLabel = 5
+ };
+ }
+
+ namespace NFlags
+ {
+ const Byte kGarbled = 1;
+ const Byte kVolume = 4;
+ const Byte kExtFile = 8;
+ const Byte kPathSym = 0x10;
+ const Byte kBackup = 0x20;
+ }
+
+ namespace NHostOS
+ {
+ enum EEnum
+ {
+ kMSDOS = 0, // filesystem used by MS-DOS, OS/2, Win32
+ // pkarj 2.50 (FAT / VFAT / FAT32 file systems)
+ kPRIMOS,
+ kUnix,
+ kAMIGA,
+ kMac,
+ kOS_2,
+ kAPPLE_GS,
+ kAtari_ST,
+ kNext,
+ kVAX_VMS,
+ kWIN95
+ };
+ }
+}
+
+struct CArchiveHeader
+{
+ // Byte ArchiverVersion;
+ // Byte ExtractVersion;
+ Byte HostOS;
+ // Byte Flags;
+ // Byte SecuryVersion;
+ // Byte FileType;
+ // Byte Reserved;
+ UInt32 CTime;
+ UInt32 MTime;
+ UInt32 ArchiveSize;
+ // UInt32 SecurityEnvelopeFilePosition;
+ // UInt16 FilespecPositionInFilename;
+ // UInt16 LengthOfSecurityEnvelopeSata;
+ // Byte EncryptionVersion;
+ // Byte LastChapter;
+ AString Name;
+ AString Comment;
+
+ HRESULT Parse(const Byte *p, unsigned size);
+};
+
+static HRESULT ReadString(const Byte *p, unsigned &size, AString &res)
+{
+ AString s;
+ for (unsigned i = 0; i < size;)
+ {
+ char c = (char)p[i++];
+ if (c == 0)
+ {
+ size = i;
+ res = s;
+ return S_OK;
+ }
+ s += c;
+ }
+ return S_FALSE;
+}
+
+HRESULT CArchiveHeader::Parse(const Byte *p, unsigned size)
+{
+ if (size < kBlockSizeMin)
+ return S_FALSE;
+ Byte firstHeaderSize = p[0];
+ if (firstHeaderSize > size)
+ return S_FALSE;
+ // ArchiverVersion = p[1];
+ // ExtractVersion = p[2];
+ HostOS = p[3];
+ // Flags = p[4];
+ // SecuryVersion = p[5];
+ if (p[6] != NFileHeader::NFileType::kArchiveHeader)
+ return S_FALSE;
+ // Reserved = p[7];
+ CTime = Get32(p + 8);
+ MTime = Get32(p + 12);
+ ArchiveSize = Get32(p + 16);
+ // SecurityEnvelopeFilePosition = Get32(p + 20);
+ // UInt16 filespecPositionInFilename = Get16(p + 24);
+ // LengthOfSecurityEnvelopeSata = Get16(p + 26);
+ // EncryptionVersion = p[28];
+ // LastChapter = p[29];
+ unsigned pos = firstHeaderSize;
+ unsigned size1 = size - pos;
+ RINOK(ReadString(p + pos, size1, Name));
+ pos += size1;
+ size1 = size - pos;
+ RINOK(ReadString(p + pos, size1, Comment));
+ pos += size1;
+ return S_OK;
+}
+
+struct CItem
+{
+ AString Name;
+ AString Comment;
+
+ UInt32 MTime;
+ UInt32 PackSize;
+ UInt32 Size;
+ UInt32 FileCRC;
+ UInt32 SplitPos;
+
+ Byte Version;
+ Byte ExtractVersion;
+ Byte HostOS;
+ Byte Flags;
+ Byte Method;
+ Byte FileType;
+
+ // UInt16 FilespecPositionInFilename;
+ UInt16 FileAccessMode;
+ // Byte FirstChapter;
+ // Byte LastChapter;
+
+ UInt64 DataPosition;
+
+ bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kGarbled) != 0; }
+ bool IsDir() const { return (FileType == NFileHeader::NFileType::kDirectory); }
+ bool IsSplitAfter() const { return (Flags & NFileHeader::NFlags::kVolume) != 0; }
+ bool IsSplitBefore() const { return (Flags & NFileHeader::NFlags::kExtFile) != 0; }
+ UInt32 GetWinAttributes() const
+ {
+ UInt32 winAtrributes;
+ switch(HostOS)
+ {
+ case NFileHeader::NHostOS::kMSDOS:
+ case NFileHeader::NHostOS::kWIN95:
+ winAtrributes = FileAccessMode;
+ break;
+ default:
+ winAtrributes = 0;
+ }
+ if (IsDir())
+ winAtrributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAtrributes;
+ }
+
+ HRESULT Parse(const Byte *p, unsigned size);
+};
+
+HRESULT CItem::Parse(const Byte *p, unsigned size)
+{
+ if (size < kBlockSizeMin)
+ return S_FALSE;
+
+ Byte firstHeaderSize = p[0];
+
+ Version = p[1];
+ ExtractVersion = p[2];
+ HostOS = p[3];
+ Flags = p[4];
+ Method = p[5];
+ FileType = p[6];
+ // Reserved = p[7];
+ MTime = Get32(p + 8);
+ PackSize = Get32(p + 12);
+ Size = Get32(p + 16);
+ FileCRC = Get32(p + 20);
+ // FilespecPositionInFilename = Get16(p + 24);
+ FileAccessMode = Get16(p + 26);
+ // FirstChapter = p[28];
+ // FirstChapter = p[29];
+
+ SplitPos = 0;
+ if (IsSplitBefore() && firstHeaderSize >= 34)
+ SplitPos = Get32(p + 30);
+
+ unsigned pos = firstHeaderSize;
+ unsigned size1 = size - pos;
+ RINOK(ReadString(p + pos, size1, Name));
+ pos += size1;
+ size1 = size - pos;
+ RINOK(ReadString(p + pos, size1, Comment));
+ pos += size1;
+
+ return S_OK;
+}
+
+struct CInArchiveException
+{
+ enum CCauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kCRCError,
+ kIncorrectArchive
+ }
+ Cause;
+ CInArchiveException(CCauseType cause): Cause(cause) {};
+};
+
+class CInArchive
+{
+ UInt32 _blockSize;
+ Byte _block[kBlockSizeMax + 4];
+
+ HRESULT ReadBlock(bool &filled);
+ HRESULT ReadSignatureAndBlock(bool &filled);
+ HRESULT SkipExtendedHeaders();
+
+ HRESULT SafeReadBytes(void *data, UInt32 size);
+
+public:
+ CArchiveHeader Header;
+
+ IInStream *Stream;
+ IArchiveOpenCallback *Callback;
+ UInt64 NumFiles;
+ UInt64 NumBytes;
+
+ HRESULT Open(const UInt64 *searchHeaderSizeLimit);
+ HRESULT GetNextItem(bool &filled, CItem &item);
+};
+
+static inline bool TestMarkerCandidate(const Byte *p, unsigned maxSize)
+{
+ if (p[0] != NSignature::kSig0 || p[1] != NSignature::kSig1)
+ return false;
+ UInt32 blockSize = Get16(p + 2);
+ p += 4;
+ if (p[6] != NFileHeader::NFileType::kArchiveHeader ||
+ p[0] > blockSize ||
+ maxSize < 2 + 2 + blockSize + 4 ||
+ blockSize < kBlockSizeMin || blockSize > kBlockSizeMax ||
+ p[28] > 8) // EncryptionVersion
+ return false;
+ // return (Get32(p + blockSize) == CrcCalc(p, blockSize));
+ return true;
+}
+
+static HRESULT FindAndReadMarker(ISequentialInStream *stream, const UInt64 *searchHeaderSizeLimit, UInt64 &position)
+{
+ position = 0;
+
+ const int kMarkerSizeMin = 2 + 2 + kBlockSizeMin + 4;
+ const int kMarkerSizeMax = 2 + 2 + kBlockSizeMax + 4;
+
+ CByteBuffer byteBuffer;
+ const UInt32 kBufSize = 1 << 16;
+ byteBuffer.SetCapacity(kBufSize);
+ Byte *buf = byteBuffer;
+
+ size_t processedSize = kMarkerSizeMax;
+ RINOK(ReadStream(stream, buf, &processedSize));
+ if (processedSize < kMarkerSizeMin)
+ return S_FALSE;
+ if (TestMarkerCandidate(buf, (unsigned)processedSize))
+ return S_OK;
+
+ UInt32 numBytesPrev = (UInt32)processedSize - 1;
+ memmove(buf, buf + 1, numBytesPrev);
+ UInt64 curTestPos = 1;
+ for (;;)
+ {
+ if (searchHeaderSizeLimit != NULL)
+ if (curTestPos > *searchHeaderSizeLimit)
+ return S_FALSE;
+ processedSize = kBufSize - numBytesPrev;
+ RINOK(ReadStream(stream, buf + numBytesPrev, &processedSize));
+ UInt32 numBytesInBuffer = numBytesPrev + (UInt32)processedSize;
+ if (numBytesInBuffer < kMarkerSizeMin)
+ return S_FALSE;
+ UInt32 numTests = numBytesInBuffer - kMarkerSizeMin + 1;
+ UInt32 pos;
+ for (pos = 0; pos < numTests; pos++)
+ {
+ for (; buf[pos] != NSignature::kSig0 && pos < numTests; pos++);
+ if (pos == numTests)
+ break;
+ if (TestMarkerCandidate(buf + pos, numBytesInBuffer - pos))
+ {
+ position = curTestPos + pos;
+ return S_OK;
+ }
+ }
+ curTestPos += pos;
+ numBytesPrev = numBytesInBuffer - numTests;
+ memmove(buf, buf + numTests, numBytesPrev);
+ }
+}
+
+HRESULT CInArchive::SafeReadBytes(void *data, UInt32 size)
+{
+ size_t processed = size;
+ RINOK(ReadStream(Stream, data, &processed));
+ if (processed != size)
+ throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadBlock(bool &filled)
+{
+ filled = false;
+ Byte buf[2];
+ RINOK(SafeReadBytes(buf, 2));
+ _blockSize = Get16(buf);
+ if (_blockSize == 0)
+ return S_OK;
+ if (_blockSize > kBlockSizeMax)
+ throw CInArchiveException(CInArchiveException::kIncorrectArchive);
+ RINOK(SafeReadBytes(_block, _blockSize + 4));
+ NumBytes += _blockSize + 6;
+ if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize))
+ throw CInArchiveException(CInArchiveException::kCRCError);
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadSignatureAndBlock(bool &filled)
+{
+ Byte id[2];
+ RINOK(SafeReadBytes(id, 2));
+ if (id[0] != NSignature::kSig0 || id[1] != NSignature::kSig1)
+ throw CInArchiveException(CInArchiveException::kIncorrectArchive);
+ return ReadBlock(filled);
+}
+
+HRESULT CInArchive::SkipExtendedHeaders()
+{
+ for (UInt32 i = 0;; i++)
+ {
+ bool filled;
+ RINOK(ReadBlock(filled));
+ if (!filled)
+ return S_OK;
+ if (Callback && (i & 0xFF) == 0)
+ RINOK(Callback->SetCompleted(&NumFiles, &NumBytes));
+ }
+}
+
+HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit)
+{
+ UInt64 position = 0;
+ RINOK(FindAndReadMarker(Stream, searchHeaderSizeLimit, position));
+ RINOK(Stream->Seek(position, STREAM_SEEK_SET, NULL));
+ bool filled;
+ RINOK(ReadSignatureAndBlock(filled));
+ if (!filled)
+ return S_FALSE;
+ RINOK(Header.Parse(_block, _blockSize));
+ return SkipExtendedHeaders();
+}
+
+HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
+{
+ RINOK(ReadSignatureAndBlock(filled));
+ if (!filled)
+ return S_OK;
+ filled = false;
+ RINOK(item.Parse(_block, _blockSize));
+ /*
+ UInt32 extraData;
+ if ((header.Flags & NFileHeader::NFlags::kExtFile) != 0)
+ extraData = GetUi32(_block + pos);
+ */
+
+ RINOK(SkipExtendedHeaders());
+ filled = true;
+ return S_OK;
+}
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+
+ INTERFACE_IInArchive(;)
+
+ HRESULT Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *callback);
+private:
+ CInArchive _archive;
+ CObjectVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+};
+
+const wchar_t *kHostOS[] =
+{
+ L"MSDOS",
+ L"PRIMOS",
+ L"UNIX",
+ L"AMIGA",
+ L"MAC",
+ L"OS/2",
+ L"APPLE GS",
+ L"ATARI ST",
+ L"NEXT",
+ L"VAX VMS",
+ L"WIN95"
+};
+
+const wchar_t *kUnknownOS = L"Unknown";
+
+const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidName, VT_BSTR},
+ { NULL, kpidCTime, VT_BSTR},
+ { NULL, kpidMTime, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidComment, VT_BSTR}
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI4},
+ { NULL, kpidPosition, VT_UI8},
+ { NULL, kpidPackSize, VT_UI4},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidMethod, VT_UI1},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidComment, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop)
+{
+ if (dosTime == 0)
+ return;
+ FILETIME localFileTime, utc;
+ if (NTime::DosTimeToFileTime(dosTime, localFileTime))
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utc))
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ else
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ prop = utc;
+}
+
+static void SetHostOS(Byte hostOS, NWindows::NCOM::CPropVariant &prop)
+{
+ prop = hostOS < kNumHostOSes ? kHostOS[hostOS] : kUnknownOS;
+}
+
+static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &prop)
+{
+ if (!s.IsEmpty())
+ prop = MultiByteToUnicodeString(s, CP_OEMCP);
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidName: SetUnicodeString(_archive.Header.Name, prop); break;
+ case kpidCTime: SetTime(_archive.Header.CTime, prop); break;
+ case kpidMTime: SetTime(_archive.Header.MTime, prop); break;
+ case kpidHostOS: SetHostOS(_archive.Header.HostOS, prop); break;
+ case kpidComment: SetUnicodeString(_archive.Header.Comment, prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break;
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidCRC: prop = item.FileCRC; break;
+ case kpidMethod: prop = item.Method; break;
+ case kpidHostOS: SetHostOS(item.HostOS, prop); break;
+ case kpidMTime: SetTime(item.MTime, prop); break;
+ case kpidComment: SetUnicodeString(item.Comment, prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *callback)
+{
+ Close();
+
+ UInt64 endPos = 0;
+ if (callback != NULL)
+ {
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+
+ _archive.Stream = inStream;
+ _archive.Callback = callback;
+ _archive.NumFiles = _archive.NumBytes = 0;
+
+ RINOK(_archive.Open(maxCheckStartPosition));
+ if (callback != NULL)
+ RINOK(callback->SetTotal(NULL, &endPos));
+ for (;;)
+ {
+ CItem item;
+ bool filled;
+
+
+ RINOK(_archive.GetNextItem(filled, item));
+
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition));
+
+ if (!filled)
+ break;
+ _items.Add(item);
+
+ if (inStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL) != S_OK)
+ throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+
+ _archive.NumFiles = _items.Size();
+ _archive.NumBytes = item.DataPosition;
+
+ if (callback != NULL && _items.Size() % 100 == 0)
+ {
+ RINOK(callback->SetCompleted(&_archive.NumFiles, &_archive.NumBytes));
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ res = Open2(inStream, maxCheckStartPosition, callback);
+ if (res == S_OK)
+ {
+ _stream = inStream;
+ return S_OK;
+ }
+ }
+ catch(const CInArchiveException &) { res = S_FALSE; }
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ UInt64 totalUnpacked = 0, totalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _items[allFilesMode ? i : indices[i]];
+ totalUnpacked += item.Size;
+ totalPacked += item.PackSize;
+ }
+ extractCallback->SetTotal(totalUnpacked);
+
+ totalUnpacked = totalPacked = 0;
+ UInt64 curUnpacked, curPacked;
+
+ CMyComPtr<ICompressCoder> arj1Decoder;
+ CMyComPtr<ICompressCoder> arj2Decoder;
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
+ inStreamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
+ {
+ lps->InSize = totalPacked;
+ lps->OutSize = totalUnpacked;
+ RINOK(lps->SetCur());
+
+ curUnpacked = curPacked = 0;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ continue;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ curUnpacked = item.Size;
+ curPacked = item.PackSize;
+
+ {
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init();
+
+ inStreamSpec->Init(item.PackSize);
+
+ UInt64 pos;
+ _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
+
+ HRESULT result = S_OK;
+ Int32 opRes = NExtract::NOperationResult::kOK;
+
+ if (item.IsEncrypted())
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ switch(item.Method)
+ {
+ case NFileHeader::NCompressionMethod::kStored:
+ {
+ result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
+ result = S_FALSE;
+ break;
+ }
+ case NFileHeader::NCompressionMethod::kCompressed1a:
+ case NFileHeader::NCompressionMethod::kCompressed1b:
+ case NFileHeader::NCompressionMethod::kCompressed1c:
+ {
+ if (!arj1Decoder)
+ arj1Decoder = new NCompress::NArj::NDecoder1::CCoder;
+ result = arj1Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
+ break;
+ }
+ case NFileHeader::NCompressionMethod::kCompressed2:
+ {
+ if (!arj2Decoder)
+ arj2Decoder = new NCompress::NArj::NDecoder2::CCoder;
+ result = arj2Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
+ break;
+ }
+ default:
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ }
+ }
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ if (result == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(result);
+ opRes = (outStreamSpec->GetCRC() == item.FileCRC) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Arj", L"arj", 0, 4, { 0x60, 0xEA }, 2, false, CreateArc, 0 };
+
+REGISTER_ARC(Arj)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Bz2Handler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Bz2Handler.cpp
new file mode 100644
index 000000000..98cbcc182
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Bz2Handler.cpp
@@ -0,0 +1,423 @@
+// Bz2Handler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#ifndef _7ZIP_ST
+#include "../../Windows/System.h"
+#endif
+
+#include "../Common/CreateCoder.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BZip2Decoder.h"
+#include "../Compress/BZip2Encoder.h"
+#include "../Compress/CopyCoder.h"
+
+#include "Common/DummyOutStream.h"
+#include "Common/ParseProperties.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NBz2 {
+
+static const UInt32 kNumPassesX1 = 1;
+static const UInt32 kNumPassesX7 = 2;
+static const UInt32 kNumPassesX9 = 7;
+
+static const UInt32 kDicSizeX1 = 100000;
+static const UInt32 kDicSizeX3 = 500000;
+static const UInt32 kDicSizeX5 = 900000;
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IOutArchive,
+ public ISetProperties,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+ UInt64 _packSize;
+ UInt64 _startPosition;
+ bool _packSizeDefined;
+
+ UInt32 _level;
+ UInt32 _dicSize;
+ UInt32 _numPasses;
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ #endif
+
+ void InitMethodProperties()
+ {
+ _level = 5;
+ _dicSize =
+ _numPasses = 0xFFFFFFFF;
+ #ifndef _7ZIP_ST
+ _numThreads = NWindows::NSystem::GetNumberOfProcessors();;
+ #endif
+ }
+
+public:
+ MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
+
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+
+ CHandler() { InitMethodProperties(); }
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPackSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+ const int kSignatureSize = 3;
+ Byte buf[kSignatureSize];
+ RINOK(ReadStream_FALSE(stream, buf, kSignatureSize));
+ if (buf[0] != 'B' || buf[1] != 'Z' || buf[2] != 'h')
+ return S_FALSE;
+
+ UInt64 endPosition;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition));
+ _packSize = endPosition - _startPosition;
+ _packSizeDefined = true;
+ _stream = stream;
+ _seqStream = stream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_stream)
+ extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ }
+
+ decoderSpec->SetInStream(_seqStream);
+
+ #ifndef _7ZIP_ST
+ RINOK(decoderSpec->SetNumberOfThreads(_numThreads));
+ #endif
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ HRESULT result = S_OK;
+
+ bool firstItem = true;
+ for (;;)
+ {
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = outStreamSpec->GetSize();
+
+ RINOK(lps->SetCur());
+
+ bool isBz2;
+ result = decoderSpec->CodeResume(outStream, isBz2, progress);
+
+ if (result != S_OK)
+ break;
+ if (!isBz2)
+ {
+ if (firstItem)
+ result = S_FALSE;
+ break;
+ }
+ firstItem = false;
+
+ _packSize = currentTotalPacked = decoderSpec->GetInputProcessedSize();
+ _packSizeDefined = true;
+ }
+ decoderSpec->ReleaseInStream();
+ outStream.Release();
+
+ Int32 retResult;
+ if (result == S_OK)
+ retResult = NExtract::NOperationResult::kOK;
+ else if (result == S_FALSE)
+ retResult = NExtract::NOperationResult::kDataError;
+ else
+ return result;
+ return extractCallback->SetOperationResult(retResult);
+
+ COM_TRY_END
+}
+
+static HRESULT UpdateArchive(
+ UInt64 unpackSize,
+ ISequentialOutStream *outStream,
+ int indexInClient,
+ UInt32 dictionary,
+ UInt32 numPasses,
+ #ifndef _7ZIP_ST
+ UInt32 numThreads,
+ #endif
+ IArchiveUpdateCallback *updateCallback)
+{
+ RINOK(updateCallback->SetTotal(unpackSize));
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetCompleted(&complexity));
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+
+ RINOK(updateCallback->GetStream(indexInClient, &fileInStream));
+
+ CLocalProgress *localProgressSpec = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
+ localProgressSpec->Init(updateCallback, true);
+
+ NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+ {
+ NWindows::NCOM::CPropVariant properties[] =
+ {
+ dictionary,
+ numPasses
+ #ifndef _7ZIP_ST
+ , numThreads
+ #endif
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumPasses
+ #ifndef _7ZIP_ST
+ , NCoderPropID::kNumThreads
+ #endif
+ };
+ RINOK(encoderSpec->SetCoderProperties(propIDs, properties, sizeof(propIDs) / sizeof(propIDs[0])));
+ }
+
+ RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
+
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+}
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+{
+ *type = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
+ if (prop.vt == VT_BOOL)
+ {
+ if (prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+
+ UInt32 dicSize = _dicSize;
+ if (dicSize == 0xFFFFFFFF)
+ dicSize = (_level >= 5 ? kDicSizeX5 :
+ (_level >= 3 ? kDicSizeX3 :
+ kDicSizeX1));
+
+ UInt32 numPasses = _numPasses;
+ if (numPasses == 0xFFFFFFFF)
+ numPasses = (_level >= 9 ? kNumPassesX9 :
+ (_level >= 7 ? kNumPassesX7 :
+ kNumPassesX1));
+
+ return UpdateArchive(
+ size, outStream, 0, dicSize, numPasses,
+ #ifndef _7ZIP_ST
+ _numThreads,
+ #endif
+ updateCallback);
+ }
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+ if (_stream)
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ return NCompress::CopyStream(_stream, outStream, NULL);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ InitMethodProperties();
+ #ifndef _7ZIP_ST
+ const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+ _numThreads = numProcessors;
+ #endif
+
+ for (int i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &prop = values[i];
+ if (name[0] == L'X')
+ {
+ UInt32 level = 9;
+ RINOK(ParsePropValue(name.Mid(1), prop, level));
+ _level = level;
+ }
+ else if (name[0] == L'D')
+ {
+ UInt32 dicSize = kDicSizeX5;
+ RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
+ _dicSize = dicSize;
+ }
+ else if (name.Left(4) == L"PASS")
+ {
+ UInt32 num = kNumPassesX9;
+ RINOK(ParsePropValue(name.Mid(4), prop, num));
+ _numPasses = num;
+ }
+ else if (name.Left(2) == L"MT")
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
+ #endif
+ }
+ else
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"bzip2", L"bz2 bzip2 tbz2 tbz", L"* * .tar .tar", 2, { 'B', 'Z', 'h' }, 3, true, CreateArc, CreateArcOut };
+
+REGISTER_ARC(BZip2)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
new file mode 100644
index 000000000..12c73eb5f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
@@ -0,0 +1,189 @@
+// CabBlockInStream.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+
+#include "Common/Defs.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "CabBlockInStream.h"
+
+namespace NArchive {
+namespace NCab {
+
+static const UInt32 kBlockSize = (1 << 16);
+
+bool CCabBlockInStream::Create()
+{
+ if (!_buffer)
+ _buffer = (Byte *)::MyAlloc(kBlockSize);
+ return (_buffer != 0);
+}
+
+CCabBlockInStream::~CCabBlockInStream()
+{
+ MyFree(_buffer);
+}
+
+class CCheckSum2
+{
+ UInt32 m_Value;
+ int m_Pos;
+ Byte m_Hist[4];
+public:
+ CCheckSum2(): m_Value(0){};
+ void Init() { m_Value = 0; m_Pos = 0; }
+ void Update(const void *data, UInt32 size);
+ void FinishDataUpdate()
+ {
+ for (int i = 0; i < m_Pos; i++)
+ m_Value ^= ((UInt32)(m_Hist[i])) << (8 * (m_Pos - i - 1));
+ }
+ void UpdateUInt32(UInt32 v) { m_Value ^= v; }
+ UInt32 GetResult() const { return m_Value; }
+};
+
+void CCheckSum2::Update(const void *data, UInt32 size)
+{
+ UInt32 checkSum = m_Value;
+ const Byte *dataPointer = (const Byte *)data;
+
+ while (size != 0 && m_Pos != 0)
+ {
+ m_Hist[m_Pos] = *dataPointer++;
+ m_Pos = (m_Pos + 1) & 3;
+ size--;
+ if (m_Pos == 0)
+ for (int i = 0; i < 4; i++)
+ checkSum ^= ((UInt32)m_Hist[i]) << (8 * i);
+ }
+
+ int numWords = size / 4;
+
+ while (numWords-- != 0)
+ {
+ UInt32 temp = *dataPointer++;
+ temp |= ((UInt32)(*dataPointer++)) << 8;
+ temp |= ((UInt32)(*dataPointer++)) << 16;
+ temp |= ((UInt32)(*dataPointer++)) << 24;
+ checkSum ^= temp;
+ }
+ m_Value = checkSum;
+
+ size &= 3;
+
+ while (size != 0)
+ {
+ m_Hist[m_Pos] = *dataPointer++;
+ m_Pos = (m_Pos + 1) & 3;
+ size--;
+ }
+}
+
+static const UInt32 kDataBlockHeaderSize = 8;
+
+class CTempCabInBuffer2
+{
+public:
+ Byte Buffer[kDataBlockHeaderSize];
+ UInt32 Pos;
+ Byte ReadByte()
+ {
+ return Buffer[Pos++];
+ }
+ UInt32 ReadUInt32()
+ {
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ value |= (((UInt32)ReadByte()) << (8 * i));
+ return value;
+ }
+ UInt16 ReadUInt16()
+ {
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ value |= (((UInt16)ReadByte()) << (8 * i));
+ return value;
+ }
+};
+
+HRESULT CCabBlockInStream::PreRead(UInt32 &packSize, UInt32 &unpackSize)
+{
+ CTempCabInBuffer2 inBuffer;
+ inBuffer.Pos = 0;
+ RINOK(ReadStream_FALSE(_stream, inBuffer.Buffer, kDataBlockHeaderSize))
+
+ UInt32 checkSum = inBuffer.ReadUInt32();
+ packSize = inBuffer.ReadUInt16();
+ unpackSize = inBuffer.ReadUInt16();
+ if (ReservedSize != 0)
+ {
+ RINOK(ReadStream_FALSE(_stream, _buffer, ReservedSize));
+ }
+ _pos = 0;
+ CCheckSum2 checkSumCalc;
+ checkSumCalc.Init();
+ UInt32 packSize2 = packSize;
+ if (MsZip && _size == 0)
+ {
+ if (packSize < 2)
+ return S_FALSE; // bad block;
+ Byte sig[2];
+ RINOK(ReadStream_FALSE(_stream, sig, 2));
+ if (sig[0] != 0x43 || sig[1] != 0x4B)
+ return S_FALSE;
+ packSize2 -= 2;
+ checkSumCalc.Update(sig, 2);
+ }
+
+ if (kBlockSize - _size < packSize2)
+ return S_FALSE;
+
+ UInt32 curSize = packSize2;
+ if (curSize != 0)
+ {
+ size_t processedSizeLoc = curSize;
+ RINOK(ReadStream(_stream, _buffer + _size, &processedSizeLoc));
+ checkSumCalc.Update(_buffer + _size, (UInt32)processedSizeLoc);
+ _size += (UInt32)processedSizeLoc;
+ if (processedSizeLoc != curSize)
+ return S_FALSE;
+ }
+ TotalPackSize = _size;
+
+ checkSumCalc.FinishDataUpdate();
+
+ bool dataError;
+ if (checkSum == 0)
+ dataError = false;
+ else
+ {
+ checkSumCalc.UpdateUInt32(packSize | (((UInt32)unpackSize) << 16));
+ dataError = (checkSumCalc.GetResult() != checkSum);
+ }
+ DataError |= dataError;
+ return dataError ? S_FALSE : S_OK;
+}
+
+STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != 0)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_size != 0)
+ {
+ size = MyMin(_size, size);
+ memmove(data, _buffer + _pos, size);
+ _pos += size;
+ _size -= size;
+ if (processedSize != 0)
+ *processedSize = size;
+ return S_OK;
+ }
+ return S_OK; // no blocks data
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabBlockInStream.h b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabBlockInStream.h
new file mode 100644
index 000000000..1db3835b4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabBlockInStream.h
@@ -0,0 +1,44 @@
+// CabBlockInStream.cpp
+
+#ifndef __CABBLOCKINSTREAM_H
+#define __CABBLOCKINSTREAM_H
+
+#include "Common/MyCom.h"
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NCab {
+
+class CCabBlockInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ Byte *_buffer;
+ UInt32 _pos;
+ UInt32 _size;
+
+public:
+ UInt32 TotalPackSize;
+ UInt32 ReservedSize;
+ bool DataError;
+ bool MsZip;
+
+ CCabBlockInStream(): _buffer(0), ReservedSize(0), MsZip(false), DataError(false), TotalPackSize(0) {}
+ ~CCabBlockInStream();
+ bool Create();
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+
+ void InitForNewFolder() { TotalPackSize = 0; }
+ void InitForNewBlock() { _size = 0; }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ HRESULT PreRead(UInt32 &packSize, UInt32 &unpackSize);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHandler.cpp
new file mode 100644
index 000000000..20f670d35
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHandler.cpp
@@ -0,0 +1,929 @@
+// CabHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/Defs.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/DeflateDecoder.h"
+#include "../../Compress/LzxDecoder.h"
+#include "../../Compress/QuantumDecoder.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "CabBlockInStream.h"
+#include "CabHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NCab {
+
+// #define _CAB_DETAILS
+
+#ifdef _CAB_DETAILS
+enum
+{
+ kpidBlockReal = kpidUserDefined
+};
+#endif
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidBlock, VT_I4}
+ #ifdef _CAB_DETAILS
+ ,
+ { L"BlockReal", kpidBlockReal, VT_UI4},
+ { NULL, kpidOffset, VT_UI4},
+ { NULL, kpidVolume, VT_UI4}
+ #endif
+};
+
+static const char *kMethods[] =
+{
+ "None",
+ "MSZip",
+ "Quantum",
+ "LZX"
+};
+
+static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
+static const char *kUnknownMethod = "Unknown";
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ // { NULL, kpidSolid, VT_BOOL},
+ { NULL, kpidNumBlocks, VT_UI4},
+ { NULL, kpidNumVolumes, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ AString resString;
+ CRecordVector<Byte> ids;
+ int i;
+ for (int v = 0; v < m_Database.Volumes.Size(); v++)
+ {
+ const CDatabaseEx &de = m_Database.Volumes[v];
+ for (i = 0; i < de.Folders.Size(); i++)
+ ids.AddToUniqueSorted(de.Folders[i].GetCompressionMethod());
+ }
+ for (i = 0; i < ids.Size(); i++)
+ {
+ Byte id = ids[i];
+ AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod;
+ if (!resString.IsEmpty())
+ resString += ' ';
+ resString += method;
+ }
+ prop = resString;
+ break;
+ }
+ // case kpidSolid: prop = _database.IsSolid(); break;
+ case kpidNumBlocks:
+ {
+ UInt32 numFolders = 0;
+ for (int v = 0; v < m_Database.Volumes.Size(); v++)
+ numFolders += m_Database.Volumes[v].Folders.Size();
+ prop = numFolders;
+ break;
+ }
+ case kpidNumVolumes:
+ {
+ prop = (UInt32)m_Database.Volumes.Size();
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CMvItem &mvItem = m_Database.Items[index];
+ const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
+ int itemIndex = mvItem.ItemIndex;
+ const CItem &item = db.Items[itemIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString unicodeName;
+ if (item.IsNameUTF())
+ ConvertUTF8ToUnicode(item.Name, unicodeName);
+ else
+ unicodeName = MultiByteToUnicodeString(item.Name, CP_ACP);
+ prop = (const wchar_t *)NItemName::WinNameToOSName(unicodeName);
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+
+ case kpidMTime:
+ {
+ FILETIME localFileTime, utcFileTime;
+ if (NTime::DosTimeToFileTime(item.Time, localFileTime))
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ }
+ else
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ prop = utcFileTime;
+ break;
+ }
+
+ case kpidMethod:
+ {
+ UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size());
+ const CFolder &folder = db.Folders[realFolderIndex];
+ int methodIndex = folder.GetCompressionMethod();
+ AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
+ if (methodIndex == NHeader::NCompressionMethodMajor::kLZX ||
+ methodIndex == NHeader::NCompressionMethodMajor::kQuantum)
+ {
+ method += ':';
+ char temp[32];
+ ConvertUInt64ToString(folder.CompressionTypeMinor, temp);
+ method += temp;
+ }
+ prop = method;
+ break;
+ }
+ case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break;
+
+ #ifdef _CAB_DETAILS
+
+ case kpidBlockReal: prop = (UInt32)item.FolderIndex; break;
+ case kpidOffset: prop = (UInt32)item.Offset; break;
+ case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break;
+
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+/*
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback;
+public:
+ STDMETHOD(SetTotal)(const UInt64 *numFiles);
+ STDMETHOD(SetCompleted)(const UInt64 *numFiles);
+ void Init(IArchiveOpenCallback *openArchiveCallback)
+ { m_OpenArchiveCallback = openArchiveCallback; }
+};
+
+STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles)
+{
+ if (m_OpenArchiveCallback)
+ return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
+{
+ if (m_OpenArchiveCallback)
+ return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
+ return S_OK;
+}
+*/
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ HRESULT res = S_FALSE;
+ CInArchive archive;
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+
+ CMyComPtr<IInStream> nextStream = inStream;
+ bool prevChecked = false;
+ UInt64 numItems = 0;
+ try
+ {
+ while (nextStream != 0)
+ {
+ CDatabaseEx db;
+ db.Stream = nextStream;
+ res = archive.Open(maxCheckStartPosition, db);
+ if (res == S_OK)
+ {
+ if (!m_Database.Volumes.IsEmpty())
+ {
+ const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0];
+ if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID ||
+ dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) !=
+ db.ArchiveInfo.CabinetNumber)
+ res = S_FALSE;
+ }
+ }
+ if (res == S_OK)
+ m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db);
+ else if (res != S_FALSE)
+ return res;
+ else
+ {
+ if (m_Database.Volumes.IsEmpty())
+ return S_FALSE;
+ if (prevChecked)
+ break;
+ prevChecked = true;
+ }
+
+ numItems += db.Items.Size();
+ RINOK(callback->SetCompleted(&numItems, NULL));
+
+ nextStream = 0;
+ for (;;)
+ {
+ const COtherArchive *otherArchive = 0;
+ if (!prevChecked)
+ {
+ const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo;
+ if (ai.IsTherePrev())
+ otherArchive = &ai.PrevArc;
+ else
+ prevChecked = true;
+ }
+ if (otherArchive == 0)
+ {
+ const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo;
+ if (ai.IsThereNext())
+ otherArchive = &ai.NextArc;
+ }
+ if (!otherArchive)
+ break;
+ const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP);
+ if (!openVolumeCallback)
+ break;
+
+ HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
+ if (result == S_OK)
+ break;
+ if (result != S_FALSE)
+ return result;
+ if (prevChecked)
+ break;
+ prevChecked = true;
+ }
+ }
+ if (res == S_OK)
+ {
+ m_Database.FillSortAndShrink();
+ if (!m_Database.Check())
+ res = S_FALSE;
+ }
+ }
+ catch(...)
+ {
+ res = S_FALSE;
+ }
+ if (res != S_OK)
+ {
+ Close();
+ return res;
+ }
+ COM_TRY_END
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ m_Database.Clear();
+ return S_OK;
+}
+
+class CFolderOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+private:
+ const CMvDatabaseEx *m_Database;
+ const CRecordVector<bool> *m_ExtractStatuses;
+
+ Byte *TempBuf;
+ UInt32 TempBufSize;
+ int NumIdenticalFiles;
+ bool TempBufMode;
+ UInt32 m_BufStartFolderOffset;
+
+ int m_StartIndex;
+ int m_CurrentIndex;
+ CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
+ bool m_TestMode;
+
+ CMyComPtr<ISequentialOutStream> m_RealOutStream;
+
+ bool m_IsOk;
+ bool m_FileIsOpen;
+ UInt32 m_RemainFileSize;
+ UInt64 m_FolderSize;
+ UInt64 m_PosInFolder;
+
+ void FreeTempBuf()
+ {
+ ::MyFree(TempBuf);
+ TempBuf = NULL;
+ }
+
+ HRESULT OpenFile();
+ HRESULT CloseFileWithResOp(Int32 resOp);
+ HRESULT CloseFile();
+ HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
+public:
+ HRESULT WriteEmptyFiles();
+
+ CFolderOutStream(): TempBuf(NULL) {}
+ ~CFolderOutStream() { FreeTempBuf(); }
+ void Init(
+ const CMvDatabaseEx *database,
+ const CRecordVector<bool> *extractStatuses,
+ int startIndex,
+ UInt64 folderSize,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode);
+ HRESULT FlushCorrupted();
+ HRESULT Unsupported();
+
+ UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; }
+ UInt64 GetPosInFolder() const { return m_PosInFolder; }
+};
+
+void CFolderOutStream::Init(
+ const CMvDatabaseEx *database,
+ const CRecordVector<bool> *extractStatuses,
+ int startIndex,
+ UInt64 folderSize,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode)
+{
+ m_Database = database;
+ m_ExtractStatuses = extractStatuses;
+ m_StartIndex = startIndex;
+ m_FolderSize = folderSize;
+
+ m_ExtractCallback = extractCallback;
+ m_TestMode = testMode;
+
+ m_CurrentIndex = 0;
+ m_PosInFolder = 0;
+ m_FileIsOpen = false;
+ m_IsOk = true;
+ TempBufMode = false;
+ NumIdenticalFiles = 0;
+}
+
+HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp)
+{
+ m_RealOutStream.Release();
+ m_FileIsOpen = false;
+ NumIdenticalFiles--;
+ return m_ExtractCallback->SetOperationResult(resOp);
+}
+
+HRESULT CFolderOutStream::CloseFile()
+{
+ return CloseFileWithResOp(m_IsOk ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError);
+}
+
+HRESULT CFolderOutStream::OpenFile()
+{
+ if (NumIdenticalFiles == 0)
+ {
+ const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
+ const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ int numExtractItems = 0;
+ int curIndex;
+ for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++)
+ {
+ const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex];
+ const CItem &item2 = m_Database->Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex];
+ if (item.Offset != item2.Offset ||
+ item.Size != item2.Size ||
+ item.Size == 0)
+ break;
+ if (!m_TestMode && (*m_ExtractStatuses)[curIndex])
+ numExtractItems++;
+ }
+ NumIdenticalFiles = (curIndex - m_CurrentIndex);
+ if (NumIdenticalFiles == 0)
+ NumIdenticalFiles = 1;
+ TempBufMode = false;
+ if (numExtractItems > 1)
+ {
+ if (!TempBuf || item.Size > TempBufSize)
+ {
+ FreeTempBuf();
+ TempBuf = (Byte *)MyAlloc(item.Size);
+ TempBufSize = item.Size;
+ if (TempBuf == NULL)
+ return E_OUTOFMEMORY;
+ }
+ TempBufMode = true;
+ m_BufStartFolderOffset = item.Offset;
+ }
+ else if (numExtractItems == 1)
+ {
+ while (NumIdenticalFiles && !(*m_ExtractStatuses)[m_CurrentIndex])
+ {
+ CMyComPtr<ISequentialOutStream> stream;
+ RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &stream, NExtract::NAskMode::kSkip));
+ if (stream)
+ return E_FAIL;
+ RINOK(m_ExtractCallback->PrepareOperation(NExtract::NAskMode::kSkip));
+ m_CurrentIndex++;
+ m_FileIsOpen = true;
+ CloseFile();
+ }
+ }
+ }
+
+ Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract) :
+ NExtract::NAskMode::kSkip;
+ RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));
+ if (!m_RealOutStream && !m_TestMode)
+ askMode = NExtract::NAskMode::kSkip;
+ return m_ExtractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CFolderOutStream::WriteEmptyFiles()
+{
+ if (m_FileIsOpen)
+ return S_OK;
+ for (; m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++)
+ {
+ const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
+ const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ UInt64 fileSize = item.Size;
+ if (fileSize != 0)
+ return S_OK;
+ HRESULT result = OpenFile();
+ m_RealOutStream.Release();
+ RINOK(result);
+ RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+}
+
+// This is Write function
+HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
+{
+ COM_TRY_BEGIN
+ UInt32 realProcessed = 0;
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (m_FileIsOpen)
+ {
+ UInt32 numBytesToWrite = MyMin(m_RemainFileSize, size);
+ HRESULT res = S_OK;
+ if (numBytesToWrite > 0)
+ {
+ if (!isOK)
+ m_IsOk = false;
+ if (m_RealOutStream)
+ {
+ UInt32 processedSizeLocal = 0;
+ res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
+ numBytesToWrite = processedSizeLocal;
+ }
+ if (TempBufMode && TempBuf)
+ memcpy(TempBuf + (m_PosInFolder - m_BufStartFolderOffset), data, numBytesToWrite);
+ }
+ realProcessed += numBytesToWrite;
+ if (processedSize != NULL)
+ *processedSize = realProcessed;
+ data = (const void *)((const Byte *)data + numBytesToWrite);
+ size -= numBytesToWrite;
+ m_RemainFileSize -= numBytesToWrite;
+ m_PosInFolder += numBytesToWrite;
+ if (res != S_OK)
+ return res;
+ if (m_RemainFileSize == 0)
+ {
+ RINOK(CloseFile());
+
+ while (NumIdenticalFiles)
+ {
+ HRESULT result = OpenFile();
+ m_FileIsOpen = true;
+ m_CurrentIndex++;
+ if (result == S_OK && m_RealOutStream && TempBuf)
+ result = WriteStream(m_RealOutStream, TempBuf, (size_t)(m_PosInFolder - m_BufStartFolderOffset));
+
+ if (!TempBuf && TempBufMode && m_RealOutStream)
+ {
+ RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnSupportedMethod));
+ }
+ else
+ {
+ RINOK(CloseFile());
+ }
+ RINOK(result);
+ }
+ TempBufMode = false;
+ }
+ if (realProcessed > 0)
+ break; // with this break this function works as Write-Part
+ }
+ else
+ {
+ if (m_CurrentIndex >= m_ExtractStatuses->Size())
+ return E_FAIL;
+
+ const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
+ const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+
+ m_RemainFileSize = item.Size;
+
+ UInt32 fileOffset = item.Offset;
+ if (fileOffset < m_PosInFolder)
+ return E_FAIL;
+ if (fileOffset > m_PosInFolder)
+ {
+ UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size);
+ realProcessed += numBytesToWrite;
+ if (processedSize != NULL)
+ *processedSize = realProcessed;
+ data = (const void *)((const Byte *)data + numBytesToWrite);
+ size -= numBytesToWrite;
+ m_PosInFolder += numBytesToWrite;
+ }
+ if (fileOffset == m_PosInFolder)
+ {
+ RINOK(OpenFile());
+ m_FileIsOpen = true;
+ m_CurrentIndex++;
+ m_IsOk = true;
+ }
+ }
+ }
+ return WriteEmptyFiles();
+ COM_TRY_END
+}
+
+STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ return Write2(data, size, processedSize, true);
+}
+
+HRESULT CFolderOutStream::FlushCorrupted()
+{
+ const UInt32 kBufferSize = (1 << 10);
+ Byte buffer[kBufferSize];
+ for (int i = 0; i < kBufferSize; i++)
+ buffer[i] = 0;
+ for (;;)
+ {
+ UInt64 remain = GetRemain();
+ if (remain == 0)
+ return S_OK;
+ UInt32 size = (UInt32)MyMin(remain, (UInt64)kBufferSize);
+ UInt32 processedSizeLocal = 0;
+ RINOK(Write2(buffer, size, &processedSizeLocal, false));
+ }
+}
+
+HRESULT CFolderOutStream::Unsupported()
+{
+ while(m_CurrentIndex < m_ExtractStatuses->Size())
+ {
+ HRESULT result = OpenFile();
+ if (result != S_FALSE && result != S_OK)
+ return result;
+ m_RealOutStream.Release();
+ RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ m_CurrentIndex++;
+ }
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = m_Database.Items.Size();
+ if(numItems == 0)
+ return S_OK;
+ bool testMode = (testModeSpec != 0);
+ UInt64 totalUnPacked = 0;
+
+ UInt32 i;
+ int lastFolder = -2;
+ UInt64 lastFolderSize = 0;
+ for(i = 0; i < numItems; i++)
+ {
+ int index = allFilesMode ? i : indices[i];
+ const CMvItem &mvItem = m_Database.Items[index];
+ const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ if (item.IsDir())
+ continue;
+ int folderIndex = m_Database.GetFolderIndex(&mvItem);
+ if (folderIndex != lastFolder)
+ totalUnPacked += lastFolderSize;
+ lastFolder = folderIndex;
+ lastFolderSize = item.GetEndOffset();
+ }
+ totalUnPacked += lastFolderSize;
+
+ extractCallback->SetTotal(totalUnPacked);
+
+ totalUnPacked = 0;
+
+ UInt64 totalPacked = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> deflateDecoder;
+
+ NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> lzxDecoder;
+
+ NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> quantumDecoder;
+
+ CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
+ CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
+ if (!cabBlockInStreamSpec->Create())
+ return E_OUTOFMEMORY;
+
+ CRecordVector<bool> extractStatuses;
+ for(i = 0; i < numItems;)
+ {
+ int index = allFilesMode ? i : indices[i];
+
+ const CMvItem &mvItem = m_Database.Items[index];
+ const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
+ int itemIndex = mvItem.ItemIndex;
+ const CItem &item = db.Items[itemIndex];
+
+ i++;
+ if (item.IsDir())
+ {
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ int folderIndex = m_Database.GetFolderIndex(&mvItem);
+ if (folderIndex < 0)
+ {
+ // If we need previous archive
+ Int32 askMode= testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ int startIndex2 = m_Database.FolderStartFileIndex[folderIndex];
+ int startIndex = startIndex2;
+ extractStatuses.Clear();
+ for (; startIndex < index; startIndex++)
+ extractStatuses.Add(false);
+ extractStatuses.Add(true);
+ startIndex++;
+ UInt64 curUnpack = item.GetEndOffset();
+ for(;i < numItems; i++)
+ {
+ int indexNext = allFilesMode ? i : indices[i];
+ const CMvItem &mvItem = m_Database.Items[indexNext];
+ const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ if (item.IsDir())
+ continue;
+ int newFolderIndex = m_Database.GetFolderIndex(&mvItem);
+
+ if (newFolderIndex != folderIndex)
+ break;
+ for (; startIndex < indexNext; startIndex++)
+ extractStatuses.Add(false);
+ extractStatuses.Add(true);
+ startIndex++;
+ curUnpack = item.GetEndOffset();
+ }
+
+ lps->OutSize = totalUnPacked;
+ lps->InSize = totalPacked;
+ RINOK(lps->SetCur());
+
+ CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);
+
+ const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())];
+
+ cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2,
+ curUnpack, extractCallback, testMode);
+
+ cabBlockInStreamSpec->MsZip = false;
+ switch(folder.GetCompressionMethod())
+ {
+ case NHeader::NCompressionMethodMajor::kNone:
+ break;
+ case NHeader::NCompressionMethodMajor::kMSZip:
+ if(deflateDecoderSpec == NULL)
+ {
+ deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
+ deflateDecoder = deflateDecoderSpec;
+ }
+ cabBlockInStreamSpec->MsZip = true;
+ break;
+ case NHeader::NCompressionMethodMajor::kLZX:
+ if(lzxDecoderSpec == NULL)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder;
+ lzxDecoder = lzxDecoderSpec;
+ }
+ RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor));
+ break;
+ case NHeader::NCompressionMethodMajor::kQuantum:
+ if(quantumDecoderSpec == NULL)
+ {
+ quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
+ quantumDecoder = quantumDecoderSpec;
+ }
+ quantumDecoderSpec->SetParams(folder.CompressionTypeMinor);
+ break;
+ default:
+ {
+ RINOK(cabFolderOutStream->Unsupported());
+ totalUnPacked += curUnpack;
+ continue;
+ }
+ }
+
+ cabBlockInStreamSpec->InitForNewFolder();
+
+ HRESULT res = S_OK;
+
+ {
+ int volIndex = mvItem.VolumeIndex;
+ int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
+ bool keepHistory = false;
+ bool keepInputBuffer = false;
+ for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;)
+ {
+ if (volIndex >= m_Database.Volumes.Size())
+ {
+ res = S_FALSE;
+ break;
+ }
+
+ const CDatabaseEx &db = m_Database.Volumes[volIndex];
+ const CFolder &folder = db.Folders[locFolderIndex];
+ if (f == 0)
+ {
+ cabBlockInStreamSpec->SetStream(db.Stream);
+ cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize();
+ RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL));
+ }
+ if (f == folder.NumDataBlocks)
+ {
+ volIndex++;
+ locFolderIndex = 0;
+ f = 0;
+ continue;
+ }
+ f++;
+
+ cabBlockInStreamSpec->DataError = false;
+
+ if (!keepInputBuffer)
+ cabBlockInStreamSpec->InitForNewBlock();
+
+ UInt32 packSize, unpackSize;
+ res = cabBlockInStreamSpec->PreRead(packSize, unpackSize);
+ if (res == S_FALSE)
+ break;
+ RINOK(res);
+ keepInputBuffer = (unpackSize == 0);
+ if (keepInputBuffer)
+ continue;
+
+ UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder();
+ totalPacked += packSize;
+
+ lps->OutSize = totalUnPacked2;
+ lps->InSize = totalPacked;
+ RINOK(lps->SetCur());
+
+ UInt64 unpackRemain = cabFolderOutStream->GetRemain();
+
+ const UInt32 kBlockSizeMax = (1 << 15);
+ if (unpackRemain > kBlockSizeMax)
+ unpackRemain = kBlockSizeMax;
+ if (unpackRemain > unpackSize)
+ unpackRemain = unpackSize;
+
+ switch(folder.GetCompressionMethod())
+ {
+ case NHeader::NCompressionMethodMajor::kNone:
+ res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
+ break;
+ case NHeader::NCompressionMethodMajor::kMSZip:
+ deflateDecoderSpec->SetKeepHistory(keepHistory);
+ res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
+ break;
+ case NHeader::NCompressionMethodMajor::kLZX:
+ lzxDecoderSpec->SetKeepHistory(keepHistory);
+ res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
+ break;
+ case NHeader::NCompressionMethodMajor::kQuantum:
+ quantumDecoderSpec->SetKeepHistory(keepHistory);
+ res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
+ break;
+ }
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ RINOK(res);
+ break;
+ }
+ keepHistory = true;
+ }
+ if (res == S_OK)
+ {
+ RINOK(cabFolderOutStream->WriteEmptyFiles());
+ }
+ }
+ if (res != S_OK || cabFolderOutStream->GetRemain() != 0)
+ {
+ RINOK(cabFolderOutStream->FlushCorrupted());
+ }
+ totalUnPacked += curUnpack;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = m_Database.Items.Size();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHandler.h
new file mode 100644
index 000000000..1edcd11e2
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHandler.h
@@ -0,0 +1,28 @@
+// CabHandler.h
+
+#ifndef __CAB_HANDLER_H
+#define __CAB_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "CabIn.h"
+
+namespace NArchive {
+namespace NCab {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+
+ INTERFACE_IInArchive(;)
+
+private:
+ CMvDatabaseEx m_Database;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHeader.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHeader.cpp
new file mode 100644
index 000000000..0cba1b0b7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHeader.cpp
@@ -0,0 +1,15 @@
+// CabHeader.cpp
+
+#include "StdAfx.h"
+
+#include "CabHeader.h"
+
+namespace NArchive {
+namespace NCab {
+namespace NHeader {
+
+Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 };
+
+// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; }; } g_SignatureInitializer;
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHeader.h b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHeader.h
new file mode 100644
index 000000000..0f0d2af35
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabHeader.h
@@ -0,0 +1,44 @@
+// Archive/Cab/Header.h
+
+#ifndef __ARCHIVE_CAB_HEADER_H
+#define __ARCHIVE_CAB_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NCab {
+namespace NHeader {
+
+const unsigned kMarkerSize = 8;
+extern Byte kMarker[kMarkerSize];
+
+namespace NArchive
+{
+ namespace NFlags
+ {
+ const int kPrevCabinet = 0x0001;
+ const int kNextCabinet = 0x0002;
+ const int kReservePresent = 0x0004;
+ }
+}
+
+namespace NCompressionMethodMajor
+{
+ const Byte kNone = 0;
+ const Byte kMSZip = 1;
+ const Byte kQuantum = 2;
+ const Byte kLZX = 3;
+}
+
+const int kFileNameIsUTFAttributeMask = 0x80;
+
+namespace NFolderIndex
+{
+ const int kContinuedFromPrev = 0xFFFD;
+ const int kContinuedToNext = 0xFFFE;
+ const int kContinuedPrevAndNext = 0xFFFF;
+}
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabIn.cpp
new file mode 100644
index 000000000..c0bffa2d2
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabIn.cpp
@@ -0,0 +1,272 @@
+// Archive/CabIn.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/FindSignature.h"
+
+#include "CabIn.h"
+
+namespace NArchive {
+namespace NCab {
+
+Byte CInArchive::Read8()
+{
+ Byte b;
+ if (!inBuffer.ReadByte(b))
+ throw CInArchiveException(CInArchiveException::kUnsupported);
+ return b;
+}
+
+UInt16 CInArchive::Read16()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = Read8();
+ value |= (UInt16(b) << (8 * i));
+ }
+ return value;
+}
+
+UInt32 CInArchive::Read32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b = Read8();
+ value |= (UInt32(b) << (8 * i));
+ }
+ return value;
+}
+
+AString CInArchive::SafeReadName()
+{
+ AString name;
+ for (;;)
+ {
+ Byte b = Read8();
+ if (b == 0)
+ return name;
+ name += (char)b;
+ }
+}
+
+void CInArchive::ReadOtherArchive(COtherArchive &oa)
+{
+ oa.FileName = SafeReadName();
+ oa.DiskName = SafeReadName();
+}
+
+void CInArchive::Skip(UInt32 size)
+{
+ while (size-- != 0)
+ Read8();
+}
+
+HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db)
+{
+ IInStream *stream = db.Stream;
+ db.Clear();
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, &db.StartPosition));
+
+ RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
+ searchHeaderSizeLimit, db.StartPosition));
+
+ RINOK(stream->Seek(db.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL));
+ if (!inBuffer.Create(1 << 17))
+ return E_OUTOFMEMORY;
+ inBuffer.SetStream(stream);
+ inBuffer.Init();
+
+ CInArchiveInfo &ai = db.ArchiveInfo;
+
+ ai.Size = Read32();
+ if (Read32() != 0)
+ return S_FALSE;
+ ai.FileHeadersOffset = Read32();
+ if (Read32() != 0)
+ return S_FALSE;
+
+ ai.VersionMinor = Read8();
+ ai.VersionMajor = Read8();
+ ai.NumFolders = Read16();
+ ai.NumFiles = Read16();
+ ai.Flags = Read16();
+ if (ai.Flags > 7)
+ return S_FALSE;
+ ai.SetID = Read16();
+ ai.CabinetNumber = Read16();
+
+ if (ai.ReserveBlockPresent())
+ {
+ ai.PerCabinetAreaSize = Read16();
+ ai.PerFolderAreaSize = Read8();
+ ai.PerDataBlockAreaSize = Read8();
+
+ Skip(ai.PerCabinetAreaSize);
+ }
+
+ {
+ if (ai.IsTherePrev())
+ ReadOtherArchive(ai.PrevArc);
+ if (ai.IsThereNext())
+ ReadOtherArchive(ai.NextArc);
+ }
+
+ int i;
+ for (i = 0; i < ai.NumFolders; i++)
+ {
+ CFolder folder;
+
+ folder.DataStart = Read32();
+ folder.NumDataBlocks = Read16();
+ folder.CompressionTypeMajor = Read8();
+ folder.CompressionTypeMinor = Read8();
+
+ Skip(ai.PerFolderAreaSize);
+ db.Folders.Add(folder);
+ }
+
+ RINOK(stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL));
+
+ inBuffer.SetStream(stream);
+ inBuffer.Init();
+ for (i = 0; i < ai.NumFiles; i++)
+ {
+ CItem item;
+ item.Size = Read32();
+ item.Offset = Read32();
+ item.FolderIndex = Read16();
+ UInt16 pureDate = Read16();
+ UInt16 pureTime = Read16();
+ item.Time = ((UInt32(pureDate) << 16)) | pureTime;
+ item.Attributes = Read16();
+ item.Name = SafeReadName();
+ int folderIndex = item.GetFolderIndex(db.Folders.Size());
+ if (folderIndex >= db.Folders.Size())
+ return S_FALSE;
+ db.Items.Add(item);
+ }
+ return S_OK;
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
+{
+ const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param;
+ const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex];
+ const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex];
+ const CItem &item1 = db1.Items[p1->ItemIndex];
+ const CItem &item2 = db2.Items[p2->ItemIndex];;
+ bool isDir1 = item1.IsDir();
+ bool isDir2 = item2.IsDir();
+ if (isDir1 && !isDir2)
+ return -1;
+ if (isDir2 && !isDir1)
+ return 1;
+ int f1 = mvDb.GetFolderIndex(p1);
+ int f2 = mvDb.GetFolderIndex(p2);
+ RINOZ(MyCompare(f1, f2));
+ RINOZ(MyCompare(item1.Offset, item2.Offset));
+ RINOZ(MyCompare(item1.Size, item2.Size));
+ RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex));
+ return MyCompare(p1->ItemIndex, p2->ItemIndex);
+}
+
+bool CMvDatabaseEx::AreItemsEqual(int i1, int i2)
+{
+ const CMvItem *p1 = &Items[i1];
+ const CMvItem *p2 = &Items[i2];
+ const CDatabaseEx &db1 = Volumes[p1->VolumeIndex];
+ const CDatabaseEx &db2 = Volumes[p2->VolumeIndex];
+ const CItem &item1 = db1.Items[p1->ItemIndex];
+ const CItem &item2 = db2.Items[p2->ItemIndex];;
+ return GetFolderIndex(p1) == GetFolderIndex(p2) &&
+ item1.Offset == item2.Offset &&
+ item1.Size == item2.Size &&
+ item1.Name == item2.Name;
+}
+
+void CMvDatabaseEx::FillSortAndShrink()
+{
+ Items.Clear();
+ StartFolderOfVol.Clear();
+ FolderStartFileIndex.Clear();
+ int offset = 0;
+ for (int v = 0; v < Volumes.Size(); v++)
+ {
+ const CDatabaseEx &db = Volumes[v];
+ int curOffset = offset;
+ if (db.IsTherePrevFolder())
+ curOffset--;
+ StartFolderOfVol.Add(curOffset);
+ offset += db.GetNumberOfNewFolders();
+
+ CMvItem mvItem;
+ mvItem.VolumeIndex = v;
+ for (int i = 0 ; i < db.Items.Size(); i++)
+ {
+ mvItem.ItemIndex = i;
+ Items.Add(mvItem);
+ }
+ }
+
+ Items.Sort(CompareMvItems, (void *)this);
+ int j = 1;
+ int i;
+ for (i = 1; i < Items.Size(); i++)
+ if (!AreItemsEqual(i, i -1))
+ Items[j++] = Items[i];
+ Items.DeleteFrom(j);
+
+ for (i = 0; i < Items.Size(); i++)
+ {
+ int folderIndex = GetFolderIndex(&Items[i]);
+ if (folderIndex >= FolderStartFileIndex.Size())
+ FolderStartFileIndex.Add(i);
+ }
+}
+
+bool CMvDatabaseEx::Check()
+{
+ for (int v = 1; v < Volumes.Size(); v++)
+ {
+ const CDatabaseEx &db1 = Volumes[v];
+ if (db1.IsTherePrevFolder())
+ {
+ const CDatabaseEx &db0 = Volumes[v - 1];
+ if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty())
+ return false;
+ const CFolder &f0 = db0.Folders.Back();
+ const CFolder &f1 = db1.Folders.Front();
+ if (f0.CompressionTypeMajor != f1.CompressionTypeMajor ||
+ f0.CompressionTypeMinor != f1.CompressionTypeMinor)
+ return false;
+ }
+ }
+ UInt32 beginPos = 0;
+ UInt64 endPos = 0;
+ int prevFolder = -2;
+ for (int i = 0; i < Items.Size(); i++)
+ {
+ const CMvItem &mvItem = Items[i];
+ int fIndex = GetFolderIndex(&mvItem);
+ if (fIndex >= FolderStartFileIndex.Size())
+ return false;
+ const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ if (item.IsDir())
+ continue;
+ int folderIndex = GetFolderIndex(&mvItem);
+ if (folderIndex != prevFolder)
+ prevFolder = folderIndex;
+ else if (item.Offset < endPos &&
+ (item.Offset != beginPos || item.GetEndOffset() != endPos))
+ return false;
+ beginPos = item.Offset;
+ endPos = item.GetEndOffset();
+ }
+ return true;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabIn.h
new file mode 100644
index 000000000..1e9b188b5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabIn.h
@@ -0,0 +1,161 @@
+// Archive/CabIn.h
+
+#ifndef __ARCHIVE_CAB_IN_H
+#define __ARCHIVE_CAB_IN_H
+
+#include "../../IStream.h"
+#include "../../Common/InBuffer.h"
+#include "CabHeader.h"
+#include "CabItem.h"
+
+namespace NArchive {
+namespace NCab {
+
+class CInArchiveException
+{
+public:
+ enum CCauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kIncorrectArchive,
+ kUnsupported
+ } Cause;
+ CInArchiveException(CCauseType cause) : Cause(cause) {}
+};
+
+struct COtherArchive
+{
+ AString FileName;
+ AString DiskName;
+};
+
+struct CArchiveInfo
+{
+ Byte VersionMinor; /* cabinet file format version, minor */
+ Byte VersionMajor; /* cabinet file format version, major */
+ UInt16 NumFolders; /* number of CFFOLDER entries in this cabinet */
+ UInt16 NumFiles; /* number of CFFILE entries in this cabinet */
+ UInt16 Flags; /* cabinet file option indicators */
+ UInt16 SetID; /* must be the same for all cabinets in a set */
+ UInt16 CabinetNumber; /* number of this cabinet file in a set */
+
+ bool ReserveBlockPresent() const { return (Flags & NHeader::NArchive::NFlags::kReservePresent) != 0; }
+
+ bool IsTherePrev() const { return (Flags & NHeader::NArchive::NFlags::kPrevCabinet) != 0; }
+ bool IsThereNext() const { return (Flags & NHeader::NArchive::NFlags::kNextCabinet) != 0; }
+
+ UInt16 PerCabinetAreaSize; // (optional) size of per-cabinet reserved area
+ Byte PerFolderAreaSize; // (optional) size of per-folder reserved area
+ Byte PerDataBlockAreaSize; // (optional) size of per-datablock reserved area
+
+ Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlockAreaSize : 0); }
+
+ COtherArchive PrevArc;
+ COtherArchive NextArc;
+
+ CArchiveInfo()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ PerCabinetAreaSize = 0;
+ PerFolderAreaSize = 0;
+ PerDataBlockAreaSize = 0;
+ }
+};
+
+struct CInArchiveInfo: public CArchiveInfo
+{
+ UInt32 Size; /* size of this cabinet file in bytes */
+ UInt32 FileHeadersOffset; // offset of the first CFFILE entry
+};
+
+
+struct CDatabase
+{
+ UInt64 StartPosition;
+ CInArchiveInfo ArchiveInfo;
+ CObjectVector<CFolder> Folders;
+ CObjectVector<CItem> Items;
+
+ void Clear()
+ {
+ ArchiveInfo.Clear();
+ Folders.Clear();
+ Items.Clear();
+ }
+ bool IsTherePrevFolder() const
+ {
+ for (int i = 0; i < Items.Size(); i++)
+ if (Items[i].ContinuedFromPrev())
+ return true;
+ return false;
+ }
+ int GetNumberOfNewFolders() const
+ {
+ int res = Folders.Size();
+ if (IsTherePrevFolder())
+ res--;
+ return res;
+ }
+ UInt32 GetFileOffset(int index) const { return Items[index].Offset; }
+ UInt32 GetFileSize(int index) const { return Items[index].Size; }
+};
+
+struct CDatabaseEx: public CDatabase
+{
+ CMyComPtr<IInStream> Stream;
+};
+
+struct CMvItem
+{
+ int VolumeIndex;
+ int ItemIndex;
+};
+
+class CMvDatabaseEx
+{
+ bool AreItemsEqual(int i1, int i2);
+public:
+ CObjectVector<CDatabaseEx> Volumes;
+ CRecordVector<CMvItem> Items;
+ CRecordVector<int> StartFolderOfVol;
+ CRecordVector<int> FolderStartFileIndex;
+
+ int GetFolderIndex(const CMvItem *mvi) const
+ {
+ const CDatabaseEx &db = Volumes[mvi->VolumeIndex];
+ return StartFolderOfVol[mvi->VolumeIndex] +
+ db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size());
+ }
+ void Clear()
+ {
+ Volumes.Clear();
+ Items.Clear();
+ StartFolderOfVol.Clear();
+ FolderStartFileIndex.Clear();
+ }
+ void FillSortAndShrink();
+ bool Check();
+};
+
+class CInArchive
+{
+ CInBuffer inBuffer;
+
+ Byte Read8();
+ UInt16 Read16();
+ UInt32 Read32();
+ AString SafeReadName();
+ void Skip(UInt32 size);
+ void ReadOtherArchive(COtherArchive &oa);
+
+public:
+ HRESULT Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabItem.h b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabItem.h
new file mode 100644
index 000000000..63a1e856c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabItem.h
@@ -0,0 +1,63 @@
+// Archive/CabItem.h
+
+#ifndef __ARCHIVE_CAB_ITEM_H
+#define __ARCHIVE_CAB_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+#include "CabHeader.h"
+
+namespace NArchive {
+namespace NCab {
+
+struct CFolder
+{
+ UInt32 DataStart; // offset of the first CFDATA block in this folder
+ UInt16 NumDataBlocks; // number of CFDATA blocks in this folder
+ Byte CompressionTypeMajor;
+ Byte CompressionTypeMinor;
+ Byte GetCompressionMethod() const { return (Byte)(CompressionTypeMajor & 0xF); }
+};
+
+struct CItem
+{
+ AString Name;
+ UInt32 Offset;
+ UInt32 Size;
+ UInt32 Time;
+ UInt16 FolderIndex;
+ UInt16 Flags;
+ UInt16 Attributes;
+
+ UInt64 GetEndOffset() const { return (UInt64)Offset + Size; }
+ UInt32 GetWinAttributes() const { return (Attributes & ~NHeader::kFileNameIsUTFAttributeMask); }
+ bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUTFAttributeMask) != 0; }
+ bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; }
+
+ bool ContinuedFromPrev() const
+ {
+ return
+ (FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev) ||
+ (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext);
+ }
+
+ bool ContinuedToNext() const
+ {
+ return
+ (FolderIndex == NHeader::NFolderIndex::kContinuedToNext) ||
+ (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext);
+ }
+
+ int GetFolderIndex(int numFolders) const
+ {
+ if (ContinuedFromPrev())
+ return 0;
+ if (ContinuedToNext())
+ return (numFolders - 1);
+ return FolderIndex;
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabRegister.cpp
new file mode 100644
index 000000000..15fe4099f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Cab/CabRegister.cpp
@@ -0,0 +1,13 @@
+// CabRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "CabHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NCab::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Cab", L"cab", 0, 8, { 0x4D, 0x53, 0x43, 0x46 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Cab)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHandler.cpp
new file mode 100644
index 000000000..a9e334b03
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHandler.cpp
@@ -0,0 +1,721 @@
+// ChmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/Defs.h"
+#include "Common/StringConvert.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/LzxDecoder.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "ChmHandler.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NChm {
+
+// #define _CHM_DETAILS
+
+#ifdef _CHM_DETAILS
+
+enum
+{
+ kpidSection = kpidUserDefined
+};
+
+#endif
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidBlock, VT_UI4}
+
+ #ifdef _CHM_DETAILS
+ ,
+ { L"Section", kpidSection, VT_UI4},
+ { NULL, kpidOffset, VT_UI4}
+ #endif
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidNumBlocks, VT_UI8}
+};
+
+IMP_IInArchive_Props
+
+IMP_IInArchive_ArcProps_NO
+/*
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidNumBlocks:
+ {
+ UInt64 numBlocks = 0;
+ for (int i = 0; i < m_Database.Sections.Size(); i++)
+ {
+ const CSectionInfo &s = m_Database.Sections[i];
+ for (int j = 0; j < s.Methods.Size(); j++)
+ {
+ const CMethodInfo &m = s.Methods[j];
+ if (m.IsLzx())
+ numBlocks += m.LzxInfo.ResetTable.GetNumBlocks();
+ }
+ }
+ prop = numBlocks;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+*/
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ if (m_Database.NewFormat)
+ {
+ switch(propID)
+ {
+ case kpidSize:
+ prop = (UInt64)m_Database.NewFormatString.Length();
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ }
+ int entryIndex;
+ if (m_Database.LowLevel)
+ entryIndex = index;
+ else
+ entryIndex = m_Database.Indices[index];
+ const CItem &item = m_Database.Items[entryIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString us;
+ if (ConvertUTF8ToUnicode(item.Name, us))
+ {
+ if (!m_Database.LowLevel)
+ {
+ if (us.Length() > 1)
+ if (us[0] == L'/')
+ us.Delete(0);
+ }
+ prop = NItemName::GetOSName2(us);
+ }
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidMethod:
+ {
+ if (!item.IsDir())
+ if (item.Section == 0)
+ prop = L"Copy";
+ else if (item.Section < m_Database.Sections.Size())
+ prop = m_Database.Sections[(int)item.Section].GetMethodName();
+ break;
+ }
+ case kpidBlock:
+ if (m_Database.LowLevel)
+ prop = item.Section;
+ else if (item.Section != 0)
+ prop = m_Database.GetFolder(index);
+ break;
+
+ #ifdef _CHM_DETAILS
+
+ case kpidSection: prop = (UInt32)item.Section; break;
+ case kpidOffset: prop = (UInt32)item.Offset; break;
+
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+public:
+ STDMETHOD(SetTotal)(const UInt64 *numFiles);
+ STDMETHOD(SetCompleted)(const UInt64 *numFiles);
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {};
+};
+
+STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ m_Stream.Release();
+ try
+ {
+ CInArchive archive;
+ // CProgressImp progressImp(openArchiveCallback);
+ RINOK(archive.Open(inStream, maxCheckStartPosition, m_Database));
+ /*
+ if (m_Database.LowLevel)
+ return S_FALSE;
+ */
+ m_Stream = inStream;
+ }
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ m_Database.Clear();
+ m_Stream.Release();
+ return S_OK;
+}
+
+class CChmFolderOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+
+ UInt64 m_FolderSize;
+ UInt64 m_PosInFolder;
+ UInt64 m_PosInSection;
+ const CRecordVector<bool> *m_ExtractStatuses;
+ int m_StartIndex;
+ int m_CurrentIndex;
+ int m_NumFiles;
+
+private:
+ const CFilesDatabase *m_Database;
+ CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
+ bool m_TestMode;
+
+ bool m_IsOk;
+ bool m_FileIsOpen;
+ UInt64 m_RemainFileSize;
+ CMyComPtr<ISequentialOutStream> m_RealOutStream;
+
+ HRESULT OpenFile();
+ HRESULT WriteEmptyFiles();
+public:
+ void Init(
+ const CFilesDatabase *database,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode);
+ HRESULT FlushCorrupted(UInt64 maxSize);
+};
+
+void CChmFolderOutStream::Init(
+ const CFilesDatabase *database,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode)
+{
+ m_Database = database;
+ m_ExtractCallback = extractCallback;
+ m_TestMode = testMode;
+
+ m_CurrentIndex = 0;
+ m_FileIsOpen = false;
+}
+
+HRESULT CChmFolderOutStream::OpenFile()
+{
+ Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract) :
+ NExtract::NAskMode::kSkip;
+ m_RealOutStream.Release();
+ RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));
+ if (!m_RealOutStream && !m_TestMode)
+ askMode = NExtract::NAskMode::kSkip;
+ return m_ExtractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CChmFolderOutStream::WriteEmptyFiles()
+{
+ if (m_FileIsOpen)
+ return S_OK;
+ for (;m_CurrentIndex < m_NumFiles; m_CurrentIndex++)
+ {
+ UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex);
+ if (fileSize != 0)
+ return S_OK;
+ HRESULT result = OpenFile();
+ m_RealOutStream.Release();
+ RINOK(result);
+ RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+}
+
+// This is WritePart function
+HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
+{
+ UInt32 realProcessed = 0;
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while(size != 0)
+ {
+ if (m_FileIsOpen)
+ {
+ UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size));
+ HRESULT res = S_OK;
+ if (numBytesToWrite > 0)
+ {
+ if (!isOK)
+ m_IsOk = false;
+ if (m_RealOutStream)
+ {
+ UInt32 processedSizeLocal = 0;
+ res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
+ numBytesToWrite = processedSizeLocal;
+ }
+ }
+ realProcessed += numBytesToWrite;
+ if (processedSize != NULL)
+ *processedSize = realProcessed;
+ data = (const void *)((const Byte *)data + numBytesToWrite);
+ size -= numBytesToWrite;
+ m_RemainFileSize -= numBytesToWrite;
+ m_PosInSection += numBytesToWrite;
+ m_PosInFolder += numBytesToWrite;
+ if (res != S_OK)
+ return res;
+ if (m_RemainFileSize == 0)
+ {
+ m_RealOutStream.Release();
+ RINOK(m_ExtractCallback->SetOperationResult(
+ m_IsOk ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ m_FileIsOpen = false;
+ }
+ if (realProcessed > 0)
+ break; // with this break this function works as write part
+ }
+ else
+ {
+ if (m_CurrentIndex >= m_NumFiles)
+ return E_FAIL;
+ int fullIndex = m_StartIndex + m_CurrentIndex;
+ m_RemainFileSize = m_Database->GetFileSize(fullIndex);
+ UInt64 fileOffset = m_Database->GetFileOffset(fullIndex);
+ if (fileOffset < m_PosInSection)
+ return E_FAIL;
+ if (fileOffset > m_PosInSection)
+ {
+ UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size));
+ realProcessed += numBytesToWrite;
+ if (processedSize != NULL)
+ *processedSize = realProcessed;
+ data = (const void *)((const Byte *)data + numBytesToWrite);
+ size -= numBytesToWrite;
+ m_PosInSection += numBytesToWrite;
+ m_PosInFolder += numBytesToWrite;
+ }
+ if (fileOffset == m_PosInSection)
+ {
+ RINOK(OpenFile());
+ m_FileIsOpen = true;
+ m_CurrentIndex++;
+ m_IsOk = true;
+ }
+ }
+ }
+ return WriteEmptyFiles();
+}
+
+STDMETHODIMP CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ return Write2(data, size, processedSize, true);
+}
+
+HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize)
+{
+ const UInt32 kBufferSize = (1 << 10);
+ Byte buffer[kBufferSize];
+ for (int i = 0; i < kBufferSize; i++)
+ buffer[i] = 0;
+ if (maxSize > m_FolderSize)
+ maxSize = m_FolderSize;
+ while (m_PosInFolder < maxSize)
+ {
+ UInt32 size = (UInt32)MyMin(maxSize - m_PosInFolder, (UInt64)kBufferSize);
+ UInt32 processedSizeLocal = 0;
+ RINOK(Write2(buffer, size, &processedSizeLocal, false));
+ if (processedSizeLocal == 0)
+ return S_OK;
+ }
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+
+ if (allFilesMode)
+ numItems = m_Database.NewFormat ? 1:
+ (m_Database.LowLevel ?
+ m_Database.Items.Size():
+ m_Database.Indices.Size());
+ if (numItems == 0)
+ return S_OK;
+ bool testMode = (testModeSpec != 0);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+ UInt32 i;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(m_Stream);
+
+ if (m_Database.LowLevel)
+ {
+ UInt64 currentItemSize = 0;
+ UInt64 totalSize = 0;
+ if (m_Database.NewFormat)
+ totalSize = m_Database.NewFormatString.Length();
+ else
+ for (i = 0; i < numItems; i++)
+ totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ currentItemSize = 0;
+ lps->InSize = currentTotalSize; // Change it
+ lps->OutSize = currentTotalSize;
+
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode= testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (m_Database.NewFormat)
+ {
+ if (index != 0)
+ return E_FAIL;
+ if (!testMode && !realOutStream)
+ continue;
+ if (!testMode)
+ {
+ UInt32 size = m_Database.NewFormatString.Length();
+ RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size));
+ }
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ const CItem &item = m_Database.Items[index];
+
+ currentItemSize = item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (item.Section != 0)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ }
+
+ UInt64 lastFolderIndex = ((UInt64)0 - 1);
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = allFilesMode ? i : indices[i];
+ int entryIndex = m_Database.Indices[index];
+ const CItem &item = m_Database.Items[entryIndex];
+ UInt64 sectionIndex = item.Section;
+ if (item.IsDir() || item.Size == 0)
+ continue;
+ if (sectionIndex == 0)
+ {
+ currentTotalSize += item.Size;
+ continue;
+ }
+ const CSectionInfo &section = m_Database.Sections[(int)item.Section];
+ if (section.IsLzx())
+ {
+ const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
+ UInt64 folderIndex = m_Database.GetFolder(index);
+ if (lastFolderIndex == folderIndex)
+ folderIndex++;
+ lastFolderIndex = m_Database.GetLastFolder(index);
+ for (; folderIndex <= lastFolderIndex; folderIndex++)
+ currentTotalSize += lzxInfo.GetFolderSize();
+ }
+ }
+
+ RINOK(extractCallback->SetTotal(currentTotalSize));
+
+ NCompress::NLzx::CDecoder *lzxDecoderSpec = 0;
+ CMyComPtr<ICompressCoder> lzxDecoder;
+ CChmFolderOutStream *chmFolderOutStream = 0;
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ currentTotalSize = 0;
+
+ CRecordVector<bool> extractStatuses;
+ for (i = 0; i < numItems;)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ UInt32 index = allFilesMode ? i : indices[i];
+ i++;
+ int entryIndex = m_Database.Indices[index];
+ const CItem &item = m_Database.Items[entryIndex];
+ UInt64 sectionIndex = item.Section;
+ Int32 askMode= testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ if (item.IsDir())
+ {
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ lps->InSize = currentTotalSize; // Change it
+ lps->OutSize = currentTotalSize;
+
+ if (item.Size == 0 || sectionIndex == 0)
+ {
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ if (!testMode && item.Size != 0)
+ {
+ RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != item.Size)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ currentTotalSize += item.Size;
+ continue;
+ }
+
+ const CSectionInfo &section = m_Database.Sections[(int)sectionIndex];
+
+ if (!section.IsLzx())
+ {
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+
+ const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
+
+ if (chmFolderOutStream == 0)
+ {
+ chmFolderOutStream = new CChmFolderOutStream;
+ outStream = chmFolderOutStream;
+ }
+
+ chmFolderOutStream->Init(&m_Database, extractCallback, testMode);
+
+ if (lzxDecoderSpec == NULL)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder;
+ lzxDecoder = lzxDecoderSpec;
+ }
+
+ UInt64 folderIndex = m_Database.GetFolder(index);
+
+ UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
+ UInt32 numDictBits = lzxInfo.GetNumDictBits();
+ RINOK(lzxDecoderSpec->SetParams(numDictBits));
+
+ const CItem *lastItem = &item;
+ extractStatuses.Clear();
+ extractStatuses.Add(true);
+
+ for (;; folderIndex++)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+
+ UInt64 startPos = lzxInfo.GetFolderPos(folderIndex);
+ UInt64 finishPos = lastItem->Offset + lastItem->Size;
+ UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos);
+
+ lastFolderIndex = m_Database.GetLastFolder(index);
+ UInt64 folderSize = lzxInfo.GetFolderSize();
+ UInt64 unPackSize = folderSize;
+ if (extractStatuses.IsEmpty())
+ chmFolderOutStream->m_StartIndex = index + 1;
+ else
+ chmFolderOutStream->m_StartIndex = index;
+ if (limitFolderIndex == folderIndex)
+ {
+ for (; i < numItems; i++)
+ {
+ UInt32 nextIndex = allFilesMode ? i : indices[i];
+ int entryIndex = m_Database.Indices[nextIndex];
+ const CItem &nextItem = m_Database.Items[entryIndex];
+ if (nextItem.Section != sectionIndex)
+ break;
+ UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex);
+ if (nextFolderIndex != folderIndex)
+ break;
+ for (index++; index < nextIndex; index++)
+ extractStatuses.Add(false);
+ extractStatuses.Add(true);
+ index = nextIndex;
+ lastItem = &nextItem;
+ if (nextItem.Size != 0)
+ finishPos = nextItem.Offset + nextItem.Size;
+ lastFolderIndex = m_Database.GetLastFolder(index);
+ }
+ }
+ unPackSize = MyMin(finishPos - startPos, unPackSize);
+
+ chmFolderOutStream->m_FolderSize = folderSize;
+ chmFolderOutStream->m_PosInFolder = 0;
+ chmFolderOutStream->m_PosInSection = startPos;
+ chmFolderOutStream->m_ExtractStatuses = &extractStatuses;
+ chmFolderOutStream->m_NumFiles = extractStatuses.Size();
+ chmFolderOutStream->m_CurrentIndex = 0;
+ try
+ {
+ UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex);
+ const CResetTable &rt = lzxInfo.ResetTable;
+ UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize);
+ for (UInt32 b = 0; b < numBlocks; b++)
+ {
+ UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos;
+ RINOK(extractCallback->SetCompleted(&completedSize));
+ UInt64 bCur = startBlock + b;
+ if (bCur >= rt.ResetOffsets.Size())
+ return E_FAIL;
+ UInt64 offset = rt.ResetOffsets[(int)bCur];
+ UInt64 compressedSize;
+ rt.GetCompressedSizeOfBlock(bCur, compressedSize);
+ UInt64 rem = finishPos - chmFolderOutStream->m_PosInSection;
+ if (rem > rt.BlockSize)
+ rem = rt.BlockSize;
+ RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL));
+ streamSpec->SetStream(m_Stream);
+ streamSpec->Init(compressedSize);
+ lzxDecoderSpec->SetKeepHistory(b > 0);
+ HRESULT res = lzxDecoder->Code(inStream, outStream, NULL, &rem, NULL);
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ throw 1;
+ }
+ }
+ }
+ catch(...)
+ {
+ RINOK(chmFolderOutStream->FlushCorrupted(unPackSize));
+ }
+ currentTotalSize += folderSize;
+ if (folderIndex == lastFolderIndex)
+ break;
+ extractStatuses.Clear();
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = m_Database.NewFormat ? 1:
+ (m_Database.LowLevel ?
+ m_Database.Items.Size():
+ m_Database.Indices.Size());
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHandler.h
new file mode 100644
index 000000000..440c50f11
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHandler.h
@@ -0,0 +1,29 @@
+// ChmHandler.h
+
+#ifndef __ARCHIVE_CHM_HANDLER_H
+#define __ARCHIVE_CHM_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "ChmIn.h"
+
+namespace NArchive {
+namespace NChm {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+
+ INTERFACE_IInArchive(;)
+
+private:
+ CFilesDatabase m_Database;
+ CMyComPtr<IInStream> m_Stream;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHeader.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHeader.cpp
new file mode 100644
index 000000000..e8dc9f3e8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHeader.cpp
@@ -0,0 +1,24 @@
+// Archive/Chm/Header.h
+
+#include "StdAfx.h"
+
+#include "ChmHeader.h"
+
+namespace NArchive{
+namespace NChm{
+namespace NHeader{
+
+UInt32 kItsfSignature = 0x46535449 + 1;
+UInt32 kItolSignature = 0x4C4F5449 + 1;
+static class CSignatureInitializer
+{
+public:
+ CSignatureInitializer()
+ {
+ kItsfSignature--;
+ kItolSignature--;
+ }
+}g_SignatureInitializer;
+
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHeader.h b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHeader.h
new file mode 100644
index 000000000..9f1bd42b6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmHeader.h
@@ -0,0 +1,28 @@
+// Archive/Chm/Header.h
+
+#ifndef __ARCHIVE_CHM_HEADER_H
+#define __ARCHIVE_CHM_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NChm {
+namespace NHeader{
+
+const UInt32 kItspSignature = 0x50535449;
+const UInt32 kPmglSignature = 0x4C474D50;
+const UInt32 kLzxcSignature = 0x43585A4C;
+
+const UInt32 kIfcmSignature = 0x4D434649;
+const UInt32 kAollSignature = 0x4C4C4F41;
+const UInt32 kCaolSignature = 0x4C4F4143;
+
+extern UInt32 kItsfSignature;
+
+extern UInt32 kItolSignature;
+const UInt32 kItlsSignature = 0x534C5449;
+UInt64 inline GetHxsSignature() { return ((UInt64)kItlsSignature << 32) | kItolSignature; }
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmIn.cpp
new file mode 100644
index 000000000..d52b9ba6c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmIn.cpp
@@ -0,0 +1,937 @@
+// Archive/ChmIn.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/UTFConvert.h"
+
+#include "../../Common/LimitedStreams.h"
+
+#include "ChmIn.h"
+
+namespace NArchive {
+namespace NChm {
+
+// define CHM_LOW, if you want to see low level items
+// #define CHM_LOW
+
+static const GUID kChmLzxGuid = { 0x7FC28940, 0x9D31, 0x11D0, { 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C } };
+static const GUID kHelp2LzxGuid = { 0x0A9007C6, 0x4076, 0x11D3, { 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 } };
+static const GUID kDesGuid = { 0x67F6E4A2, 0x60BF, 0x11D3, { 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF } };
+
+static bool AreGuidsEqual(REFGUID g1, REFGUID g2)
+{
+ if (g1.Data1 != g2.Data1 ||
+ g1.Data2 != g2.Data2 ||
+ g1.Data3 != g2.Data3)
+ return false;
+ for (int i = 0; i < 8; i++)
+ if (g1.Data4[i] != g2.Data4[i])
+ return false;
+ return true;
+}
+
+static char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+static void PrintByte(Byte b, AString &s)
+{
+ s += GetHex(b >> 4);
+ s += GetHex(b & 0xF);
+}
+
+static void PrintUInt16(UInt16 v, AString &s)
+{
+ PrintByte((Byte)(v >> 8), s);
+ PrintByte((Byte)v, s);
+}
+
+static void PrintUInt32(UInt32 v, AString &s)
+{
+ PrintUInt16((UInt16)(v >> 16), s);
+ PrintUInt16((UInt16)v, s);
+}
+
+AString CMethodInfo::GetGuidString() const
+{
+ AString s;
+ s += '{';
+ PrintUInt32(Guid.Data1, s);
+ s += '-';
+ PrintUInt16(Guid.Data2, s);
+ s += '-';
+ PrintUInt16(Guid.Data3, s);
+ s += '-';
+ PrintByte(Guid.Data4[0], s);
+ PrintByte(Guid.Data4[1], s);
+ s += '-';
+ for (int i = 2; i < 8; i++)
+ PrintByte(Guid.Data4[i], s);
+ s += '}';
+ return s;
+}
+
+bool CMethodInfo::IsLzx() const
+{
+ if (AreGuidsEqual(Guid, kChmLzxGuid))
+ return true;
+ return AreGuidsEqual(Guid, kHelp2LzxGuid);
+}
+
+bool CMethodInfo::IsDes() const
+{
+ return AreGuidsEqual(Guid, kDesGuid);
+}
+
+UString CMethodInfo::GetName() const
+{
+ UString s;
+ if (IsLzx())
+ {
+ s = L"LZX:";
+ wchar_t temp[16];
+ ConvertUInt32ToString(LzxInfo.GetNumDictBits(), temp);
+ s += temp;
+ }
+ else
+ {
+ AString s2;
+ if (IsDes())
+ s2 = "DES";
+ else
+ {
+ s2 = GetGuidString();
+ if (ControlData.GetCapacity() > 0)
+ {
+ s2 += ':';
+ for (size_t i = 0; i < ControlData.GetCapacity(); i++)
+ PrintByte(ControlData[i], s2);
+ }
+ }
+ ConvertUTF8ToUnicode(s2, s);
+ }
+ return s;
+}
+
+bool CSectionInfo::IsLzx() const
+{
+ if (Methods.Size() != 1)
+ return false;
+ return Methods[0].IsLzx();
+}
+
+UString CSectionInfo::GetMethodName() const
+{
+ UString s;
+ if (!IsLzx())
+ {
+ UString temp;
+ if (ConvertUTF8ToUnicode(Name, temp))
+ s += temp;
+ s += L": ";
+ }
+ for (int i = 0; i < Methods.Size(); i++)
+ {
+ if (i != 0)
+ s += L' ';
+ s += Methods[i].GetName();
+ }
+ return s;
+}
+
+Byte CInArchive::ReadByte()
+{
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ throw 1;
+ return b;
+}
+
+void CInArchive::Skip(size_t size)
+{
+ while (size-- != 0)
+ ReadByte();
+}
+
+void CInArchive::ReadBytes(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ data[i] = ReadByte();
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ value |= ((UInt16)(ReadByte()) << (8 * i));
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ value |= ((UInt32)(ReadByte()) << (8 * i));
+ return value;
+}
+
+UInt64 CInArchive::ReadUInt64()
+{
+ UInt64 value = 0;
+ for (int i = 0; i < 8; i++)
+ value |= ((UInt64)(ReadByte()) << (8 * i));
+ return value;
+}
+
+UInt64 CInArchive::ReadEncInt()
+{
+ UInt64 val = 0;;
+ for (int i = 0; i < 10; i++)
+ {
+ Byte b = ReadByte();
+ val |= (b & 0x7F);
+ if (b < 0x80)
+ return val;
+ val <<= 7;
+ }
+ throw 1;
+}
+
+void CInArchive::ReadGUID(GUID &g)
+{
+ g.Data1 = ReadUInt32();
+ g.Data2 = ReadUInt16();
+ g.Data3 = ReadUInt16();
+ ReadBytes(g.Data4, 8);
+}
+
+void CInArchive::ReadString(int size, AString &s)
+{
+ s.Empty();
+ while(size-- != 0)
+ {
+ char c = (char)ReadByte();
+ if (c == 0)
+ {
+ Skip(size);
+ return;
+ }
+ s += c;
+ }
+}
+
+void CInArchive::ReadUString(int size, UString &s)
+{
+ s.Empty();
+ while(size-- != 0)
+ {
+ wchar_t c = ReadUInt16();
+ if (c == 0)
+ {
+ Skip(2 * size);
+ return;
+ }
+ s += c;
+ }
+}
+
+HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size)
+{
+ RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL));
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> limitedStream(streamSpec);
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(size);
+ _inBuffer.SetStream(limitedStream);
+ _inBuffer.Init();
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadDirEntry(CDatabase &database)
+{
+ CItem item;
+ UInt64 nameLength = ReadEncInt();
+ if (nameLength == 0 || nameLength >= 0x10000000)
+ return S_FALSE;
+ ReadString((int)nameLength, item.Name);
+ item.Section = ReadEncInt();
+ item.Offset = ReadEncInt();
+ item.Size = ReadEncInt();
+ database.Items.Add(item);
+ return S_OK;
+}
+
+HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
+{
+ UInt32 headerSize = ReadUInt32();
+ if (headerSize != 0x60)
+ return S_FALSE;
+ UInt32 unknown1 = ReadUInt32();
+ if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file
+ return S_FALSE;
+ /* UInt32 timeStamp = */ ReadUInt32();
+ // Considered as a big-endian DWORD, it appears to contain seconds (MSB) and
+ // fractional seconds (second byte).
+ // The third and fourth bytes may contain even more fractional bits.
+ // The 4 least significant bits in the last byte are constant.
+ /* UInt32 lang = */ ReadUInt32();
+ GUID g;
+ ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}
+ ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}
+ const int kNumSections = 2;
+ UInt64 sectionOffsets[kNumSections];
+ UInt64 sectionSizes[kNumSections];
+ int i;
+ for (i = 0; i < kNumSections; i++)
+ {
+ sectionOffsets[i] = ReadUInt64();
+ sectionSizes[i] = ReadUInt64();
+ }
+ // if (chmVersion == 3)
+ database.ContentOffset = ReadUInt64();
+ /*
+ else
+ database.ContentOffset = _startPosition + 0x58
+ */
+
+ /*
+ // Section 0
+ ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]);
+ if (sectionSizes[0] != 0x18)
+ return S_FALSE;
+ ReadUInt32(); // unknown: 01FE
+ ReadUInt32(); // unknown: 0
+ UInt64 fileSize = ReadUInt64();
+ ReadUInt32(); // unknown: 0
+ ReadUInt32(); // unknown: 0
+ */
+
+ // Section 1: The Directory Listing
+ ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]);
+ if (ReadUInt32() != NHeader::kItspSignature)
+ return S_FALSE;
+ if (ReadUInt32() != 1) // version
+ return S_FALSE;
+ /* UInt32 dirHeaderSize = */ ReadUInt32();
+ ReadUInt32(); // 0x0A (unknown)
+ UInt32 dirChunkSize = ReadUInt32(); // $1000
+ if (dirChunkSize < 32)
+ return S_FALSE;
+ /* UInt32 density = */ ReadUInt32(); // "Density" of quickref section, usually 2.
+ /* UInt32 depth = */ ReadUInt32(); // Depth of the index tree: 1 there is no index,
+ // 2 if there is one level of PMGI chunks.
+
+ /* UInt32 chunkNumber = */ ReadUInt32(); // Chunk number of root index chunk, -1 if there is none
+ // (though at least one file has 0 despite there being no
+ // index chunk, probably a bug.)
+ /* UInt32 firstPmglChunkNumber = */ ReadUInt32(); // Chunk number of first PMGL (listing) chunk
+ /* UInt32 lastPmglChunkNumber = */ ReadUInt32(); // Chunk number of last PMGL (listing) chunk
+ ReadUInt32(); // -1 (unknown)
+ UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total)
+ /* UInt32 windowsLangId = */ ReadUInt32();
+ ReadGUID(g); // {5D02926A-212E-11D0-9DF9-00A0C922E6EC}
+ ReadUInt32(); // 0x54 (This is the length again)
+ ReadUInt32(); // -1 (unknown)
+ ReadUInt32(); // -1 (unknown)
+ ReadUInt32(); // -1 (unknown)
+
+ for (UInt32 ci = 0; ci < numDirChunks; ci++)
+ {
+ UInt64 chunkPos = _inBuffer.GetProcessedSize();
+ if (ReadUInt32() == NHeader::kPmglSignature)
+ {
+ // The quickref area is written backwards from the end of the chunk.
+ // One quickref entry exists for every n entries in the file, where n
+ // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5.
+
+ UInt32 quickrefLength = ReadUInt32(); // Length of free space and/or quickref area at end of directory chunk
+ if (quickrefLength > dirChunkSize || quickrefLength < 2)
+ return S_FALSE;
+ ReadUInt32(); // Always 0
+ ReadUInt32(); // Chunk number of previous listing chunk when reading
+ // directory in sequence (-1 if this is the first listing chunk)
+ ReadUInt32(); // Chunk number of next listing chunk when reading
+ // directory in sequence (-1 if this is the last listing chunk)
+ int numItems = 0;
+ for (;;)
+ {
+ UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
+ UInt32 offsetLimit = dirChunkSize - quickrefLength;
+ if (offset > offsetLimit)
+ return S_FALSE;
+ if (offset == offsetLimit)
+ break;
+ RINOK(ReadDirEntry(database));
+ numItems++;
+ }
+ Skip(quickrefLength - 2);
+ if (ReadUInt16() != numItems)
+ return S_FALSE;
+ }
+ else
+ Skip(dirChunkSize - 4);
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
+{
+ if (ReadUInt32() != 1) // version
+ return S_FALSE;
+ if (ReadUInt32() != 0x28) // Location of header section table
+ return S_FALSE;
+ UInt32 numHeaderSections = ReadUInt32();
+ const int kNumHeaderSectionsMax = 5;
+ if (numHeaderSections != kNumHeaderSectionsMax)
+ return S_FALSE;
+ ReadUInt32(); // Length of post-header table
+ GUID g;
+ ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754}
+
+ // header section table
+ UInt64 sectionOffsets[kNumHeaderSectionsMax];
+ UInt64 sectionSizes[kNumHeaderSectionsMax];
+ UInt32 i;
+ for (i = 0; i < numHeaderSections; i++)
+ {
+ sectionOffsets[i] = ReadUInt64();
+ sectionSizes[i] = ReadUInt64();
+ }
+
+ // Post-Header
+ ReadUInt32(); // 2
+ ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header)
+ // ----- Directory information
+ ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1
+ ReadUInt64(); // Chunk number of first AOLL chunk in directory
+ ReadUInt64(); // Chunk number of last AOLL chunk in directory
+ ReadUInt64(); // 0 (unknown)
+ ReadUInt32(); // $2000 (Directory chunk size of directory)
+ ReadUInt32(); // Quickref density for main directory, usually 2
+ ReadUInt32(); // 0 (unknown)
+ ReadUInt32(); // Depth of main directory index tree
+ // 1 there is no index, 2 if there is one level of AOLI chunks.
+ ReadUInt64(); // 0 (unknown)
+ UInt64 numDirEntries = ReadUInt64(); // Number of directory entries
+ // ----- Directory Index Information
+ ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index)
+ ReadUInt64(); // Chunk number of first AOLL chunk in directory index
+ ReadUInt64(); // Chunk number of last AOLL chunk in directory index
+ ReadUInt64(); // 0 (unknown)
+ ReadUInt32(); // $200 (Directory chunk size of directory index)
+ ReadUInt32(); // Quickref density for directory index, usually 2
+ ReadUInt32(); // 0 (unknown)
+ ReadUInt32(); // Depth of directory index index tree.
+ ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0.
+ ReadUInt64(); // Number of directory index entries (same as number of AOLL
+ // chunks in main directory)
+
+ // (The obvious guess for the following two fields, which recur in a number
+ // of places, is they are maximum sizes for the directory and directory index.
+ // However, I have seen no direct evidence that this is the case.)
+
+ ReadUInt32(); // $100000 (Same as field following chunk size in directory)
+ ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
+
+ ReadUInt64(); // 0 (unknown)
+ if (ReadUInt32() != NHeader::kCaolSignature)
+ return S_FALSE;
+ if (ReadUInt32() != 2) // (Most likely a version number)
+ return S_FALSE;
+ UInt32 caolLength = ReadUInt32(); // $50 (Length of the CAOL section, which includes the ITSF section)
+ if (caolLength >= 0x2C)
+ {
+ /* UInt32 c7 = */ ReadUInt16(); // Unknown. Remains the same when identical files are built.
+ // Does not appear to be a checksum. Many files have
+ // 'HH' (HTML Help?) here, indicating this may be a compiler ID
+ // field. But at least one ITOL/ITLS compiler does not set this
+ // field to a constant value.
+ ReadUInt16(); // 0 (Unknown. Possibly part of 00A4 field)
+ ReadUInt32(); // Unknown. Two values have been seen -- $43ED, and 0.
+ ReadUInt32(); // $2000 (Directory chunk size of directory)
+ ReadUInt32(); // $200 (Directory chunk size of directory index)
+ ReadUInt32(); // $100000 (Same as field following chunk size in directory)
+ ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
+ ReadUInt32(); // 0 (unknown)
+ ReadUInt32(); // 0 (Unknown)
+ if (caolLength == 0x2C)
+ {
+ database.ContentOffset = 0;
+ database.NewFormat = true;
+ }
+ else if (caolLength == 0x50)
+ {
+ ReadUInt32(); // 0 (Unknown)
+ if (ReadUInt32() != NHeader::kItsfSignature)
+ return S_FALSE;
+ if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3)
+ return S_FALSE;
+ if (ReadUInt32() != 0x20) // $20 (length of ITSF)
+ return S_FALSE;
+ UInt32 unknown = ReadUInt32();
+ if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases;
+ return S_FALSE;
+ database.ContentOffset = _startPosition + ReadUInt64();
+ /* UInt32 timeStamp = */ ReadUInt32();
+ // A timestamp of some sort.
+ // Considered as a big-endian DWORD, it appears to contain
+ // seconds (MSB) and fractional seconds (second byte).
+ // The third and fourth bytes may contain even more fractional
+ // bits. The 4 least significant bits in the last byte are constant.
+ /* UInt32 lang = */ ReadUInt32(); // BE?
+ }
+ else
+ return S_FALSE;
+ }
+
+ /*
+ // Section 0
+ ReadChunk(inStream, _startPosition + sectionOffsets[0], sectionSizes[0]);
+ if (sectionSizes[0] != 0x18)
+ return S_FALSE;
+ ReadUInt32(); // unknown: 01FE
+ ReadUInt32(); // unknown: 0
+ UInt64 fileSize = ReadUInt64();
+ ReadUInt32(); // unknown: 0
+ ReadUInt32(); // unknown: 0
+ */
+
+ // Section 1: The Directory Listing
+ ReadChunk(inStream, _startPosition + sectionOffsets[1], sectionSizes[1]);
+ if (ReadUInt32() != NHeader::kIfcmSignature)
+ return S_FALSE;
+ if (ReadUInt32() != 1) // (probably a version number)
+ return S_FALSE;
+ UInt32 dirChunkSize = ReadUInt32(); // $2000
+ if (dirChunkSize < 64)
+ return S_FALSE;
+ ReadUInt32(); // $100000 (unknown)
+ ReadUInt32(); // -1 (unknown)
+ ReadUInt32(); // -1 (unknown)
+ UInt32 numDirChunks = ReadUInt32();
+ ReadUInt32(); // 0 (unknown, probably high word of above)
+
+ for (UInt32 ci = 0; ci < numDirChunks; ci++)
+ {
+ UInt64 chunkPos = _inBuffer.GetProcessedSize();
+ if (ReadUInt32() == NHeader::kAollSignature)
+ {
+ UInt32 quickrefLength = ReadUInt32(); // Length of quickref area at end of directory chunk
+ if (quickrefLength > dirChunkSize || quickrefLength < 2)
+ return S_FALSE;
+ ReadUInt64(); // Directory chunk number
+ // This must match physical position in file, that is
+ // the chunk size times the chunk number must be the
+ // offset from the end of the directory header.
+ ReadUInt64(); // Chunk number of previous listing chunk when reading
+ // directory in sequence (-1 if first listing chunk)
+ ReadUInt64(); // Chunk number of next listing chunk when reading
+ // directory in sequence (-1 if last listing chunk)
+ ReadUInt64(); // Number of first listing entry in this chunk
+ ReadUInt32(); // 1 (unknown -- other values have also been seen here)
+ ReadUInt32(); // 0 (unknown)
+
+ int numItems = 0;
+ for (;;)
+ {
+ UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
+ UInt32 offsetLimit = dirChunkSize - quickrefLength;
+ if (offset > offsetLimit)
+ return S_FALSE;
+ if (offset == offsetLimit)
+ break;
+ if (database.NewFormat)
+ {
+ UInt16 nameLength = ReadUInt16();
+ if (nameLength == 0)
+ return S_FALSE;
+ UString name;
+ ReadUString((int)nameLength, name);
+ AString s;
+ ConvertUnicodeToUTF8(name, s);
+ Byte b = ReadByte();
+ s += ' ';
+ PrintByte(b, s);
+ s += ' ';
+ UInt64 len = ReadEncInt();
+ // then number of items ?
+ // then length ?
+ // then some data (binary encoding?)
+ while (len-- != 0)
+ {
+ b = ReadByte();
+ PrintByte(b, s);
+ }
+ database.NewFormatString += s;
+ database.NewFormatString += "\r\n";
+ }
+ else
+ {
+ RINOK(ReadDirEntry(database));
+ }
+ numItems++;
+ }
+ Skip(quickrefLength - 2);
+ if (ReadUInt16() != numItems)
+ return S_FALSE;
+ if (numItems > numDirEntries)
+ return S_FALSE;
+ numDirEntries -= numItems;
+ }
+ else
+ Skip(dirChunkSize - 4);
+ }
+ return numDirEntries == 0 ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name)
+{
+ int index = database.FindItem(name);
+ if (index < 0)
+ return S_FALSE;
+ const CItem &item = database.Items[index];
+ _chunkSize = item.Size;
+ return ReadChunk(inStream, database.ContentOffset + item.Offset, item.Size);
+}
+
+
+#define DATA_SPACE "::DataSpace/"
+static const char *kNameList = DATA_SPACE "NameList";
+static const char *kStorage = DATA_SPACE "Storage/";
+static const char *kContent = "Content";
+static const char *kControlData = "ControlData";
+static const char *kSpanInfo = "SpanInfo";
+static const char *kTransform = "Transform/";
+static const char *kResetTable = "/InstanceData/ResetTable";
+static const char *kTransformList = "List";
+
+static AString GetSectionPrefix(const AString &name)
+{
+ return AString(kStorage) + name + AString("/");
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareFiles(const int *p1, const int *p2, void *param)
+{
+ const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
+ const CItem &item1 = items[*p1];
+ const CItem &item2 = items[*p2];
+ bool isDir1 = item1.IsDir();
+ bool isDir2 = item2.IsDir();
+ if (isDir1 && !isDir2)
+ return -1;
+ if (isDir2)
+ {
+ if (isDir1)
+ return MyCompare(*p1, *p2);
+ return 1;
+ }
+ RINOZ(MyCompare(item1.Section, item2.Section));
+ RINOZ(MyCompare(item1.Offset, item2.Offset));
+ RINOZ(MyCompare(item1.Size, item2.Size));
+ return MyCompare(*p1, *p2);
+}
+
+void CFilesDatabase::SetIndices()
+{
+ for (int i = 0; i < Items.Size(); i++)
+ {
+ const CItem &item = Items[i];
+ if (item.IsUserItem() && item.Name.Length() != 1)
+ Indices.Add(i);
+ }
+}
+
+void CFilesDatabase::Sort()
+{
+ Indices.Sort(CompareFiles, (void *)&Items);
+}
+
+bool CFilesDatabase::Check()
+{
+ UInt64 maxPos = 0;
+ UInt64 prevSection = 0;
+ for(int i = 0; i < Indices.Size(); i++)
+ {
+ const CItem &item = Items[Indices[i]];
+ if (item.Section == 0 || item.IsDir())
+ continue;
+ if (item.Section != prevSection)
+ {
+ prevSection = item.Section;
+ maxPos = 0;
+ continue;
+ }
+ if (item.Offset < maxPos)
+ return false;
+ maxPos = item.Offset + item.Size;
+ if (maxPos < item.Offset)
+ return false;
+ }
+ return true;
+}
+
+HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
+{
+ {
+ // The NameList file
+ RINOK(DecompressStream(inStream, database, kNameList));
+ /* UInt16 length = */ ReadUInt16();
+ UInt16 numSections = ReadUInt16();
+ for (int i = 0; i < numSections; i++)
+ {
+ CSectionInfo section;
+ UInt16 nameLength = ReadUInt16();
+ UString name;
+ ReadUString(nameLength, name);
+ if (ReadUInt16() != 0)
+ return S_FALSE;
+ if (!ConvertUnicodeToUTF8(name, section.Name))
+ return S_FALSE;
+ database.Sections.Add(section);
+ }
+ }
+
+ int i;
+ for (i = 1; i < database.Sections.Size(); i++)
+ {
+ CSectionInfo &section = database.Sections[i];
+ AString sectionPrefix = GetSectionPrefix(section.Name);
+ {
+ // Content
+ int index = database.FindItem(sectionPrefix + kContent);
+ if (index < 0)
+ return S_FALSE;
+ const CItem &item = database.Items[index];
+ section.Offset = item.Offset;
+ section.CompressedSize = item.Size;
+ }
+ AString transformPrefix = sectionPrefix + kTransform;
+ if (database.Help2Format)
+ {
+ // Transform List
+ RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList));
+ if ((_chunkSize & 0xF) != 0)
+ return S_FALSE;
+ int numGuids = (int)(_chunkSize / 0x10);
+ if (numGuids < 1)
+ return S_FALSE;
+ for (int i = 0; i < numGuids; i++)
+ {
+ CMethodInfo method;
+ ReadGUID(method.Guid);
+ section.Methods.Add(method);
+ }
+ }
+ else
+ {
+ CMethodInfo method;
+ method.Guid = kChmLzxGuid;
+ section.Methods.Add(method);
+ }
+
+ {
+ // Control Data
+ RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData));
+ for (int mi = 0; mi < section.Methods.Size(); mi++)
+ {
+ CMethodInfo &method = section.Methods[mi];
+ UInt32 numDWORDS = ReadUInt32();
+ if (method.IsLzx())
+ {
+ if (numDWORDS < 5)
+ return S_FALSE;
+ if (ReadUInt32() != NHeader::kLzxcSignature)
+ return S_FALSE;
+ CLzxInfo &li = method.LzxInfo;
+ li.Version = ReadUInt32();
+ if (li.Version != 2 && li.Version != 3)
+ return S_FALSE;
+ li.ResetInterval = ReadUInt32();
+ li.WindowSize = ReadUInt32();
+ li.CacheSize = ReadUInt32();
+ if (
+ li.ResetInterval != 1 &&
+ li.ResetInterval != 2 &&
+ li.ResetInterval != 4 &&
+ li.ResetInterval != 8 &&
+ li.ResetInterval != 16 &&
+ li.ResetInterval != 32 &&
+ li.ResetInterval != 64)
+ return S_FALSE;
+ if (
+ li.WindowSize != 1 &&
+ li.WindowSize != 2 &&
+ li.WindowSize != 4 &&
+ li.WindowSize != 8 &&
+ li.WindowSize != 16 &&
+ li.WindowSize != 32 &&
+ li.WindowSize != 64)
+ return S_FALSE;
+ numDWORDS -= 5;
+ while (numDWORDS-- != 0)
+ ReadUInt32();
+ }
+ else
+ {
+ UInt32 numBytes = numDWORDS * 4;
+ method.ControlData.SetCapacity(numBytes);
+ ReadBytes(method.ControlData, numBytes);
+ }
+ }
+ }
+
+ {
+ // SpanInfo
+ RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo));
+ section.UncompressedSize = ReadUInt64();
+ }
+
+ // read ResetTable for LZX
+ for (int mi = 0; mi < section.Methods.Size(); mi++)
+ {
+ CMethodInfo &method = section.Methods[mi];
+ if (method.IsLzx())
+ {
+ // ResetTable;
+ RINOK(DecompressStream(inStream, database, transformPrefix +
+ method.GetGuidString() + kResetTable));
+ CResetTable &rt = method.LzxInfo.ResetTable;
+ if (_chunkSize < 4)
+ {
+ if (_chunkSize != 0)
+ return S_FALSE;
+ // ResetTable is empty in .chw files
+ if (section.UncompressedSize != 0)
+ return S_FALSE;
+ rt.UncompressedSize = 0;
+ rt.CompressedSize = 0;
+ rt.BlockSize = 0;
+ }
+ else
+ {
+ UInt32 ver = ReadUInt32(); // 2 unknown (possibly a version number)
+ if (ver != 2 && ver != 3)
+ return S_FALSE;
+ UInt32 numEntries = ReadUInt32();
+ if (ReadUInt32() != 8) // Size of table entry (bytes)
+ return S_FALSE;
+ if (ReadUInt32() != 0x28) // Length of table header
+ return S_FALSE;
+ rt.UncompressedSize = ReadUInt64();
+ rt.CompressedSize = ReadUInt64();
+ rt.BlockSize = ReadUInt64(); // 0x8000 block size for locations below
+ if (rt.BlockSize != 0x8000)
+ return S_FALSE;
+ rt.ResetOffsets.Reserve(numEntries);
+ for (UInt32 i = 0; i < numEntries; i++)
+ rt.ResetOffsets.Add(ReadUInt64());
+ }
+ }
+ }
+ }
+
+ database.SetIndices();
+ database.Sort();
+ return database.Check() ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::Open2(IInStream *inStream,
+ const UInt64 *searchHeaderSizeLimit,
+ CFilesDatabase &database)
+{
+ database.Clear();
+
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+
+ database.Help2Format = false;
+ const UInt32 chmVersion = 3;
+ {
+ if (!_inBuffer.Create(1 << 14))
+ return E_OUTOFMEMORY;
+ _inBuffer.SetStream(inStream);
+ _inBuffer.Init();
+ UInt64 value = 0;
+ const int kSignatureSize = 8;
+ UInt64 hxsSignature = NHeader::GetHxsSignature();
+ UInt64 chmSignature = ((UInt64)chmVersion << 32)| NHeader::kItsfSignature;
+ UInt64 limit = 1 << 18;
+ if (searchHeaderSizeLimit)
+ if (limit > *searchHeaderSizeLimit)
+ limit = *searchHeaderSizeLimit;
+
+ for (;;)
+ {
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ return S_FALSE;
+ value >>= 8;
+ value |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
+ if (_inBuffer.GetProcessedSize() >= kSignatureSize)
+ {
+ if (value == chmSignature)
+ break;
+ if (value == hxsSignature)
+ {
+ database.Help2Format = true;
+ break;
+ }
+ if (_inBuffer.GetProcessedSize() > limit)
+ return S_FALSE;
+ }
+ }
+ _startPosition += _inBuffer.GetProcessedSize() - kSignatureSize;
+ }
+
+ if (database.Help2Format)
+ {
+ RINOK(OpenHelp2(inStream, database));
+ if (database.NewFormat)
+ return S_OK;
+ }
+ else
+ {
+ RINOK(OpenChm(inStream, database));
+ }
+
+ #ifndef CHM_LOW
+ try
+ {
+ HRESULT res = OpenHighLevel(inStream, database);
+ if (res == S_FALSE)
+ {
+ database.HighLevelClear();
+ return S_OK;
+ }
+ RINOK(res);
+ database.LowLevel = false;
+ }
+ catch(...)
+ {
+ return S_OK;
+ }
+ #endif
+ return S_OK;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream,
+ const UInt64 *searchHeaderSizeLimit,
+ CFilesDatabase &database)
+{
+ try
+ {
+ HRESULT res = Open2(inStream, searchHeaderSizeLimit, database);
+ _inBuffer.ReleaseStream();
+ return res;
+ }
+ catch(...)
+ {
+ _inBuffer.ReleaseStream();
+ throw;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmIn.h
new file mode 100644
index 000000000..4719a484d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmIn.h
@@ -0,0 +1,244 @@
+// Archive/ChmIn.h
+
+#ifndef __ARCHIVE_CHM_IN_H
+#define __ARCHIVE_CHM_IN_H
+
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+
+#include "../../IStream.h"
+#include "../../Common/InBuffer.h"
+
+#include "ChmHeader.h"
+
+namespace NArchive {
+namespace NChm {
+
+struct CItem
+{
+ UInt64 Section;
+ UInt64 Offset;
+ UInt64 Size;
+ AString Name;
+
+ bool IsFormatRelatedItem() const
+ {
+ if (Name.Length() < 2)
+ return false;
+ return Name[0] == ':' && Name[1] == ':';
+ }
+
+ bool IsUserItem() const
+ {
+ if (Name.Length() < 2)
+ return false;
+ return Name[0] == '/';
+ }
+
+ bool IsDir() const
+ {
+ if (Name.Length() == 0)
+ return false;
+ return (Name[Name.Length() - 1] == '/');
+ }
+};
+
+struct CDatabase
+{
+ UInt64 ContentOffset;
+ CObjectVector<CItem> Items;
+ AString NewFormatString;
+ bool Help2Format;
+ bool NewFormat;
+
+ int FindItem(const AString &name) const
+ {
+ for (int i = 0; i < Items.Size(); i++)
+ if (Items[i].Name == name)
+ return i;
+ return -1;
+ }
+
+ void Clear()
+ {
+ NewFormat = false;
+ NewFormatString.Empty();
+ Help2Format = false;
+ Items.Clear();
+ }
+};
+
+struct CResetTable
+{
+ UInt64 UncompressedSize;
+ UInt64 CompressedSize;
+ UInt64 BlockSize;
+ CRecordVector<UInt64> ResetOffsets;
+ bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
+ {
+ if (blockIndex >= ResetOffsets.Size())
+ return false;
+ UInt64 startPos = ResetOffsets[(int)blockIndex];
+ if (blockIndex + numBlocks >= ResetOffsets.Size())
+ size = CompressedSize - startPos;
+ else
+ size = ResetOffsets[(int)(blockIndex + numBlocks)] - startPos;
+ return true;
+ }
+ bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const
+ {
+ return GetCompressedSizeOfBlocks(blockIndex, 1, size);
+ }
+ UInt64 GetNumBlocks(UInt64 size) const
+ {
+ return (size + BlockSize - 1) / BlockSize;
+ }
+};
+
+struct CLzxInfo
+{
+ UInt32 Version;
+ UInt32 ResetInterval;
+ UInt32 WindowSize;
+ UInt32 CacheSize;
+ CResetTable ResetTable;
+
+ UInt32 GetNumDictBits() const
+ {
+ if (Version == 2 || Version == 3)
+ {
+ for (int i = 0; i <= 31; i++)
+ if (((UInt32)1 << i) >= WindowSize)
+ return 15 + i;
+ }
+ return 0;
+ }
+
+ UInt64 GetFolderSize() const { return ResetTable.BlockSize * ResetInterval; };
+ UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); };
+ UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); };
+ UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex * ResetInterval; };
+ bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const
+ {
+ UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
+ if (blockIndex >= ResetTable.ResetOffsets.Size())
+ return false;
+ offset = ResetTable.ResetOffsets[(int)blockIndex];
+ return true;
+ }
+ bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const
+ {
+ UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
+ return ResetTable.GetCompressedSizeOfBlocks(blockIndex, ResetInterval, size);
+ }
+};
+
+struct CMethodInfo
+{
+ GUID Guid;
+ CByteBuffer ControlData;
+ CLzxInfo LzxInfo;
+ bool IsLzx() const;
+ bool IsDes() const;
+ AString GetGuidString() const;
+ UString GetName() const;
+};
+
+struct CSectionInfo
+{
+ UInt64 Offset;
+ UInt64 CompressedSize;
+ UInt64 UncompressedSize;
+
+ AString Name;
+ CObjectVector<CMethodInfo> Methods;
+
+ bool IsLzx() const;
+ UString GetMethodName() const;
+};
+
+class CFilesDatabase: public CDatabase
+{
+public:
+ bool LowLevel;
+ CRecordVector<int> Indices;
+ CObjectVector<CSectionInfo> Sections;
+
+ UInt64 GetFileSize(int fileIndex) const { return Items[Indices[fileIndex]].Size; }
+ UInt64 GetFileOffset(int fileIndex) const { return Items[Indices[fileIndex]].Offset; }
+
+ UInt64 GetFolder(int fileIndex) const
+ {
+ const CItem &item = Items[Indices[fileIndex]];
+ const CSectionInfo &section = Sections[(int)item.Section];
+ if (section.IsLzx())
+ return section.Methods[0].LzxInfo.GetFolder(item.Offset);
+ return 0;
+ }
+
+ UInt64 GetLastFolder(int fileIndex) const
+ {
+ const CItem &item = Items[Indices[fileIndex]];
+ const CSectionInfo &section = Sections[(int)item.Section];
+ if (section.IsLzx())
+ return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1);
+ return 0;
+ }
+
+ void HighLevelClear()
+ {
+ LowLevel = true;
+ Indices.Clear();
+ Sections.Clear();
+ }
+
+ void Clear()
+ {
+ CDatabase::Clear();
+ HighLevelClear();
+ }
+ void SetIndices();
+ void Sort();
+ bool Check();
+};
+
+class CProgressVirt
+{
+public:
+ STDMETHOD(SetTotal)(const UInt64 *numFiles) PURE;
+ STDMETHOD(SetCompleted)(const UInt64 *numFiles) PURE;
+};
+
+class CInArchive
+{
+ UInt64 _startPosition;
+ ::CInBuffer _inBuffer;
+ UInt64 _chunkSize;
+
+ Byte ReadByte();
+ void ReadBytes(Byte *data, UInt32 size);
+ void Skip(size_t size);
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ UInt64 ReadEncInt();
+ void ReadString(int size, AString &s);
+ void ReadUString(int size, UString &s);
+ void ReadGUID(GUID &g);
+
+ HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size);
+
+ HRESULT ReadDirEntry(CDatabase &database);
+ HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name);
+
+public:
+ HRESULT OpenChm(IInStream *inStream, CDatabase &database);
+ HRESULT OpenHelp2(IInStream *inStream, CDatabase &database);
+ HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database);
+ HRESULT Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database);
+ HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmRegister.cpp
new file mode 100644
index 000000000..e5f38afa4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Chm/ChmRegister.cpp
@@ -0,0 +1,13 @@
+// ChmRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "ChmHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NChm::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Chm", L"chm chi chq chw hxs hxi hxr hxq hxw lit", 0, 0xE9, { 'I', 'T', 'S', 'F' }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Chm)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComHandler.cpp
new file mode 100644
index 000000000..58f76439f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComHandler.cpp
@@ -0,0 +1,239 @@
+// ComHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "ComHandler.h"
+
+namespace NArchive {
+namespace NCom {
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidSectorSize, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
+ case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break;
+ case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CRef &ref = _db.Refs[index];
+ const CItem &item = _db.Items[ref.Did];
+
+ switch(propID)
+ {
+ case kpidPath: prop = _db.GetItemPath(index); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidCTime: prop = item.CTime; break;
+ case kpidMTime: prop = item.MTime; break;
+ case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
+ case kpidSize: if (!item.IsDir()) prop = item.Size; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ if (_db.Open(inStream) != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _db.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _db.Refs.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for(i = 0; i < numItems; i++)
+ {
+ const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _db.Items[_db.Refs[index].Did];
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ totalPackSize += _db.GetItemPackSize(item.Size);
+ totalSize += item.Size;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ Int32 res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(index, &inStream);
+ if (hres == S_FALSE)
+ res = NExtract::NOperationResult::kDataError;
+ else if (hres == E_NOTIMPL)
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize == item.Size)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.Refs.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ const CItem &item = _db.Items[_db.Refs[index].Did];
+ CClusterInStream *streamSpec = new CClusterInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Stream = _stream;
+ streamSpec->StartOffset = 0;
+
+ bool isLargeStream = _db.IsLargeStream(item.Size);
+ int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
+ streamSpec->BlockSizeLog = bsLog;
+ streamSpec->Size = item.Size;
+
+ UInt32 clusterSize = (UInt32)1 << bsLog;
+ UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
+ if (numClusters64 >= ((UInt32)1 << 31))
+ return E_NOTIMPL;
+ streamSpec->Vector.Reserve((int)numClusters64);
+ UInt32 sid = item.Sid;
+ UInt64 size = item.Size;
+
+ if (size != 0)
+ {
+ for (;; size -= clusterSize)
+ {
+ if (isLargeStream)
+ {
+ if (sid >= _db.FatSize)
+ return S_FALSE;
+ streamSpec->Vector.Add(sid + 1);
+ sid = _db.Fat[sid];
+ }
+ else
+ {
+ UInt64 val;
+ if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
+ return S_FALSE;
+ streamSpec->Vector.Add((UInt32)val);
+ sid = _db.Mat[sid];
+ }
+ if (size <= clusterSize)
+ break;
+ }
+ }
+ if (sid != NFatID::kEndOfChain)
+ return S_FALSE;
+ RINOK(streamSpec->InitAndSeek());
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComHandler.h
new file mode 100644
index 000000000..f2b7de96d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComHandler.h
@@ -0,0 +1,28 @@
+// ComHandler.h
+
+#ifndef __ARCHIVE_COM_HANDLER_H
+#define __ARCHIVE_COM_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "ComIn.h"
+
+namespace NArchive {
+namespace NCom {
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CDatabase _db;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComIn.cpp
new file mode 100644
index 000000000..2203ca531
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComIn.cpp
@@ -0,0 +1,389 @@
+// Archive/ComIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "ComIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive{
+namespace NCom{
+
+static const UInt32 kSignatureSize = 8;
+static const Byte kSignature[kSignatureSize] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
+
+void CUInt32Buf::Free()
+{
+ MyFree(_buf);
+ _buf = 0;
+}
+
+bool CUInt32Buf::Allocate(UInt32 numItems)
+{
+ Free();
+ if (numItems == 0)
+ return true;
+ size_t newSize = (size_t)numItems * sizeof(UInt32);
+ if (newSize / sizeof(UInt32) != numItems)
+ return false;
+ _buf = (UInt32 *)MyAlloc(newSize);
+ return (_buf != 0);
+}
+
+static HRESULT ReadSector(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid)
+{
+ RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(inStream, buf, (UInt32)1 << sectorSizeBits);
+}
+
+static HRESULT ReadIDs(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid, UInt32 *dest)
+{
+ RINOK(ReadSector(inStream, buf, sectorSizeBits, sid));
+ UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
+ for (UInt32 t = 0; t < sectorSize; t += 4)
+ *dest++ = Get32(buf + t);
+ return S_OK;
+}
+
+static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
+{
+ ft->dwLowDateTime = Get32(p);
+ ft->dwHighDateTime = Get32(p + 4);
+}
+
+void CItem::Parse(const Byte *p, bool mode64bit)
+{
+ memcpy(Name, p, kNameSizeMax);
+ // NameSize = Get16(p + 64);
+ Type = p[66];
+ LeftDid = Get32(p + 68);
+ RightDid = Get32(p + 72);
+ SonDid = Get32(p + 76);
+ // Flags = Get32(p + 96);
+ GetFileTimeFromMem(p + 100, &CTime);
+ GetFileTimeFromMem(p + 108, &MTime);
+ Sid = Get32(p + 116);
+ Size = Get32(p + 120);
+ if (mode64bit)
+ Size |= ((UInt64)Get32(p + 124) << 32);
+}
+
+void CDatabase::Clear()
+{
+ Fat.Free();
+ MiniSids.Free();
+ Mat.Free();
+ Items.Clear();
+ Refs.Clear();
+}
+
+static const UInt32 kNoDid = 0xFFFFFFFF;
+
+HRESULT CDatabase::AddNode(int parent, UInt32 did)
+{
+ if (did == kNoDid)
+ return S_OK;
+ if (did >= (UInt32)Items.Size())
+ return S_FALSE;
+ const CItem &item = Items[did];
+ if (item.IsEmpty())
+ return S_FALSE;
+ CRef ref;
+ ref.Parent = parent;
+ ref.Did = did;
+ int index = Refs.Add(ref);
+ if (Refs.Size() > Items.Size())
+ return S_FALSE;
+ RINOK(AddNode(parent, item.LeftDid));
+ RINOK(AddNode(parent, item.RightDid));
+ if (item.IsDir())
+ {
+ RINOK(AddNode(index, item.SonDid));
+ }
+ return S_OK;
+}
+
+static const char kCharOpenBracket = '[';
+static const char kCharCloseBracket = ']';
+
+static UString CompoundNameToFileName(const UString &s)
+{
+ UString res;
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ if (c < 0x20)
+ {
+ res += kCharOpenBracket;
+ wchar_t buf[32];
+ ConvertUInt32ToString(c, buf);
+ res += buf;
+ res += kCharCloseBracket;
+ }
+ else
+ res += c;
+ }
+ return res;
+}
+
+static char g_MsiChars[] =
+"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._";
+
+static const wchar_t *kMsi_ID = L""; // L"{msi}";
+
+static const int kMsiNumBits = 6;
+static const UInt32 kMsiNumChars = 1 << kMsiNumBits;
+static const UInt32 kMsiCharMask = kMsiNumChars - 1;
+static const UInt32 kMsiStartUnicodeChar = 0x3800;
+static const UInt32 kMsiUnicodeRange = kMsiNumChars * (kMsiNumChars + 1);
+
+bool CompoundMsiNameToFileName(const UString &name, UString &resultName)
+{
+ resultName.Empty();
+ for (int i = 0; i < name.Length(); i++)
+ {
+ wchar_t c = name[i];
+ if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange)
+ return false;
+ if (i == 0)
+ resultName += kMsi_ID;
+ c -= kMsiStartUnicodeChar;
+
+ UInt32 c0 = c & kMsiCharMask;
+ UInt32 c1 = c >> kMsiNumBits;
+
+ if (c1 <= kMsiNumChars)
+ {
+ resultName += (wchar_t)g_MsiChars[c0];
+ if (c1 == kMsiNumChars)
+ break;
+ resultName += (wchar_t)g_MsiChars[c1];
+ }
+ else
+ resultName += L'!';
+ }
+ return true;
+}
+
+static UString ConvertName(const Byte *p, bool &isMsi)
+{
+ isMsi = false;
+ UString s;
+ for (int i = 0; i < kNameSizeMax; i += 2)
+ {
+ wchar_t c = (p[i] | (wchar_t)p[i + 1] << 8);
+ if (c == 0)
+ break;
+ s += c;
+ }
+ UString msiName;
+ if (CompoundMsiNameToFileName(s, msiName))
+ {
+ isMsi = true;
+ return msiName;
+ }
+ return CompoundNameToFileName(s);
+}
+
+static UString ConvertName(const Byte *p)
+{
+ bool isMsi;
+ return ConvertName(p, isMsi);
+}
+
+UString CDatabase::GetItemPath(UInt32 index) const
+{
+ UString s;
+ while (index != kNoDid)
+ {
+ const CRef &ref = Refs[index];
+ const CItem &item = Items[ref.Did];
+ if (!s.IsEmpty())
+ s = (UString)WCHAR_PATH_SEPARATOR + s;
+ s = ConvertName(item.Name) + s;
+ index = ref.Parent;
+ }
+ return s;
+}
+
+HRESULT CDatabase::Open(IInStream *inStream)
+{
+ MainSubfile = -1;
+ static const UInt32 kHeaderSize = 512;
+ Byte p[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, p, kHeaderSize));
+ if (memcmp(p, kSignature, kSignatureSize) != 0)
+ return S_FALSE;
+ if (Get16(p + 0x1A) > 4) // majorVer
+ return S_FALSE;
+ if (Get16(p + 0x1C) != 0xFFFE)
+ return S_FALSE;
+ int sectorSizeBits = Get16(p + 0x1E);
+ bool mode64bit = (sectorSizeBits >= 12);
+ int miniSectorSizeBits = Get16(p + 0x20);
+ SectorSizeBits = sectorSizeBits;
+ MiniSectorSizeBits = miniSectorSizeBits;
+
+ if (sectorSizeBits > 28 || miniSectorSizeBits > 28 ||
+ sectorSizeBits < 7 || miniSectorSizeBits < 2 || miniSectorSizeBits > sectorSizeBits)
+ return S_FALSE;
+ UInt32 numSectorsForFAT = Get32(p + 0x2C);
+ LongStreamMinSize = Get32(p + 0x38);
+
+ UInt32 sectSize = (UInt32)1 << (int)sectorSizeBits;
+
+ CByteBuffer sect;
+ sect.SetCapacity(sectSize);
+
+ int ssb2 = (int)(sectorSizeBits - 2);
+ UInt32 numSidsInSec = (UInt32)1 << ssb2;
+ UInt32 numFatItems = numSectorsForFAT << ssb2;
+ if ((numFatItems >> ssb2) != numSectorsForFAT)
+ return S_FALSE;
+ FatSize = numFatItems;
+
+ {
+ CUInt32Buf bat;
+ UInt32 numSectorsForBat = Get32(p + 0x48);
+ const UInt32 kNumHeaderBatItems = 109;
+ UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2);
+ if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat)
+ return S_FALSE;
+ if (!bat.Allocate(numBatItems))
+ return S_FALSE;
+ UInt32 i;
+ for (i = 0; i < kNumHeaderBatItems; i++)
+ bat[i] = Get32(p + 0x4c + i * 4);
+ UInt32 sid = Get32(p + 0x44);
+ for (UInt32 s = 0; s < numSectorsForBat; s++)
+ {
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i));
+ i += numSidsInSec - 1;
+ sid = bat[i];
+ }
+ numBatItems = i;
+
+ if (!Fat.Allocate(numFatItems))
+ return S_FALSE;
+ UInt32 j = 0;
+
+ for (i = 0; i < numFatItems; j++, i += numSidsInSec)
+ {
+ if (j >= numBatItems)
+ return S_FALSE;
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i));
+ }
+ }
+
+ UInt32 numMatItems;
+ {
+ UInt32 numSectorsForMat = Get32(p + 0x40);
+ numMatItems = (UInt32)numSectorsForMat << ssb2;
+ if ((numMatItems >> ssb2) != numSectorsForMat)
+ return S_FALSE;
+ if (!Mat.Allocate(numMatItems))
+ return S_FALSE;
+ UInt32 i;
+ UInt32 sid = Get32(p + 0x3C);
+ for (i = 0; i < numMatItems; i += numSidsInSec)
+ {
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i));
+ if (sid >= numFatItems)
+ return S_FALSE;
+ sid = Fat[sid];
+ }
+ if (sid != NFatID::kEndOfChain)
+ return S_FALSE;
+ }
+
+ {
+ UInt32 sid = Get32(p + 0x30);
+ for (;;)
+ {
+ if (sid >= numFatItems)
+ return S_FALSE;
+ RINOK(ReadSector(inStream, sect, sectorSizeBits, sid));
+ for (UInt32 i = 0; i < sectSize; i += 128)
+ {
+ CItem item;
+ item.Parse(sect + i, mode64bit);
+ Items.Add(item);
+ }
+ sid = Fat[sid];
+ if (sid == NFatID::kEndOfChain)
+ break;
+ }
+ }
+
+ CItem root = Items[0];
+
+ {
+ UInt32 numSectorsInMiniStream;
+ {
+ UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits;
+ if (numSatSects64 > NFatID::kMaxValue)
+ return S_FALSE;
+ numSectorsInMiniStream = (UInt32)numSatSects64;
+ }
+ NumSectorsInMiniStream = numSectorsInMiniStream;
+ if (!MiniSids.Allocate(numSectorsInMiniStream))
+ return S_FALSE;
+ {
+ UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits;
+ if (matSize64 > NFatID::kMaxValue)
+ return S_FALSE;
+ MatSize = (UInt32)matSize64;
+ if (numMatItems < MatSize)
+ return S_FALSE;
+ }
+
+ UInt32 sid = root.Sid;
+ for (UInt32 i = 0; ; i++)
+ {
+ if (sid == NFatID::kEndOfChain)
+ {
+ if (i != numSectorsInMiniStream)
+ return S_FALSE;
+ break;
+ }
+ if (i >= numSectorsInMiniStream)
+ return S_FALSE;
+ MiniSids[i] = sid;
+ if (sid >= numFatItems)
+ return S_FALSE;
+ sid = Fat[sid];
+ }
+ }
+
+ RINOK(AddNode(-1, root.SonDid));
+
+ unsigned numCabs = 0;
+ for (int i = 0; i < Refs.Size(); i++)
+ {
+ const CItem &item = Items[Refs[i].Did];
+ if (item.IsDir() || numCabs > 1)
+ continue;
+ bool isMsiName;
+ UString msiName = ConvertName(item.Name, isMsiName);
+ if (isMsiName && msiName.Right(4).CompareNoCase(L".cab") == 0)
+ {
+ numCabs++;
+ MainSubfile = i;
+ }
+ }
+ if (numCabs > 1)
+ MainSubfile = -1;
+
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComIn.h
new file mode 100644
index 000000000..429d3796e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComIn.h
@@ -0,0 +1,119 @@
+// Archive/ComIn.h
+
+#ifndef __ARCHIVE_COM_IN_H
+#define __ARCHIVE_COM_IN_H
+
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+
+namespace NArchive {
+namespace NCom {
+
+struct CUInt32Buf
+{
+ UInt32 *_buf;
+public:
+ CUInt32Buf(): _buf(0) {}
+ ~CUInt32Buf() { Free(); }
+ void Free();
+ bool Allocate(UInt32 numItems);
+ operator UInt32 *() const { return _buf; };
+};
+
+namespace NFatID
+{
+ const UInt32 kFree = 0xFFFFFFFF;
+ const UInt32 kEndOfChain = 0xFFFFFFFE;
+ const UInt32 kFatSector = 0xFFFFFFFD;
+ const UInt32 kMatSector = 0xFFFFFFFC;
+ const UInt32 kMaxValue = 0xFFFFFFFA;
+}
+
+namespace NItemType
+{
+ const Byte kEmpty = 0;
+ const Byte kStorage = 1;
+ const Byte kStream = 2;
+ const Byte kLockBytes = 3;
+ const Byte kProperty = 4;
+ const Byte kRootStorage = 5;
+}
+
+const UInt32 kNameSizeMax = 64;
+
+struct CItem
+{
+ Byte Name[kNameSizeMax];
+ // UInt16 NameSize;
+ // UInt32 Flags;
+ FILETIME CTime;
+ FILETIME MTime;
+ UInt64 Size;
+ UInt32 LeftDid;
+ UInt32 RightDid;
+ UInt32 SonDid;
+ UInt32 Sid;
+ Byte Type;
+
+ bool IsEmpty() const { return Type == NItemType::kEmpty; }
+ bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; }
+
+ void Parse(const Byte *p, bool mode64bit);
+};
+
+struct CRef
+{
+ int Parent;
+ UInt32 Did;
+};
+
+class CDatabase
+{
+ UInt32 NumSectorsInMiniStream;
+ CUInt32Buf MiniSids;
+
+ HRESULT AddNode(int parent, UInt32 did);
+public:
+
+ CUInt32Buf Fat;
+ UInt32 FatSize;
+
+ CUInt32Buf Mat;
+ UInt32 MatSize;
+
+ CObjectVector<CItem> Items;
+ CRecordVector<CRef> Refs;
+
+ UInt32 LongStreamMinSize;
+ int SectorSizeBits;
+ int MiniSectorSizeBits;
+
+ Int32 MainSubfile;
+
+ void Clear();
+ bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; }
+ UString GetItemPath(UInt32 index) const;
+
+ UInt64 GetItemPackSize(UInt64 size) const
+ {
+ UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
+ return (size + mask) & ~mask;
+ }
+
+ bool GetMiniCluster(UInt32 sid, UInt64 &res) const
+ {
+ int subBits = SectorSizeBits - MiniSectorSizeBits;
+ UInt32 fid = sid >> subBits;
+ if (fid >= NumSectorsInMiniStream)
+ return false;
+ res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
+ return true;
+ }
+
+ HRESULT Open(IInStream *inStream);
+};
+
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComRegister.cpp
new file mode 100644
index 000000000..6712b890f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Com/ComRegister.cpp
@@ -0,0 +1,13 @@
+// ComRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "ComHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NCom::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Compound", L"msi msp doc xls ppt", 0, 0xE5, { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, 8, false, CreateArc, 0 };
+
+REGISTER_ARC(Com)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.cpp
new file mode 100644
index 000000000..0b06a489f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.cpp
@@ -0,0 +1,121 @@
+// CoderMixer2.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2.h"
+
+namespace NCoderMixer {
+
+CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo):
+ _srcBindInfo(srcBindInfo)
+{
+ srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams);
+
+ UInt32 j;
+ for (j = 0; j < NumSrcInStreams; j++)
+ {
+ _srcInToDestOutMap.Add(0);
+ DestOutToSrcInMap.Add(0);
+ }
+ for (j = 0; j < _numSrcOutStreams; j++)
+ {
+ _srcOutToDestInMap.Add(0);
+ _destInToSrcOutMap.Add(0);
+ }
+
+ UInt32 destInOffset = 0;
+ UInt32 destOutOffset = 0;
+ UInt32 srcInOffset = NumSrcInStreams;
+ UInt32 srcOutOffset = _numSrcOutStreams;
+
+ for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+ {
+ const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i];
+
+ srcInOffset -= srcCoderInfo.NumInStreams;
+ srcOutOffset -= srcCoderInfo.NumOutStreams;
+
+ UInt32 j;
+ for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++)
+ {
+ UInt32 index = srcInOffset + j;
+ _srcInToDestOutMap[index] = destOutOffset;
+ DestOutToSrcInMap[destOutOffset] = index;
+ }
+ for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++)
+ {
+ UInt32 index = srcOutOffset + j;
+ _srcOutToDestInMap[index] = destInOffset;
+ _destInToSrcOutMap[destInOffset] = index;
+ }
+ }
+}
+
+void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo)
+{
+ destBindInfo.Coders.Clear();
+ destBindInfo.BindPairs.Clear();
+ destBindInfo.InStreams.Clear();
+ destBindInfo.OutStreams.Clear();
+
+ int i;
+ for (i = _srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+ {
+ const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i];
+ CCoderStreamsInfo destCoderInfo;
+ destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams;
+ destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams;
+ destBindInfo.Coders.Add(destCoderInfo);
+ }
+ for (i = _srcBindInfo.BindPairs.Size() - 1; i >= 0; i--)
+ {
+ const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i];
+ CBindPair destBindPair;
+ destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex];
+ destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex];
+ destBindInfo.BindPairs.Add(destBindPair);
+ }
+ for (i = 0; i < _srcBindInfo.InStreams.Size(); i++)
+ destBindInfo.OutStreams.Add(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]);
+ for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++)
+ destBindInfo.InStreams.Add(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]);
+}
+
+CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams):
+ NumInStreams(numInStreams),
+ NumOutStreams(numOutStreams)
+{
+ InSizes.Reserve(NumInStreams);
+ InSizePointers.Reserve(NumInStreams);
+ OutSizes.Reserve(NumOutStreams);
+ OutSizePointers.Reserve(NumOutStreams);
+}
+
+static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
+ CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
+{
+ sizes.Clear();
+ sizePointers.Clear();
+ for(UInt32 i = 0; i < numItems; i++)
+ {
+ if (srcSizes == 0 || srcSizes[i] == NULL)
+ {
+ sizes.Add(0);
+ sizePointers.Add(NULL);
+ }
+ else
+ {
+ sizes.Add(*srcSizes[i]);
+ sizePointers.Add(&sizes.Back());
+ }
+ }
+}
+
+void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes,
+ const UInt64 **outSizes)
+{
+ SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+ SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.h
new file mode 100644
index 000000000..a03722d61
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2.h
@@ -0,0 +1,174 @@
+// CoderMixer2.h
+
+#ifndef __CODER_MIXER2_H
+#define __CODER_MIXER2_H
+
+#include "../../../Common/MyVector.h"
+#include "../../../Common/Types.h"
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+
+namespace NCoderMixer {
+
+struct CBindPair
+{
+ UInt32 InIndex;
+ UInt32 OutIndex;
+};
+
+struct CCoderStreamsInfo
+{
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+};
+
+struct CBindInfo
+{
+ CRecordVector<CCoderStreamsInfo> Coders;
+ CRecordVector<CBindPair> BindPairs;
+ CRecordVector<UInt32> InStreams;
+ CRecordVector<UInt32> OutStreams;
+
+ void Clear()
+ {
+ Coders.Clear();
+ BindPairs.Clear();
+ InStreams.Clear();
+ OutStreams.Clear();
+ }
+
+ /*
+ UInt32 GetCoderStartOutStream(UInt32 coderIndex) const
+ {
+ UInt32 numOutStreams = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ numOutStreams += Coders[i].NumOutStreams;
+ return numOutStreams;
+ }
+ */
+
+
+ void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const
+ {
+ numInStreams = 0;
+ numOutStreams = 0;
+ for (int i = 0; i < Coders.Size(); i++)
+ {
+ const CCoderStreamsInfo &coderStreamsInfo = Coders[i];
+ numInStreams += coderStreamsInfo.NumInStreams;
+ numOutStreams += coderStreamsInfo.NumOutStreams;
+ }
+ }
+
+ int FindBinderForInStream(UInt32 inStream) const
+ {
+ for (int i = 0; i < BindPairs.Size(); i++)
+ if (BindPairs[i].InIndex == inStream)
+ return i;
+ return -1;
+ }
+ int FindBinderForOutStream(UInt32 outStream) const
+ {
+ for (int i = 0; i < BindPairs.Size(); i++)
+ if (BindPairs[i].OutIndex == outStream)
+ return i;
+ return -1;
+ }
+
+ UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const
+ {
+ UInt32 streamIndex = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ streamIndex += Coders[i].NumInStreams;
+ return streamIndex;
+ }
+
+ UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const
+ {
+ UInt32 streamIndex = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ streamIndex += Coders[i].NumOutStreams;
+ return streamIndex;
+ }
+
+
+ void FindInStream(UInt32 streamIndex, UInt32 &coderIndex,
+ UInt32 &coderStreamIndex) const
+ {
+ for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++)
+ {
+ UInt32 curSize = Coders[coderIndex].NumInStreams;
+ if (streamIndex < curSize)
+ {
+ coderStreamIndex = streamIndex;
+ return;
+ }
+ streamIndex -= curSize;
+ }
+ throw 1;
+ }
+ void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex,
+ UInt32 &coderStreamIndex) const
+ {
+ for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++)
+ {
+ UInt32 curSize = Coders[coderIndex].NumOutStreams;
+ if (streamIndex < curSize)
+ {
+ coderStreamIndex = streamIndex;
+ return;
+ }
+ streamIndex -= curSize;
+ }
+ throw 1;
+ }
+};
+
+class CBindReverseConverter
+{
+ UInt32 _numSrcOutStreams;
+ NCoderMixer::CBindInfo _srcBindInfo;
+ CRecordVector<UInt32> _srcInToDestOutMap;
+ CRecordVector<UInt32> _srcOutToDestInMap;
+ CRecordVector<UInt32> _destInToSrcOutMap;
+public:
+ UInt32 NumSrcInStreams;
+ CRecordVector<UInt32> DestOutToSrcInMap;
+
+ CBindReverseConverter(const NCoderMixer::CBindInfo &srcBindInfo);
+ void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo);
+};
+
+struct CCoderInfo2
+{
+ CMyComPtr<ICompressCoder> Coder;
+ CMyComPtr<ICompressCoder2> Coder2;
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+
+ CRecordVector<UInt64> InSizes;
+ CRecordVector<UInt64> OutSizes;
+ CRecordVector<const UInt64 *> InSizePointers;
+ CRecordVector<const UInt64 *> OutSizePointers;
+
+ CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams);
+ void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+
+ HRESULT QueryInterface(REFGUID iid, void** pp) const
+ {
+ IUnknown *p = Coder ? (IUnknown *)Coder : (IUnknown *)Coder2;
+ return p->QueryInterface(iid, pp);
+ }
+};
+
+class CCoderMixer2
+{
+public:
+ virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) = 0;
+ virtual void ReInit() = 0;
+ virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0;
+};
+
+}
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
new file mode 100644
index 000000000..d76450bd1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
@@ -0,0 +1,240 @@
+// CoderMixer2MT.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2MT.h"
+
+namespace NCoderMixer {
+
+CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams):
+ CCoderInfo2(numInStreams, numOutStreams)
+{
+ InStreams.Reserve(NumInStreams);
+ InStreamPointers.Reserve(NumInStreams);
+ OutStreams.Reserve(NumOutStreams);
+ OutStreamPointers.Reserve(NumOutStreams);
+}
+
+void CCoder2::Execute() { Code(NULL); }
+
+void CCoder2::Code(ICompressProgressInfo *progress)
+{
+ InStreamPointers.Clear();
+ OutStreamPointers.Clear();
+ UInt32 i;
+ for (i = 0; i < NumInStreams; i++)
+ {
+ if (InSizePointers[i] != NULL)
+ InSizePointers[i] = &InSizes[i];
+ InStreamPointers.Add((ISequentialInStream *)InStreams[i]);
+ }
+ for (i = 0; i < NumOutStreams; i++)
+ {
+ if (OutSizePointers[i] != NULL)
+ OutSizePointers[i] = &OutSizes[i];
+ OutStreamPointers.Add((ISequentialOutStream *)OutStreams[i]);
+ }
+ if (Coder)
+ Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0],
+ InSizePointers[0], OutSizePointers[0], progress);
+ else
+ Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams,
+ &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress);
+ {
+ int i;
+ for (i = 0; i < InStreams.Size(); i++)
+ InStreams[i].Release();
+ for (i = 0; i < OutStreams.Size(); i++)
+ OutStreams[i].Release();
+ }
+}
+
+static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
+ CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
+{
+ sizes.Clear();
+ sizePointers.Clear();
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ if (srcSizes == 0 || srcSizes[i] == NULL)
+ {
+ sizes.Add(0);
+ sizePointers.Add(NULL);
+ }
+ else
+ {
+ sizes.Add(*srcSizes[i]);
+ sizePointers.Add(&sizes.Back());
+ }
+ }
+}
+
+
+void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes)
+{
+ SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+ SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+
+//////////////////////////////////////
+// CCoderMixer2MT
+
+HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo)
+{
+ _bindInfo = bindInfo;
+ _streamBinders.Clear();
+ for (int i = 0; i < _bindInfo.BindPairs.Size(); i++)
+ {
+ _streamBinders.Add(CStreamBinder());
+ RINOK(_streamBinders.Back().CreateEvents());
+ }
+ return S_OK;
+}
+
+void CCoderMixer2MT::AddCoderCommon()
+{
+ const CCoderStreamsInfo &c = _bindInfo.Coders[_coders.Size()];
+ CCoder2 threadCoderInfo(c.NumInStreams, c.NumOutStreams);
+ _coders.Add(threadCoderInfo);
+}
+
+void CCoderMixer2MT::AddCoder(ICompressCoder *coder)
+{
+ AddCoderCommon();
+ _coders.Back().Coder = coder;
+}
+
+void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder)
+{
+ AddCoderCommon();
+ _coders.Back().Coder2 = coder;
+}
+
+
+void CCoderMixer2MT::ReInit()
+{
+ for (int i = 0; i < _streamBinders.Size(); i++)
+ _streamBinders[i].ReInit();
+}
+
+
+HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams)
+{
+ /*
+ if (_coders.Size() != _bindInfo.Coders.Size())
+ throw 0;
+ */
+ int i;
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ CCoder2 &coderInfo = _coders[i];
+ const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i];
+ coderInfo.InStreams.Clear();
+ UInt32 j;
+ for (j = 0; j < coderStreamsInfo.NumInStreams; j++)
+ coderInfo.InStreams.Add(NULL);
+ coderInfo.OutStreams.Clear();
+ for (j = 0; j < coderStreamsInfo.NumOutStreams; j++)
+ coderInfo.OutStreams.Add(NULL);
+ }
+
+ for (i = 0; i < _bindInfo.BindPairs.Size(); i++)
+ {
+ const CBindPair &bindPair = _bindInfo.BindPairs[i];
+ UInt32 inCoderIndex, inCoderStreamIndex;
+ UInt32 outCoderIndex, outCoderStreamIndex;
+ _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex);
+ _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex);
+
+ _streamBinders[i].CreateStreams(
+ &_coders[inCoderIndex].InStreams[inCoderStreamIndex],
+ &_coders[outCoderIndex].OutStreams[outCoderStreamIndex]);
+
+ CMyComPtr<ICompressSetBufSize> inSetSize, outSetSize;
+ _coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize);
+ _coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize);
+ if (inSetSize && outSetSize)
+ {
+ const UInt32 kBufSize = 1 << 19;
+ inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize);
+ outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize);
+ }
+ }
+
+ for (i = 0; i < _bindInfo.InStreams.Size(); i++)
+ {
+ UInt32 inCoderIndex, inCoderStreamIndex;
+ _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex);
+ _coders[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i];
+ }
+
+ for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ UInt32 outCoderIndex, outCoderStreamIndex;
+ _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex);
+ _coders[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i];
+ }
+ return S_OK;
+}
+
+HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code)
+{
+ for (int i = 0; i < _coders.Size(); i++)
+ if (_coders[i].Result == code)
+ return code;
+ return S_OK;
+}
+
+STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams,
+ const UInt64 ** /* inSizes */,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 ** /* outSizes */,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != (UInt32)_bindInfo.InStreams.Size() ||
+ numOutStreams != (UInt32)_bindInfo.OutStreams.Size())
+ return E_INVALIDARG;
+
+ Init(inStreams, outStreams);
+
+ int i;
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ {
+ RINOK(_coders[i].Create());
+ }
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ _coders[i].Start();
+
+ _coders[_progressCoderIndex].Code(progress);
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ _coders[i].WaitFinish();
+
+ RINOK(ReturnIfError(E_ABORT));
+ RINOK(ReturnIfError(E_OUTOFMEMORY));
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ HRESULT result = _coders[i].Result;
+ if (result != S_OK && result != E_FAIL && result != S_FALSE)
+ return result;
+ }
+
+ RINOK(ReturnIfError(S_FALSE));
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ HRESULT result = _coders[i].Result;
+ if (result != S_OK)
+ return result;
+ }
+ return S_OK;
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.h
new file mode 100644
index 000000000..d1c7f4d07
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2MT.h
@@ -0,0 +1,80 @@
+// CoderMixer2MT.h
+
+#ifndef __CODER_MIXER2_MT_H
+#define __CODER_MIXER2_MT_H
+
+#include "CoderMixer2.h"
+#include "../../../Common/MyCom.h"
+#include "../../Common/StreamBinder.h"
+#include "../../Common/VirtThread.h"
+
+namespace NCoderMixer {
+
+struct CCoder2: public CCoderInfo2, public CVirtThread
+{
+ HRESULT Result;
+ CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
+ CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
+ CRecordVector<ISequentialInStream*> InStreamPointers;
+ CRecordVector<ISequentialOutStream*> OutStreamPointers;
+
+ CCoder2(UInt32 numInStreams, UInt32 numOutStreams);
+ void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+ virtual void Execute();
+ void Code(ICompressProgressInfo *progress);
+};
+
+
+/*
+ SetBindInfo()
+ for each coder
+ AddCoder[2]()
+ SetProgressIndex(UInt32 coderIndex);
+
+ for each file
+ {
+ ReInit()
+ for each coder
+ SetCoderInfo
+ Code
+ }
+*/
+
+class CCoderMixer2MT:
+ public ICompressCoder2,
+ public CCoderMixer2,
+ public CMyUnknownImp
+{
+ CBindInfo _bindInfo;
+ CObjectVector<CStreamBinder> _streamBinders;
+ int _progressCoderIndex;
+
+ void AddCoderCommon();
+ HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams);
+ HRESULT ReturnIfError(HRESULT code);
+public:
+ CObjectVector<CCoder2> _coders;
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Code)(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ HRESULT SetBindInfo(const CBindInfo &bindInfo);
+ void AddCoder(ICompressCoder *coder);
+ void AddCoder2(ICompressCoder2 *coder);
+ void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; }
+
+ void ReInit();
+ void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes)
+ { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); }
+ UInt64 GetWriteProcessedSize(UInt32 binderIndex) const
+ { return _streamBinders[binderIndex].ProcessedSize; }
+};
+
+}
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2ST.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2ST.cpp
new file mode 100644
index 000000000..a59ce5fc0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2ST.cpp
@@ -0,0 +1,239 @@
+// CoderMixer2ST.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2ST.h"
+
+namespace NCoderMixer2 {
+
+CCoderMixer2ST::CCoderMixer2ST() {}
+
+CCoderMixer2ST::~CCoderMixer2ST(){ }
+
+HRESULT CCoderMixer2ST::SetBindInfo(const CBindInfo &bindInfo)
+{
+ _bindInfo = bindInfo;
+ return S_OK;
+}
+
+void CCoderMixer2ST::AddCoderCommon(bool isMain)
+{
+ const CCoderStreamsInfo &csi = _bindInfo.Coders[_coders.Size()];
+ _coders.Add(CSTCoderInfo(csi.NumInStreams, csi.NumOutStreams, isMain));
+}
+
+void CCoderMixer2ST::AddCoder(ICompressCoder *coder, bool isMain)
+{
+ AddCoderCommon(isMain);
+ _coders.Back().Coder = coder;
+}
+
+void CCoderMixer2ST::AddCoder2(ICompressCoder2 *coder, bool isMain)
+{
+ AddCoderCommon(isMain);
+ _coders.Back().Coder2 = coder;
+}
+
+void CCoderMixer2ST::ReInit() { }
+
+HRESULT CCoderMixer2ST::GetInStream(
+ ISequentialInStream **inStreams, const UInt64 **inSizes,
+ UInt32 streamIndex, ISequentialInStream **inStreamRes)
+{
+ CMyComPtr<ISequentialInStream> seqInStream;
+ int i;
+ for(i = 0; i < _bindInfo.InStreams.Size(); i++)
+ if (_bindInfo.InStreams[i] == streamIndex)
+ {
+ seqInStream = inStreams[i];
+ *inStreamRes = seqInStream.Detach();
+ return S_OK;
+ }
+ int binderIndex = _bindInfo.FindBinderForInStream(streamIndex);
+ if (binderIndex < 0)
+ return E_INVALIDARG;
+
+ UInt32 coderIndex, coderStreamIndex;
+ _bindInfo.FindOutStream(_bindInfo.BindPairs[binderIndex].OutIndex,
+ coderIndex, coderStreamIndex);
+
+ CCoderInfo &coder = _coders[coderIndex];
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ coder.Coder.QueryInterface(IID_ISequentialInStream, &seqInStream);
+ if (!seqInStream)
+ return E_NOTIMPL;
+
+ UInt32 startIndex = _bindInfo.GetCoderInStreamIndex(coderIndex);
+
+ CMyComPtr<ICompressSetInStream> setInStream;
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ coder.Coder.QueryInterface(IID_ICompressSetInStream, &setInStream);
+ if (!setInStream)
+ return E_NOTIMPL;
+
+ if (coder.NumInStreams > 1)
+ return E_NOTIMPL;
+ for (i = 0; i < (int)coder.NumInStreams; i++)
+ {
+ CMyComPtr<ISequentialInStream> seqInStream2;
+ RINOK(GetInStream(inStreams, inSizes, startIndex + i, &seqInStream2));
+ RINOK(setInStream->SetInStream(seqInStream2));
+ }
+ *inStreamRes = seqInStream.Detach();
+ return S_OK;
+}
+
+HRESULT CCoderMixer2ST::GetOutStream(
+ ISequentialOutStream **outStreams, const UInt64 **outSizes,
+ UInt32 streamIndex, ISequentialOutStream **outStreamRes)
+{
+ CMyComPtr<ISequentialOutStream> seqOutStream;
+ int i;
+ for(i = 0; i < _bindInfo.OutStreams.Size(); i++)
+ if (_bindInfo.OutStreams[i] == streamIndex)
+ {
+ seqOutStream = outStreams[i];
+ *outStreamRes = seqOutStream.Detach();
+ return S_OK;
+ }
+ int binderIndex = _bindInfo.FindBinderForOutStream(streamIndex);
+ if (binderIndex < 0)
+ return E_INVALIDARG;
+
+ UInt32 coderIndex, coderStreamIndex;
+ _bindInfo.FindInStream(_bindInfo.BindPairs[binderIndex].InIndex,
+ coderIndex, coderStreamIndex);
+
+ CCoderInfo &coder = _coders[coderIndex];
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ coder.Coder.QueryInterface(IID_ISequentialOutStream, &seqOutStream);
+ if (!seqOutStream)
+ return E_NOTIMPL;
+
+ UInt32 startIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
+
+ CMyComPtr<ICompressSetOutStream> setOutStream;
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
+ if (!setOutStream)
+ return E_NOTIMPL;
+
+ if (coder.NumOutStreams > 1)
+ return E_NOTIMPL;
+ for (i = 0; i < (int)coder.NumOutStreams; i++)
+ {
+ CMyComPtr<ISequentialOutStream> seqOutStream2;
+ RINOK(GetOutStream(outStreams, outSizes, startIndex + i, &seqOutStream2));
+ RINOK(setOutStream->SetOutStream(seqOutStream2));
+ }
+ *outStreamRes = seqOutStream.Detach();
+ return S_OK;
+}
+
+
+STDMETHODIMP CCoderMixer2ST::Code(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != (UInt32)_bindInfo.InStreams.Size() ||
+ numOutStreams != (UInt32)_bindInfo.OutStreams.Size())
+ return E_INVALIDARG;
+
+ // Find main coder
+ int _mainCoderIndex = -1;
+ int i;
+ for (i = 0; i < _coders.Size(); i++)
+ if (_coders[i].IsMain)
+ {
+ _mainCoderIndex = i;
+ break;
+ }
+ if (_mainCoderIndex < 0)
+ for (i = 0; i < _coders.Size(); i++)
+ if (_coders[i].NumInStreams > 1)
+ {
+ if (_mainCoderIndex >= 0)
+ return E_NOTIMPL;
+ _mainCoderIndex = i;
+ }
+ if (_mainCoderIndex < 0)
+ _mainCoderIndex = 0;
+
+ // _mainCoderIndex = 0;
+ // _mainCoderIndex = _coders.Size() - 1;
+ CCoderInfo &mainCoder = _coders[_mainCoderIndex];
+
+ CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams;
+ CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams;
+ UInt32 startInIndex = _bindInfo.GetCoderInStreamIndex(_mainCoderIndex);
+ UInt32 startOutIndex = _bindInfo.GetCoderOutStreamIndex(_mainCoderIndex);
+ for (i = 0; i < (int)mainCoder.NumInStreams; i++)
+ {
+ CMyComPtr<ISequentialInStream> seqInStream;
+ RINOK(GetInStream(inStreams, inSizes, startInIndex + i, &seqInStream));
+ seqInStreams.Add(seqInStream);
+ }
+ for (i = 0; i < (int)mainCoder.NumOutStreams; i++)
+ {
+ CMyComPtr<ISequentialOutStream> seqOutStream;
+ RINOK(GetOutStream(outStreams, outSizes, startOutIndex + i, &seqOutStream));
+ seqOutStreams.Add(seqOutStream);
+ }
+ CRecordVector< ISequentialInStream * > seqInStreamsSpec;
+ CRecordVector< ISequentialOutStream * > seqOutStreamsSpec;
+ for (i = 0; i < (int)mainCoder.NumInStreams; i++)
+ seqInStreamsSpec.Add(seqInStreams[i]);
+ for (i = 0; i < (int)mainCoder.NumOutStreams; i++)
+ seqOutStreamsSpec.Add(seqOutStreams[i]);
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ if (i == _mainCoderIndex)
+ continue;
+ CCoderInfo &coder = _coders[i];
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ coder.Coder.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
+ if (setOutStreamSize)
+ {
+ RINOK(setOutStreamSize->SetOutStreamSize(coder.OutSizePointers[0]));
+ }
+ }
+ if (mainCoder.Coder)
+ {
+ RINOK(mainCoder.Coder->Code(
+ seqInStreamsSpec[0], seqOutStreamsSpec[0],
+ mainCoder.InSizePointers[0], mainCoder.OutSizePointers[0],
+ progress));
+ }
+ else
+ {
+ RINOK(mainCoder.Coder2->Code(
+ &seqInStreamsSpec.Front(),
+ &mainCoder.InSizePointers.Front(), mainCoder.NumInStreams,
+ &seqOutStreamsSpec.Front(),
+ &mainCoder.OutSizePointers.Front(), mainCoder.NumOutStreams,
+ progress));
+ }
+ CMyComPtr<IOutStreamFlush> flush;
+ seqOutStreams.Front().QueryInterface(IID_IOutStreamFlush, &flush);
+ if (flush)
+ return flush->Flush();
+ return S_OK;
+}
+
+/*
+UInt64 CCoderMixer2ST::GetWriteProcessedSize(UInt32 binderIndex) const
+{
+ return _streamBinders[binderIndex].ProcessedSize;
+}
+*/
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2ST.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2ST.h
new file mode 100644
index 000000000..a4ea7e80d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CoderMixer2ST.h
@@ -0,0 +1,88 @@
+// CoderMixer2ST.h
+
+#ifndef __CODER_MIXER2_ST_H
+#define __CODER_MIXER2_ST_H
+
+#include "CoderMixer2.h"
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+
+namespace NCoderMixer2 {
+
+// SetBindInfo()
+// for each coder
+// {
+// AddCoder[2]()
+// }
+//
+// for each file
+// {
+// ReInit()
+// for each coder
+// {
+// SetCoderInfo
+// }
+// SetProgressIndex(UInt32 coderIndex);
+// Code
+// }
+
+struct CSTCoderInfo: public CCoderInfo
+{
+ bool IsMain;
+ CSTCoderInfo(UInt32 numInStreams, UInt32 numOutStreams, bool isMain):
+ CCoderInfo(numInStreams, numOutStreams),IsMain(isMain) {}
+};
+
+class CCoderMixer2ST:
+ public ICompressCoder2,
+ public CCoderMixer2,
+ public CMyUnknownImp
+{
+ MY_UNKNOWN_IMP
+
+ HRESULT GetInStream(
+ ISequentialInStream **inStreams, const UInt64 **inSizes,
+ UInt32 streamIndex, ISequentialInStream **inStreamRes);
+ HRESULT GetOutStream(
+ ISequentialOutStream **outStreams, const UInt64 **outSizes,
+ UInt32 streamIndex, ISequentialOutStream **outStreamRes);
+public:
+ STDMETHOD(Code)(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ CCoderMixer2ST();
+ ~CCoderMixer2ST();
+ void AddCoderCommon(bool isMain);
+ void AddCoder(ICompressCoder *coder, bool isMain);
+ void AddCoder2(ICompressCoder2 *coder, bool isMain);
+
+ void ReInit();
+ void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes)
+ {
+ { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); }
+ }
+
+ void SetProgressCoderIndex(UInt32 /*coderIndex*/)
+ {
+ // _progressCoderIndex = coderIndex;
+ }
+
+ // UInt64 GetWriteProcessedSize(UInt32 binderIndex) const;
+
+private:
+ CBindInfo _bindInfo;
+ CObjectVector<CSTCoderInfo> _coders;
+ int _mainCoderIndex;
+public:
+ HRESULT SetBindInfo(const CBindInfo &bindInfo);
+
+};
+
+}
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/CrossThreadProgress.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
new file mode 100644
index 000000000..a974b54c7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
@@ -0,0 +1,15 @@
+// CrossThreadProgress.cpp
+
+#include "StdAfx.h"
+
+#include "CrossThreadProgress.h"
+
+STDMETHODIMP CCrossThreadProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ InSize = inSize;
+ OutSize = outSize;
+ ProgressEvent.Set();
+ WaitEvent.Lock();
+ return Result;
+}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/CrossThreadProgress.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CrossThreadProgress.h
new file mode 100644
index 000000000..7e0b10538
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/CrossThreadProgress.h
@@ -0,0 +1,37 @@
+// CrossThreadProgress.h
+
+#ifndef __CROSSTHREADPROGRESS_H
+#define __CROSSTHREADPROGRESS_H
+
+#include "../../ICoder.h"
+#include "../../../Windows/Synchronization.h"
+#include "../../../Common/MyCom.h"
+
+class CCrossThreadProgress:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ const UInt64 *InSize;
+ const UInt64 *OutSize;
+ HRESULT Result;
+ NWindows::NSynchronization::CAutoResetEvent ProgressEvent;
+ NWindows::NSynchronization::CAutoResetEvent WaitEvent;
+
+ HRes Create()
+ {
+ RINOK(ProgressEvent.CreateIfNotCreated());
+ return WaitEvent.CreateIfNotCreated();
+ }
+ void Init()
+ {
+ ProgressEvent.Reset();
+ WaitEvent.Reset();
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.cpp
new file mode 100644
index 000000000..54bcfec11
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.cpp
@@ -0,0 +1,22 @@
+// DummyOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "DummyOutStream.h"
+
+STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result;
+ if(!_stream)
+ {
+ realProcessedSize = size;
+ result = S_OK;
+ }
+ else
+ result = _stream->Write(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.h
new file mode 100644
index 000000000..13d5b62ca
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/DummyOutStream.h
@@ -0,0 +1,24 @@
+// DummyOutStream.h
+
+#ifndef __DUMMYOUTSTREAM_H
+#define __DUMMYOUTSTREAM_H
+
+#include "../../IStream.h"
+#include "Common/MyCom.h"
+
+class CDummyOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialOutStream *outStream) { _stream = outStream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _size = 0; }
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ UInt64 GetSize() const { return _size; }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.cpp
new file mode 100644
index 000000000..15aa6ceae
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.cpp
@@ -0,0 +1,62 @@
+// FindSignature.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Buffer.h"
+
+#include "FindSignature.h"
+
+#include "../../Common/StreamUtils.h"
+
+HRESULT FindSignatureInStream(ISequentialInStream *stream,
+ const Byte *signature, unsigned signatureSize,
+ const UInt64 *limit, UInt64 &resPos)
+{
+ resPos = 0;
+ CByteBuffer byteBuffer2;
+ byteBuffer2.SetCapacity(signatureSize);
+ RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize));
+
+ if (memcmp(byteBuffer2, signature, signatureSize) == 0)
+ return S_OK;
+
+ const UInt32 kBufferSize = (1 << 16);
+ CByteBuffer byteBuffer;
+ byteBuffer.SetCapacity(kBufferSize);
+ Byte *buffer = byteBuffer;
+ UInt32 numPrevBytes = signatureSize - 1;
+ memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes);
+ resPos = 1;
+ for (;;)
+ {
+ if (limit != NULL)
+ if (resPos > *limit)
+ return S_FALSE;
+ do
+ {
+ UInt32 numReadBytes = kBufferSize - numPrevBytes;
+ UInt32 processedSize;
+ RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
+ numPrevBytes += processedSize;
+ if (processedSize == 0)
+ return S_FALSE;
+ }
+ while (numPrevBytes < signatureSize);
+ UInt32 numTests = numPrevBytes - signatureSize + 1;
+ for (UInt32 pos = 0; pos < numTests; pos++)
+ {
+ Byte b = signature[0];
+ for (; buffer[pos] != b && pos < numTests; pos++);
+ if (pos == numTests)
+ break;
+ if (memcmp(buffer + pos, signature, signatureSize) == 0)
+ {
+ resPos += pos;
+ return S_OK;
+ }
+ }
+ resPos += numTests;
+ numPrevBytes -= numTests;
+ memmove(buffer, buffer + numTests, numPrevBytes);
+ }
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.h
new file mode 100644
index 000000000..e15af5732
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/FindSignature.h
@@ -0,0 +1,12 @@
+// FindSignature.h
+
+#ifndef __FINDSIGNATURE_H
+#define __FINDSIGNATURE_H
+
+#include "../../IStream.h"
+
+HRESULT FindSignatureInStream(ISequentialInStream *stream,
+ const Byte *signature, unsigned signatureSize,
+ const UInt64 *limit, UInt64 &resPos);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.cpp
new file mode 100644
index 000000000..70ad47aad
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -0,0 +1,623 @@
+// HandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/System.h"
+#endif
+
+#include "../../ICoder.h"
+
+#include "../Common/ParseProperties.h"
+
+#include "HandlerOut.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+
+static const wchar_t *kCopyMethod = L"Copy";
+static const wchar_t *kLZMAMethodName = L"LZMA";
+static const wchar_t *kLZMA2MethodName = L"LZMA2";
+static const wchar_t *kBZip2MethodName = L"BZip2";
+static const wchar_t *kPpmdMethodName = L"PPMd";
+static const wchar_t *kDeflateMethodName = L"Deflate";
+static const wchar_t *kDeflate64MethodName = L"Deflate64";
+
+static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
+static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
+
+static const UInt32 kLzmaAlgoX1 = 0;
+static const UInt32 kLzmaAlgoX5 = 1;
+
+static const UInt32 kLzmaDicSizeX1 = 1 << 16;
+static const UInt32 kLzmaDicSizeX3 = 1 << 20;
+static const UInt32 kLzmaDicSizeX5 = 1 << 24;
+static const UInt32 kLzmaDicSizeX7 = 1 << 25;
+static const UInt32 kLzmaDicSizeX9 = 1 << 26;
+
+static const UInt32 kLzmaFastBytesX1 = 32;
+static const UInt32 kLzmaFastBytesX7 = 64;
+
+static const UInt32 kPpmdMemSizeX1 = (1 << 22);
+static const UInt32 kPpmdMemSizeX5 = (1 << 24);
+static const UInt32 kPpmdMemSizeX7 = (1 << 26);
+static const UInt32 kPpmdMemSizeX9 = (192 << 20);
+
+static const UInt32 kPpmdOrderX1 = 4;
+static const UInt32 kPpmdOrderX5 = 6;
+static const UInt32 kPpmdOrderX7 = 16;
+static const UInt32 kPpmdOrderX9 = 32;
+
+static const UInt32 kDeflateAlgoX1 = 0;
+static const UInt32 kDeflateAlgoX5 = 1;
+
+static const UInt32 kDeflateFastBytesX1 = 32;
+static const UInt32 kDeflateFastBytesX7 = 64;
+static const UInt32 kDeflateFastBytesX9 = 128;
+
+static const UInt32 kDeflatePassesX1 = 1;
+static const UInt32 kDeflatePassesX7 = 3;
+static const UInt32 kDeflatePassesX9 = 10;
+
+static const UInt32 kBZip2NumPassesX1 = 1;
+static const UInt32 kBZip2NumPassesX7 = 2;
+static const UInt32 kBZip2NumPassesX9 = 7;
+
+static const UInt32 kBZip2DicSizeX1 = 100000;
+static const UInt32 kBZip2DicSizeX3 = 500000;
+static const UInt32 kBZip2DicSizeX5 = 900000;
+
+static const wchar_t *kDefaultMethodName = kLZMAMethodName;
+
+static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
+static const UInt32 kDictionaryForHeaders = 1 << 20;
+static const UInt32 kNumFastBytesForHeaders = 273;
+static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5;
+
+static bool AreEqual(const UString &methodName, const wchar_t *s)
+ { return (methodName.CompareNoCase(s) == 0); }
+
+bool COneMethodInfo::IsLzma() const
+{
+ return
+ AreEqual(MethodName, kLZMAMethodName) ||
+ AreEqual(MethodName, kLZMA2MethodName);
+}
+
+static inline bool IsBZip2Method(const UString &methodName)
+ { return AreEqual(methodName, kBZip2MethodName); }
+
+static inline bool IsPpmdMethod(const UString &methodName)
+ { return AreEqual(methodName, kPpmdMethodName); }
+
+static inline bool IsDeflateMethod(const UString &methodName)
+{
+ return
+ AreEqual(methodName, kDeflateMethodName) ||
+ AreEqual(methodName, kDeflate64MethodName);
+}
+
+struct CNameToPropID
+{
+ PROPID PropID;
+ VARTYPE VarType;
+ const wchar_t *Name;
+};
+
+static CNameToPropID g_NameToPropID[] =
+{
+ { NCoderPropID::kBlockSize, VT_UI4, L"C" },
+ { NCoderPropID::kDictionarySize, VT_UI4, L"D" },
+ { NCoderPropID::kUsedMemorySize, VT_UI4, L"MEM" },
+
+ { NCoderPropID::kOrder, VT_UI4, L"O" },
+ { NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
+ { NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
+ { NCoderPropID::kLitPosBits, VT_UI4, L"LP" },
+ { NCoderPropID::kEndMarker, VT_BOOL, L"eos" },
+
+ { NCoderPropID::kNumPasses, VT_UI4, L"Pass" },
+ { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" },
+ { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
+ { NCoderPropID::kAlgorithm, VT_UI4, L"a" },
+ { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
+ { NCoderPropID::kNumThreads, VT_UI4, L"mt" },
+ { NCoderPropID::kDefaultProp, VT_UI4, L"" }
+};
+
+static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
+{
+ if (varType == srcProp.vt)
+ {
+ destProp = srcProp;
+ return true;
+ }
+ if (varType == VT_UI1)
+ {
+ if (srcProp.vt == VT_UI4)
+ {
+ UInt32 value = srcProp.ulVal;
+ if (value > 0xFF)
+ return false;
+ destProp = (Byte)value;
+ return true;
+ }
+ }
+ else if (varType == VT_BOOL)
+ {
+ bool res;
+ if (SetBoolProperty(res, srcProp) != S_OK)
+ return false;
+ destProp = res;
+ return true;
+ }
+ return false;
+}
+
+static int FindPropIdExact(const UString &name)
+{
+ for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
+ if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
+ return i;
+ return -1;
+}
+
+static int FindPropIdStart(const UString &name)
+{
+ for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
+ {
+ UString t = g_NameToPropID[i].Name;
+ if (t.CompareNoCase(name.Left(t.Length())) == 0)
+ return i;
+ }
+ return -1;
+}
+
+static void SetMethodProp(COneMethodInfo &m, PROPID propID, const NCOM::CPropVariant &value)
+{
+ for (int j = 0; j < m.Props.Size(); j++)
+ if (m.Props[j].Id == propID)
+ return;
+ CProp prop;
+ prop.Id = propID;
+ prop.Value = value;
+ m.Props.Add(prop);
+}
+
+void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ )
+{
+ UInt32 level = _level;
+ if (oneMethodInfo.MethodName.IsEmpty())
+ oneMethodInfo.MethodName = kDefaultMethodName;
+
+ if (oneMethodInfo.IsLzma())
+ {
+ UInt32 dicSize =
+ (level >= 9 ? kLzmaDicSizeX9 :
+ (level >= 7 ? kLzmaDicSizeX7 :
+ (level >= 5 ? kLzmaDicSizeX5 :
+ (level >= 3 ? kLzmaDicSizeX3 :
+ kLzmaDicSizeX1))));
+
+ UInt32 algo =
+ (level >= 5 ? kLzmaAlgoX5 :
+ kLzmaAlgoX1);
+
+ UInt32 fastBytes =
+ (level >= 7 ? kLzmaFastBytesX7 :
+ kLzmaFastBytesX1);
+
+ const wchar_t *matchFinder =
+ (level >= 5 ? kLzmaMatchFinderX5 :
+ kLzmaMatchFinderX1);
+
+ SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
+ #ifndef _7ZIP_ST
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+ #endif
+ }
+ else if (IsDeflateMethod(oneMethodInfo.MethodName))
+ {
+ UInt32 fastBytes =
+ (level >= 9 ? kDeflateFastBytesX9 :
+ (level >= 7 ? kDeflateFastBytesX7 :
+ kDeflateFastBytesX1));
+
+ UInt32 numPasses =
+ (level >= 9 ? kDeflatePassesX9 :
+ (level >= 7 ? kDeflatePassesX7 :
+ kDeflatePassesX1));
+
+ UInt32 algo =
+ (level >= 5 ? kDeflateAlgoX5 :
+ kDeflateAlgoX1);
+
+ SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
+ }
+ else if (IsBZip2Method(oneMethodInfo.MethodName))
+ {
+ UInt32 numPasses =
+ (level >= 9 ? kBZip2NumPassesX9 :
+ (level >= 7 ? kBZip2NumPassesX7 :
+ kBZip2NumPassesX1));
+
+ UInt32 dicSize =
+ (level >= 5 ? kBZip2DicSizeX5 :
+ (level >= 3 ? kBZip2DicSizeX3 :
+ kBZip2DicSizeX1));
+
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
+ #ifndef _7ZIP_ST
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+ #endif
+ }
+ else if (IsPpmdMethod(oneMethodInfo.MethodName))
+ {
+ UInt32 useMemSize =
+ (level >= 9 ? kPpmdMemSizeX9 :
+ (level >= 7 ? kPpmdMemSizeX7 :
+ (level >= 5 ? kPpmdMemSizeX5 :
+ kPpmdMemSizeX1)));
+
+ UInt32 order =
+ (level >= 9 ? kPpmdOrderX9 :
+ (level >= 7 ? kPpmdOrderX7 :
+ (level >= 5 ? kPpmdOrderX5 :
+ kPpmdOrderX1)));
+
+ SetMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
+ }
+}
+
+static void SplitParams(const UString &srcString, UStringVector &subStrings)
+{
+ subStrings.Clear();
+ UString name;
+ int len = srcString.Length();
+ if (len == 0)
+ return;
+ for (int i = 0; i < len; i++)
+ {
+ wchar_t c = srcString[i];
+ if (c == L':')
+ {
+ subStrings.Add(name);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ subStrings.Add(name);
+}
+
+static void SplitParam(const UString &param, UString &name, UString &value)
+{
+ int eqPos = param.Find(L'=');
+ if (eqPos >= 0)
+ {
+ name = param.Left(eqPos);
+ value = param.Mid(eqPos + 1);
+ return;
+ }
+ for(int i = 0; i < param.Length(); i++)
+ {
+ wchar_t c = param[i];
+ if (c >= L'0' && c <= L'9')
+ {
+ name = param.Left(i);
+ value = param.Mid(i);
+ return;
+ }
+ }
+ name = param;
+}
+
+HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value)
+{
+ CProp prop;
+ int index = FindPropIdExact(name);
+ if (index < 0)
+ return E_INVALIDARG;
+ const CNameToPropID &nameToPropID = g_NameToPropID[index];
+ prop.Id = nameToPropID.PropID;
+
+ if (prop.Id == NCoderPropID::kBlockSize ||
+ prop.Id == NCoderPropID::kDictionarySize ||
+ prop.Id == NCoderPropID::kUsedMemorySize)
+ {
+ UInt32 dicSize;
+ RINOK(ParsePropDictionaryValue(value, dicSize));
+ prop.Value = dicSize;
+ }
+ else
+ {
+ NCOM::CPropVariant propValue;
+
+ if (nameToPropID.VarType == VT_BSTR)
+ propValue = value;
+ else if (nameToPropID.VarType == VT_BOOL)
+ {
+ bool res;
+ if (!StringToBool(value, res))
+ return E_INVALIDARG;
+ propValue = res;
+ }
+ else
+ {
+ UInt32 number;
+ if (ParseStringToUInt32(value, number) == value.Length())
+ propValue = number;
+ else
+ propValue = value;
+ }
+
+ if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
+ return E_INVALIDARG;
+ }
+ oneMethodInfo.Props.Add(prop);
+ return S_OK;
+}
+
+HRESULT COutHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString)
+{
+ UStringVector params;
+ SplitParams(srcString, params);
+ if (params.Size() > 0)
+ oneMethodInfo.MethodName = params[0];
+ for (int i = 1; i < params.Size(); i++)
+ {
+ const UString &param = params[i];
+ UString name, value;
+ SplitParam(param, name, value);
+ RINOK(SetParam(oneMethodInfo, name, value));
+ }
+ return S_OK;
+}
+
+HRESULT COutHandler::SetSolidSettings(const UString &s)
+{
+ UString s2 = s;
+ s2.MakeUpper();
+ for (int i = 0; i < s2.Length();)
+ {
+ const wchar_t *start = ((const wchar_t *)s2) + i;
+ const wchar_t *end;
+ UInt64 v = ConvertStringToUInt64(start, &end);
+ if (start == end)
+ {
+ if (s2[i++] != 'E')
+ return E_INVALIDARG;
+ _solidExtension = true;
+ continue;
+ }
+ i += (int)(end - start);
+ if (i == s2.Length())
+ return E_INVALIDARG;
+ wchar_t c = s2[i++];
+ switch(c)
+ {
+ case 'F':
+ if (v < 1)
+ v = 1;
+ _numSolidFiles = v;
+ break;
+ case 'B':
+ _numSolidBytes = v;
+ _numSolidBytesDefined = true;
+ break;
+ case 'K':
+ _numSolidBytes = (v << 10);
+ _numSolidBytesDefined = true;
+ break;
+ case 'M':
+ _numSolidBytes = (v << 20);
+ _numSolidBytesDefined = true;
+ break;
+ case 'G':
+ _numSolidBytes = (v << 30);
+ _numSolidBytesDefined = true;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT COutHandler::SetSolidSettings(const PROPVARIANT &value)
+{
+ bool isSolid;
+ switch(value.vt)
+ {
+ case VT_EMPTY:
+ isSolid = true;
+ break;
+ case VT_BOOL:
+ isSolid = (value.boolVal != VARIANT_FALSE);
+ break;
+ case VT_BSTR:
+ if (StringToBool(value.bstrVal, isSolid))
+ break;
+ return SetSolidSettings(value.bstrVal);
+ default:
+ return E_INVALIDARG;
+ }
+ if (isSolid)
+ InitSolid();
+ else
+ _numSolidFiles = 1;
+ return S_OK;
+}
+
+void COutHandler::Init()
+{
+ _removeSfxBlock = false;
+ _compressHeaders = true;
+ _encryptHeadersSpecified = false;
+ _encryptHeaders = false;
+
+ WriteCTime = false;
+ WriteATime = false;
+ WriteMTime = true;
+
+ #ifndef _7ZIP_ST
+ _numThreads = NSystem::GetNumberOfProcessors();
+ #endif
+
+ _level = 5;
+ _autoFilter = true;
+ _volumeMode = false;
+ _crcSize = 4;
+ InitSolid();
+}
+
+void COutHandler::BeforeSetProperty()
+{
+ Init();
+ #ifndef _7ZIP_ST
+ numProcessors = NSystem::GetNumberOfProcessors();
+ #endif
+
+ mainDicSize = 0xFFFFFFFF;
+ mainDicMethodIndex = 0xFFFFFFFF;
+ minNumber = 0;
+ _crcSize = 4;
+}
+
+HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
+{
+ UString name = nameSpec;
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ if (name[0] == 'X')
+ {
+ name.Delete(0);
+ _level = 9;
+ return ParsePropValue(name, value, _level);
+ }
+
+ if (name[0] == L'S')
+ {
+ name.Delete(0);
+ if (name.IsEmpty())
+ return SetSolidSettings(value);
+ if (value.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return SetSolidSettings(name);
+ }
+
+ if (name == L"CRC")
+ {
+ _crcSize = 4;
+ name.Delete(0, 3);
+ return ParsePropValue(name, value, _crcSize);
+ }
+
+ UInt32 number;
+ int index = ParseStringToUInt32(name, number);
+ UString realName = name.Mid(index);
+ if (index == 0)
+ {
+ if(name.Left(2).CompareNoCase(L"MT") == 0)
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
+ #endif
+ return S_OK;
+ }
+ if (name.CompareNoCase(L"RSFX") == 0) return SetBoolProperty(_removeSfxBlock, value);
+ if (name.CompareNoCase(L"F") == 0) return SetBoolProperty(_autoFilter, value);
+ if (name.CompareNoCase(L"HC") == 0) return SetBoolProperty(_compressHeaders, value);
+ if (name.CompareNoCase(L"HCF") == 0)
+ {
+ bool compressHeadersFull = true;
+ RINOK(SetBoolProperty(compressHeadersFull, value));
+ if (!compressHeadersFull)
+ return E_INVALIDARG;
+ return S_OK;
+ }
+ if (name.CompareNoCase(L"HE") == 0)
+ {
+ RINOK(SetBoolProperty(_encryptHeaders, value));
+ _encryptHeadersSpecified = true;
+ return S_OK;
+ }
+ if (name.CompareNoCase(L"TC") == 0) return SetBoolProperty(WriteCTime, value);
+ if (name.CompareNoCase(L"TA") == 0) return SetBoolProperty(WriteATime, value);
+ if (name.CompareNoCase(L"TM") == 0) return SetBoolProperty(WriteMTime, value);
+ if (name.CompareNoCase(L"V") == 0) return SetBoolProperty(_volumeMode, value);
+ number = 0;
+ }
+ if (number > 10000)
+ return E_FAIL;
+ if (number < minNumber)
+ return E_INVALIDARG;
+ number -= minNumber;
+ for(int j = _methods.Size(); j <= (int)number; j++)
+ {
+ COneMethodInfo oneMethodInfo;
+ _methods.Add(oneMethodInfo);
+ }
+
+ COneMethodInfo &oneMethodInfo = _methods[number];
+
+ if (realName.Length() == 0)
+ {
+ if (value.vt != VT_BSTR)
+ return E_INVALIDARG;
+
+ RINOK(SetParams(oneMethodInfo, value.bstrVal));
+ }
+ else
+ {
+ int index = FindPropIdStart(realName);
+ if (index < 0)
+ return E_INVALIDARG;
+ const CNameToPropID &nameToPropID = g_NameToPropID[index];
+ CProp prop;
+ prop.Id = nameToPropID.PropID;
+
+ if (prop.Id == NCoderPropID::kBlockSize ||
+ prop.Id == NCoderPropID::kDictionarySize ||
+ prop.Id == NCoderPropID::kUsedMemorySize)
+ {
+ UInt32 dicSize;
+ RINOK(ParsePropDictionaryValue(realName.Mid(MyStringLen(nameToPropID.Name)), value, dicSize));
+ prop.Value = dicSize;
+ if (number <= mainDicMethodIndex)
+ mainDicSize = dicSize;
+ }
+ else
+ {
+ int index = FindPropIdExact(realName);
+ if (index < 0)
+ return E_INVALIDARG;
+ const CNameToPropID &nameToPropID = g_NameToPropID[index];
+ prop.Id = nameToPropID.PropID;
+ if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
+ return E_INVALIDARG;
+ }
+ oneMethodInfo.Props.Add(prop);
+ }
+ return S_OK;
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.h
new file mode 100644
index 000000000..72ea40321
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/HandlerOut.h
@@ -0,0 +1,87 @@
+// HandlerOut.h
+
+#ifndef __HANDLER_OUT_H
+#define __HANDLER_OUT_H
+
+#include "../../../Common/MyString.h"
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+
+struct COneMethodInfo
+{
+ CObjectVector<CProp> Props;
+ UString MethodName;
+
+ bool IsLzma() const;
+};
+
+class COutHandler
+{
+public:
+ HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
+
+ HRESULT SetSolidSettings(const UString &s);
+ HRESULT SetSolidSettings(const PROPVARIANT &value);
+
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ #endif
+
+ UInt32 _crcSize;
+
+ CObjectVector<COneMethodInfo> _methods;
+ bool _removeSfxBlock;
+
+ UInt64 _numSolidFiles;
+ UInt64 _numSolidBytes;
+ bool _numSolidBytesDefined;
+ bool _solidExtension;
+
+ bool _compressHeaders;
+ bool _encryptHeadersSpecified;
+ bool _encryptHeaders;
+
+ bool WriteCTime;
+ bool WriteATime;
+ bool WriteMTime;
+
+ bool _autoFilter;
+ UInt32 _level;
+
+ bool _volumeMode;
+
+ HRESULT SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value);
+ HRESULT SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString);
+
+ void SetCompressionMethod2(COneMethodInfo &oneMethodInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ );
+
+ void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); }
+ void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); }
+ void InitSolid()
+ {
+ InitSolidFiles();
+ InitSolidSize();
+ _solidExtension = false;
+ _numSolidBytesDefined = false;
+ }
+
+ void Init();
+
+ COutHandler() { Init(); }
+
+ void BeforeSetProperty();
+
+ UInt32 minNumber;
+ UInt32 numProcessors;
+ UInt32 mainDicSize;
+ UInt32 mainDicMethodIndex;
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
new file mode 100644
index 000000000..569a56f3b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
@@ -0,0 +1,42 @@
+// InStreamWithCRC.cpp
+
+#include "StdAfx.h"
+
+#include "InStreamWithCRC.h"
+
+STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (size > 0 && realProcessedSize == 0)
+ _wasFinished = true;
+ _crc = CrcUpdate(_crc, data, realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ /*
+ if (size > 0 && realProcessedSize == 0)
+ _wasFinished = true;
+ */
+ _size += realProcessedSize;
+ _crc = CrcUpdate(_crc, data, realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+STDMETHODIMP CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if (seekOrigin != STREAM_SEEK_SET || offset != 0)
+ return E_FAIL;
+ _size = 0;
+ _crc = CRC_INIT_VAL;
+ return _stream->Seek(offset, seekOrigin, newPosition);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.h
new file mode 100644
index 000000000..31b761e45
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/InStreamWithCRC.h
@@ -0,0 +1,67 @@
+// InStreamWithCRC.h
+
+#ifndef __IN_STREAM_WITH_CRC_H
+#define __IN_STREAM_WITH_CRC_H
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+class CSequentialInStreamWithCRC:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+private:
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _wasFinished;
+public:
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ _wasFinished = false;
+ _crc = CRC_INIT_VAL;
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+ UInt64 GetSize() const { return _size; }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+class CInStreamWithCRC:
+ public IInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+private:
+ CMyComPtr<IInStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ // bool _wasFinished;
+public:
+ void SetStream(IInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ // _wasFinished = false;
+ _crc = CRC_INIT_VAL;
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+ UInt64 GetSize() const { return _size; }
+ // bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.cpp
new file mode 100644
index 000000000..a5e0dc0be
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.cpp
@@ -0,0 +1,61 @@
+// Archive/Common/ItemNameUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Types.h"
+
+#include "ItemNameUtils.h"
+
+namespace NArchive {
+namespace NItemName {
+
+static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR;
+static const wchar_t kDirDelimiter = L'/';
+
+UString MakeLegalName(const UString &name)
+{
+ UString zipName = name;
+ zipName.Replace(kOSDirDelimiter, kDirDelimiter);
+ return zipName;
+}
+
+UString GetOSName(const UString &name)
+{
+ UString newName = name;
+ newName.Replace(kDirDelimiter, kOSDirDelimiter);
+ return newName;
+}
+
+UString GetOSName2(const UString &name)
+{
+ if (name.IsEmpty())
+ return UString();
+ UString newName = GetOSName(name);
+ if (newName[newName.Length() - 1] == kOSDirDelimiter)
+ newName.Delete(newName.Length() - 1);
+ return newName;
+}
+
+bool HasTailSlash(const AString &name, UINT codePage)
+{
+ if (name.IsEmpty())
+ return false;
+ LPCSTR prev =
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ CharPrevExA((WORD)codePage, name, &name[name.Length()], 0);
+ #else
+ (LPCSTR)(name) + (name.Length() - 1);
+ #endif
+ return (*prev == '/');
+}
+
+#ifndef _WIN32
+UString WinNameToOSName(const UString &name)
+{
+ UString newName = name;
+ newName.Replace(L'\\', kOSDirDelimiter);
+ return newName;
+}
+#endif
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.h
new file mode 100644
index 000000000..5eafacb12
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -0,0 +1,24 @@
+// Archive/Common/ItemNameUtils.h
+
+#ifndef __ARCHIVE_ITEMNAMEUTILS_H
+#define __ARCHIVE_ITEMNAMEUTILS_H
+
+#include "../../../Common/MyString.h"
+
+namespace NArchive {
+namespace NItemName {
+
+ UString MakeLegalName(const UString &name);
+ UString GetOSName(const UString &name);
+ UString GetOSName2(const UString &name);
+ bool HasTailSlash(const AString &name, UINT codePage);
+
+ #ifdef _WIN32
+ inline UString WinNameToOSName(const UString &name) { return name; }
+ #else
+ UString WinNameToOSName(const UString &name);
+ #endif
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.cpp
new file mode 100644
index 000000000..04d11cafb
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.cpp
@@ -0,0 +1,190 @@
+// MultiStream.cpp
+
+#include "StdAfx.h"
+
+#include "MultiStream.h"
+
+STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos >= _totalLength)
+ return (_pos == _totalLength) ? S_OK : E_FAIL;
+
+ {
+ int left = 0, mid = _streamIndex, right = Streams.Size();
+ for (;;)
+ {
+ CSubStreamInfo &m = Streams[mid];
+ if (_pos < m.GlobalOffset)
+ right = mid;
+ else if (_pos >= m.GlobalOffset + m.Size)
+ left = mid + 1;
+ else
+ {
+ _streamIndex = mid;
+ break;
+ }
+ mid = (left + right) / 2;
+ }
+ _streamIndex = mid;
+ }
+
+ CSubStreamInfo &s = Streams[_streamIndex];
+ UInt64 localPos = _pos - s.GlobalOffset;
+ if (localPos != s.LocalPos)
+ {
+ RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos));
+ }
+ UInt64 rem = s.Size - localPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ HRESULT result = s.Stream->Read(data, size, &size);
+ _pos += size;
+ s.LocalPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _pos = offset; break;
+ case STREAM_SEEK_CUR: _pos = _pos + offset; break;
+ case STREAM_SEEK_END: _pos = _totalLength + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition != 0)
+ *newPosition = _pos;
+ return S_OK;
+}
+
+
+/*
+class COutVolumeStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ int _volIndex;
+ UInt64 _volSize;
+ UInt64 _curPos;
+ CMyComPtr<ISequentialOutStream> _volumeStream;
+ COutArchive _archive;
+ CCRC _crc;
+
+public:
+ MY_UNKNOWN_IMP
+
+ CFileItem _file;
+ CUpdateOptions _options;
+ CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ void Init(IArchiveUpdateCallback2 *volumeCallback,
+ const UString &name)
+ {
+ _file.Name = name;
+ _file.IsStartPosDefined = true;
+ _file.StartPos = 0;
+
+ VolumeCallback = volumeCallback;
+ _volIndex = 0;
+ _volSize = 0;
+ }
+
+ HRESULT Flush();
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+HRESULT COutVolumeStream::Flush()
+{
+ if (_volumeStream)
+ {
+ _file.UnPackSize = _curPos;
+ _file.FileCRC = _crc.GetDigest();
+ RINOK(WriteVolumeHeader(_archive, _file, _options));
+ _archive.Close();
+ _volumeStream.Release();
+ _file.StartPos += _file.UnPackSize;
+ }
+ return S_OK;
+}
+*/
+
+/*
+STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if(processedSize != NULL)
+ *processedSize = 0;
+ while(size > 0)
+ {
+ if (_streamIndex >= Streams.Size())
+ {
+ CSubStreamInfo subStream;
+ RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size));
+ RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream));
+ subStream.Pos = 0;
+ Streams.Add(subStream);
+ continue;
+ }
+ CSubStreamInfo &subStream = Streams[_streamIndex];
+ if (_offsetPos >= subStream.Size)
+ {
+ _offsetPos -= subStream.Size;
+ _streamIndex++;
+ continue;
+ }
+ if (_offsetPos != subStream.Pos)
+ {
+ CMyComPtr<IOutStream> outStream;
+ RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
+ RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
+ subStream.Pos = _offsetPos;
+ }
+
+ UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);
+ UInt32 realProcessed;
+ RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
+ data = (void *)((Byte *)data + realProcessed);
+ size -= realProcessed;
+ subStream.Pos += realProcessed;
+ _offsetPos += realProcessed;
+ _absPos += realProcessed;
+ if (_absPos > _length)
+ _length = _absPos;
+ if(processedSize != NULL)
+ *processedSize += realProcessed;
+ if (subStream.Pos == subStream.Size)
+ {
+ _streamIndex++;
+ _offsetPos = 0;
+ }
+ if (realProcessed != curSize && realProcessed == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if(seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET:
+ _absPos = offset;
+ break;
+ case STREAM_SEEK_CUR:
+ _absPos += offset;
+ break;
+ case STREAM_SEEK_END:
+ _absPos = _length + offset;
+ break;
+ }
+ _offsetPos = _absPos;
+ _streamIndex = 0;
+ return S_OK;
+}
+*/
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.h
new file mode 100644
index 000000000..3fceb7cce
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/MultiStream.h
@@ -0,0 +1,84 @@
+// MultiStream.h
+
+#ifndef __MULTI_STREAM_H
+#define __MULTI_STREAM_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyVector.h"
+
+#include "../../IStream.h"
+
+class CMultiStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _pos;
+ UInt64 _totalLength;
+ int _streamIndex;
+public:
+ struct CSubStreamInfo
+ {
+ CMyComPtr<IInStream> Stream;
+ UInt64 Size;
+ UInt64 GlobalOffset;
+ UInt64 LocalPos;
+ };
+ CObjectVector<CSubStreamInfo> Streams;
+
+ HRESULT Init()
+ {
+ UInt64 total = 0;
+ for (int i = 0; i < Streams.Size(); i++)
+ {
+ CSubStreamInfo &s = Streams[i];
+ s.GlobalOffset = total;
+ total += Streams[i].Size;
+ RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos));
+ }
+ _totalLength = total;
+ _pos = 0;
+ _streamIndex = 0;
+ return S_OK;
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+/*
+class COutMultiStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ int _streamIndex; // required stream
+ UInt64 _offsetPos; // offset from start of _streamIndex index
+ UInt64 _absPos;
+ UInt64 _length;
+
+ struct CSubStreamInfo
+ {
+ CMyComPtr<ISequentialOutStream> Stream;
+ UInt64 Size;
+ UInt64 Pos;
+ };
+ CObjectVector<CSubStreamInfo> Streams;
+public:
+ CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ void Init()
+ {
+ _streamIndex = 0;
+ _offsetPos = 0;
+ _absPos = 0;
+ _length = 0;
+ }
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+*/
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
new file mode 100644
index 000000000..f955c2254
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
@@ -0,0 +1,18 @@
+// OutStreamWithCRC.cpp
+
+#include "StdAfx.h"
+
+#include "OutStreamWithCRC.h"
+
+STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ _crc = CrcUpdate(_crc, data, size);
+ _size += size;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.h
new file mode 100644
index 000000000..115b442aa
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithCRC.h
@@ -0,0 +1,36 @@
+// OutStreamWithCRC.h
+
+#ifndef __OUT_STREAM_WITH_CRC_H
+#define __OUT_STREAM_WITH_CRC_H
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+class COutStreamWithCRC:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _calculate;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ _crc = CRC_INIT_VAL;
+ }
+ void InitCRC() { _crc = CRC_INIT_VAL; }
+ UInt64 GetSize() const { return _size; }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
new file mode 100644
index 000000000..0526c1b1d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
@@ -0,0 +1,18 @@
+// OutStreamWithSha1.cpp
+
+#include "StdAfx.h"
+
+#include "OutStreamWithSha1.h"
+
+STDMETHODIMP COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ _sha.Update((const Byte *)data, size);
+ _size += size;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithSha1.h
new file mode 100644
index 000000000..3bbfbbe19
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/OutStreamWithSha1.h
@@ -0,0 +1,36 @@
+// OutStreamWithSha1.h
+
+#ifndef __OUT_STREAM_WITH_SHA1_H
+#define __OUT_STREAM_WITH_SHA1_H
+
+#include "../../Crypto/Sha1.h"
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+class COutStreamWithSha1:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ NCrypto::NSha1::CContext _sha;
+ bool _calculate;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ _sha.Init();
+ }
+ void InitSha1() { _sha.Init(); }
+ UInt64 GetSize() const { return _size; }
+ void Final(Byte *digest) { _sha.Final(digest); }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.cpp
new file mode 100644
index 000000000..5cd849e29
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.cpp
@@ -0,0 +1,177 @@
+// ParseProperties.cpp
+
+#include "StdAfx.h"
+
+#include "ParseProperties.h"
+
+#include "Common/StringToInt.h"
+#include "Common/MyCom.h"
+
+HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
+{
+ if (prop.vt == VT_UI4)
+ {
+ if (!name.IsEmpty())
+ return E_INVALIDARG;
+ resValue = prop.ulVal;
+ }
+ else if (prop.vt == VT_EMPTY)
+ {
+ if(!name.IsEmpty())
+ {
+ const wchar_t *start = name;
+ const wchar_t *end;
+ UInt64 v = ConvertStringToUInt64(start, &end);
+ if (end - start != name.Length())
+ return E_INVALIDARG;
+ resValue = (UInt32)v;
+ }
+ }
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+static const int kLogarithmicSizeLimit = 32;
+static const wchar_t kByteSymbol = L'B';
+static const wchar_t kKiloByteSymbol = L'K';
+static const wchar_t kMegaByteSymbol = L'M';
+
+HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize)
+{
+ UString srcString = srcStringSpec;
+ srcString.MakeUpper();
+
+ const wchar_t *start = srcString;
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(start, &end);
+ int numDigits = (int)(end - start);
+ if (numDigits == 0 || srcString.Length() > numDigits + 1)
+ return E_INVALIDARG;
+ if (srcString.Length() == numDigits)
+ {
+ if (number >= kLogarithmicSizeLimit)
+ return E_INVALIDARG;
+ dicSize = (UInt32)1 << (int)number;
+ return S_OK;
+ }
+ switch (srcString[numDigits])
+ {
+ case kByteSymbol:
+ if (number >= ((UInt64)1 << kLogarithmicSizeLimit))
+ return E_INVALIDARG;
+ dicSize = (UInt32)number;
+ break;
+ case kKiloByteSymbol:
+ if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 10)))
+ return E_INVALIDARG;
+ dicSize = (UInt32)(number << 10);
+ break;
+ case kMegaByteSymbol:
+ if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 20)))
+ return E_INVALIDARG;
+ dicSize = (UInt32)(number << 20);
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
+{
+ if (name.IsEmpty())
+ {
+ if (prop.vt == VT_UI4)
+ {
+ UInt32 logDicSize = prop.ulVal;
+ if (logDicSize >= 32)
+ return E_INVALIDARG;
+ resValue = (UInt32)1 << logDicSize;
+ return S_OK;
+ }
+ if (prop.vt == VT_BSTR)
+ return ParsePropDictionaryValue(prop.bstrVal, resValue);
+ return E_INVALIDARG;
+ }
+ return ParsePropDictionaryValue(name, resValue);
+}
+
+bool StringToBool(const UString &s, bool &res)
+{
+ if (s.IsEmpty() || s.CompareNoCase(L"ON") == 0 || s.Compare(L"+") == 0)
+ {
+ res = true;
+ return true;
+ }
+ if (s.CompareNoCase(L"OFF") == 0 || s.Compare(L"-") == 0)
+ {
+ res = false;
+ return true;
+ }
+ return false;
+}
+
+HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value)
+{
+ switch(value.vt)
+ {
+ case VT_EMPTY:
+ dest = true;
+ return S_OK;
+ case VT_BOOL:
+ dest = (value.boolVal != VARIANT_FALSE);
+ return S_OK;
+ /*
+ case VT_UI4:
+ dest = (value.ulVal != 0);
+ break;
+ */
+ case VT_BSTR:
+ return StringToBool(value.bstrVal, dest) ? S_OK : E_INVALIDARG;
+ }
+ return E_INVALIDARG;
+}
+
+int ParseStringToUInt32(const UString &srcString, UInt32 &number)
+{
+ const wchar_t *start = srcString;
+ const wchar_t *end;
+ UInt64 number64 = ConvertStringToUInt64(start, &end);
+ if (number64 > 0xFFFFFFFF)
+ {
+ number = 0;
+ return 0;
+ }
+ number = (UInt32)number64;
+ return (int)(end - start);
+}
+
+HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads)
+{
+ if (name.IsEmpty())
+ {
+ switch(prop.vt)
+ {
+ case VT_UI4:
+ numThreads = prop.ulVal;
+ break;
+ default:
+ {
+ bool val;
+ RINOK(SetBoolProperty(val, prop));
+ numThreads = (val ? defaultNumThreads : 1);
+ break;
+ }
+ }
+ }
+ else
+ {
+ UInt32 number;
+ int index = ParseStringToUInt32(name, number);
+ if (index != name.Length())
+ return E_INVALIDARG;
+ numThreads = number;
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.h b/src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.h
new file mode 100644
index 000000000..6f80f6344
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Common/ParseProperties.h
@@ -0,0 +1,18 @@
+// ParseProperties.h
+
+#ifndef __PARSEPROPERTIES_H
+#define __PARSEPROPERTIES_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
+HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize);
+HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
+
+bool StringToBool(const UString &s, bool &res);
+HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value);
+int ParseStringToUInt32(const UString &srcString, UInt32 &number);
+HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/CpioHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/CpioHandler.cpp
new file mode 100644
index 000000000..0f32ef663
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/CpioHandler.cpp
@@ -0,0 +1,624 @@
+// CpioHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+
+namespace NArchive {
+namespace NCpio {
+
+namespace NFileHeader
+{
+ namespace NMagic
+ {
+ const char *kMagic1 = "070701";
+ const char *kMagic2 = "070702";
+ const char *kMagic3 = "070707";
+ const char *kEndName = "TRAILER!!!";
+
+ const Byte kMagicForRecord2[2] = { 0xC7, 0x71 };
+ }
+
+ const UInt32 kRecord2Size = 26;
+ /*
+ struct CRecord2
+ {
+ unsigned short c_magic;
+ short c_dev;
+ unsigned short c_ino;
+ unsigned short c_mode;
+ unsigned short c_uid;
+ unsigned short c_gid;
+ unsigned short c_nlink;
+ short c_rdev;
+ unsigned short c_mtimes[2];
+ unsigned short c_namesize;
+ unsigned short c_filesizes[2];
+ };
+ */
+
+ const UInt32 kRecordSize = 110;
+ /*
+ struct CRecord
+ {
+ char Magic[6]; // "070701" for "new" portable format, "070702" for CRC format
+ char inode[8];
+ char Mode[8];
+ char UID[8];
+ char GID[8];
+ char nlink[8];
+ char mtime[8];
+ char Size[8]; // must be 0 for FIFOs and directories
+ char DevMajor[8];
+ char DevMinor[8];
+ char RDevMajor[8]; //only valid for chr and blk special files
+ char RDevMinor[8]; //only valid for chr and blk special files
+ char NameSize[8]; // count includes terminating NUL in pathname
+ char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file
+ bool CheckMagic() const
+ { return memcmp(Magic, NMagic::kMagic1, 6) == 0 ||
+ memcmp(Magic, NMagic::kMagic2, 6) == 0; };
+ };
+ */
+
+ const UInt32 kOctRecordSize = 76;
+
+}
+
+struct CItem
+{
+ AString Name;
+ UInt32 inode;
+ UInt32 Mode;
+ UInt32 UID;
+ UInt32 GID;
+ UInt32 Size;
+ UInt32 MTime;
+
+ // char LinkFlag;
+ // AString LinkName; ?????
+ char Magic[8];
+ UInt32 NumLinks;
+ UInt32 DevMajor;
+ UInt32 DevMinor;
+ UInt32 RDevMajor;
+ UInt32 RDevMinor;
+ UInt32 ChkSum;
+
+ UInt32 Align;
+
+ bool IsDir() const { return (Mode & 0170000) == 0040000; }
+};
+
+class CItemEx: public CItem
+{
+public:
+ UInt64 HeaderPosition;
+ UInt32 HeaderSize;
+ UInt64 GetDataPosition() const { return HeaderPosition + HeaderSize; };
+};
+
+const UInt32 kMaxBlockSize = NFileHeader::kRecordSize;
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+ UInt64 m_Position;
+
+ UInt16 _blockSize;
+ Byte _block[kMaxBlockSize];
+ UInt32 _blockPos;
+ Byte ReadByte();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+
+ bool ReadNumber(UInt32 &resultValue);
+ bool ReadOctNumber(int size, UInt32 &resultValue);
+
+ HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
+public:
+ HRESULT Open(IInStream *inStream);
+ HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
+ HRESULT Skip(UInt64 numBytes);
+ HRESULT SkipDataRecords(UInt64 dataSize, UInt32 align);
+};
+
+HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
+{
+ size_t realProcessedSize = size;
+ RINOK(ReadStream(m_Stream, data, &realProcessedSize));
+ processedSize = (UInt32)realProcessedSize;
+ m_Position += processedSize;
+ return S_OK;
+}
+
+Byte CInArchive::ReadByte()
+{
+ if (_blockPos >= _blockSize)
+ throw "Incorrect cpio archive";
+ return _block[_blockPos++];
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = ReadByte();
+ value |= (UInt16(b) << (8 * i));
+ }
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b = ReadByte();
+ value |= (UInt32(b) << (8 * i));
+ }
+ return value;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
+ m_Stream = inStream;
+ return S_OK;
+}
+
+bool CInArchive::ReadNumber(UInt32 &resultValue)
+{
+ resultValue = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ char c = char(ReadByte());
+ int d;
+ if (c >= '0' && c <= '9')
+ d = c - '0';
+ else if (c >= 'A' && c <= 'F')
+ d = 10 + c - 'A';
+ else if (c >= 'a' && c <= 'f')
+ d = 10 + c - 'a';
+ else
+ return false;
+ resultValue *= 0x10;
+ resultValue += d;
+ }
+ return true;
+}
+
+static bool OctalToNumber(const char *s, UInt64 &res)
+{
+ const char *end;
+ res = ConvertOctStringToUInt64(s, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool OctalToNumber32(const char *s, UInt32 &res)
+{
+ UInt64 res64;
+ if (!OctalToNumber(s, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+bool CInArchive::ReadOctNumber(int size, UInt32 &resultValue)
+{
+ char sz[32 + 4];
+ int i;
+ for (i = 0; i < size && i < 32; i++)
+ sz[i] = (char)ReadByte();
+ sz[i] = 0;
+ return OctalToNumber32(sz, resultValue);
+}
+
+#define GetFromHex(y) { if (!ReadNumber(y)) return S_FALSE; }
+#define GetFromOct6(y) { if (!ReadOctNumber(6, y)) return S_FALSE; }
+#define GetFromOct11(y) { if (!ReadOctNumber(11, y)) return S_FALSE; }
+
+static unsigned short ConvertValue(unsigned short value, bool convert)
+{
+ if (!convert)
+ return value;
+ return (unsigned short)((((unsigned short)(value & 0xFF)) << 8) | (value >> 8));
+}
+
+static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
+{
+ while ((size & (align - 1)) != 0)
+ size++;
+ return size;
+}
+
+
+HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
+{
+ filled = false;
+
+ UInt32 processedSize;
+ item.HeaderPosition = m_Position;
+
+ _blockSize = kMaxBlockSize;
+ RINOK(ReadBytes(_block, 2, processedSize));
+ if (processedSize != 2)
+ return S_FALSE;
+ _blockPos = 0;
+
+ UInt32 nameSize;
+
+ bool oldBE =
+ _block[0] == NFileHeader::NMagic::kMagicForRecord2[1] &&
+ _block[1] == NFileHeader::NMagic::kMagicForRecord2[0];
+
+ bool binMode = (_block[0] == NFileHeader::NMagic::kMagicForRecord2[0] &&
+ _block[1] == NFileHeader::NMagic::kMagicForRecord2[1]) ||
+ oldBE;
+
+ if (binMode)
+ {
+ RINOK(ReadBytes(_block + 2, NFileHeader::kRecord2Size - 2, processedSize));
+ if (processedSize != NFileHeader::kRecord2Size - 2)
+ return S_FALSE;
+ item.Align = 2;
+ _blockPos = 2;
+ item.DevMajor = 0;
+ item.DevMinor = ConvertValue(ReadUInt16(), oldBE);
+ item.inode = ConvertValue(ReadUInt16(), oldBE);
+ item.Mode = ConvertValue(ReadUInt16(), oldBE);
+ item.UID = ConvertValue(ReadUInt16(), oldBE);
+ item.GID = ConvertValue(ReadUInt16(), oldBE);
+ item.NumLinks = ConvertValue(ReadUInt16(), oldBE);
+ item.RDevMajor =0;
+ item.RDevMinor = ConvertValue(ReadUInt16(), oldBE);
+ UInt16 timeHigh = ConvertValue(ReadUInt16(), oldBE);
+ UInt16 timeLow = ConvertValue(ReadUInt16(), oldBE);
+ item.MTime = (UInt32(timeHigh) << 16) + timeLow;
+ nameSize = ConvertValue(ReadUInt16(), oldBE);
+ UInt16 sizeHigh = ConvertValue(ReadUInt16(), oldBE);
+ UInt16 sizeLow = ConvertValue(ReadUInt16(), oldBE);
+ item.Size = (UInt32(sizeHigh) << 16) + sizeLow;
+
+ item.ChkSum = 0;
+ item.HeaderSize = GetAlignedSize(
+ nameSize + NFileHeader::kRecord2Size, item.Align);
+ nameSize = item.HeaderSize - NFileHeader::kRecord2Size;
+ }
+ else
+ {
+ RINOK(ReadBytes(_block + 2, 4, processedSize));
+ if (processedSize != 4)
+ return S_FALSE;
+
+ bool magicOK =
+ memcmp(_block, NFileHeader::NMagic::kMagic1, 6) == 0 ||
+ memcmp(_block, NFileHeader::NMagic::kMagic2, 6) == 0;
+ _blockPos = 6;
+ if (magicOK)
+ {
+ RINOK(ReadBytes(_block + 6, NFileHeader::kRecordSize - 6, processedSize));
+ if (processedSize != NFileHeader::kRecordSize - 6)
+ return S_FALSE;
+ item.Align = 4;
+
+ GetFromHex(item.inode);
+ GetFromHex(item.Mode);
+ GetFromHex(item.UID);
+ GetFromHex(item.GID);
+ GetFromHex(item.NumLinks);
+ UInt32 mTime;
+ GetFromHex(mTime);
+ item.MTime = mTime;
+ GetFromHex(item.Size);
+ GetFromHex(item.DevMajor);
+ GetFromHex(item.DevMinor);
+ GetFromHex(item.RDevMajor);
+ GetFromHex(item.RDevMinor);
+ GetFromHex(nameSize);
+ GetFromHex(item.ChkSum);
+ item.HeaderSize = GetAlignedSize(
+ nameSize + NFileHeader::kRecordSize, item.Align);
+ nameSize = item.HeaderSize - NFileHeader::kRecordSize;
+ }
+ else
+ {
+ if (!memcmp(_block, NFileHeader::NMagic::kMagic3, 6) == 0)
+ return S_FALSE;
+ RINOK(ReadBytes(_block + 6, NFileHeader::kOctRecordSize - 6, processedSize));
+ if (processedSize != NFileHeader::kOctRecordSize - 6)
+ return S_FALSE;
+ item.Align = 1;
+ item.DevMajor = 0;
+ GetFromOct6(item.DevMinor);
+ GetFromOct6(item.inode);
+ GetFromOct6(item.Mode);
+ GetFromOct6(item.UID);
+ GetFromOct6(item.GID);
+ GetFromOct6(item.NumLinks);
+ item.RDevMajor = 0;
+ GetFromOct6(item.RDevMinor);
+ UInt32 mTime;
+ GetFromOct11(mTime);
+ item.MTime = mTime;
+ GetFromOct6(nameSize);
+ GetFromOct11(item.Size); // ?????
+ item.HeaderSize = GetAlignedSize(
+ nameSize + NFileHeader::kOctRecordSize, item.Align);
+ nameSize = item.HeaderSize - NFileHeader::kOctRecordSize;
+ }
+ }
+ if (nameSize == 0 || nameSize >= (1 << 27))
+ return E_FAIL;
+ RINOK(ReadBytes(item.Name.GetBuffer(nameSize), nameSize, processedSize));
+ if (processedSize != nameSize)
+ return E_FAIL;
+ item.Name.ReleaseBuffer();
+ if (strcmp(item.Name, NFileHeader::NMagic::kEndName) == 0)
+ return S_OK;
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CInArchive::Skip(UInt64 numBytes)
+{
+ UInt64 newPostion;
+ RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
+ m_Position += numBytes;
+ if (m_Position != newPostion)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT CInArchive::SkipDataRecords(UInt64 dataSize, UInt32 align)
+{
+ while ((dataSize & (align - 1)) != 0)
+ dataSize++;
+ return Skip(dataSize);
+}
+
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CObjectVector<CItemEx> _items;
+ CMyComPtr<IInStream> _stream;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+/*
+enum
+{
+ kpidinode = kpidUserDefined,
+ kpidiChkSum
+};
+*/
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidPosixAttrib, VT_UI4},
+ // { L"inode", kpidinode, VT_UI4}
+ // { L"CheckSum", kpidiChkSum, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ // try
+ {
+ CInArchive archive;
+
+ UInt64 endPos = 0;
+ bool needSetTotal = true;
+
+ if (callback != NULL)
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+
+ RINOK(archive.Open(stream));
+
+ _items.Clear();
+
+ for (;;)
+ {
+ CItemEx item;
+ bool filled;
+ HRESULT result = archive.GetNextItem(filled, item);
+ if (result == S_FALSE)
+ return S_FALSE;
+ if (result != S_OK)
+ return S_FALSE;
+ if (!filled)
+ break;
+ _items.Add(item);
+ archive.SkipDataRecords(item.Size, item.Align);
+ if (callback != NULL)
+ {
+ if (needSetTotal)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos));
+ needSetTotal = false;
+ }
+ if (_items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = item.HeaderPosition;
+ RINOK(callback->SetCompleted(&numFiles, &numBytes));
+ }
+ }
+ }
+ if (_items.Size() == 0)
+ return S_FALSE;
+
+ _stream = stream;
+ }
+ /*
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ */
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItemEx &item = _items[index];
+
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size;
+ break;
+ case kpidMTime:
+ {
+ if (item.MTime != 0)
+ {
+ FILETIME utc;
+ NWindows::NTime::UnixTimeToFileTime(item.MTime, utc);
+ prop = utc;
+ }
+ break;
+ }
+ case kpidPosixAttrib: prop = item.Mode; break;
+ /*
+ case kpidinode: prop = item.inode; break;
+ case kpidiChkSum: prop = item.ChkSum; break;
+ */
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItemEx &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ currentTotalSize += item.Size;
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItemEx &item = _items[index];
+ return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NCpio::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Cpio", L"cpio", 0, 0xED, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Cpio)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp
new file mode 100644
index 000000000..a55e3743d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/CramfsHandler.cpp
@@ -0,0 +1,644 @@
+// CramfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/Alloc.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+namespace NArchive {
+namespace NCramfs {
+
+#define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' }
+
+static const UInt32 kSignatureSize = 16;
+static const char kSignature[kSignatureSize] = SIGNATURE;
+
+static const UInt32 kArcSizeMax = (256 + 16) << 20;
+static const UInt32 kNumFilesMax = (1 << 19);
+static const unsigned kNumDirLevelsMax = (1 << 8);
+
+static const UInt32 kHeaderSize = 0x40;
+static const unsigned kHeaderNameSize = 16;
+static const UInt32 kNodeSize = 12;
+
+static const UInt32 kFlag_FsVer2 = (1 << 0);
+
+static const CUInt32PCharPair k_Flags[] =
+{
+ { 0, "Ver2" },
+ { 1, "SortedDirs" },
+ { 8, "Holes" },
+ { 9, "WrongSignature" },
+ { 10, "ShiftedRootOffset" }
+};
+
+static const unsigned kBlockSizeLog = 12;
+static const UInt32 kBlockSize = 1 << kBlockSizeLog;
+
+/*
+struct CNode
+{
+ UInt16 Mode;
+ UInt16 Uid;
+ UInt32 Size;
+ Byte Gid;
+ UInt32 NameLen;
+ UInt32 Offset;
+
+ void Parse(const Byte *p)
+ {
+ Mode = GetUi16(p);
+ Uid = GetUi16(p + 2);
+ Size = Get32(p + 4) & 0xFFFFFF;
+ Gid = p[7];
+ NameLen = p[8] & 0x3F;
+ Offset = Get32(p + 8) >> 6;
+ }
+};
+*/
+
+#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
+
+static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
+static bool IsDir(const Byte *p, bool be) { return (GetMode(p, be) & 0xF000) == 0x4000; }
+
+static UInt32 GetSize(const Byte *p, bool be)
+{
+ if (be)
+ return GetBe32(p + 4) >> 8;
+ else
+ return GetUi32(p + 4) & 0xFFFFFF;
+}
+
+static UInt32 GetNameLen(const Byte *p, bool be)
+{
+ if (be)
+ return (p[8] & 0xFC);
+ else
+ return (p[8] & 0x3F) << 2;
+}
+
+static UInt32 GetOffset(const Byte *p, bool be)
+{
+ if (be)
+ return (GetBe32(p + 8) & 0x03FFFFFF) << 2;
+ else
+ return GetUi32(p + 8) >> 6 << 2;
+}
+
+struct CItem
+{
+ UInt32 Offset;
+ int Parent;
+};
+
+struct CHeader
+{
+ bool be;
+ UInt32 Size;
+ UInt32 Flags;
+ // UInt32 Future;
+ UInt32 Crc;
+ // UInt32 Edition;
+ UInt32 NumBlocks;
+ UInt32 NumFiles;
+ char Name[kHeaderNameSize];
+
+ bool Parse(const Byte *p)
+ {
+ if (memcmp(p + 16, kSignature, kSignatureSize) != 0)
+ return false;
+ switch(GetUi32(p))
+ {
+ case 0x28CD3D45: be = false; break;
+ case 0x453DCD28: be = true; break;
+ default: return false;
+ }
+ Size = Get32(p + 4);
+ Flags = Get32(p + 8);
+ // Future = Get32(p + 0xC);
+ Crc = Get32(p + 0x20);
+ // Edition = Get32(p + 0x24);
+ NumBlocks = Get32(p + 0x28);
+ NumFiles = Get32(p + 0x2C);
+ memcpy(Name, p + 0x30, kHeaderNameSize);
+ return true;
+ }
+
+ bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; }
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CRecordVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ Byte *_data;
+ UInt32 _size;
+ UInt32 _headersSize;
+ AString _errorMessage;
+ CHeader _h;
+
+ // Current file
+
+ NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+ CMyComPtr<ICompressCoder> _zlibDecoder;
+
+ CBufInStream *_inStreamSpec;
+ CMyComPtr<ISequentialInStream> _inStream;
+
+ CBufPtrSeqOutStream *_outStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outStream;
+
+ UInt32 _curBlocksOffset;
+ UInt32 _curNumBlocks;
+
+ HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level);
+ HRESULT Open2(IInStream *inStream);
+ AString GetPath(int index) const;
+ bool GetPackSize(int index, UInt32 &res) const;
+ void Free();
+public:
+ CHandler(): _data(0) {}
+ ~CHandler() { Free(); }
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+};
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI4},
+ { NULL, kpidPackSize, VT_UI4},
+ { NULL, kpidPosixAttrib, VT_UI4}
+ // { NULL, kpidOffset, VT_UI4}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidName, VT_BSTR},
+ { NULL, kpidBigEndian, VT_BOOL},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI4},
+ { NULL, kpidHeadersSize, VT_UI4},
+ { NULL, kpidNumSubFiles, VT_UI4},
+ { NULL, kpidNumBlocks, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level)
+{
+ const Byte *p = _data + baseOffset;
+ bool be = _h.be;
+ if (!IsDir(p, be))
+ return S_OK;
+ UInt32 offset = GetOffset(p, be);
+ UInt32 size = GetSize(p, be);
+ if (offset == 0 && size == 0)
+ return S_OK;
+ UInt32 end = offset + size;
+ if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax)
+ return S_FALSE;
+ if (end > _headersSize)
+ _headersSize = end;
+
+ int startIndex = _items.Size();
+
+ while (size != 0)
+ {
+ if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax)
+ return S_FALSE;
+ CItem item;
+ item.Parent = parent;
+ item.Offset = offset;
+ _items.Add(item);
+ UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be);
+ if (size < nodeLen)
+ return S_FALSE;
+ offset += nodeLen;
+ size -= nodeLen;
+ }
+
+ int endIndex = _items.Size();
+ for (int i = startIndex; i < endIndex; i++)
+ {
+ RINOK(OpenDir(i, _items[i].Offset, level + 1));
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *inStream)
+{
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
+ if (!_h.Parse(buf))
+ return S_FALSE;
+ if (_h.IsVer2())
+ {
+ if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax)
+ return S_FALSE;
+ }
+ else
+ {
+ UInt64 size;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &size));
+ if (size > kArcSizeMax)
+ return S_FALSE;
+ _h.Size = (UInt32)size;
+ RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL));
+ }
+ _data = (Byte *)MidAlloc(_h.Size);
+ if (_data == 0)
+ return E_OUTOFMEMORY;
+ memcpy(_data, buf, kHeaderSize);
+ size_t processed = _h.Size - kHeaderSize;
+ RINOK(ReadStream(inStream, _data + kHeaderSize, &processed));
+ if (processed < kNodeSize)
+ return S_FALSE;
+ _size = kHeaderSize + (UInt32)processed;
+ if (_size != _h.Size)
+ _errorMessage = "Unexpected end of archive";
+ else
+ {
+ SetUi32(_data + 0x20, 0);
+ if (_h.IsVer2())
+ if (CrcCalc(_data, _h.Size) != _h.Crc)
+ _errorMessage = "CRC error";
+ }
+ if (_h.IsVer2())
+ _items.Reserve(_h.NumFiles - 1);
+ return OpenDir(-1, kHeaderSize, 0);
+}
+
+AString CHandler::GetPath(int index) const
+{
+ unsigned len = 0;
+ int indexMem = index;
+ do
+ {
+ const CItem &item = _items[index];
+ index = item.Parent;
+ const Byte *p = _data + item.Offset;
+ unsigned size = GetNameLen(p, _h.be);
+ p += kNodeSize;
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ len += i + 1;
+ }
+ while (index >= 0);
+ len--;
+
+ AString path;
+ char *dest = path.GetBuffer(len) + len;
+ index = indexMem;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ index = item.Parent;
+ const Byte *p = _data + item.Offset;
+ unsigned size = GetNameLen(p, _h.be);
+ p += kNodeSize;
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ dest -= i;
+ memcpy(dest, p, i);
+ if (index < 0)
+ break;
+ *(--dest) = CHAR_PATH_SEPARATOR;
+ }
+ path.ReleaseBuffer(len);
+ return path;
+}
+
+bool CHandler::GetPackSize(int index, UInt32 &res) const
+{
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+ bool be = _h.be;
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ return false;
+ UInt32 numBlocks = (GetSize(p, be) + kBlockSize - 1) >> kBlockSizeLog;
+ UInt32 start = offset + numBlocks * 4;
+ if (start > _size)
+ return false;
+ UInt32 end = Get32(_data + start - 4);
+ if (end < start)
+ return false;
+ res = end - start;
+ return true;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ RINOK(Open2(stream));
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::Free()
+{
+ MidFree(_data);
+ _data = 0;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _headersSize = 0;
+ _items.Clear();
+ _stream.Release();
+ _errorMessage.Empty();
+ Free();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidName:
+ {
+ char dest[kHeaderNameSize + 4];
+ memcpy(dest, _h.Name, kHeaderNameSize);
+ dest[kHeaderNameSize] = 0;
+ prop = dest;
+ break;
+ }
+ case kpidBigEndian: prop = _h.be; break;
+ case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
+ case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break;
+ case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break;
+ case kpidPhySize: if (_h.IsVer2()) prop = _h.Size; break;
+ case kpidHeadersSize: prop = _headersSize; break;
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+ bool be = _h.be;
+ bool isDir = IsDir(p, be);
+ switch(propID)
+ {
+ case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
+ case kpidIsDir: prop = isDir; break;
+ // case kpidOffset: prop = (UInt32)GetOffset(p, be); break;
+ case kpidSize: if (!isDir) prop = GetSize(p, be); break;
+ case kpidPackSize:
+ if (!isDir)
+ {
+ UInt32 size;
+ if (GetPackSize(index, size))
+ prop = size;
+ }
+ break;
+ case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CCramfsInStream: public CCachedInStream
+{
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+public:
+ CHandler *Handler;
+};
+
+HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ return Handler->ReadBlock(blockIndex, dest, blockSize);
+}
+
+HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ if (!_zlibDecoder)
+ {
+ _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+ _zlibDecoder = _zlibDecoderSpec;
+ }
+ if (!_inStream)
+ {
+ _inStreamSpec = new CBufInStream();
+ _inStream = _inStreamSpec;
+ }
+ if (!_outStream)
+ {
+ _outStreamSpec = new CBufPtrSeqOutStream();
+ _outStream = _outStreamSpec;
+ }
+ bool be = _h.be;
+ const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4);
+ UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4));
+ UInt32 end = Get32(p);
+ if (end < start || end > _size)
+ return S_FALSE;
+ UInt32 inSize = end - start;
+ _inStreamSpec->Init(_data + start, inSize);
+ _outStreamSpec->Init(dest, blockSize);
+ RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL));
+ return (_zlibDecoderSpec->GetInputProcessedSize() == inSize &&
+ _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ bool be = _h.be;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset;
+ if (!IsDir(p, be))
+ totalSize += GetSize(p, be);
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ const Byte *p = _data + item.Offset;
+
+ if (IsDir(p, be))
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ UInt32 curSize = GetSize(p, be);
+ totalSize += curSize;
+ UInt32 packSize;
+ if (GetPackSize(index, packSize))
+ totalPackSize += packSize;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ curSize = 0;
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ CMyComPtr<IInStream> inStream;
+ HRESULT hres = GetStream(index, &inSeqStream);
+ if (inSeqStream)
+ inSeqStream.QueryInterface(IID_IInStream, &inStream);
+ if (hres == E_OUTOFMEMORY)
+ return E_OUTOFMEMORY;
+ if (hres == S_FALSE || !inStream)
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres != S_OK && hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ if (copyCoderSpec->TotalSize == curSize && hres == S_OK)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+
+ bool be = _h.be;
+ if (IsDir(p, be))
+ return E_FAIL;
+
+ UInt32 size = GetSize(p, be);
+ UInt32 numBlocks = (size + kBlockSize - 1) >> kBlockSizeLog;
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ {
+ if (offset != 0)
+ return S_FALSE;
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Init(NULL, 0);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+
+ if (offset + numBlocks * 4 > _size)
+ return S_FALSE;
+ UInt32 prev = offset;
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt32 next = Get32(_data + offset + i * 4);
+ if (next < prev || next > _size)
+ return S_FALSE;
+ prev = next;
+ }
+
+ CCramfsInStream *streamSpec = new CCramfsInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ _curNumBlocks = numBlocks;
+ _curBlocksOffset = offset;
+ streamSpec->Handler = this;
+ if (!streamSpec->Alloc(kBlockSizeLog, 21 - kBlockSizeLog))
+ return E_OUTOFMEMORY;
+ streamSpec->Init(size);
+ *stream = streamTemp.Detach();
+
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NCramfs::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"CramFS", L"cramfs", 0, 0xD3, SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+
+REGISTER_ARC(Cramfs)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp
new file mode 100644
index 000000000..82d2cde88
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/DebHandler.cpp
@@ -0,0 +1,413 @@
+// DebHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NDeb {
+
+namespace NHeader
+{
+ const int kSignatureLen = 8;
+
+ const char *kSignature = "!<arch>\n";
+
+ const int kNameSize = 16;
+ const int kTimeSize = 12;
+ const int kModeSize = 8;
+ const int kSizeSize = 10;
+
+ /*
+ struct CHeader
+ {
+ char Name[kNameSize];
+ char MTime[kTimeSize];
+ char Number0[6];
+ char Number1[6];
+ char Mode[kModeSize];
+ char Size[kSizeSize];
+ char Quote;
+ char NewLine;
+ };
+ */
+ const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1;
+}
+
+struct CItem
+{
+ AString Name;
+ UInt64 Size;
+ UInt32 MTime;
+ UInt32 Mode;
+
+ UInt64 HeaderPos;
+ UInt64 GetDataPos() const { return HeaderPos + NHeader::kHeaderSize; };
+ // UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; };
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+
+ HRESULT GetNextItemReal(bool &filled, CItem &itemInfo);
+public:
+ UInt64 m_Position;
+ HRESULT Open(IInStream *inStream);
+ HRESULT GetNextItem(bool &filled, CItem &itemInfo);
+ HRESULT SkipData(UInt64 dataSize);
+};
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
+ char signature[NHeader::kSignatureLen];
+ RINOK(ReadStream_FALSE(inStream, signature, NHeader::kSignatureLen));
+ m_Position += NHeader::kSignatureLen;
+ if (memcmp(signature, NHeader::kSignature, NHeader::kSignatureLen) != 0)
+ return S_FALSE;
+ m_Stream = inStream;
+ return S_OK;
+}
+
+static void MyStrNCpy(char *dest, const char *src, int size)
+{
+ for (int i = 0; i < size; i++)
+ {
+ char c = src[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+}
+
+static bool OctalToNumber(const char *s, int size, UInt64 &res)
+{
+ char sz[32];
+ MyStrNCpy(sz, s, size);
+ sz[size] = 0;
+ const char *end;
+ int i;
+ for (i = 0; sz[i] == ' '; i++);
+ res = ConvertOctStringToUInt64(sz + i, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool OctalToNumber32(const char *s, int size, UInt32 &res)
+{
+ UInt64 res64;
+ if (!OctalToNumber(s, size, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+static bool DecimalToNumber(const char *s, int size, UInt64 &res)
+{
+ char sz[32];
+ MyStrNCpy(sz, s, size);
+ sz[size] = 0;
+ const char *end;
+ int i;
+ for (i = 0; sz[i] == ' '; i++);
+ res = ConvertStringToUInt64(sz + i, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool DecimalToNumber32(const char *s, int size, UInt32 &res)
+{
+ UInt64 res64;
+ if (!DecimalToNumber(s, size, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+
+HRESULT CInArchive::GetNextItemReal(bool &filled, CItem &item)
+{
+ filled = false;
+
+ char header[NHeader::kHeaderSize];
+ const char *cur = header;
+
+ size_t processedSize = sizeof(header);
+ item.HeaderPos = m_Position;
+ RINOK(ReadStream(m_Stream, header, &processedSize));
+ if (processedSize != sizeof(header))
+ return S_OK;
+ m_Position += processedSize;
+
+ char tempString[NHeader::kNameSize + 1];
+ MyStrNCpy(tempString, cur, NHeader::kNameSize);
+ cur += NHeader::kNameSize;
+ tempString[NHeader::kNameSize] = '\0';
+ item.Name = tempString;
+ item.Name.Trim();
+
+ for (int i = 0; i < item.Name.Length(); i++)
+ if (((Byte)item.Name[i]) < 0x20)
+ return S_FALSE;
+
+ RIF(DecimalToNumber32(cur, NHeader::kTimeSize, item.MTime));
+ cur += NHeader::kTimeSize;
+
+ cur += 6 + 6;
+
+ RIF(OctalToNumber32(cur, NHeader::kModeSize, item.Mode));
+ cur += NHeader::kModeSize;
+
+ RIF(DecimalToNumber(cur, NHeader::kSizeSize, item.Size));
+ cur += NHeader::kSizeSize;
+
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
+{
+ for (;;)
+ {
+ RINOK(GetNextItemReal(filled, item));
+ if (!filled)
+ return S_OK;
+ if (item.Name.Compare("debian-binary") != 0)
+ return S_OK;
+ if (item.Size != 4)
+ return S_OK;
+ SkipData(item.Size);
+ }
+}
+
+HRESULT CInArchive::SkipData(UInt64 dataSize)
+{
+ return m_Stream->Seek((dataSize + 1) & (~((UInt64)0x1)), STREAM_SEEK_CUR, &m_Position);
+}
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CObjectVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ Int32 _mainSubfile;
+ UInt64 _phySize;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidPhySize, VT_UI8}
+};
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ {
+ _mainSubfile = -1;
+ CInArchive archive;
+ if (archive.Open(stream) != S_OK)
+ return S_FALSE;
+ _items.Clear();
+
+ if (openArchiveCallback != NULL)
+ {
+ RINOK(openArchiveCallback->SetTotal(NULL, NULL));
+ UInt64 numFiles = _items.Size();
+ RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
+ }
+
+ for (;;)
+ {
+ CItem item;
+ bool filled;
+ HRESULT result = archive.GetNextItem(filled, item);
+ if (result == S_FALSE)
+ return S_FALSE;
+ if (result != S_OK)
+ return S_FALSE;
+ if (!filled)
+ break;
+ if (item.Name.Left(5) == "data.")
+ _mainSubfile = _items.Size();
+ _items.Add(item);
+ archive.SkipData(item.Size);
+ if (openArchiveCallback != NULL)
+ {
+ UInt64 numFiles = _items.Size();
+ RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
+ }
+ }
+ _stream = stream;
+ _phySize = archive.m_Position;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _items.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: prop = _phySize; break;
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+
+ switch(propID)
+ {
+ case kpidPath: prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = item.Size;
+ break;
+ case kpidMTime:
+ {
+ if (item.MTime != 0)
+ {
+ FILETIME fileTime;
+ NTime::UnixTimeToFileTime(item.MTime, fileTime);
+ prop = fileTime;
+ }
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ currentTotalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 };
+
+REGISTER_ARC(Deb)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/DeflateProps.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/DeflateProps.cpp
new file mode 100644
index 000000000..8498e0565
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/DeflateProps.cpp
@@ -0,0 +1,118 @@
+// DeflateProps.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/PropVariant.h"
+
+#include "Common/ParseProperties.h"
+
+#include "DeflateProps.h"
+
+namespace NArchive {
+
+static const UInt32 kAlgo1 = 0;
+static const UInt32 kAlgo5 = 1;
+
+static const UInt32 kPasses1 = 1;
+static const UInt32 kPasses7 = 3;
+static const UInt32 kPasses9 = 10;
+
+static const UInt32 kFb1 = 32;
+static const UInt32 kFb7 = 64;
+static const UInt32 kFb9 = 128;
+
+void CDeflateProps::Normalize()
+{
+ UInt32 level = Level;
+ if (level == 0xFFFFFFFF)
+ level = 5;
+
+ if (Algo == 0xFFFFFFFF)
+ Algo = (level >= 5 ?
+ kAlgo5 :
+ kAlgo1);
+
+ if (NumPasses == 0xFFFFFFFF)
+ NumPasses =
+ (level >= 9 ? kPasses9 :
+ (level >= 7 ? kPasses7 :
+ kPasses1));
+ if (Fb == 0xFFFFFFFF)
+ Fb =
+ (level >= 9 ? kFb9 :
+ (level >= 7 ? kFb7 :
+ kFb1));
+}
+
+HRESULT CDeflateProps::SetCoderProperties(ICompressSetCoderProperties *setCoderProperties)
+{
+ Normalize();
+
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ Algo,
+ NumPasses,
+ Fb,
+ Mc
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumPasses,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinderCycles
+ };
+ int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ if (!McDefined)
+ numProps--;
+ return setCoderProperties->SetCoderProperties(propIDs, props, numProps);
+}
+
+HRESULT CDeflateProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ Init();
+ for (int i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &prop = values[i];
+ if (name[0] == L'X')
+ {
+ UInt32 a = 9;
+ RINOK(ParsePropValue(name.Mid(1), prop, a));
+ Level = a;
+ }
+ else if (name.Left(1) == L"A")
+ {
+ UInt32 a = kAlgo5;
+ RINOK(ParsePropValue(name.Mid(1), prop, a));
+ Algo = a;
+ }
+ else if (name.Left(4) == L"PASS")
+ {
+ UInt32 a = kPasses9;
+ RINOK(ParsePropValue(name.Mid(4), prop, a));
+ NumPasses = a;
+ }
+ else if (name.Left(2) == L"FB")
+ {
+ UInt32 a = kFb9;
+ RINOK(ParsePropValue(name.Mid(2), prop, a));
+ Fb = a;
+ }
+ else if (name.Left(2) == L"MC")
+ {
+ UInt32 a = 0xFFFFFFFF;
+ RINOK(ParsePropValue(name.Mid(2), prop, a));
+ Mc = a;
+ McDefined = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/DeflateProps.h b/src/libs/7zip/unix/CPP/7zip/Archive/DeflateProps.h
new file mode 100644
index 000000000..e05a9d4aa
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/DeflateProps.h
@@ -0,0 +1,35 @@
+// DeflateProps.h
+
+#ifndef __DEFLATE_PROPS_H
+#define __DEFLATE_PROPS_H
+
+#include "../ICoder.h"
+
+namespace NArchive {
+
+class CDeflateProps
+{
+ UInt32 Level;
+ UInt32 NumPasses;
+ UInt32 Fb;
+ UInt32 Algo;
+ UInt32 Mc;
+ bool McDefined;
+
+ void Init()
+ {
+ Level = NumPasses = Fb = Algo = Mc = 0xFFFFFFFF;
+ McDefined = false;
+ }
+ void Normalize();
+public:
+ CDeflateProps() { Init(); }
+ bool IsMaximum() const { return Algo > 0; }
+
+ HRESULT SetCoderProperties(ICompressSetCoderProperties *setCoderProperties);
+ HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/DllExports2.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/DllExports2.cpp
new file mode 100644
index 000000000..1febea714
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/DllExports2.cpp
@@ -0,0 +1,76 @@
+// DLLExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+
+#if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+#include "../../../C/Alloc.h"
+#endif
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/NtCheck.h"
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#include "IArchive.h"
+
+HINSTANCE g_hInstance;
+
+#define NT_CHECK_FAIL_ACTION return FALSE;
+
+#ifdef _WIN32
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hInstance = (HINSTANCE)hInstance;
+ NT_CHECK;
+ }
+ return TRUE;
+}
+#endif
+
+DEFINE_GUID(CLSID_CArchiveHandler,
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ // COM_TRY_BEGIN
+ *outObject = 0;
+ if (*iid == IID_ICompressCoder || *iid == IID_ICompressCoder2 || *iid == IID_ICompressFilter)
+ {
+ return CreateCoder(clsid, iid, outObject);
+ }
+ else
+ {
+ return CreateArchiver(clsid, iid, outObject);
+ }
+ // COM_TRY_END
+}
+
+STDAPI SetLargePageMode()
+{
+ #if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+ SetLargePageSize();
+ #endif
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/DmgHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/DmgHandler.cpp
new file mode 100644
index 000000000..5040d5182
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/DmgHandler.cpp
@@ -0,0 +1,918 @@
+// DmgHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyXml.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BZip2Decoder.h"
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+// #define DMG_SHOW_RAW
+
+// #include <stdio.h>
+#define PRF(x) // x
+
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+static int Base64ToByte(char c)
+{
+ if (c >= 'A' && c <= 'Z') return c - 'A';
+ if (c >= 'a' && c <= 'z') return c - 'a' + 26;
+ if (c >= '0' && c <= '9') return c - '0' + 52;
+ if (c == '+') return 62;
+ if (c == '/') return 63;
+ if (c == '=') return 0;
+ return -1;
+}
+
+static int Base64ToBin(Byte *dest, const char *src, int srcLen)
+{
+ int srcPos = 0;
+ int destPos = 0;
+ while (srcPos < srcLen)
+ {
+ Byte buf[4];
+ int filled = 0;
+ while (srcPos < srcLen)
+ {
+ int n = Base64ToByte(src[srcPos++]);
+ if (n >= 0)
+ {
+ buf[filled++] = (Byte)n;
+ if (filled == 4)
+ break;
+ }
+ }
+ if (filled >= 2) { if (dest) dest[destPos] = (buf[0] << 2) | (buf[1] >> 4); destPos++; }
+ if (filled >= 3) { if (dest) dest[destPos] = (buf[1] << 4) | (buf[2] >> 2); destPos++; }
+ if (filled >= 4) { if (dest) dest[destPos] = (buf[2] << 6) | (buf[3] ); destPos++; }
+ }
+ return destPos;
+}
+
+static UString GetSizeString(UInt64 value)
+{
+ wchar_t s[32];
+ wchar_t c;
+ if (value < (UInt64)20000) c = 0;
+ else if (value < ((UInt64)20000 << 10)) { value >>= 10; c = L'K'; }
+ else if (value < ((UInt64)20000 << 20)) { value >>= 20; c = L'M'; }
+ else { value >>= 30; c = L'G'; }
+ ConvertUInt64ToString(value, s);
+ int p = MyStringLen(s);
+ s[p++] = c;
+ s[p++] = L'\0';
+ return s;
+}
+
+namespace NArchive {
+namespace NDmg {
+
+struct CBlock
+{
+ UInt32 Type;
+ UInt64 UnpPos;
+ UInt64 UnpSize;
+ UInt64 PackPos;
+ UInt64 PackSize;
+
+ UInt64 GetNextPackOffset() const { return PackPos + PackSize; }
+};
+
+struct CFile
+{
+ CByteBuffer Raw;
+ UInt64 StartPos;
+ CRecordVector<CBlock> Blocks;
+ UInt64 GetUnpackSize() const
+ {
+ UInt64 size = 0;
+ for (int i = 0; i < Blocks.Size(); i++)
+ size += Blocks[i].UnpSize;
+ return size;
+ };
+ UInt64 GetPackSize() const
+ {
+ UInt64 size = 0;
+ for (int i = 0; i < Blocks.Size(); i++)
+ size += Blocks[i].PackSize;
+ return size;
+ };
+
+ AString Name;
+};
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+
+ AString _xml;
+ CObjectVector<CFile> _files;
+ CRecordVector<int> _fileIndices;
+
+ HRESULT Open2(IInStream *stream);
+ HRESULT Extract(IInStream *stream);
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+const UInt32 kXmlSizeMax = ((UInt32)1 << 31) - (1 << 14);
+
+enum
+{
+ METHOD_ZERO_0 = 0,
+ METHOD_COPY = 1,
+ METHOD_ZERO_2 = 2,
+ METHOD_ADC = 0x80000004,
+ METHOD_ZLIB = 0x80000005,
+ METHOD_BZIP2 = 0x80000006,
+ METHOD_DUMMY = 0x7FFFFFFE,
+ METHOD_END = 0xFFFFFFFF
+};
+
+struct CMethodStat
+{
+ UInt32 NumBlocks;
+ UInt64 PackSize;
+ UInt64 UnpSize;
+ CMethodStat(): NumBlocks(0), PackSize(0), UnpSize(0) {}
+};
+
+struct CMethods
+{
+ CRecordVector<CMethodStat> Stats;
+ CRecordVector<UInt32> Types;
+ void Update(const CFile &file);
+ UString GetString() const;
+};
+
+void CMethods::Update(const CFile &file)
+{
+ for (int i = 0; i < file.Blocks.Size(); i++)
+ {
+ const CBlock &b = file.Blocks[i];
+ int index = Types.FindInSorted(b.Type);
+ if (index < 0)
+ {
+ index = Types.AddToUniqueSorted(b.Type);
+ Stats.Insert(index, CMethodStat());
+ }
+ CMethodStat &m = Stats[index];
+ m.PackSize += b.PackSize;
+ m.UnpSize += b.UnpSize;
+ m.NumBlocks++;
+ }
+}
+
+UString CMethods::GetString() const
+{
+ UString res;
+ for (int i = 0; i < Types.Size(); i++)
+ {
+ if (i != 0)
+ res += L' ';
+ wchar_t buf[32];
+ const wchar_t *s;
+ const CMethodStat &m = Stats[i];
+ bool showPack = true;
+ UInt32 type = Types[i];
+ switch(type)
+ {
+ case METHOD_ZERO_0: s = L"zero0"; showPack = (m.PackSize != 0); break;
+ case METHOD_ZERO_2: s = L"zero2"; showPack = (m.PackSize != 0); break;
+ case METHOD_COPY: s = L"copy"; showPack = (m.UnpSize != m.PackSize); break;
+ case METHOD_ADC: s = L"adc"; break;
+ case METHOD_ZLIB: s = L"zlib"; break;
+ case METHOD_BZIP2: s = L"bzip2"; break;
+ default: ConvertUInt64ToString(type, buf); s = buf;
+ }
+ res += s;
+ if (m.NumBlocks != 1)
+ {
+ res += L'[';
+ ConvertUInt64ToString(m.NumBlocks, buf);
+ res += buf;
+ res += L']';
+ }
+ res += L'-';
+ res += GetSizeString(m.UnpSize);
+ if (showPack)
+ {
+ res += L'-';
+ res += GetSizeString(m.PackSize);
+ }
+ }
+ return res;
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidNumBlocks, VT_UI4}
+};
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ CMethods m;
+ for (int i = 0; i < _files.Size(); i++)
+ m.Update(_files[i]);
+ prop = m.GetString();
+ break;
+ }
+ case kpidNumBlocks:
+ {
+ UInt64 numBlocks = 0;
+ for (int i = 0; i < _files.Size(); i++)
+ numBlocks += _files[i].Blocks.Size();
+ prop = numBlocks;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+IMP_IInArchive_ArcProps
+
+static int FindKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag)
+{
+ for (int i = 0; i + 1 < item.SubItems.Size(); i++)
+ {
+ const CXmlItem &si = item.SubItems[i];
+ if (si.IsTagged("key") && si.GetSubString() == key && item.SubItems[i + 1].IsTagged(nextTag))
+ return i + 1;
+ }
+ return -1;
+}
+
+static AString GetStringFromKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag)
+{
+ int index = FindKeyPair(item, key, nextTag);
+ if (index >= 0)
+ return item.SubItems[index].GetSubString();
+ return AString();
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ const int HEADER_SIZE = 0x1E0;
+
+ UInt64 headerPos;
+ RINOK(stream->Seek(-HEADER_SIZE, STREAM_SEEK_END, &headerPos));
+ Byte buf[HEADER_SIZE];
+ RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE));
+ UInt64 address1 = Get64(buf + 0);
+ UInt64 address2 = Get64(buf + 0xB8);
+ UInt64 size64 = Get64(buf + 0xC0);
+ if (address1 != address2 || size64 >= kXmlSizeMax || size64 == 0 ||
+ address1 >= headerPos || address1 + size64 > headerPos)
+ return S_FALSE;
+ RINOK(stream->Seek(address1, STREAM_SEEK_SET, NULL));
+ size_t size = (size_t)size64;
+
+ char *ss = _xml.GetBuffer((int)size + 1);
+ RINOK(ReadStream_FALSE(stream, ss, size));
+ ss[size] = 0;
+ _xml.ReleaseBuffer();
+
+ CXml xml;
+ if (!xml.Parse(_xml))
+ return S_FALSE;
+ if (xml.Root.Name != "plist")
+ return S_FALSE;
+
+ int dictIndex = xml.Root.FindSubTag("dict");
+ if (dictIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &dictItem = xml.Root.SubItems[dictIndex];
+ int rfDictIndex = FindKeyPair(dictItem, "resource-fork", "dict");
+ if (rfDictIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &rfDictItem = dictItem.SubItems[rfDictIndex];
+ int arrIndex = FindKeyPair(rfDictItem, "blkx", "array");
+ if (arrIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex];
+
+ int i;
+ for (i = 0; i < arrItem.SubItems.Size(); i++)
+ {
+ const CXmlItem &item = arrItem.SubItems[i];
+ if (!item.IsTagged("dict"))
+ continue;
+
+ CFile file;
+ file.StartPos = 0;
+
+ int destLen;
+ {
+ AString dataString;
+ AString name = GetStringFromKeyPair(item, "Name", "string");
+ if (name.IsEmpty())
+ name = GetStringFromKeyPair(item, "CFName", "string");
+ file.Name = name;
+ dataString = GetStringFromKeyPair(item, "Data", "data");
+
+ destLen = Base64ToBin(NULL, dataString, dataString.Length());
+ file.Raw.SetCapacity(destLen);
+ Base64ToBin(file.Raw, dataString, dataString.Length());
+ }
+
+ if (destLen > 0xCC && Get32(file.Raw) == 0x6D697368)
+ {
+ PRF(printf("\n\n index = %d", _files.Size()));
+ const int kRecordSize = 40;
+ for (int offset = 0xCC; offset + kRecordSize <= destLen; offset += kRecordSize)
+ {
+ const Byte *p = (const Byte *)file.Raw + offset;
+ CBlock b;
+ b.Type = Get32(p);
+ if (b.Type == METHOD_END)
+ break;
+ if (b.Type == METHOD_DUMMY)
+ continue;
+
+ b.UnpPos = Get64(p + 0x08) << 9;
+ b.UnpSize = Get64(p + 0x10) << 9;
+ b.PackPos = Get64(p + 0x18);
+ b.PackSize = Get64(p + 0x20);
+
+ file.Blocks.Add(b);
+
+ PRF(printf("\nType=%8x m[1]=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x",
+ b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize));
+ }
+ }
+ int itemIndex = _files.Add(file);
+ if (file.Blocks.Size() > 0)
+ {
+ // if (file.Name.Find("HFS") >= 0)
+ _fileIndices.Add(itemIndex);
+ }
+ }
+
+ // PackPos for each new file is 0 in some DMG files. So we use additional StartPos
+
+ bool allStartAreZeros = true;
+ for (i = 0; i < _files.Size(); i++)
+ {
+ const CFile &file = _files[i];
+ if (!file.Blocks.IsEmpty() && file.Blocks[0].PackPos != 0)
+ allStartAreZeros = false;
+ }
+ UInt64 startPos = 0;
+ if (allStartAreZeros)
+ {
+ for (i = 0; i < _files.Size(); i++)
+ {
+ CFile &file = _files[i];
+ file.StartPos = startPos;
+ if (!file.Blocks.IsEmpty())
+ startPos += file.Blocks.Back().GetNextPackOffset();
+ }
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ if (Open2(stream) != S_OK)
+ return S_FALSE;
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _fileIndices.Clear();
+ _files.Clear();
+ _xml.Empty();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _fileIndices.Size()
+ #ifdef DMG_SHOW_RAW
+ + _files.Size() + 1;
+ #endif
+ ;
+ return S_OK;
+}
+
+#define RAW_PREFIX L"raw" WSTRING_PATH_SEPARATOR
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ #ifdef DMG_SHOW_RAW
+ if ((int)index == _fileIndices.Size())
+ {
+ switch(propID)
+ {
+ case kpidPath:
+ prop = RAW_PREFIX L"a.xml";
+ break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)_xml.Length();
+ break;
+ }
+ }
+ else if ((int)index > _fileIndices.Size())
+ {
+ int rawIndex = (int)index - (_fileIndices.Size() + 1);
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ wchar_t s[32] = RAW_PREFIX;
+ ConvertUInt64ToString(rawIndex, s + MyStringLen(s));
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)_files[rawIndex].Raw.GetCapacity();
+ break;
+ }
+ }
+ else
+ #endif
+ {
+ int itemIndex = _fileIndices[index];
+ const CFile &item = _files[itemIndex];
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ CMethods m;
+ m.Update(item);
+ UString resString = m.GetString();
+ if (!resString.IsEmpty())
+ prop = resString;
+ break;
+ }
+
+ // case kpidExtension: prop = L"hfs"; break;
+
+ case kpidPath:
+ {
+ // break;
+ UString name;
+ wchar_t s[32];
+ ConvertUInt64ToString(index, s);
+ name = s;
+ int num = 10;
+ int numDigits;
+ for (numDigits = 1; num < _fileIndices.Size(); numDigits++)
+ num *= 10;
+ while (name.Length() < numDigits)
+ name = L'0' + name;
+
+ AString subName;
+ int pos1 = item.Name.Find('(');
+ if (pos1 >= 0)
+ {
+ pos1++;
+ int pos2 = item.Name.Find(')', pos1);
+ if (pos2 >= 0)
+ {
+ subName = item.Name.Mid(pos1, pos2 - pos1);
+ pos1 = subName.Find(':');
+ if (pos1 >= 0)
+ subName = subName.Left(pos1);
+ }
+ }
+ subName.Trim();
+ if (!subName.IsEmpty())
+ {
+ if (subName == "Apple_HFS")
+ subName = "hfs";
+ else if (subName == "Apple_HFSX")
+ subName = "hfsx";
+ else if (subName == "Apple_Free")
+ subName = "free";
+ else if (subName == "DDM")
+ subName = "ddm";
+ UString name2;
+ ConvertUTF8ToUnicode(subName, name2);
+ name += L'.';
+ name += name2;
+ }
+ else
+ {
+ UString name2;
+ ConvertUTF8ToUnicode(item.Name, name2);
+ if (!name2.IsEmpty())
+ name += L" - ";
+ name += name2;
+ }
+ prop = name;
+ break;
+ }
+ case kpidComment:
+ {
+ UString name;
+ ConvertUTF8ToUnicode(item.Name, name);
+ prop = name;
+ break;
+ }
+
+ case kpidSize: prop = item.GetUnpackSize(); break;
+ case kpidPackSize: prop = item.GetPackSize(); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CAdcDecoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ CInBuffer m_InStream;
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InStream.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CAdcDecoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(CodeReal)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+};
+
+STDMETHODIMP CAdcDecoder::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ if (!m_OutWindowStream.Create(1 << 18))
+ return E_OUTOFMEMORY;
+ if (!m_InStream.Create(1 << 18))
+ return E_OUTOFMEMORY;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InStream.SetStream(inStream);
+ m_InStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ const UInt32 kStep = (1 << 20);
+ UInt64 nextLimit = kStep;
+
+ UInt64 pos = 0;
+ while (pos < *outSize)
+ {
+ if (pos > nextLimit && progress)
+ {
+ UInt64 packSize = m_InStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ nextLimit += kStep;
+ }
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ UInt64 rem = *outSize - pos;
+ if (b & 0x80)
+ {
+ unsigned num = (b & 0x7F) + 1;
+ if (num > rem)
+ return S_FALSE;
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ m_OutWindowStream.PutByte(b);
+ }
+ pos += num;
+ continue;
+ }
+ Byte b1;
+ if (!m_InStream.ReadByte(b1))
+ return S_FALSE;
+
+ UInt32 len, distance;
+
+ if (b & 0x40)
+ {
+ len = ((UInt32)b & 0x3F) + 4;
+ Byte b2;
+ if (!m_InStream.ReadByte(b2))
+ return S_FALSE;
+ distance = ((UInt32)b1 << 8) + b2;
+ }
+ else
+ {
+ b &= 0x3F;
+ len = ((UInt32)b >> 2) + 3;
+ distance = (((UInt32)b & 3) << 8) + b1;
+ }
+
+ if (distance >= pos || len > rem)
+ return S_FALSE;
+ m_OutWindowStream.CopyBlock(distance, len);
+ pos += len;
+ }
+ if (*inSize != m_InStream.GetProcessedSize())
+ return S_FALSE;
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CAdcDecoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _files.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ int index = (int)(allFilesMode ? i : indices[i]);
+ #ifdef DMG_SHOW_RAW
+ if (index == _fileIndices.Size())
+ totalSize += _xml.Length();
+ else if (index > _fileIndices.Size())
+ totalSize += _files[index - (_fileIndices.Size() + 1)].Raw.GetCapacity();
+ else
+ #endif
+ totalSize += _files[_fileIndices[index]].GetUnpackSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentPackTotal = 0;
+ UInt64 currentUnpTotal = 0;
+ UInt64 currentPackSize = 0;
+ UInt64 currentUnpSize = 0;
+
+ const UInt32 kZeroBufSize = (1 << 14);
+ CByteBuffer zeroBuf;
+ zeroBuf.SetCapacity(kZeroBufSize);
+ memset(zeroBuf, 0, kZeroBufSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+ CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ CAdcDecoder *adcCoderSpec = new CAdcDecoder();
+ CMyComPtr<ICompressCoder> adcCoder = adcCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
+ {
+ lps->InSize = currentPackTotal;
+ lps->OutSize = currentUnpTotal;
+ currentPackSize = 0;
+ currentUnpSize = 0;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ // const CItemEx &item = _files[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+
+ realOutStream.Release();
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ #ifdef DMG_SHOW_RAW
+ if (index > _fileIndices.Size())
+ {
+ const CByteBuffer &buf = _files[index - (_fileIndices.Size() + 1)].Raw;
+ outStreamSpec->Init(buf.GetCapacity());
+ RINOK(WriteStream(outStream, buf, buf.GetCapacity()));
+ currentPackSize = currentUnpSize = buf.GetCapacity();
+ }
+ else if (index == _fileIndices.Size())
+ {
+ outStreamSpec->Init(_xml.Length());
+ RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
+ currentPackSize = currentUnpSize = _xml.Length();
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[_fileIndices[index]];
+ currentPackSize = item.GetPackSize();
+ currentUnpSize = item.GetUnpackSize();
+
+ UInt64 unpPos = 0;
+ UInt64 packPos = 0;
+ {
+ for (int j = 0; j < item.Blocks.Size(); j++)
+ {
+ lps->InSize = currentPackTotal + packPos;
+ lps->OutSize = currentUnpTotal + unpPos;
+ RINOK(lps->SetCur());
+
+ const CBlock &block = item.Blocks[j];
+
+ packPos += block.PackSize;
+ if (block.UnpPos != unpPos)
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ RINOK(_inStream->Seek(item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(block.PackSize);
+ // UInt64 startSize = outStreamSpec->GetSize();
+ bool realMethod = true;
+ outStreamSpec->Init(block.UnpSize);
+ HRESULT res = S_OK;
+
+ switch(block.Type)
+ {
+ case METHOD_ZERO_0:
+ case METHOD_ZERO_2:
+ realMethod = false;
+ if (block.PackSize != 0)
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ break;
+
+ case METHOD_COPY:
+ if (block.UnpSize != block.PackSize)
+ {
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ break;
+ }
+ res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ break;
+
+ case METHOD_ADC:
+ {
+ res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress);
+ break;
+ }
+
+ case METHOD_ZLIB:
+ {
+ res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress);
+ break;
+ }
+
+ case METHOD_BZIP2:
+ {
+ res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress);
+ if (res == S_OK)
+ if (streamSpec->GetSize() != block.PackSize)
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ default:
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ break;
+ }
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ if (opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ unpPos += block.UnpSize;
+ if (!outStreamSpec->IsFinishedOK())
+ {
+ if (realMethod && opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+
+ while (outStreamSpec->GetRem() != 0)
+ {
+ UInt64 rem = outStreamSpec->GetRem();
+ UInt32 size = (UInt32)MyMin(rem, (UInt64)kZeroBufSize);
+ RINOK(WriteStream(outStream, zeroBuf, size));
+ }
+ }
+ }
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Dmg", L"dmg", 0, 0xE4, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Dmg)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/ElfHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/ElfHandler.cpp
new file mode 100644
index 000000000..c4ad78e9e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/ElfHandler.cpp
@@ -0,0 +1,534 @@
+// ElfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+static UInt16 Get16(const Byte *p, int be) { if (be) return GetBe16(p); return GetUi16(p); }
+static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
+static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NElf {
+
+#define ELF_CLASS_32 1
+#define ELF_CLASS_64 2
+
+#define ELF_DATA_2LSB 1
+#define ELF_DATA_2MSB 2
+
+#define NUM_SCAN_SECTIONS_MAX (1 << 6)
+
+struct CHeader
+{
+ bool Mode64;
+ bool Be;
+ Byte Os;
+ Byte AbiVer;
+
+ UInt16 Type;
+ UInt16 Machine;
+ // UInt32 Version;
+
+ // UInt64 EntryVa;
+ UInt64 ProgOffset;
+ UInt64 SectOffset;
+ UInt32 Flags;
+ UInt16 ElfHeaderSize;
+ UInt16 SegmentEntrySize;
+ UInt16 NumSegments;
+ UInt16 SectEntrySize;
+ UInt16 NumSections;
+ // UInt16 SectNameStringTableIndex;
+
+ bool Parse(const Byte *buf);
+
+ bool CheckSegmentEntrySize() const
+ {
+ return (Mode64 && SegmentEntrySize == 0x38) || (!Mode64 && SegmentEntrySize == 0x20);
+ };
+
+ UInt64 GetHeadersSize() const
+ { return ElfHeaderSize +
+ (UInt64)SegmentEntrySize * NumSegments +
+ (UInt64)SectEntrySize * NumSections; }
+
+};
+
+bool CHeader::Parse(const Byte *p)
+{
+ switch(p[4])
+ {
+ case ELF_CLASS_32: Mode64 = false; break;
+ case ELF_CLASS_64: Mode64 = true; break;
+ default: return false;
+ }
+ bool be;
+ switch(p[5])
+ {
+ case ELF_DATA_2LSB: be = false; break;
+ case ELF_DATA_2MSB: be = true; break;
+ default: return false;
+ }
+ Be = be;
+ if (p[6] != 1) // Version
+ return false;
+ Os = p[7];
+ AbiVer = p[8];
+ for (int i = 9; i < 16; i++)
+ if (p[i] != 0)
+ return false;
+
+ Type = Get16(p + 0x10, be);
+ Machine = Get16(p + 0x12, be);
+ if (Get32(p + 0x14, be) != 1) // Version
+ return false;
+
+ if (Mode64)
+ {
+ // EntryVa = Get64(p + 0x18, be);
+ ProgOffset = Get64(p + 0x20, be);
+ SectOffset = Get64(p + 0x28, be);
+ p += 0x30;
+ }
+ else
+ {
+ // EntryVa = Get32(p + 0x18, be);
+ ProgOffset = Get32(p + 0x1C, be);
+ SectOffset = Get32(p + 0x20, be);
+ p += 0x24;
+ }
+
+ Flags = Get32(p + 0, be);
+ ElfHeaderSize = Get16(p + 4, be);
+ SegmentEntrySize = Get16(p + 6, be);
+ NumSegments = Get16(p + 8, be);
+ SectEntrySize = Get16(p + 10, be);
+ NumSections = Get16(p + 12, be);
+ // SectNameStringTableIndex = Get16(p + 14, be);
+ return CheckSegmentEntrySize();
+}
+
+struct CSegment
+{
+ UInt32 Type;
+ UInt32 Flags;
+ UInt64 Offset;
+ UInt64 Va;
+ // UInt64 Pa;
+ UInt64 PSize;
+ UInt64 VSize;
+ // UInt64 Align;
+
+ void UpdateTotalSize(UInt64 &totalSize)
+ {
+ UInt64 t = Offset + PSize;
+ if (t > totalSize)
+ totalSize = t;
+ }
+ void Parse(const Byte *p, bool mode64, bool be);
+};
+
+void CSegment::Parse(const Byte *p, bool mode64, bool be)
+{
+ Type = Get32(p, be);
+ if (mode64)
+ {
+ Flags = Get32(p + 4, be);
+ Offset = Get64(p + 8, be);
+ Va = Get64(p + 0x10, be);
+ // Pa = Get64(p + 0x18, be);
+ PSize = Get64(p + 0x20, be);
+ VSize = Get64(p + 0x28, be);
+ // Align = Get64(p + 0x30, be);
+ }
+ else
+ {
+ Offset = Get32(p + 4, be);
+ Va = Get32(p + 8, be);
+ // Pa = Get32(p + 12, be);
+ PSize = Get32(p + 16, be);
+ VSize = Get32(p + 20, be);
+ Flags = Get32(p + 24, be);
+ // Align = Get32(p + 28, be);
+ }
+}
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { 0, "None" },
+ { 1, "AT&T WE 32100" },
+ { 2, "SPARC" },
+ { 3, "Intel 386" },
+ { 4, "Motorola 68000" },
+ { 5, "Motorola 88000" },
+ { 6, "Intel 486" },
+ { 7, "Intel i860" },
+ { 8, "MIPS" },
+ { 9, "IBM S/370" },
+ { 10, "MIPS RS3000 LE" },
+ { 11, "RS6000" },
+
+ { 15, "PA-RISC" },
+ { 16, "nCUBE" },
+ { 17, "Fujitsu VPP500" },
+ { 18, "SPARC 32+" },
+ { 19, "Intel i960" },
+ { 20, "PowerPC" },
+ { 21, "PowerPC 64-bit" },
+ { 22, "IBM S/390" },
+
+ { 36, "NEX v800" },
+ { 37, "Fujitsu FR20" },
+ { 38, "TRW RH-32" },
+ { 39, "Motorola RCE" },
+ { 40, "ARM" },
+ { 41, "Alpha" },
+ { 42, "Hitachi SH" },
+ { 43, "SPARC-V9" },
+ { 44, "Siemens Tricore" },
+ { 45, "ARC" },
+ { 46, "H8/300" },
+ { 47, "H8/300H" },
+ { 48, "H8S" },
+ { 49, "H8/500" },
+ { 50, "IA-64" },
+ { 51, "Stanford MIPS-X" },
+ { 52, "Motorola ColdFire" },
+ { 53, "M68HC12" },
+ { 54, "Fujitsu MMA" },
+ { 55, "Siemens PCP" },
+ { 56, "Sony nCPU" },
+ { 57, "Denso NDR1" },
+ { 58, "Motorola StarCore" },
+ { 59, "Toyota ME16" },
+ { 60, "ST100" },
+ { 61, "Advanced Logic TinyJ" },
+ { 62, "AMD64" },
+ { 63, "Sony DSP" },
+
+ { 66, "Siemens FX66" },
+ { 67, "ST9+" },
+ { 68, "ST7" },
+ { 69, "MC68HC16" },
+ { 70, "MC68HC11" },
+ { 71, "MC68HC08" },
+ { 72, "MC68HC05" },
+ { 73, "Silicon Graphics SVx" },
+ { 74, "ST19" },
+ { 75, "Digital VAX" },
+ { 76, "Axis CRIS" },
+ { 77, "Infineon JAVELIN" },
+ { 78, "Element 14 FirePath" },
+ { 79, "LSI ZSP" },
+ { 80, "MMIX" },
+ { 81, "HUANY" },
+ { 82, "SiTera Prism" },
+ { 83, "Atmel AVR" },
+ { 84, "Fujitsu FR30" },
+ { 85, "Mitsubishi D10V" },
+ { 86, "Mitsubishi D30V" },
+ { 87, "NEC v850" },
+ { 88, "Mitsubishi M32R" },
+ { 89, "Matsushita MN10300" },
+ { 90, "Matsushita MN10200" },
+ { 91, "picoJava" },
+ { 92, "OpenRISC" },
+ { 93, "ARC Tangent-A5" },
+ { 94, "Tensilica Xtensa" },
+ { 0x9026, "Alpha" }
+};
+
+static const CUInt32PCharPair g_AbiOS[] =
+{
+ { 0, "None" },
+ { 1, "HP-UX" },
+ { 2, "NetBSD" },
+ { 3, "Linux" },
+
+ { 6, "Solaris" },
+ { 7, "AIX" },
+ { 8, "IRIX" },
+ { 9, "FreeBSD" },
+ { 10, "TRU64" },
+ { 11, "Novell Modesto" },
+ { 12, "OpenBSD" },
+ { 13, "OpenVMS" },
+ { 14, "HP NSK" },
+ { 15, "AROS" },
+ { 97, "ARM" },
+ { 255, "Standalone" }
+};
+
+static const CUInt32PCharPair g_SegmentFlags[] =
+{
+ { 0, "Execute" },
+ { 1, "Write" },
+ { 2, "Read" }
+};
+
+static const char *g_Types[] =
+{
+ "None",
+ "Relocatable file",
+ "Executable file",
+ "Shared object file",
+ "Core file"
+};
+
+static const char *g_SegnmentTypes[] =
+{
+ "Unused",
+ "Loadable segment",
+ "Dynamic linking tables",
+ "Program interpreter path name",
+ "Note section",
+ "SHLIB",
+ "Program header table",
+ "TLS"
+};
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+ CObjectVector<CSegment> _sections;
+ UInt32 _peOffset;
+ CHeader _header;
+ UInt64 _totalSize;
+ HRESULT Open2(IInStream *stream);
+ bool Parse(const Byte *buf, UInt32 size);
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+#define ELF_PT_PHDR 6
+
+bool CHandler::Parse(const Byte *buf, UInt32 size)
+{
+ if (size < 64)
+ return false;
+ if (!_header.Parse(buf))
+ return false;
+ if (_header.ProgOffset > size ||
+ _header.ProgOffset + (UInt64)_header.SegmentEntrySize * _header.NumSegments > size ||
+ _header.NumSegments > NUM_SCAN_SECTIONS_MAX)
+ return false;
+ const Byte *p = buf + _header.ProgOffset;
+ _totalSize = _header.ProgOffset;
+
+ for (int i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize)
+ {
+ CSegment sect;
+ sect.Parse(p, _header.Mode64, _header.Be);
+ sect.UpdateTotalSize(_totalSize);
+ if (sect.Type != ELF_PT_PHDR)
+ _sections.Add(sect);
+ }
+ UInt64 total2 = _header.SectOffset + (UInt64)_header.SectEntrySize * _header.NumSections;
+ if (total2 > _totalSize)
+ _totalSize = total2;
+ return true;
+}
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCpu, VT_BSTR},
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidBigEndian, VT_BOOL},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8}
+ };
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidType, VT_BSTR},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidVa, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _header.GetHeadersSize(); break;
+ case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break;
+ case kpidBigEndian: if (_header.Be) prop = _header.Be; break;
+ case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
+ case kpidHostOS: PAIR_TO_PROP(g_AbiOS, _header.Os, prop); break;
+ case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CSegment &item = _sections[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ wchar_t sz[32];
+ ConvertUInt64ToString(index, sz);
+ prop = sz;
+ break;
+ }
+ case kpidSize: prop = (UInt64)item.VSize; break;
+ case kpidPackSize: prop = (UInt64)item.PSize; break;
+ case kpidOffset: prop = item.Offset; break;
+ case kpidVa: prop = item.Va; break;
+ case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break;
+ case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ const UInt32 kBufSize = 1 << 18;
+ const UInt32 kSigSize = 4;
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ size_t processed = kSigSize;
+ RINOK(ReadStream_FALSE(stream, buf, processed));
+ if (buf[0] != 0x7F || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F')
+ return S_FALSE;
+ processed = kBufSize - kSigSize;
+ RINOK(ReadStream(stream, buf + kSigSize, &processed));
+ processed += kSigSize;
+ if (!Parse(buf, (UInt32)processed))
+ return S_FALSE;
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ return (fileSize == _totalSize) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream));
+ _inStream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _sections.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _sections.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _sections.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _sections[allFilesMode ? i : indices[i]].PSize;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CSegment &item = _sections[index];
+ currentItemSize = item.PSize;
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(_inStream->Seek(item.Offset, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"ELF", L"", 0, 0xDE, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Elf)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/FatHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/FatHandler.cpp
new file mode 100644
index 000000000..1c374a444
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/FatHandler.cpp
@@ -0,0 +1,996 @@
+// FatHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/DummyOutStream.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+#define PRF(x) /* x */
+
+namespace NArchive {
+namespace NFat {
+
+static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31;
+
+struct CHeader
+{
+ UInt32 NumSectors;
+ UInt16 NumReservedSectors;
+ Byte NumFats;
+ UInt32 NumFatSectors;
+ UInt32 RootDirSector;
+ UInt32 NumRootDirSectors;
+ UInt32 DataSector;
+
+ UInt32 FatSize;
+ UInt32 BadCluster;
+
+ Byte NumFatBits;
+ Byte SectorSizeLog;
+ Byte SectorsPerClusterLog;
+ Byte ClusterSizeLog;
+
+ UInt16 SectorsPerTrack;
+ UInt16 NumHeads;
+ UInt32 NumHiddenSectors;
+
+ bool VolFieldsDefined;
+
+ UInt32 VolId;
+ // Byte VolName[11];
+ // Byte FileSys[8];
+
+ // Byte OemName[5];
+ Byte MediaType;
+
+ // 32-bit FAT
+ UInt16 Flags;
+ UInt16 FsInfoSector;
+ UInt32 RootCluster;
+
+ bool IsFat32() const { return NumFatBits == 32; }
+ UInt64 GetPhySize() const { return (UInt64)NumSectors << SectorSizeLog; }
+ UInt32 SectorSize() const { return (UInt32)1 << SectorSizeLog; }
+ UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
+ UInt32 ClusterToSector(UInt32 c) const { return DataSector + ((c - 2) << SectorsPerClusterLog); }
+ UInt32 IsEoc(UInt32 c) const { return c > BadCluster; }
+ UInt32 IsEocAndUnused(UInt32 c) const { return c > BadCluster && (c & kFatItemUsedByDirMask) == 0; }
+ UInt32 IsValidCluster(UInt32 c) const { return c >= 2 && c < FatSize; }
+ UInt32 SizeToSectors(UInt32 size) const { return (size + SectorSize() - 1) >> SectorSizeLog; }
+ UInt32 CalcFatSizeInSectors() const { return SizeToSectors((FatSize * (NumFatBits / 4) + 1) / 2); }
+
+ UInt32 GetFatSector() const
+ {
+ UInt32 index = (IsFat32() && (Flags & 0x80) != 0) ? (Flags & 0xF) : 0;
+ if (index > NumFats)
+ index = 0;
+ return NumReservedSectors + index * NumFatSectors;
+ }
+
+ UInt64 GetFilePackSize(UInt32 unpackSize) const
+ {
+ UInt64 mask = ClusterSize() - 1;
+ return (unpackSize + mask) & ~mask;
+ }
+
+ UInt32 GetNumClusters(UInt32 size) const
+ { return (UInt32)(((UInt64)size + ClusterSize() - 1) >> ClusterSizeLog); }
+
+ bool Parse(const Byte *p);
+};
+
+static int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+
+ int codeOffset = 0;
+ switch (p[0])
+ {
+ case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break;
+ case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break;
+ default: return false;
+ }
+ {
+ int s = GetLog(Get16(p + 11));
+ if (s < 9 || s > 12)
+ return false;
+ SectorSizeLog = (Byte)s;
+ s = GetLog(p[13]);
+ if (s < 0)
+ return false;
+ SectorsPerClusterLog = (Byte)s;
+ ClusterSizeLog = SectorSizeLog + SectorsPerClusterLog;
+ }
+
+ NumReservedSectors = Get16(p + 14);
+ if (NumReservedSectors == 0)
+ return false;
+
+ NumFats = p[16];
+ if (NumFats < 1 || NumFats > 4)
+ return false;
+
+ UInt16 numRootDirEntries = Get16(p + 17);
+ if (numRootDirEntries == 0)
+ {
+ if (codeOffset < 90)
+ return false;
+ NumFatBits = 32;
+ NumRootDirSectors = 0;
+ }
+ else
+ {
+ if (codeOffset < 62)
+ return false;
+ NumFatBits = 0;
+ UInt32 mask = (1 << (SectorSizeLog - 5)) - 1;
+ if ((numRootDirEntries & mask) != 0)
+ return false;
+ NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5);
+ }
+
+ NumSectors = Get16(p + 19);
+ if (NumSectors == 0)
+ NumSectors = Get32(p + 32);
+ else if (IsFat32())
+ return false;
+
+ MediaType = p[21];
+ NumFatSectors = Get16(p + 22);
+ SectorsPerTrack = Get16(p + 24);
+ NumHeads = Get16(p + 26);
+ NumHiddenSectors = Get32(p + 28);
+
+ // memcpy(OemName, p + 3, 5);
+
+ p += 36;
+ if (IsFat32())
+ {
+ if (NumFatSectors != 0)
+ return false;
+ NumFatSectors = Get32(p);
+ if (NumFatSectors >= (1 << 24))
+ return false;
+
+ Flags = Get16(p + 4);
+ if (Get16(p + 6) != 0)
+ return false;
+ RootCluster = Get32(p + 8);
+ FsInfoSector = Get16(p + 12);
+ for (int i = 16; i < 28; i++)
+ if (p[i] != 0)
+ return false;
+ p += 28;
+ }
+
+ // DriveNumber = p[0];
+ VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig
+ VolId = Get32(p + 3);
+ // memcpy(VolName, p + 7, 11);
+ // memcpy(FileSys, p + 18, 8);
+
+ if (NumFatSectors == 0)
+ return false;
+ RootDirSector = NumReservedSectors + NumFatSectors * NumFats;
+ DataSector = RootDirSector + NumRootDirSectors;
+ if (NumSectors < DataSector)
+ return false;
+ UInt32 numDataSectors = NumSectors - DataSector;
+ UInt32 numClusters = numDataSectors >> SectorsPerClusterLog;
+
+ BadCluster = 0x0FFFFFF7;
+ if (numClusters < 0xFFF5)
+ {
+ if (NumFatBits == 32)
+ return false;
+ NumFatBits = (numClusters < 0xFF5) ? 12: 16;
+ BadCluster &= ((1 << NumFatBits) - 1);
+ }
+ else if (NumFatBits != 32)
+ return false;
+
+ FatSize = numClusters + 2;
+ if (FatSize > BadCluster || CalcFatSizeInSectors() > NumFatSectors)
+ return false;
+ return true;
+}
+
+struct CItem
+{
+ UString UName;
+ char DosName[11];
+ Byte CTime2;
+ UInt32 CTime;
+ UInt32 MTime;
+ UInt16 ADate;
+ Byte Attrib;
+ Byte Flags;
+ UInt32 Size;
+ UInt32 Cluster;
+ Int32 Parent;
+
+ // NT uses Flags to store Low Case status
+ bool NameIsLow() const { return (Flags & 0x8) != 0; }
+ bool ExtIsLow() const { return (Flags & 0x10) != 0; }
+ bool IsDir() const { return (Attrib & 0x10) != 0; }
+ UString GetShortName() const;
+ UString GetName() const;
+ UString GetVolName() const;
+};
+
+static int CopyAndTrim(char *dest, const char *src, int size, bool toLower)
+{
+ int i;
+ memcpy(dest, src, size);
+ if (toLower)
+ for (i = 0; i < size; i++)
+ {
+ char c = dest[i];
+ if (c >= 'A' && c <= 'Z')
+ dest[i] = c + 0x20;
+ }
+ for (i = size - 1; i >= 0 && dest[i] == ' '; i--);
+ return i + 1;
+}
+
+static UString FatStringToUnicode(const char *s)
+{
+ return MultiByteToUnicodeString(s, CP_OEMCP);
+}
+
+UString CItem::GetShortName() const
+{
+ char s[16];
+ int i = CopyAndTrim(s, DosName, 8, NameIsLow());
+ s[i++] = '.';
+ int j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow());
+ if (j == 0)
+ j--;
+ s[i + j] = 0;
+ return FatStringToUnicode(s);
+}
+
+UString CItem::GetName() const
+{
+ if (!UName.IsEmpty())
+ return UName;
+ return GetShortName();
+}
+
+UString CItem::GetVolName() const
+{
+ if (!UName.IsEmpty())
+ return UName;
+ char s[12];
+ int i = CopyAndTrim(s, DosName, 11, false);
+ s[i] = 0;
+ return FatStringToUnicode(s);
+}
+
+struct CDatabase
+{
+ CHeader Header;
+ CObjectVector<CItem> Items;
+ UInt32 *Fat;
+ CMyComPtr<IInStream> InStream;
+ IArchiveOpenCallback *OpenCallback;
+
+ UInt32 NumFreeClusters;
+ bool VolItemDefined;
+ CItem VolItem;
+ UInt32 NumDirClusters;
+ CByteBuffer ByteBuf;
+ UInt64 NumCurUsedBytes;
+
+ CDatabase(): Fat(0) {}
+ ~CDatabase() { ClearAndClose(); }
+
+ void Clear();
+ void ClearAndClose();
+ HRESULT OpenProgressFat(bool changeTotal = true);
+ HRESULT OpenProgress();
+
+ UString GetItemPath(Int32 index) const;
+ HRESULT Open();
+ HRESULT ReadDir(Int32 parent, UInt32 cluster, int level);
+
+ UInt64 GetHeadersSize() const
+ {
+ return (UInt64)(Header.DataSector + (NumDirClusters << Header.SectorsPerClusterLog)) << Header.SectorSizeLog;
+ }
+ HRESULT SeekToSector(UInt32 sector);
+ HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); }
+};
+
+HRESULT CDatabase::SeekToSector(UInt32 sector)
+{
+ return InStream->Seek((UInt64)sector << Header.SectorSizeLog, STREAM_SEEK_SET, NULL);
+}
+
+void CDatabase::Clear()
+{
+ VolItemDefined = false;
+ NumDirClusters = 0;
+ NumCurUsedBytes = 0;
+
+ Items.Clear();
+ delete []Fat;
+ Fat = 0;
+}
+
+void CDatabase::ClearAndClose()
+{
+ Clear();
+ InStream.Release();
+}
+
+HRESULT CDatabase::OpenProgressFat(bool changeTotal)
+{
+ if (!OpenCallback)
+ return S_OK;
+ if (changeTotal)
+ {
+ UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) +
+ ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog);
+ RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes));
+ }
+ return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes);
+}
+
+HRESULT CDatabase::OpenProgress()
+{
+ if (!OpenCallback)
+ return S_OK;
+ UInt64 numItems = Items.Size();
+ return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes);
+}
+
+UString CDatabase::GetItemPath(Int32 index) const
+{
+ const CItem *item = &Items[index];
+ UString name = item->GetName();
+ for (;;)
+ {
+ index = item->Parent;
+ if (index < 0)
+ return name;
+ item = &Items[index];
+ name = item->GetName() + WCHAR_PATH_SEPARATOR + name;
+ }
+}
+
+static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, int numChars)
+{
+ for (int i = 0; i < numChars; i++)
+ {
+ wchar_t c = Get16(p + i * 2);
+ if (c != 0 && c != 0xFFFF)
+ *dest++ = c;
+ }
+ *dest = 0;
+ return dest;
+}
+
+HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level)
+{
+ int startIndex = Items.Size();
+ if (startIndex >= (1 << 30) || level > 256)
+ return S_FALSE;
+
+ UInt32 sectorIndex = 0;
+ UInt32 blockSize = Header.ClusterSize();
+ bool clusterMode = (Header.IsFat32() || parent >= 0);
+ if (!clusterMode)
+ {
+ blockSize = Header.SectorSize();
+ RINOK(SeekToSector(Header.RootDirSector));
+ }
+
+ ByteBuf.SetCapacity(blockSize);
+ UString curName;
+ int checkSum = -1;
+ int numLongRecords = -1;
+ for (UInt32 pos = blockSize;; pos += 32)
+ {
+ if (pos == blockSize)
+ {
+ pos = 0;
+
+ if ((NumDirClusters & 0xFF) == 0)
+ {
+ RINOK(OpenProgress());
+ }
+
+ if (clusterMode)
+ {
+ if (Header.IsEoc(cluster))
+ break;
+ if (!Header.IsValidCluster(cluster))
+ return S_FALSE;
+ PRF(printf("\nCluster = %4X", cluster));
+ RINOK(SeekToCluster(cluster));
+ UInt32 newCluster = Fat[cluster];
+ if ((newCluster & kFatItemUsedByDirMask) != 0)
+ return S_FALSE;
+ Fat[cluster] |= kFatItemUsedByDirMask;
+ cluster = newCluster;
+ NumDirClusters++;
+ NumCurUsedBytes += Header.ClusterSize();
+ }
+ else if (sectorIndex++ >= Header.NumRootDirSectors)
+ break;
+
+ RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize));
+ }
+ const Byte *p = ByteBuf + pos;
+ if (p[0] == 0)
+ {
+ /*
+ // FreeDOS formats FAT partition with cluster chain longer than required.
+ if (clusterMode && !Header.IsEoc(cluster))
+ return S_FALSE;
+ */
+ break;
+ }
+ if (p[0] == 0xE5)
+ {
+ if (numLongRecords > 0)
+ return S_FALSE;
+ continue;
+ }
+
+ Byte attrib = p[11];
+ if ((attrib & 0x3F) == 0xF)
+ {
+ if (p[0] > 0x7F || Get16(p + 26) != 0)
+ return S_FALSE;
+ int longIndex = p[0] & 0x3F;
+ if (longIndex == 0)
+ return S_FALSE;
+ bool isLast = (p[0] & 0x40) != 0;
+ if (numLongRecords < 0)
+ {
+ if (!isLast)
+ return S_FALSE;
+ numLongRecords = longIndex;
+ }
+ else if (isLast || numLongRecords != longIndex)
+ return S_FALSE;
+
+ numLongRecords--;
+
+ if (p[12] == 0)
+ {
+ wchar_t nameBuf[14];
+ wchar_t *dest;
+
+ dest = AddSubStringToName(nameBuf, p + 1, 5);
+ dest = AddSubStringToName(dest, p + 14, 6);
+ AddSubStringToName(dest, p + 28, 2);
+ curName = nameBuf + curName;
+ if (isLast)
+ checkSum = p[13];
+ if (checkSum != p[13])
+ return S_FALSE;
+ }
+ }
+ else
+ {
+ if (numLongRecords > 0)
+ return S_FALSE;
+ CItem item;
+ memcpy(item.DosName, p, 11);
+
+ if (checkSum >= 0)
+ {
+ Byte sum = 0;
+ for (int i = 0; i < 11; i++)
+ sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i];
+ if (sum == checkSum)
+ item.UName = curName;
+ }
+
+ if (item.DosName[0] == 5)
+ item.DosName[0] = (char)(Byte)0xE5;
+ item.Attrib = attrib;
+ item.Flags = p[12];
+ item.Size = Get32(p + 28);
+ item.Cluster = Get16(p + 26);
+ if (Header.NumFatBits > 16)
+ item.Cluster |= ((UInt32)Get16(p + 20) << 16);
+ else
+ {
+ // OS/2 and WinNT probably can store EA (extended atributes) in that field.
+ }
+
+ item.CTime = Get32(p + 14);
+ item.CTime2 = p[13];
+ item.ADate = Get16(p + 18);
+ item.MTime = Get32(p + 22);
+ item.Parent = parent;
+
+ if (attrib == 8)
+ {
+ VolItem = item;
+ VolItemDefined = true;
+ }
+ else
+ if (memcmp(item.DosName, ". ", 11) != 0 &&
+ memcmp(item.DosName, ".. ", 11) != 0)
+ {
+ if (!item.IsDir())
+ NumCurUsedBytes += Header.GetFilePackSize(item.Size);
+ Items.Add(item);
+ PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1)));
+ }
+ numLongRecords = -1;
+ curName.Empty();
+ checkSum = -1;
+ }
+ }
+
+ int finishIndex = Items.Size();
+ for (int i = startIndex; i < finishIndex; i++)
+ {
+ const CItem &item = Items[i];
+ if (item.IsDir())
+ {
+ PRF(printf("\n%S", GetItemPath(i)));
+ RINOK(CDatabase::ReadDir(i, item.Cluster, level + 1));
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CDatabase::Open()
+{
+ Clear();
+ bool numFreeClustersDefined = false;
+ {
+ static const UInt32 kHeaderSize = 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
+ if (!Header.Parse(buf))
+ return S_FALSE;
+ UInt64 fileSize;
+ RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize));
+
+ /* we comment that check to support truncated images */
+ /*
+ if (fileSize < Header.GetPhySize())
+ return S_FALSE;
+ */
+
+ if (Header.IsFat32())
+ {
+ SeekToSector(Header.FsInfoSector);
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
+ if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+ return S_FALSE;
+ if (Get32(buf) == 0x41615252 && Get32(buf + 484) == 0x61417272)
+ {
+ NumFreeClusters = Get32(buf + 488);
+ numFreeClustersDefined = (NumFreeClusters <= Header.FatSize);
+ }
+ }
+ }
+
+ // numFreeClustersDefined = false; // to recalculate NumFreeClusters
+ if (!numFreeClustersDefined)
+ NumFreeClusters = 0;
+
+ CByteBuffer byteBuf;
+ Fat = new UInt32[Header.FatSize];
+
+ RINOK(OpenProgressFat());
+ RINOK(SeekToSector(Header.GetFatSector()));
+ if (Header.NumFatBits == 32)
+ {
+ const UInt32 kBufSize = (1 << 15);
+ byteBuf.SetCapacity(kBufSize);
+ for (UInt32 i = 0; i < Header.FatSize;)
+ {
+ UInt32 size = Header.FatSize - i;
+ const UInt32 kBufSize32 = kBufSize / 4;
+ if (size > kBufSize32)
+ size = kBufSize32;
+ UInt32 readSize = Header.SizeToSectors(size * 4) << Header.SectorSizeLog;
+ RINOK(ReadStream_FALSE(InStream, byteBuf, readSize));
+ NumCurUsedBytes += readSize;
+
+ const UInt32 *src = (const UInt32 *)(const Byte *)byteBuf;
+ UInt32 *dest = Fat + i;
+ if (numFreeClustersDefined)
+ for (UInt32 j = 0; j < size; j++)
+ dest[j] = Get32(src + j) & 0x0FFFFFFF;
+ else
+ {
+ UInt32 numFreeClusters = 0;
+ for (UInt32 j = 0; j < size; j++)
+ {
+ UInt32 v = Get32(src + j) & 0x0FFFFFFF;
+ numFreeClusters += (UInt32)(v - 1) >> 31;
+ dest[j] = v;
+ }
+ NumFreeClusters += numFreeClusters;
+ }
+ i += size;
+ if ((i & 0xFFFFF) == 0)
+ {
+ RINOK(OpenProgressFat(!numFreeClustersDefined));
+ }
+ }
+ }
+ else
+ {
+ const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog;
+ NumCurUsedBytes += kBufSize;
+ byteBuf.SetCapacity(kBufSize);
+ Byte *p = byteBuf;
+ RINOK(ReadStream_FALSE(InStream, p, kBufSize));
+ UInt32 fatSize = Header.FatSize;
+ UInt32 *fat = &Fat[0];
+ if (Header.NumFatBits == 16)
+ for (UInt32 j = 0; j < fatSize; j++)
+ fat[j] = Get16(p + j * 2);
+ else
+ for (UInt32 j = 0; j < fatSize; j++)
+ fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF;
+
+ if (!numFreeClustersDefined)
+ {
+ UInt32 numFreeClusters = 0;
+ for (UInt32 i = 0; i < fatSize; i++)
+ numFreeClusters += (UInt32)(fat[i] - 1) >> 31;
+ NumFreeClusters = numFreeClusters;
+ }
+ }
+
+ RINOK(OpenProgressFat());
+
+ if ((Fat[0] & 0xFF) != Header.MediaType)
+ return S_FALSE;
+
+ return ReadDir(-1, Header.RootCluster, 0);
+}
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ CDatabase
+{
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ const CItem &item = Items[index];
+ CClusterInStream *streamSpec = new CClusterInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Stream = InStream;
+ streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog;
+ streamSpec->BlockSizeLog = Header.ClusterSizeLog;
+ streamSpec->Size = item.Size;
+
+ UInt32 numClusters = Header.GetNumClusters(item.Size);
+ streamSpec->Vector.Reserve(numClusters);
+ UInt32 cluster = item.Cluster;
+ UInt32 size = item.Size;
+
+ if (size == 0)
+ {
+ if (cluster != 0)
+ return S_FALSE;
+ }
+ else
+ {
+ UInt32 clusterSize = Header.ClusterSize();
+ for (;; size -= clusterSize)
+ {
+ if (!Header.IsValidCluster(cluster))
+ return S_FALSE;
+ streamSpec->Vector.Add(cluster - 2);
+ cluster = Fat[cluster];
+ if (size <= clusterSize)
+ break;
+ }
+ if (!Header.IsEocAndUnused(cluster))
+ return S_FALSE;
+ }
+ RINOK(streamSpec->InitAndSeek());
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI8},
+ { NULL, kpidShortName, VT_BSTR}
+};
+
+enum
+{
+ kpidNumFats = kpidUserDefined
+ // kpidOemName,
+ // kpidVolName,
+ // kpidFileSysType
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidFreeSpace, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidVolumeName, VT_BSTR},
+
+ { L"FATs", kpidNumFats, VT_UI4},
+ { NULL, kpidSectorSize, VT_UI4},
+ { NULL, kpidId, VT_UI4},
+ // { L"OEM Name", kpidOemName, VT_BSTR},
+ // { L"Volume Name", kpidVolName, VT_BSTR},
+ // { L"File System Type", kpidFileSysType, VT_BSTR}
+ // { NULL, kpidSectorsPerTrack, VT_UI4},
+ // { NULL, kpidNumHeads, VT_UI4},
+ // { NULL, kpidHiddenSectors, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME localFileTime, utc;
+ if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime))
+ if (LocalFileTimeToFileTime(&localFileTime, &utc))
+ {
+ UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
+ t64 += ms10 * 100000;
+ utc.dwLowDateTime = (DWORD)t64;
+ utc.dwHighDateTime = (DWORD)(t64 >> 32);
+ prop = utc;
+ }
+}
+
+/*
+static void StringToProp(const Byte *src, int size, NWindows::NCOM::CPropVariant &prop)
+{
+ char dest[32];
+ memcpy(dest, src, size);
+ dest[size] = 0;
+ prop = FatStringToUnicode(dest);
+}
+
+#define STRING_TO_PROP(s, p) StringToProp(s, sizeof(s), prop)
+*/
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidFileSystem:
+ {
+ wchar_t s[32] = { L'F', L'A', L'T' };
+ ConvertUInt32ToString(Header.NumFatBits, s + 3);
+ prop = s;
+ break;
+ }
+ case kpidClusterSize: prop = Header.ClusterSize(); break;
+ case kpidPhySize: prop = Header.GetPhySize(); break;
+ case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
+ case kpidHeadersSize: prop = GetHeadersSize(); break;
+ case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break;
+ case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
+ case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
+ case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
+ // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
+ // case kpidNumHeads: prop = Header.NumHeads; break;
+ // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break;
+ case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break;
+ // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break;
+ // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break;
+ // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = Items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = GetItemPath(index); break;
+ case kpidShortName: prop = item.GetShortName(); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break;
+ case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
+ case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break;
+ case kpidAttrib: prop = (UInt32)item.Attrib; break;
+ case kpidSize: if (!item.IsDir()) prop = item.Size; break;
+ case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ OpenCallback = callback;
+ InStream = stream;
+ HRESULT res;
+ try
+ {
+ res = CDatabase::Open();
+ if (res == S_OK)
+ return S_OK;
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ Close();
+ return res;
+ }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ ClearAndClose();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = Items[allFilesMode ? i : indices[i]];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = Items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ totalPackSize += Header.GetFilePackSize(item.Size);
+ totalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init();
+
+ int res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(index, &inStream);
+ if (hres != S_FALSE)
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize == item.Size)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = Items.Size();
+ return S_OK;
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"FAT", L"fat img", 0, 0xDA, { 0x55, 0xAA }, 2, false, CreateArc, 0 };
+
+REGISTER_ARC(Fat)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/FlvHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/FlvHandler.cpp
new file mode 100644
index 000000000..a22c29e30
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/FlvHandler.cpp
@@ -0,0 +1,544 @@
+// FlvHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+// #include "Common/Defs.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#define GetBe24(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 16) | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((const Byte *)(p))[2] )
+
+#define Get16(p) GetBe16(p)
+#define Get24(p) GetBe24(p)
+#define Get32(p) GetBe32(p)
+
+namespace NArchive {
+namespace NFlv {
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 30;
+static const int kNumChunksMax = (UInt32)1 << 23;
+
+const UInt32 kTagHeaderSize = 11;
+
+static const Byte kFlag_Video = 1;
+static const Byte kFlag_Audio = 4;
+
+static const Byte kType_Audio = 8;
+static const Byte kType_Video = 9;
+static const Byte kType_Meta = 18;
+static const int kNumTypes = 19;
+
+struct CItem
+{
+ UInt32 Offset;
+ UInt32 Size;
+ // UInt32 Time;
+ Byte Type;
+};
+
+struct CItem2
+{
+ Byte Type;
+ Byte SubType;
+ Byte Props;
+ bool SameSubTypes;
+ int NumChunks;
+ size_t Size;
+
+ CReferenceBuf *BufSpec;
+ CMyComPtr<IUnknown> RefBuf;
+
+ bool IsAudio() const { return Type == kType_Audio; }
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ int _isRaw;
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CItem2> _items2;
+ // CByteBuffer _metadata;
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ AString GetComment();
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidNumBlocks, VT_UI4},
+ { NULL, kpidComment, VT_BSTR}
+};
+
+/*
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidComment, VT_BSTR}
+};
+*/
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+static const char *g_AudioTypes[16] =
+{
+ "pcm",
+ "adpcm",
+ "mp3",
+ "pcm_le",
+ "nellymoser16",
+ "nellymoser8",
+ "nellymoser",
+ "g711a",
+ "g711m",
+ "audio9",
+ "aac",
+ "speex",
+ "audio12",
+ "audio13",
+ "mp3",
+ "audio15"
+};
+
+static const char *g_VideoTypes[16] =
+{
+ "video0",
+ "jpeg",
+ "h263",
+ "screen",
+ "vp6",
+ "vp6alpha",
+ "screen2",
+ "avc",
+ "video8",
+ "video9",
+ "video10",
+ "video11",
+ "video12",
+ "video13",
+ "video14",
+ "video15"
+};
+
+static const char *g_Rates[4] =
+{
+ "5.5 kHz",
+ "11 kHz",
+ "22 kHz",
+ "44 kHz"
+};
+
+static void MyStrCat(char *d, const char *s)
+{
+ MyStringCopy(d + MyStringLen(d), s);
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ const CItem2 &item = _items2[index];
+ switch(propID)
+ {
+ case kpidExtension:
+ prop = _isRaw ?
+ (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) :
+ (item.IsAudio() ? "audio.flv" : "video.flv");
+ break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size;
+ break;
+ case kpidNumBlocks: prop = (UInt32)item.NumChunks; break;
+ case kpidComment:
+ {
+ char sz[64];
+ MyStringCopy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) );
+ if (item.IsAudio())
+ {
+ MyStrCat(sz, " ");
+ MyStrCat(sz, g_Rates[(item.Props >> 2) & 3]);
+ MyStrCat(sz, (item.Props & 2) ? " 16-bit" : " 8-bit");
+ MyStrCat(sz, (item.Props & 1) ? " stereo" : " mono");
+ }
+ prop = sz;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+/*
+AString CHandler::GetComment()
+{
+ const Byte *p = _metadata;
+ size_t size = _metadata.GetCapacity();
+ AString res;
+ if (size > 0)
+ {
+ p++;
+ size--;
+ for (;;)
+ {
+ if (size < 2)
+ break;
+ int len = Get16(p);
+ p += 2;
+ size -= 2;
+ if (len == 0 || (size_t)len > size)
+ break;
+ {
+ AString temp;
+ char *sz = temp.GetBuffer(len);
+ memcpy(sz, p, len);
+ sz[len] = 0;
+ temp.ReleaseBuffer();
+ if (!res.IsEmpty())
+ res += '\n';
+ res += temp;
+ }
+ p += len;
+ size -= len;
+ if (size < 1)
+ break;
+ Byte type = *p++;
+ size--;
+ bool ok = false;
+ switch(type)
+ {
+ case 0:
+ {
+ if (size < 8)
+ break;
+ ok = true;
+ Byte reverse[8];
+ for (int i = 0; i < 8; i++)
+ {
+ bool little_endian = 1;
+ if (little_endian)
+ reverse[i] = p[7 - i];
+ else
+ reverse[i] = p[i];
+ }
+ double d = *(double *)reverse;
+ char temp[32];
+ sprintf(temp, " = %.3f", d);
+ res += temp;
+ p += 8;
+ size -= 8;
+ break;
+ }
+ case 8:
+ {
+ if (size < 4)
+ break;
+ ok = true;
+ // UInt32 numItems = Get32(p);
+ p += 4;
+ size -= 4;
+ break;
+ }
+ }
+ if (!ok)
+ break;
+ }
+ }
+ return res;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidComment: prop = GetComment(); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+*/
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ CRecordVector<CItem> items;
+
+ const UInt32 kHeaderSize = 13;
+ Byte header[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, header, kHeaderSize));
+ if (header[0] != 'F' ||
+ header[1] != 'L' ||
+ header[2] != 'V' ||
+ header[3] != 1 ||
+ (header[4] & 0xFA) != 0)
+ return S_FALSE;
+ UInt32 offset = Get32(header + 5);
+ if (offset != 9 || Get32(header + 9) != 0)
+ return S_FALSE;
+ offset += 4;
+
+ CByteBuffer inBuf;
+ size_t fileSize;
+ {
+ UInt64 fileSize64;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize64));
+ if (fileSize64 > kFileSizeMax)
+ return S_FALSE;
+
+ if (callback)
+ RINOK(callback->SetTotal(NULL, &fileSize64))
+
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ fileSize = (size_t)fileSize64;
+ inBuf.SetCapacity(fileSize);
+ for (size_t pos = 0; pos < fileSize;)
+ {
+ UInt64 offset64 = pos;
+ if (callback)
+ RINOK(callback->SetCompleted(NULL, &offset64))
+ size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20));
+ RINOK(ReadStream_FALSE(stream, inBuf + pos, rem));
+ pos += rem;
+ }
+ }
+
+ int lasts[kNumTypes];
+ int i;
+ for (i = 0; i < kNumTypes; i++)
+ lasts[i] = -1;
+
+ while (offset < fileSize)
+ {
+ CItem item;
+ item.Offset = offset;
+ const Byte *buf = inBuf + offset;
+ offset += kTagHeaderSize;
+ if (offset > fileSize)
+ return S_FALSE;
+
+ item.Type = buf[0];
+ UInt32 size = Get24(buf + 1);
+ if (size < 1)
+ return S_FALSE;
+ // item.Time = Get24(buf + 4);
+ // item.Time |= (UInt32)buf[7] << 24;
+ if (Get24(buf + 8) != 0) // streamID
+ return S_FALSE;
+
+ UInt32 curSize = kTagHeaderSize + size + 4;
+ item.Size = curSize;
+
+ offset += curSize - kTagHeaderSize;
+ if (offset > fileSize)
+ return S_FALSE;
+
+ if (Get32(buf + kTagHeaderSize + size) != kTagHeaderSize + size)
+ return S_FALSE;
+
+ // printf("\noffset = %6X type = %2d time = %6d size = %6d", (UInt32)offset, item.Type, item.Time, item.Size);
+
+ if (item.Type == kType_Meta)
+ {
+ // _metadata = item.Buf;
+ }
+ else
+ {
+ if (item.Type != kType_Audio && item.Type != kType_Video)
+ return S_FALSE;
+ if (items.Size() >= kNumChunksMax)
+ return S_FALSE;
+ Byte firstByte = buf[kTagHeaderSize];
+ Byte subType, props;
+ if (item.Type == kType_Audio)
+ {
+ subType = firstByte >> 4;
+ props = firstByte & 0xF;
+ }
+ else
+ {
+ subType = firstByte & 0xF;
+ props = firstByte >> 4;
+ }
+ int last = lasts[item.Type];
+ if (last < 0)
+ {
+ CItem2 item2;
+ item2.RefBuf = item2.BufSpec = new CReferenceBuf;
+ item2.Size = curSize;
+ item2.Type = item.Type;
+ item2.SubType = subType;
+ item2.Props = props;
+ item2.NumChunks = 1;
+ item2.SameSubTypes = true;
+ lasts[item.Type] = _items2.Add(item2);
+ }
+ else
+ {
+ CItem2 &item2 = _items2[last];
+ if (subType != item2.SubType)
+ item2.SameSubTypes = false;
+ item2.Size += curSize;
+ item2.NumChunks++;
+ }
+ items.Add(item);
+ }
+ }
+
+ _isRaw = (_items2.Size() == 1);
+ for (i = 0; i < _items2.Size(); i++)
+ {
+ CItem2 &item2 = _items2[i];
+ CByteBuffer &itemBuf = item2.BufSpec->Buf;
+ if (_isRaw)
+ {
+ if (!item2.SameSubTypes)
+ return S_FALSE;
+ itemBuf.SetCapacity((size_t)item2.Size - (kTagHeaderSize + 4 + 1) * item2.NumChunks);
+ item2.Size = 0;
+ }
+ else
+ {
+ itemBuf.SetCapacity(kHeaderSize + (size_t)item2.Size);
+ memcpy(itemBuf, header, kHeaderSize);
+ itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video;
+ item2.Size = kHeaderSize;
+ }
+ }
+
+ for (i = 0; i < items.Size(); i++)
+ {
+ const CItem &item = items[i];
+ CItem2 &item2 = _items2[lasts[item.Type]];
+ size_t size = item.Size;
+ const Byte *src = inBuf + item.Offset;
+ if (_isRaw)
+ {
+ src += kTagHeaderSize + 1;
+ size -= (kTagHeaderSize + 4 + 1);
+ }
+ memcpy(item2.BufSpec->Buf + item2.Size, src, size);
+ item2.Size += size;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ HRESULT res;
+ try
+ {
+ res = Open2(inStream, callback);
+ if (res == S_OK)
+ _stream = inStream;
+ }
+ catch(...) { res = S_FALSE; }
+ if (res != S_OK)
+ {
+ Close();
+ return S_FALSE;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _items2.Clear();
+ // _metadata.SetCapacity(0);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items2.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items2[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CItem2 &item = _items2[index];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ totalSize += item.Size;
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.GetCapacity()));
+ }
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Init(_items2[index].BufSpec);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"FLV", L"flv", 0, 0xD6, { 'F', 'L', 'V' }, 3, false, CreateArc, 0 };
+
+REGISTER_ARC(Flv)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/GzHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/GzHandler.cpp
new file mode 100644
index 000000000..7b73bddc3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/GzHandler.cpp
@@ -0,0 +1,698 @@
+// GzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/DeflateDecoder.h"
+#include "../Compress/DeflateEncoder.h"
+
+#include "Common/InStreamWithCRC.h"
+#include "Common/OutStreamWithCRC.h"
+
+#include "DeflateProps.h"
+
+#define Get32(p) GetUi32(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NGz {
+
+static const UInt16 kSignature = 0x8B1F;
+
+namespace NHeader
+{
+ namespace NFlags
+ {
+ const Byte kIsText = 1 << 0;
+ const Byte kCrc = 1 << 1;
+ const Byte kExtra = 1 << 2;
+ const Byte kName = 1 << 3;
+ const Byte kComment = 1 << 4;
+ }
+
+ namespace NExtraFlags
+ {
+ const Byte kMaximum = 2;
+ const Byte kFastest = 4;
+ }
+
+ namespace NCompressionMethod
+ {
+ const Byte kDeflate = 8;
+ }
+
+ namespace NHostOS
+ {
+ enum EEnum
+ {
+ kFAT = 0,
+ kAMIGA,
+ kVMS,
+ kUnix,
+ kVM_CMS,
+ kAtari,
+ kHPFS,
+ kMac,
+ kZ_System,
+ kCPM,
+ kTOPS20,
+ kNTFS,
+ kQDOS,
+ kAcorn,
+ kVFAT,
+ kMVS,
+ kBeOS,
+ kTandem,
+
+ kUnknown = 255
+ };
+ }
+}
+
+static const char *kHostOSes[] =
+{
+ "FAT",
+ "AMIGA",
+ "VMS",
+ "Unix",
+ "VM/CMS",
+ "Atari",
+ "HPFS",
+ "Macintosh",
+ "Z-System",
+ "CP/M",
+ "TOPS-20",
+ "NTFS",
+ "SMS/QDOS",
+ "Acorn",
+ "VFAT",
+ "MVS",
+ "BeOS",
+ "Tandem",
+ "OS/400",
+ "OS/X"
+};
+
+static const char *kUnknownOS = "Unknown";
+
+class CItem
+{
+ bool TestFlag(Byte flag) const { return (Flags & flag) != 0; }
+public:
+ Byte Method;
+ Byte Flags;
+ Byte ExtraFlags;
+ Byte HostOS;
+ UInt32 Time;
+ UInt32 Crc;
+ UInt32 Size32;
+
+ AString Name;
+ AString Comment;
+ // CByteBuffer Extra;
+
+ // bool IsText() const { return TestFlag(NHeader::NFlags::kIsText); }
+ bool HeaderCrcIsPresent() const { return TestFlag(NHeader::NFlags::kCrc); }
+ bool ExtraFieldIsPresent() const { return TestFlag(NHeader::NFlags::kExtra); }
+ bool NameIsPresent() const { return TestFlag(NHeader::NFlags::kName); }
+ bool CommentIsPresent() const { return TestFlag(NHeader::NFlags::kComment); }
+
+ void Clear()
+ {
+ Name.Empty();
+ Comment.Empty();
+ // Extra.SetCapacity(0);
+ }
+
+ HRESULT ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream);
+ HRESULT ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream);
+ HRESULT ReadFooter2(ISequentialInStream *stream);
+
+ HRESULT WriteHeader(ISequentialOutStream *stream);
+ HRESULT WriteFooter(ISequentialOutStream *stream);
+};
+
+static HRESULT ReadBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ data[i] = stream->ReadByte();
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+static HRESULT SkipBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ stream->ReadByte();
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+static HRESULT ReadUInt16(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt16 &value /* , UInt32 &crc */)
+{
+ value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = stream->ReadByte();
+ if (stream->InputEofError())
+ return S_FALSE;
+ // crc = CRC_UPDATE_BYTE(crc, b);
+ value |= (UInt16(b) << (8 * i));
+ }
+ return S_OK;
+}
+
+static HRESULT ReadString(NCompress::NDeflate::NDecoder::CCOMCoder *stream, AString &s, UInt32 limit /* , UInt32 &crc */)
+{
+ s.Empty();
+ for (UInt32 i = 0; i < limit; i++)
+ {
+ Byte b = stream->ReadByte();
+ if (stream->InputEofError())
+ return S_FALSE;
+ // crc = CRC_UPDATE_BYTE(crc, b);
+ if (b == 0)
+ return S_OK;
+ s += (char)b;
+ }
+ return S_FALSE;
+}
+
+HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
+{
+ Clear();
+
+ // Header-CRC field had another meaning in old version of gzip!
+ // UInt32 crc = CRC_INIT_VAL;
+ Byte buf[10];
+
+ RINOK(ReadBytes(stream, buf, 10));
+
+ if (GetUi16(buf) != kSignature)
+ return S_FALSE;
+
+ Method = buf[2];
+
+ if (Method != NHeader::NCompressionMethod::kDeflate)
+ return S_FALSE;
+
+ Flags = buf[3];
+ Time = Get32(buf + 4);
+ ExtraFlags = buf[8];
+ HostOS = buf[9];
+
+ // crc = CrcUpdate(crc, buf, 10);
+
+ if (ExtraFieldIsPresent())
+ {
+ UInt16 extraSize;
+ RINOK(ReadUInt16(stream, extraSize /* , crc */));
+ RINOK(SkipBytes(stream, extraSize));
+ // Extra.SetCapacity(extraSize);
+ // RINOK(ReadStream_FALSE(stream, Extra, extraSize));
+ // crc = CrcUpdate(crc, Extra, extraSize);
+ }
+ if (NameIsPresent())
+ RINOK(ReadString(stream, Name, (1 << 10) /* , crc */));
+ if (CommentIsPresent())
+ RINOK(ReadString(stream, Comment, (1 << 16) /* , crc */));
+
+ if (HeaderCrcIsPresent())
+ {
+ UInt16 headerCRC;
+ // UInt32 dummy = 0;
+ RINOK(ReadUInt16(stream, headerCRC /* , dummy */));
+ /*
+ if ((UInt16)CRC_GET_DIGEST(crc) != headerCRC)
+ return S_FALSE;
+ */
+ }
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+HRESULT CItem::ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
+{
+ Byte buf[8];
+ RINOK(ReadBytes(stream, buf, 8));
+ Crc = Get32(buf);
+ Size32 = Get32(buf + 4);
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+HRESULT CItem::ReadFooter2(ISequentialInStream *stream)
+{
+ Byte buf[8];
+ RINOK(ReadStream_FALSE(stream, buf, 8));
+ Crc = Get32(buf);
+ Size32 = Get32(buf + 4);
+ return S_OK;
+}
+
+HRESULT CItem::WriteHeader(ISequentialOutStream *stream)
+{
+ Byte buf[10];
+ SetUi16(buf, kSignature);
+ buf[2] = Method;
+ buf[3] = Flags & NHeader::NFlags::kName;
+ // buf[3] |= NHeader::NFlags::kCrc;
+ SetUi32(buf + 4, Time);
+ buf[8] = ExtraFlags;
+ buf[9] = HostOS;
+ RINOK(WriteStream(stream, buf, 10));
+ // crc = CrcUpdate(CRC_INIT_VAL, buf, 10);
+ if (NameIsPresent())
+ {
+ // crc = CrcUpdate(crc, (const char *)Name, Name.Length() + 1);
+ RINOK(WriteStream(stream, (const char *)Name, Name.Length() + 1));
+ }
+ // SetUi16(buf, (UInt16)CRC_GET_DIGEST(crc));
+ // RINOK(WriteStream(stream, buf, 2));
+ return S_OK;
+}
+
+HRESULT CItem::WriteFooter(ISequentialOutStream *stream)
+{
+ Byte buf[8];
+ SetUi32(buf, Crc);
+ SetUi32(buf + 4, Size32);
+ return WriteStream(stream, buf, 8);
+}
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IOutArchive,
+ public ISetProperties,
+ public CMyUnknownImp
+{
+ CItem _item;
+ UInt64 _startPosition;
+ UInt64 _headerSize;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ICompressCoder> _decoder;
+ NCompress::NDeflate::NDecoder::CCOMCoder *_decoderSpec;
+
+ CDeflateProps _method;
+
+public:
+ MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+
+ CHandler()
+ {
+ _decoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
+ _decoder = _decoderSpec;
+ }
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidCRC, VT_UI4}
+ // { NULL, kpidComment, VT_BSTR}
+}
+;
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPath:
+ if (_item.NameIsPresent())
+ prop = MultiByteToUnicodeString(_item.Name, CP_ACP);
+ break;
+ // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
+ case kpidMTime:
+ {
+ if (_item.Time != 0)
+ {
+ FILETIME utc;
+ NTime::UnixTimeToFileTime(_item.Time, utc);
+ prop = utc;
+ }
+ break;
+ }
+ case kpidSize: if (_stream) prop = (UInt64)_item.Size32; break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidHostOS: prop = (_item.HostOS < sizeof(kHostOSes) / sizeof(kHostOSes[0])) ?
+ kHostOSes[_item.HostOS] : kUnknownOS; break;
+ case kpidCRC: if (_stream) prop = _item.Crc; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+ res = OpenSeq(stream);
+ if (res == S_OK)
+ {
+ UInt64 endPos;
+ res = stream->Seek(-8, STREAM_SEEK_END, &endPos);
+ _packSize = endPos + 8 - _startPosition;
+ _packSizeDefined = true;
+ if (res == S_OK)
+ {
+ res = _item.ReadFooter2(stream);
+ _stream = stream;
+ }
+ }
+ }
+ catch(...) { res = S_FALSE; }
+ if (res != S_OK)
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ Close();
+ _decoderSpec->SetInStream(stream);
+ _decoderSpec->InitInStream(true);
+ res = _item.ReadHeader(_decoderSpec);
+ _headerSize = _decoderSpec->GetInputProcessedSize();
+ }
+ catch(...) { res = S_FALSE; }
+ if (res != S_OK)
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _stream.Release();
+ _decoderSpec->ReleaseInStream();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_stream)
+ extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ _decoderSpec->InitInStream(true);
+ }
+ bool firstItem = true;
+ Int32 opRes;
+ for (;;)
+ {
+ lps->InSize = _packSize = _decoderSpec->GetInputProcessedSize();
+ _packSizeDefined = true;
+ lps->OutSize = outStreamSpec->GetSize();
+ RINOK(lps->SetCur());
+
+ CItem item;
+ if (!firstItem || _stream)
+ {
+ HRESULT result = item.ReadHeader(_decoderSpec);
+ if (result != S_OK)
+ {
+ if (result != S_FALSE)
+ return result;
+ opRes = firstItem ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK;
+ break;
+ }
+ }
+ firstItem = false;
+
+ UInt64 startOffset = outStreamSpec->GetSize();
+ outStreamSpec->InitCRC();
+
+ HRESULT result = _decoderSpec->CodeResume(outStream, NULL, progress);
+ if (result != S_OK)
+ {
+ if (result != S_FALSE)
+ return result;
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ _decoderSpec->AlignToByte();
+ if (item.ReadFooter1(_decoderSpec) != S_OK)
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ if (item.Crc != outStreamSpec->GetCRC() ||
+ item.Size32 != (UInt32)(outStreamSpec->GetSize() - startOffset))
+ {
+ opRes = NExtract::NOperationResult::kCRCError;
+ break;
+ }
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+static const Byte kHostOS =
+ #ifdef _WIN32
+ NHeader::NHostOS::kFAT;
+ #else
+ NHeader::NHostOS::kUnix;
+ #endif
+
+static HRESULT UpdateArchive(
+ ISequentialOutStream *outStream,
+ UInt64 unpackSize,
+ const CItem &newItem,
+ CDeflateProps &deflateProps,
+ IArchiveUpdateCallback *updateCallback)
+{
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetTotal(unpackSize));
+ RINOK(updateCallback->SetCompleted(&complexity));
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+
+ CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
+ CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
+ inStreamSpec->SetStream(fileInStream);
+ inStreamSpec->Init();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CItem item = newItem;
+ item.Method = NHeader::NCompressionMethod::kDeflate;
+ item.ExtraFlags = deflateProps.IsMaximum() ?
+ NHeader::NExtraFlags::kMaximum :
+ NHeader::NExtraFlags::kFastest;
+
+ item.HostOS = kHostOS;
+
+ RINOK(item.WriteHeader(outStream));
+
+ NCompress::NDeflate::NEncoder::CCOMCoder *deflateEncoderSpec = new NCompress::NDeflate::NEncoder::CCOMCoder;
+ CMyComPtr<ICompressCoder> deflateEncoder = deflateEncoderSpec;
+ RINOK(deflateProps.SetCoderProperties(deflateEncoderSpec));
+ RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
+
+ item.Crc = inStreamSpec->GetCRC();
+ item.Size32 = (UInt32)inStreamSpec->GetSize();
+ RINOK(item.WriteFooter(outStream));
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+}
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+
+ CItem newItem = _item;
+ newItem.ExtraFlags = 0;
+ newItem.Flags = 0;
+ if (IntToBool(newProps))
+ {
+ {
+ FILETIME utcTime;
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidMTime, &prop));
+ if (prop.vt != VT_FILETIME)
+ return E_INVALIDARG;
+ utcTime = prop.filetime;
+ if (!NTime::FileTimeToUnixTime(utcTime, newItem.Time))
+ return E_INVALIDARG;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidPath, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ UString name = prop.bstrVal;
+ int dirDelimiterPos = name.ReverseFind(CHAR_PATH_SEPARATOR);
+ if (dirDelimiterPos >= 0)
+ name = name.Mid(dirDelimiterPos + 1);
+ newItem.Name = UnicodeStringToMultiByte(name, CP_ACP);
+ if (!newItem.Name.IsEmpty())
+ newItem.Flags |= NHeader::NFlags::kName;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
+ if (prop.vt == VT_BOOL)
+ {
+ if (prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+
+ return UpdateArchive(outStream, size, newItem, _method, updateCallback);
+ }
+
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+
+ if (!_stream)
+ return E_NOTIMPL;
+
+ UInt64 offset = _startPosition;
+ if (IntToBool(newProps))
+ {
+ newItem.WriteHeader(outStream);
+ offset += _headerSize;
+ }
+ RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
+ return NCompress::CopyStream(_stream, outStream, NULL);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ return _method.SetProperties(names, values, numProps);
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"gzip", L"gz gzip tgz tpz", L"* * .tar .tar", 0xEF, { 0x1F, 0x8B, 8 }, 3, true, CreateArc, CreateArcOut };
+
+REGISTER_ARC(GZip)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsHandler.cpp
new file mode 100644
index 000000000..f226458d4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsHandler.cpp
@@ -0,0 +1,243 @@
+// HfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Windows/PropVariant.h"
+#include "../../Common/StreamUtils.h"
+#include "HfsHandler.h"
+
+namespace NArchive {
+namespace NHfs {
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidFreeSpace, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME ft;
+ HfsTimeToFileTime(hfsTime, ft);
+ prop = ft;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod: prop = _db.Header.IsHfsX() ? L"HFSX" : L"HFS+"; break;
+ case kpidClusterSize: prop = (UInt32)1 << _db.Header.BlockSizeLog; break;
+ case kpidFreeSpace: prop = (UInt64)_db.Header.NumFreeBlocks << _db.Header.BlockSizeLog; break;
+ case kpidMTime: HfsTimeToProp(_db.Header.MTime, prop); break;
+ case kpidCTime:
+ {
+ FILETIME localFt, ft;
+ HfsTimeToFileTime(_db.Header.CTime, localFt);
+ if (LocalFileTimeToFileTime(&localFt, &ft))
+ prop = ft;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _db.Items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = _db.GetItemPath(index); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+
+ case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
+ case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
+ case kpidATime: HfsTimeToProp(item.ATime, prop); break;
+
+ case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumBlocks << _db.Header.BlockSizeLog; break;
+ case kpidSize: if (!item.IsDir()) prop = item.Size; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+public:
+ HRESULT SetTotal(UInt64 numFiles);
+ HRESULT SetCompleted(UInt64 numFiles);
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
+};
+
+HRESULT CProgressImp::SetTotal(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetTotal(&numFiles, NULL);
+ return S_OK;
+}
+
+HRESULT CProgressImp::SetCompleted(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ CProgressImp progressImp(callback);
+ HRESULT res = _db.Open(inStream, &progressImp);
+ if (res == E_ABORT)
+ return res;
+ if (res != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _db.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _db.Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _db.Items[allFilesMode ? i : indices[i]];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 currentTotalSize = 0, currentItemSize = 0;
+
+ CByteBuffer buf;
+ const UInt32 kBufSize = (1 << 16);
+ buf.SetCapacity(kBufSize);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _db.Items[index];
+ currentItemSize = 0;
+ if (!item.IsDir())
+ currentItemSize = item.Size;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ UInt64 pos = 0;
+ int res = NExtract::NOperationResult::kOK;
+ int i;
+ for (i = 0; i < item.Extents.Size(); i++)
+ {
+ if (item.Size == pos)
+ break;
+ if (res != NExtract::NOperationResult::kOK)
+ break;
+ const CExtent &e = item.Extents[i];
+ RINOK(_stream->Seek((UInt64)e.Pos << _db.Header.BlockSizeLog, STREAM_SEEK_SET, NULL));
+ UInt64 extentSize = (UInt64)e.NumBlocks << _db.Header.BlockSizeLog;
+ for (;;)
+ {
+ if (extentSize == 0)
+ break;
+ UInt64 rem = item.Size - pos;
+ if (rem == 0)
+ {
+ if (extentSize >= (UInt64)((UInt32)1 << _db.Header.BlockSizeLog))
+ res = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ UInt32 curSize = kBufSize;
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ if (curSize > extentSize)
+ curSize = (UInt32)extentSize;
+ RINOK(ReadStream_FALSE(_stream, buf, curSize));
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, buf, curSize));
+ }
+ pos += curSize;
+ extentSize -= curSize;
+ UInt64 processed = currentTotalSize + pos;
+ RINOK(extractCallback->SetCompleted(&processed));
+ }
+ }
+ if (i != item.Extents.Size() || item.Size != pos)
+ res = NExtract::NOperationResult::kDataError;
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.Items.Size();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsHandler.h
new file mode 100644
index 000000000..269af218e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsHandler.h
@@ -0,0 +1,26 @@
+// HfsHandler.h
+
+#ifndef __ARCHIVE_HFS_HANDLER_H
+#define __ARCHIVE_HFS_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "HfsIn.h"
+
+namespace NArchive {
+namespace NHfs {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CDatabase _db;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsIn.cpp
new file mode 100644
index 000000000..8391dd936
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsIn.cpp
@@ -0,0 +1,480 @@
+// HfsIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/StreamUtils.h"
+#include "Common/IntToString.h"
+
+#include "HfsIn.h"
+
+#include "../../../../C/CpuArch.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+namespace NArchive {
+namespace NHfs {
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareIdToIndex(const CIdIndexPair *p1, const CIdIndexPair *p2, void * /* param */)
+{
+ RINOZ(MyCompare(p1->ID, p2->ID));
+ return MyCompare(p1->Index, p2->Index);
+}
+
+bool operator< (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID < a2.ID); }
+bool operator> (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID > a2.ID); }
+bool operator==(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID == a2.ID); }
+bool operator!=(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID != a2.ID); }
+
+static UString GetSpecName(const UString &name, UInt32 /* id */)
+{
+ UString name2 = name;
+ name2.Trim();
+ if (name2.IsEmpty())
+ {
+ /*
+ wchar_t s[32];
+ ConvertUInt64ToString(id, s);
+ return L"[" + (UString)s + L"]";
+ */
+ return L"[]";
+ }
+ return name;
+}
+
+UString CDatabase::GetItemPath(int index) const
+{
+ const CItem *item = &Items[index];
+ UString name = GetSpecName(item->Name, item->ID);
+
+ for (int i = 0; i < 1000; i++)
+ {
+ if (item->ParentID < 16 && item->ParentID != 2)
+ {
+ if (item->ParentID != 1)
+ break;
+ return name;
+ }
+ CIdIndexPair pair;
+ pair.ID = item->ParentID;
+ pair.Index = 0;
+ int indexInMap = IdToIndexMap.FindInSorted(pair);
+ if (indexInMap < 0)
+ break;
+ item = &Items[IdToIndexMap[indexInMap].Index];
+ name = GetSpecName(item->Name, item->ID) + WCHAR_PATH_SEPARATOR + name;
+ }
+ return (UString)L"Unknown" + WCHAR_PATH_SEPARATOR + name;
+}
+
+void CFork::Parse(const Byte *p)
+{
+ Size = Get64(p);
+ // ClumpSize = Get32(p + 8);
+ NumBlocks = Get32(p + 0xC);
+ for (int i = 0; i < 8; i++)
+ {
+ CExtent &e = Extents[i];
+ e.Pos = Get32(p + 0x10 + i * 8);
+ e.NumBlocks = Get32(p + 0x10 + i * 8 + 4);
+ }
+}
+
+static HRESULT ReadExtent(int blockSizeLog, IInStream *inStream, Byte *buf, const CExtent &e)
+{
+ RINOK(inStream->Seek((UInt64)e.Pos << blockSizeLog, STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(inStream, buf, (size_t)e.NumBlocks << blockSizeLog);
+}
+
+HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream)
+{
+ if (fork.NumBlocks >= Header.NumBlocks)
+ return S_FALSE;
+ size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog;
+ if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks)
+ return S_FALSE;
+ buf.SetCapacity(totalSize);
+ UInt32 curBlock = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (curBlock >= fork.NumBlocks)
+ break;
+ const CExtent &e = fork.Extents[i];
+ if (fork.NumBlocks - curBlock < e.NumBlocks || e.Pos >= Header.NumBlocks)
+ return S_FALSE;
+ RINOK(ReadExtent(Header.BlockSizeLog, inStream,
+ (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog), e));
+ curBlock += e.NumBlocks;
+ }
+ return S_OK;
+}
+
+struct CNodeDescriptor
+{
+ UInt32 fLink;
+ UInt32 bLink;
+ Byte Kind;
+ Byte Height;
+ UInt16 NumRecords;
+ // UInt16 Reserved;
+ void Parse(const Byte *p);
+};
+
+void CNodeDescriptor::Parse(const Byte *p)
+{
+ fLink = Get32(p);
+ bLink = Get32(p + 4);
+ Kind = p[8];
+ Height = p[9];
+ NumRecords = Get16(p + 10);
+}
+
+struct CHeaderRec
+{
+ // UInt16 TreeDepth;
+ // UInt32 RootNode;
+ // UInt32 LeafRecords;
+ UInt32 FirstLeafNode;
+ // UInt32 LastLeafNode;
+ int NodeSizeLog;
+ // UInt16 MaxKeyLength;
+ UInt32 TotalNodes;
+ // UInt32 FreeNodes;
+ // UInt16 Reserved1;
+ // UInt32 ClumpSize;
+ // Byte BtreeType;
+ // Byte KeyCompareType;
+ // UInt32 Attributes;
+ // UInt32 Reserved3[16];
+
+ HRESULT Parse(const Byte *p);
+};
+
+HRESULT CHeaderRec::Parse(const Byte *p)
+{
+ // TreeDepth = Get16(p);
+ // RootNode = Get32(p + 2);
+ // LeafRecords = Get32(p + 6);
+ FirstLeafNode = Get32(p + 0xA);
+ // LastLeafNode = Get32(p + 0xE);
+ UInt32 nodeSize = Get16(p + 0x12);
+
+ int i;
+ for (i = 9; ((UInt32)1 << i) != nodeSize; i++)
+ if (i == 16)
+ return S_FALSE;
+ NodeSizeLog = i;
+
+ // MaxKeyLength = Get16(p + 0x14);
+ TotalNodes = Get32(p + 0x16);
+ // FreeNodes = Get32(p + 0x1A);
+ // Reserved1 = Get16(p + 0x1E);
+ // ClumpSize = Get32(p + 0x20);
+ // BtreeType = p[0x24];
+ // KeyCompareType = p[0x25];
+ // Attributes = Get32(p + 0x26);
+ /*
+ for (int i = 0; i < 16; i++)
+ Reserved3[i] = Get32(p + 0x2A + i * 4);
+ */
+ return S_OK;
+}
+
+
+enum ENodeType
+{
+ NODE_TYPE_LEAF = 0xFF,
+ NODE_TYPE_INDEX = 0,
+ NODE_TYPE_HEADER = 1,
+ NODE_TYPE_MODE = 2
+};
+
+HRESULT CDatabase::LoadExtentFile(IInStream *inStream)
+{
+ // FileExtents.Clear();
+ // ResExtents.Clear();
+
+ CByteBuffer extents;
+ RINOK(ReadFile(Header.ExtentsFile, extents, inStream));
+
+ const Byte *p = (const Byte *)extents;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ RINOK(hr.Parse(p + 14));
+
+ UInt32 node = hr.FirstLeafNode;
+ if (node != 0)
+ return S_FALSE;
+ /*
+ while (node != 0)
+ {
+ size_t nodeOffset = node * hr.NodeSize;
+ if ((node + 1)* hr.NodeSize > CatalogBuf.GetCapacity())
+ return S_FALSE;
+ CNodeDescriptor desc;
+ desc.Parse(p + nodeOffset);
+ if (desc.Kind != NODE_TYPE_LEAF)
+ return S_FALSE;
+ UInt32 ptr = hr.NodeSize;
+ for (int i = 0; i < desc.NumRecords; i++)
+ {
+ UInt32 offs = Get16(p + nodeOffset + hr.NodeSize - (i + 1) * 2);
+ UInt32 offsNext = Get16(p + nodeOffset + hr.NodeSize - (i + 2) * 2);
+
+ const Byte *r = p + nodeOffset + offs;
+ int keyLength = Get16(r);
+ Byte forkType = r[2];
+ UInt32 id = Get16(r + 4);
+ UInt32 startBlock = Get16(r + 4);
+ CObjectVector<CIdExtents> *extents = (forkType == 0) ? &FileExtents : &ResExtents;
+ if (extents->Size() == 0)
+ extents->Add(CIdExtents());
+ else
+ {
+ CIdExtents &e = extents->Back();
+ if (e.ID != id)
+ {
+ if (e.ID > id)
+ return S_FALSE;
+ extents->Add(CIdExtents());
+ }
+ }
+ CIdExtents &e = extents->Back();
+ for (UInt32 k = offs + 10 + 2; k + 8 <= offsNext; k += 8)
+ {
+ CExtent ee;
+ ee.Pos = Get32(p + nodeOffset + k);
+ ee.NumBlocks = Get32(p + nodeOffset + k * 4);
+ e.Extents.Add(ee);
+ }
+ }
+ node = desc.fLink;
+ }
+ */
+ return S_OK;
+}
+
+
+HRESULT CDatabase::LoadCatalog(IInStream *inStream, CProgressVirt *progress)
+{
+ Items.Clear();
+ IdToIndexMap.ClearAndFree();
+
+ CByteBuffer catalogBuf;
+ RINOK(ReadFile(Header.CatalogFile, catalogBuf, inStream));
+ const Byte *p = (const Byte *)catalogBuf;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ hr.Parse(p + 14);
+
+ // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
+
+ if ((catalogBuf.GetCapacity() >> hr.NodeSizeLog) < hr.TotalNodes)
+ return S_FALSE;
+
+ CByteBuffer usedBuf;
+ usedBuf.SetCapacity(hr.TotalNodes);
+ for (UInt32 i = 0; i < hr.TotalNodes; i++)
+ usedBuf[i] = 0;
+
+ UInt32 node = hr.FirstLeafNode;
+ while (node != 0)
+ {
+ if (node >= hr.TotalNodes)
+ return S_FALSE;
+ if (usedBuf[node])
+ return S_FALSE;
+ usedBuf[node] = 1;
+ size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
+ CNodeDescriptor desc;
+ desc.Parse(p + nodeOffset);
+ if (desc.Kind != NODE_TYPE_LEAF)
+ return S_FALSE;
+ for (int i = 0; i < desc.NumRecords; i++)
+ {
+ UInt32 nodeSize = (1 << hr.NodeSizeLog);
+ UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2);
+ UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2);
+ UInt32 recSize = offsNext - offs;
+ if (offsNext >= nodeSize || offsNext < offs || recSize < 6)
+ return S_FALSE;
+
+ CItem item;
+
+ const Byte *r = p + nodeOffset + offs;
+ UInt32 keyLength = Get16(r);
+ item.ParentID = Get32(r + 2);
+ UString name;
+ if (keyLength < 6 || (keyLength & 1) != 0 || keyLength + 2 > recSize)
+ return S_FALSE;
+ r += 6;
+ recSize -= 6;
+ keyLength -= 6;
+
+ int nameLength = Get16(r);
+ if (nameLength * 2 != (int)keyLength)
+ return S_FALSE;
+ r += 2;
+ recSize -= 2;
+
+ wchar_t *pp = name.GetBuffer(nameLength + 1);
+
+ int j;
+ for (j = 0; j < nameLength; j++)
+ pp[j] = ((wchar_t)r[j * 2] << 8) | r[j * 2 + 1];
+ pp[j] = 0;
+ name.ReleaseBuffer();
+ r += j * 2;
+ recSize -= j * 2;
+
+ if (recSize < 2)
+ return S_FALSE;
+ item.Type = Get16(r);
+
+ if (item.Type != RECORD_TYPE_FOLDER && item.Type != RECORD_TYPE_FILE)
+ continue;
+ if (recSize < 0x58)
+ return S_FALSE;
+
+ // item.Flags = Get16(r + 2);
+ // item.Valence = Get32(r + 4);
+ item.ID = Get32(r + 8);
+ item.CTime = Get32(r + 0xC);
+ item.MTime = Get32(r + 0x10);
+ // item.AttrMTime = Get32(r + 0x14);
+ item.ATime = Get32(r + 0x18);
+ // item.BackupDate = Get32(r + 0x1C);
+
+ /*
+ item.OwnerID = Get32(r + 0x20);
+ item.GroupID = Get32(r + 0x24);
+ item.AdminFlags = r[0x28];
+ item.OwnerFlags = r[0x29];
+ item.FileMode = Get16(r + 0x2A);
+ item.special.iNodeNum = Get16(r + 0x2C);
+ */
+
+ item.Name = name;
+
+ if (item.IsDir())
+ {
+ CIdIndexPair pair;
+ pair.ID = item.ID;
+ pair.Index = Items.Size();
+ IdToIndexMap.Add(pair);
+ }
+ else
+ {
+ CFork fd;
+ recSize -= 0x58;
+ r += 0x58;
+ if (recSize < 0x50 * 2)
+ return S_FALSE;
+ fd.Parse(r);
+ item.Size = fd.Size;
+ item.NumBlocks = fd.NumBlocks;
+ UInt32 curBlock = 0;
+ for (int j = 0; j < 8; j++)
+ {
+ if (curBlock >= fd.NumBlocks)
+ break;
+ const CExtent &e = fd.Extents[j];
+ item.Extents.Add(e);
+ curBlock += e.NumBlocks;
+ }
+ }
+ Items.Add(item);
+ if (progress && Items.Size() % 100 == 0)
+ {
+ RINOK(progress->SetCompleted(Items.Size()));
+ }
+ }
+ node = desc.fLink;
+ }
+ IdToIndexMap.Sort(CompareIdToIndex, NULL);
+ return S_OK;
+}
+
+HRESULT CDatabase::Open(IInStream *inStream, CProgressVirt *progress)
+{
+ static const UInt32 kHeaderSize = 1024 + 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
+ int i;
+ for (i = 0; i < 1024; i++)
+ if (buf[i] != 0)
+ return S_FALSE;
+ const Byte *p = buf + 1024;
+ CVolHeader &h = Header;
+
+ h.Header[0] = p[0];
+ h.Header[1] = p[1];
+ if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X'))
+ return S_FALSE;
+ h.Version = Get16(p + 2);
+ if (h.Version < 4 || h.Version > 5)
+ return S_FALSE;
+
+ // h.Attr = Get32(p + 4);
+ // h.LastMountedVersion = Get32(p + 8);
+ // h.JournalInfoBlock = Get32(p + 0xC);
+
+ h.CTime = Get32(p + 0x10);
+ h.MTime = Get32(p + 0x14);
+ // h.BackupTime = Get32(p + 0x18);
+ // h.CheckedTime = Get32(p + 0x1C);
+
+ // h.NumFiles = Get32(p + 0x20);
+ // h.NumFolders = Get32(p + 0x24);
+
+ UInt32 numFiles = Get32(p + 0x20);
+ UInt32 numFolders = Get32(p + 0x24);;
+ if (progress)
+ {
+ RINOK(progress->SetTotal(numFolders + numFiles));
+ }
+
+ UInt32 blockSize = Get32(p + 0x28);
+
+ for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+ if (i == 31)
+ return S_FALSE;
+ h.BlockSizeLog = i;
+
+ h.NumBlocks = Get32(p + 0x2C);
+ h.NumFreeBlocks = Get32(p + 0x30);
+
+ /*
+ h.WriteCount = Get32(p + 0x44);
+ for (i = 0; i < 6; i++)
+ h.FinderInfo[i] = Get32(p + 0x50 + i * 4);
+ h.VolID = Get64(p + 0x68);
+ */
+
+ UInt64 endPos;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
+ if ((endPos >> h.BlockSizeLog) < h.NumBlocks)
+ return S_FALSE;
+
+ // h.AllocationFile.Parse(p + 0x70 + 0x50 * 0);
+ h.ExtentsFile.Parse( p + 0x70 + 0x50 * 1);
+ h.CatalogFile.Parse( p + 0x70 + 0x50 * 2);
+ // h.AttributesFile.Parse(p + 0x70 + 0x50 * 3);
+ // h.StartupFile.Parse( p + 0x70 + 0x50 * 4);
+
+ RINOK(LoadExtentFile(inStream));
+ RINOK(LoadCatalog(inStream, progress));
+
+ // if (Header.NumFiles + Header.NumFolders != (UInt32)Items.Size()) return S_OK;
+
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsIn.h
new file mode 100644
index 000000000..c19539057
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsIn.h
@@ -0,0 +1,154 @@
+// HfsIn.h
+
+#ifndef __ARCHIVE_HFS_IN_H
+#define __ARCHIVE_HFS_IN_H
+
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+
+namespace NArchive {
+namespace NHfs {
+
+struct CExtent
+{
+ UInt32 Pos;
+ UInt32 NumBlocks;
+};
+
+struct CFork
+{
+ UInt64 Size;
+ // UInt32 ClumpSize;
+ UInt32 NumBlocks;
+ CExtent Extents[8];
+ void Parse(const Byte *p);
+};
+
+struct CVolHeader
+{
+ Byte Header[2];
+ UInt16 Version;
+ // UInt32 Attr;
+ // UInt32 LastMountedVersion;
+ // UInt32 JournalInfoBlock;
+
+ UInt32 CTime;
+ UInt32 MTime;
+ // UInt32 BackupTime;
+ // UInt32 CheckedTime;
+
+ // UInt32 NumFiles;
+ // UInt32 NumFolders;
+ int BlockSizeLog;
+ UInt32 NumBlocks;
+ UInt32 NumFreeBlocks;
+
+ // UInt32 WriteCount;
+ // UInt32 FinderInfo[8];
+ // UInt64 VolID;
+
+ // CFork AllocationFile;
+ CFork ExtentsFile;
+ CFork CatalogFile;
+ // CFork AttributesFile;
+ // CFork StartupFile;
+
+ bool IsHfsX() const { return Version > 4; }
+};
+
+inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft)
+{
+ UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+enum ERecordType
+{
+ RECORD_TYPE_FOLDER = 1,
+ RECORD_TYPE_FILE = 2,
+ RECORD_TYPE_FOLDER_THREAD = 3,
+ RECORD_TYPE_FILE_THREAD = 4
+};
+
+struct CItem
+{
+ UString Name;
+
+ UInt32 ParentID;
+
+ UInt16 Type;
+ // UInt16 Flags;
+ // UInt32 Valence;
+ UInt32 ID;
+ UInt32 CTime;
+ UInt32 MTime;
+ // UInt32 AttrMTime;
+ UInt32 ATime;
+ // UInt32 BackupDate;
+
+ /*
+ UInt32 OwnerID;
+ UInt32 GroupID;
+ Byte AdminFlags;
+ Byte OwnerFlags;
+ UInt16 FileMode;
+ union
+ {
+ UInt32 iNodeNum;
+ UInt32 LinkCount;
+ UInt32 RawDevice;
+ } special;
+ */
+
+ UInt64 Size;
+ UInt32 NumBlocks;
+ CRecordVector<CExtent> Extents;
+
+ bool IsDir() const { return Type == RECORD_TYPE_FOLDER; }
+ CItem(): Size(0), NumBlocks(0) {}
+};
+
+struct CIdIndexPair
+{
+ UInt32 ID;
+ int Index;
+};
+
+struct CProgressVirt
+{
+ virtual HRESULT SetTotal(UInt64 numFiles) PURE;
+ virtual HRESULT SetCompleted(UInt64 numFiles) PURE;
+};
+
+class CDatabase
+{
+ // CObjectVector<CIdExtents> FileExtents;
+ // CObjectVector<CIdExtents> ResExtents;
+ CRecordVector<CIdIndexPair> IdToIndexMap;
+
+ HRESULT LoadExtentFile(IInStream *inStream);
+ HRESULT LoadCatalog(IInStream *inStream, CProgressVirt *progress);
+
+ HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream);
+public:
+ CVolHeader Header;
+ CObjectVector<CItem> Items;
+ // bool CaseSensetive;
+
+ void Clear()
+ {
+ // CaseSensetive = false;
+ Items.Clear();
+ // FileExtents.Clear();
+ // ResExtents.Clear();
+ IdToIndexMap.Clear();
+ }
+
+ UString GetItemPath(int index) const;
+ HRESULT Open(IInStream *inStream, CProgressVirt *progress);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsRegister.cpp
new file mode 100644
index 000000000..51c3c2b15
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Hfs/HfsRegister.cpp
@@ -0,0 +1,13 @@
+// HfsRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "HfsHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NHfs::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"HFS", L"hfs", 0, 0xE3, { 'H', '+', 0, 4 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Hfs)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/IArchive.h b/src/libs/7zip/unix/CPP/7zip/Archive/IArchive.h
new file mode 100644
index 000000000..853202767
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/IArchive.h
@@ -0,0 +1,234 @@
+// IArchive.h
+
+#ifndef __IARCHIVE_H
+#define __IARCHIVE_H
+
+#include "../IProgress.h"
+#include "../IStream.h"
+#include "../PropID.h"
+
+#define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x)
+#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x)
+
+namespace NFileTimeType
+{
+ enum EEnum
+ {
+ kWindows,
+ kUnix,
+ kDOS
+ };
+}
+
+namespace NArchive
+{
+ enum
+ {
+ kName = 0,
+ kClassID,
+ kExtension,
+ kAddExtension,
+ kUpdate,
+ kKeepName,
+ kStartSignature,
+ kFinishSignature,
+ kAssociate
+ };
+
+ namespace NExtract
+ {
+ namespace NAskMode
+ {
+ enum
+ {
+ kExtract = 0,
+ kTest,
+ kSkip
+ };
+ }
+ namespace NOperationResult
+ {
+ enum
+ {
+ kOK = 0,
+ kUnSupportedMethod,
+ kDataError,
+ kCRCError
+ };
+ }
+ }
+ namespace NUpdate
+ {
+ namespace NOperationResult
+ {
+ enum
+ {
+ kOK = 0,
+ kError
+ };
+ }
+ }
+}
+
+#define INTERFACE_IArchiveOpenCallback(x) \
+ STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) x; \
+ STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) x; \
+
+ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
+{
+ INTERFACE_IArchiveOpenCallback(PURE);
+};
+
+
+#define INTERFACE_IArchiveExtractCallback(x) \
+ INTERFACE_IProgress(x) \
+ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
+ STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \
+ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \
+
+ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20)
+{
+ INTERFACE_IArchiveExtractCallback(PURE)
+};
+
+
+#define INTERFACE_IArchiveOpenVolumeCallback(x) \
+ STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \
+ STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \
+
+ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30)
+{
+ INTERFACE_IArchiveOpenVolumeCallback(PURE);
+};
+
+
+ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40)
+{
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE;
+};
+
+
+ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)
+{
+ STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE;
+};
+
+
+/*
+IInArchive::Extract:
+ indices must be sorted
+ numItems = 0xFFFFFFFF means "all files"
+ testMode != 0 means "test files without writing to outStream"
+*/
+
+#define INTERFACE_IInArchive(x) \
+ STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) x; \
+ STDMETHOD(Close)() x; \
+ STDMETHOD(GetNumberOfItems)(UInt32 *numItems) x; \
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
+ STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) x; \
+ STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) x; \
+ STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \
+ STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \
+ STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties) x; \
+ STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x;
+
+ARCHIVE_INTERFACE(IInArchive, 0x60)
+{
+ INTERFACE_IInArchive(PURE)
+};
+
+ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61)
+{
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE;
+};
+
+#define INTERFACE_IArchiveUpdateCallback(x) \
+ INTERFACE_IProgress(x); \
+ STDMETHOD(GetUpdateItemInfo)(UInt32 index, \
+ Int32 *newData, /*1 - new data, 0 - old data */ \
+ Int32 *newProperties, /* 1 - new properties, 0 - old properties */ \
+ UInt32 *indexInArchive /* -1 if there is no in archive, or if doesn't matter */ \
+ ) x; \
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \
+ STDMETHOD(SetOperationResult)(Int32 operationResult) x; \
+
+ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80)
+{
+ INTERFACE_IArchiveUpdateCallback(PURE);
+};
+
+#define INTERFACE_IArchiveUpdateCallback2(x) \
+ INTERFACE_IArchiveUpdateCallback(x) \
+ STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) x; \
+ STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) x; \
+
+ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
+{
+ INTERFACE_IArchiveUpdateCallback2(PURE);
+};
+
+
+#define INTERFACE_IOutArchive(x) \
+ STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \
+ STDMETHOD(GetFileTimeType)(UInt32 *type) x;
+
+ARCHIVE_INTERFACE(IOutArchive, 0xA0)
+{
+ INTERFACE_IOutArchive(PURE)
+};
+
+
+ARCHIVE_INTERFACE(ISetProperties, 0x03)
+{
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) PURE;
+};
+
+
+#define IMP_IInArchive_GetProp(k) \
+ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
+ { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \
+ const STATPROPSTG &srcItem = k[index]; \
+ *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \
+
+#define IMP_IInArchive_GetProp_WITH_NAME(k) \
+ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
+ { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \
+ const STATPROPSTG &srcItem = k[index]; \
+ *propID = srcItem.propid; *varType = srcItem.vt; \
+ if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \
+
+#define IMP_IInArchive_Props \
+ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \
+ { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps)
+
+#define IMP_IInArchive_Props_WITH_NAME \
+ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \
+ { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps)
+
+
+#define IMP_IInArchive_ArcProps \
+ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
+ { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps)
+
+#define IMP_IInArchive_ArcProps_WITH_NAME \
+ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
+ { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps)
+
+#define IMP_IInArchive_ArcProps_NO_Table \
+ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
+ { *numProperties = 0; return S_OK; } \
+ STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \
+ { return E_NOTIMPL; } \
+
+#define IMP_IInArchive_ArcProps_NO \
+ IMP_IInArchive_ArcProps_NO_Table \
+ STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \
+ { value->vt = VT_EMPTY; return S_OK; }
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHandler.cpp
new file mode 100644
index 000000000..7a9f1a458
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -0,0 +1,326 @@
+// IsoHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "IsoHandler.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NIso {
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME}
+ // { NULL, kpidPhySize, VT_UI8},
+ // { NULL, kpidHeadersSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ // try
+ {
+ if (_archive.Open(stream) != S_OK)
+ return S_FALSE;
+ _stream = stream;
+ }
+ // catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _archive.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _archive.Refs.Size() + _archive.BootEntries.Size();
+ return S_OK;
+}
+
+static void AddString(AString &s, const char *name, const Byte *p, int size)
+{
+ int i;
+ for (i = 0; i < size && p[i]; i++);
+ for (; i > 0 && p[i - 1] == ' '; i--);
+ if (i != 0)
+ {
+ AString d;
+ memcpy(d.GetBuffer(i), p, i);
+ d.ReleaseBuffer(i);
+ s += '\n';
+ s += name;
+ s += ": ";
+ s += d;
+ }
+}
+
+#define ADD_STRING(n, V) AddString(s, n, vol. V, sizeof(vol. V))
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex];
+ switch(propID)
+ {
+ case kpidComment:
+ {
+ AString s;
+ ADD_STRING("System", SystemId);
+ ADD_STRING("Volume", VolumeId);
+ ADD_STRING("VolumeSet", VolumeSetId);
+ ADD_STRING("Publisher", PublisherId);
+ ADD_STRING("Preparer", DataPreparerId);
+ ADD_STRING("Application", ApplicationId);
+ ADD_STRING("Copyright", CopyrightFileId);
+ ADD_STRING("Abstract", AbstractFileId);
+ ADD_STRING("Bib", BibFileId);
+ prop = s;
+ break;
+ }
+ case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; }
+ case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; }
+ // case kpidPhySize: break;
+ // case kpidHeadersSize: break;
+ case kpidError: if (_archive.IncorrectBigEndian) prop = "Incorrect big-endian headers"; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ if (index >= (UInt32)_archive.Refs.Size())
+ {
+ index -= _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ // wchar_t name[32];
+ // ConvertUInt64ToString(index + 1, name);
+ UString s = L"[BOOT]" WSTRING_PATH_SEPARATOR;
+ // s += name;
+ // s += L"-";
+ s += be.GetName();
+ prop = (const wchar_t *)s;
+ break;
+ }
+ case kpidIsDir: prop = false; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)_archive.GetBootItemSize(index);
+ break;
+ }
+ }
+ else
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ switch(propID)
+ {
+ case kpidPath:
+ // if (item.FileId.GetCapacity() >= 0)
+ {
+ UString s;
+ if (_archive.IsJoliet())
+ s = item.GetPathU();
+ else
+ s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP);
+
+ int pos = s.ReverseFind(L';');
+ if (pos >= 0 && pos == s.Length() - 2)
+ if (s[s.Length() - 1] == L'1')
+ s = s.Left(pos);
+ if (!s.IsEmpty())
+ if (s[s.Length() - 1] == L'.')
+ s = s.Left(s.Length() - 1);
+ prop = (const wchar_t *)NItemName::GetOSName2(s);
+ }
+ break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize:
+ case kpidPackSize:
+ if (!item.IsDir())
+ prop = (UInt64)item.DataLength;
+ break;
+ case kpidMTime:
+ {
+ FILETIME utc;
+ if (item.DateTime.GetFileTime(utc))
+ prop = utc;
+ break;
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _archive.Refs.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for(i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ totalSize += item.DataLength;
+ }
+ else
+ {
+ totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
+ }
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ currentItemSize = 0;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ UInt64 blockIndex;
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ currentItemSize = item.DataLength;
+ blockIndex = item.ExtentLocation;
+ }
+ else
+ {
+ int bootIndex = index - _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
+ currentItemSize = _archive.GetBootItemSize(bootIndex);
+ blockIndex = be.LoadRBA;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(currentItemSize);
+ RINOK(_stream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(outStreamSpec->IsFinishedOK() ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ UInt64 blockIndex;
+ UInt64 currentItemSize;
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ if (item.IsDir())
+ return S_FALSE;
+ currentItemSize = item.DataLength;
+ blockIndex = item.ExtentLocation;
+ }
+ else
+ {
+ int bootIndex = index - _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
+ currentItemSize = _archive.GetBootItemSize(bootIndex);
+ blockIndex = be.LoadRBA;
+ }
+ return CreateLimitedInStream(_stream, blockIndex * _archive.BlockSize, currentItemSize, stream);
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHandler.h
new file mode 100644
index 000000000..1dcade8f9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHandler.h
@@ -0,0 +1,30 @@
+// IsoHandler.h
+
+#ifndef __ISO_HANDLER_H
+#define __ISO_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+
+#include "IsoIn.h"
+#include "IsoItem.h"
+
+namespace NArchive {
+namespace NIso {
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CInArchive _archive;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHeader.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHeader.cpp
new file mode 100644
index 000000000..b3e418bbc
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHeader.cpp
@@ -0,0 +1,21 @@
+// Archive/Iso/Header.h
+
+#include "StdAfx.h"
+
+#include "IsoHeader.h"
+
+namespace NArchive {
+namespace NIso {
+
+const char *kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0";
+
+const wchar_t *kMediaTypes[5] =
+{
+ L"NoEmulation",
+ L"1.2M",
+ L"1.44M",
+ L"2.88M",
+ L"HardDisk"
+};
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHeader.h b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHeader.h
new file mode 100644
index 000000000..9702d70ae
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoHeader.h
@@ -0,0 +1,61 @@
+// Archive/IsoHeader.h
+
+#ifndef __ARCHIVE_ISO_HEADER_H
+#define __ARCHIVE_ISO_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NIso {
+
+namespace NVolDescType
+{
+ const Byte kBootRecord = 0;
+ const Byte kPrimaryVol = 1;
+ const Byte kSupplementaryVol = 2;
+ const Byte kVolParttition = 3;
+ const Byte kTerminator = 255;
+}
+
+const Byte kVersion = 1;
+
+namespace NFileFlags
+{
+ const Byte kDirectory = 1 << 1;
+}
+
+extern const char *kElToritoSpec;
+
+const UInt32 kStartPos = 0x8000;
+
+namespace NBootEntryId
+{
+ const Byte kValidationEntry = 1;
+ const Byte kInitialEntryNotBootable = 0;
+ const Byte kInitialEntryBootable = 0x88;
+}
+
+namespace NBootPlatformId
+{
+ const Byte kX86 = 0;
+ const Byte kPowerPC = 1;
+ const Byte kMac = 2;
+}
+
+const BYTE kBootMediaTypeMask = 0xF;
+
+namespace NBootMediaType
+{
+ const Byte kNoEmulation = 0;
+ const Byte k1d2Floppy = 1;
+ const Byte k1d44Floppy = 2;
+ const Byte k2d88Floppy = 3;
+ const Byte kHardDisk = 4;
+}
+
+const int kNumBootMediaTypes = 5;
+extern const wchar_t *kMediaTypes[];
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoIn.cpp
new file mode 100644
index 000000000..7ed618d29
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -0,0 +1,453 @@
+// Archive/IsoIn.cpp
+
+#include "StdAfx.h"
+
+#include "IsoIn.h"
+
+#include "../../Common/StreamUtils.h"
+
+namespace NArchive {
+namespace NIso {
+
+Byte CInArchive::ReadByte()
+{
+ if (m_BufferPos >= BlockSize)
+ m_BufferPos = 0;
+ if (m_BufferPos == 0)
+ {
+ size_t processedSize = BlockSize;
+ if (ReadStream(_stream, m_Buffer, &processedSize) != S_OK)
+ throw 1;
+ if (processedSize != BlockSize)
+ throw 1;
+ }
+ Byte b = m_Buffer[m_BufferPos++];
+ _position++;
+ return b;
+}
+
+void CInArchive::ReadBytes(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ data[i] = ReadByte();
+}
+
+void CInArchive::Skip(size_t size)
+{
+ while (size-- != 0)
+ ReadByte();
+}
+
+void CInArchive::SkipZeros(size_t size)
+{
+ while (size-- != 0)
+ {
+ Byte b = ReadByte();
+ if (b != 0)
+ throw 1;
+ }
+}
+
+UInt16 CInArchive::ReadUInt16Spec()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ value |= ((UInt16)(ReadByte()) << (8 * i));
+ return value;
+}
+
+
+UInt16 CInArchive::ReadUInt16()
+{
+ Byte b[4];
+ ReadBytes(b, 4);
+ UInt32 value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ if (b[i] != b[3 - i])
+ IncorrectBigEndian = true;
+ value |= ((UInt16)(b[i]) << (8 * i));
+ }
+ return (UInt16)value;
+}
+
+UInt32 CInArchive::ReadUInt32Le()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ value |= ((UInt32)(ReadByte()) << (8 * i));
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32Be()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ value <<= 8;
+ value |= ReadByte();
+ }
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ Byte b[8];
+ ReadBytes(b, 8);
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ if (b[i] != b[7 - i])
+ throw 1;
+ value |= ((UInt32)(b[i]) << (8 * i));
+ }
+ return value;
+}
+
+UInt32 CInArchive::ReadDigits(int numDigits)
+{
+ UInt32 res = 0;
+ for (int i = 0; i < numDigits; i++)
+ {
+ Byte b = ReadByte();
+ if (b < '0' || b > '9')
+ {
+ if (b == 0) // it's bug in some CD's
+ b = '0';
+ else
+ throw 1;
+ }
+ UInt32 d = (UInt32)(b - '0');
+ res *= 10;
+ res += d;
+ }
+ return res;
+}
+
+void CInArchive::ReadDateTime(CDateTime &d)
+{
+ d.Year = (UInt16)ReadDigits(4);
+ d.Month = (Byte)ReadDigits(2);
+ d.Day = (Byte)ReadDigits(2);
+ d.Hour = (Byte)ReadDigits(2);
+ d.Minute = (Byte)ReadDigits(2);
+ d.Second = (Byte)ReadDigits(2);
+ d.Hundredths = (Byte)ReadDigits(2);
+ d.GmtOffset = (signed char)ReadByte();
+}
+
+void CInArchive::ReadBootRecordDescriptor(CBootRecordDescriptor &d)
+{
+ ReadBytes(d.BootSystemId, sizeof(d.BootSystemId));
+ ReadBytes(d.BootId, sizeof(d.BootId));
+ ReadBytes(d.BootSystemUse, sizeof(d.BootSystemUse));
+}
+
+void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t)
+{
+ t.Year = ReadByte();
+ t.Month = ReadByte();
+ t.Day = ReadByte();
+ t.Hour = ReadByte();
+ t.Minute = ReadByte();
+ t.Second = ReadByte();
+ t.GmtOffset = (signed char)ReadByte();
+}
+
+void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
+{
+ r.ExtendedAttributeRecordLen = ReadByte();
+ if (r.ExtendedAttributeRecordLen != 0)
+ throw 1;
+ r.ExtentLocation = ReadUInt32();
+ r.DataLength = ReadUInt32();
+ ReadRecordingDateTime(r.DateTime);
+ r.FileFlags = ReadByte();
+ r.FileUnitSize = ReadByte();
+ r.InterleaveGapSize = ReadByte();
+ r.VolSequenceNumber = ReadUInt16();
+ Byte idLen = ReadByte();
+ r.FileId.SetCapacity(idLen);
+ ReadBytes((Byte *)r.FileId, idLen);
+ int padSize = 1 - (idLen & 1);
+
+ // SkipZeros(1 - (idLen & 1));
+ Skip(1 - (idLen & 1)); // it's bug in some cd's. Must be zeros
+
+ int curPos = 33 + idLen + padSize;
+ if (curPos > len)
+ throw 1;
+ int rem = len - curPos;
+ r.SystemUse.SetCapacity(rem);
+ ReadBytes((Byte *)r.SystemUse, rem);
+}
+
+void CInArchive::ReadDirRecord(CDirRecord &r)
+{
+ Byte len = ReadByte();
+ // Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor.
+ // But maybe we must use real "len" for other records.
+ len = 34;
+ ReadDirRecord2(r, len);
+}
+
+void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
+{
+ d.VolFlags = ReadByte();
+ ReadBytes(d.SystemId, sizeof(d.SystemId));
+ ReadBytes(d.VolumeId, sizeof(d.VolumeId));
+ SkipZeros(8);
+ d.VolumeSpaceSize = ReadUInt32();
+ ReadBytes(d.EscapeSequence, sizeof(d.EscapeSequence));
+ d.VolumeSetSize = ReadUInt16();
+ d.VolumeSequenceNumber = ReadUInt16();
+ d.LogicalBlockSize = ReadUInt16();
+ d.PathTableSize = ReadUInt32();
+ d.LPathTableLocation = ReadUInt32Le();
+ d.LOptionalPathTableLocation = ReadUInt32Le();
+ d.MPathTableLocation = ReadUInt32Be();
+ d.MOptionalPathTableLocation = ReadUInt32Be();
+ ReadDirRecord(d.RootDirRecord);
+ ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId));
+ ReadBytes(d.PublisherId, sizeof(d.PublisherId));
+ ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId));
+ ReadBytes(d.ApplicationId, sizeof(d.ApplicationId));
+ ReadBytes(d.CopyrightFileId, sizeof(d.CopyrightFileId));
+ ReadBytes(d.AbstractFileId, sizeof(d.AbstractFileId));
+ ReadBytes(d.BibFileId, sizeof(d.BibFileId));
+ ReadDateTime(d.CTime);
+ ReadDateTime(d.MTime);
+ ReadDateTime(d.ExpirationTime);
+ ReadDateTime(d.EffectiveTime);
+ d.FileStructureVersion = ReadByte(); // = 1
+ SkipZeros(1);
+ ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse));
+ SkipZeros(653);
+}
+
+static const Byte kSig_CD001[5] = { 'C', 'D', '0', '0', '1' };
+
+static const Byte kSig_NSR02[5] = { 'N', 'S', 'R', '0', '2' };
+static const Byte kSig_NSR03[5] = { 'N', 'S', 'R', '0', '3' };
+static const Byte kSig_BEA01[5] = { 'B', 'E', 'A', '0', '1' };
+static const Byte kSig_TEA01[5] = { 'T', 'E', 'A', '0', '1' };
+
+static inline bool CheckSignature(const Byte *sig, const Byte *data)
+{
+ for (int i = 0; i < 5; i++)
+ if (sig[i] != data[i])
+ return false;
+ return true;
+}
+
+void CInArchive::SeekToBlock(UInt32 blockIndex)
+{
+ if (_stream->Seek((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize, STREAM_SEEK_SET, &_position) != S_OK)
+ throw 1;
+ m_BufferPos = 0;
+}
+
+void CInArchive::ReadDir(CDir &d, int level)
+{
+ if (!d.IsDir())
+ return;
+ SeekToBlock(d.ExtentLocation);
+ UInt64 startPos = _position;
+
+ bool firstItem = true;
+ for (;;)
+ {
+ UInt64 offset = _position - startPos;
+ if (offset >= d.DataLength)
+ break;
+ Byte len = ReadByte();
+ if (len == 0)
+ continue;
+ CDir subItem;
+ ReadDirRecord2(subItem, len);
+ if (firstItem && level == 0)
+ IsSusp = subItem.CheckSusp(SuspSkipSize);
+
+ if (!subItem.IsSystemItem())
+ d._subItems.Add(subItem);
+
+ firstItem = false;
+ }
+ for (int i = 0; i < d._subItems.Size(); i++)
+ ReadDir(d._subItems[i], level + 1);
+}
+
+void CInArchive::CreateRefs(CDir &d)
+{
+ if (!d.IsDir())
+ return;
+ for (int i = 0; i < d._subItems.Size(); i++)
+ {
+ CRef ref;
+ CDir &subItem = d._subItems[i];
+ subItem.Parent = &d;
+ ref.Dir = &d;
+ ref.Index = i;
+ Refs.Add(ref);
+ CreateRefs(subItem);
+ }
+}
+
+void CInArchive::ReadBootInfo()
+{
+ if (!_bootIsDefined)
+ return;
+ if (memcmp(_bootDesc.BootSystemId, kElToritoSpec, sizeof(_bootDesc.BootSystemId)) != 0)
+ return;
+
+ const Byte *p = (const Byte *)_bootDesc.BootSystemUse;
+ UInt32 blockIndex = p[0] | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16) | ((UInt32)p[3] << 24);
+ SeekToBlock(blockIndex);
+ Byte b = ReadByte();
+ if (b != NBootEntryId::kValidationEntry)
+ return;
+ {
+ CBootValidationEntry e;
+ e.PlatformId = ReadByte();
+ if (ReadUInt16Spec() != 0)
+ throw 1;
+ ReadBytes(e.Id, sizeof(e.Id));
+ /* UInt16 checkSum = */ ReadUInt16Spec();
+ if (ReadByte() != 0x55)
+ throw 1;
+ if (ReadByte() != 0xAA)
+ throw 1;
+ }
+ b = ReadByte();
+ if (b == NBootEntryId::kInitialEntryBootable || b == NBootEntryId::kInitialEntryNotBootable)
+ {
+ CBootInitialEntry e;
+ e.Bootable = (b == NBootEntryId::kInitialEntryBootable);
+ e.BootMediaType = ReadByte();
+ e.LoadSegment = ReadUInt16Spec();
+ e.SystemType = ReadByte();
+ if (ReadByte() != 0)
+ throw 1;
+ e.SectorCount = ReadUInt16Spec();
+ e.LoadRBA = ReadUInt32Le();
+ if (ReadByte() != 0)
+ throw 1;
+ BootEntries.Add(e);
+ }
+ else
+ return;
+}
+
+HRESULT CInArchive::Open2()
+{
+ Clear();
+ RINOK(_stream->Seek(kStartPos, STREAM_SEEK_CUR, &_position));
+
+ m_BufferPos = 0;
+ BlockSize = kBlockSize;
+ for (;;)
+ {
+ Byte sig[7];
+ ReadBytes(sig, 7);
+ Byte ver = sig[6];
+ if (!CheckSignature(kSig_CD001, sig + 1))
+ {
+ return S_FALSE;
+ /*
+ if (sig[0] != 0 || ver != 1)
+ break;
+ if (CheckSignature(kSig_BEA01, sig + 1))
+ {
+ }
+ else if (CheckSignature(kSig_TEA01, sig + 1))
+ {
+ break;
+ }
+ else if (CheckSignature(kSig_NSR02, sig + 1))
+ {
+ }
+ else
+ break;
+ SkipZeros(0x800 - 7);
+ continue;
+ */
+ }
+ // version = 2 for ISO 9660:1999?
+ if (ver > 2)
+ throw S_FALSE;
+
+ if (sig[0] == NVolDescType::kTerminator)
+ {
+ break;
+ // Skip(0x800 - 7);
+ // continue;
+ }
+ switch(sig[0])
+ {
+ case NVolDescType::kBootRecord:
+ {
+ _bootIsDefined = true;
+ ReadBootRecordDescriptor(_bootDesc);
+ break;
+ }
+ case NVolDescType::kPrimaryVol:
+ case NVolDescType::kSupplementaryVol:
+ {
+ // some ISOs have two PrimaryVols.
+ CVolumeDescriptor vd;
+ ReadVolumeDescriptor(vd);
+ if (sig[0] == NVolDescType::kPrimaryVol)
+ {
+ // some burners write "Joliet" Escape Sequence to primary volume
+ memset(vd.EscapeSequence, 0, sizeof(vd.EscapeSequence));
+ }
+ VolDescs.Add(vd);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (VolDescs.IsEmpty())
+ return S_FALSE;
+ for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
+ if (VolDescs[MainVolDescIndex].IsJoliet())
+ break;
+ // MainVolDescIndex = 0; // to read primary volume
+ const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
+ if (vd.LogicalBlockSize != kBlockSize)
+ return S_FALSE;
+ (CDirRecord &)_rootDir = vd.RootDirRecord;
+ ReadDir(_rootDir, 0);
+ CreateRefs(_rootDir);
+ ReadBootInfo();
+ return S_OK;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ _stream = inStream;
+ UInt64 pos;
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &pos));
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &_archiveSize));
+ RINOK(_stream->Seek(pos, STREAM_SEEK_SET, &_position));
+ HRESULT res = S_FALSE;
+ try { res = Open2(); }
+ catch(...) { Clear(); res = S_FALSE; }
+ _stream.Release();
+ return res;
+}
+
+void CInArchive::Clear()
+{
+ IncorrectBigEndian = false;
+ Refs.Clear();
+ _rootDir.Clear();
+ VolDescs.Clear();
+ _bootIsDefined = false;
+ BootEntries.Clear();
+ SuspSkipSize = 0;
+ IsSusp = false;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoIn.h
new file mode 100644
index 000000000..f9c6f6403
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoIn.h
@@ -0,0 +1,315 @@
+// Archive/IsoIn.h
+
+#ifndef __ARCHIVE_ISO_IN_H
+#define __ARCHIVE_ISO_IN_H
+
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+
+#include "../../IStream.h"
+
+#include "IsoHeader.h"
+#include "IsoItem.h"
+
+namespace NArchive {
+namespace NIso {
+
+struct CDir: public CDirRecord
+{
+ CDir *Parent;
+ CObjectVector<CDir> _subItems;
+
+ void Clear()
+ {
+ Parent = 0;
+ _subItems.Clear();
+ }
+
+ int GetLength(bool checkSusp, int skipSize) const
+ {
+ int len = GetLengthCur(checkSusp, skipSize);
+ if (Parent != 0)
+ if (Parent->Parent != 0)
+ len += 1 + Parent->GetLength(checkSusp, skipSize);
+ return len;
+ }
+
+ int GetLengthU() const
+ {
+ int len = (int)(FileId.GetCapacity() / 2);
+ if (Parent != 0)
+ if (Parent->Parent != 0)
+ len += 1 + Parent->GetLengthU();
+ return len;
+ }
+
+ AString GetPath(bool checkSusp, int skipSize) const
+ {
+ AString s;
+ int len = GetLength(checkSusp, skipSize);
+ char *p = s.GetBuffer(len + 1);
+ p += len;
+ *p = 0;
+ const CDir *cur = this;
+ for (;;)
+ {
+ int curLen = cur->GetLengthCur(checkSusp, skipSize);
+ p -= curLen;
+ memmove(p, (const char *)(const Byte *)cur->GetNameCur(checkSusp, skipSize), curLen);
+ cur = cur->Parent;
+ if (cur == 0)
+ break;
+ if (cur->Parent == 0)
+ break;
+ p--;
+ *p = CHAR_PATH_SEPARATOR;
+ }
+ s.ReleaseBuffer();
+ return s;
+ }
+
+ UString GetPathU() const
+ {
+ UString s;
+ int len = GetLengthU();
+ wchar_t *p = s.GetBuffer(len + 1);
+ p += len;
+ *p = 0;
+ const CDir *cur = this;
+ for (;;)
+ {
+ int curLen = (int)(cur->FileId.GetCapacity() / 2);
+ p -= curLen;
+ for (int i = 0; i < curLen; i++)
+ {
+ Byte b0 = ((const Byte *)cur->FileId)[i * 2];
+ Byte b1 = ((const Byte *)cur->FileId)[i * 2 + 1];
+ p[i] = (wchar_t)(((wchar_t)b0 << 8) | b1);
+ }
+ cur = cur->Parent;
+ if (cur == 0)
+ break;
+ if (cur->Parent == 0)
+ break;
+ p--;
+ *p = WCHAR_PATH_SEPARATOR;
+ }
+ s.ReleaseBuffer();
+ return s;
+ }
+};
+
+struct CDateTime
+{
+ UInt16 Year;
+ Byte Month;
+ Byte Day;
+ Byte Hour;
+ Byte Minute;
+ Byte Second;
+ Byte Hundredths;
+ signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
+ bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
+ Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
+
+ bool GetFileTime(FILETIME &ft) const
+ {
+ UInt64 value;
+ bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value);
+ if (res)
+ {
+ value -= (UInt64)((Int64)GmtOffset * 15 * 60);
+ value *= 10000000;
+ }
+ ft.dwLowDateTime = (DWORD)value;
+ ft.dwHighDateTime = (DWORD)(value >> 32);
+ return res;
+ }
+};
+
+struct CBootRecordDescriptor
+{
+ Byte BootSystemId[32]; // a-characters
+ Byte BootId[32]; // a-characters
+ Byte BootSystemUse[1977];
+};
+
+struct CBootValidationEntry
+{
+ Byte PlatformId;
+ Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM.
+};
+
+struct CBootInitialEntry
+{
+ bool Bootable;
+ Byte BootMediaType;
+ UInt16 LoadSegment;
+ /* This is the load segment for the initial boot image. If this
+ value is 0 the system will use the traditional segment of 7C0. If this value
+ is non-zero the system will use the specified segment. This applies to x86
+ architectures only. For "flat" model architectures (such as Motorola) this
+ is the address divided by 10. */
+ Byte SystemType; // This must be a copy of byte 5 (System Type) from the
+ // Partition Table found in the boot image.
+ UInt16 SectorCount; // This is the number of virtual/emulated sectors the system
+ // will store at Load Segment during the initial boot procedure.
+ UInt32 LoadRBA; // This is the start address of the virtual disk. CD’s use
+ // Relative/Logical block addressing.
+
+ UInt64 GetSize() const
+ {
+ // if (BootMediaType == NBootMediaType::k1d44Floppy) (1440 << 10);
+ return SectorCount * 512;
+ }
+
+ UString GetName() const
+ {
+ UString s;
+ if (Bootable)
+ s += L"Bootable";
+ else
+ s += L"NotBootable";
+ s += L"_";
+ if (BootMediaType >= kNumBootMediaTypes)
+ {
+ wchar_t name[16];
+ ConvertUInt32ToString(BootMediaType, name);
+ s += name;
+ }
+ else
+ s += kMediaTypes[BootMediaType];
+ s += L".img";
+ return s;
+ }
+};
+
+struct CVolumeDescriptor
+{
+ Byte VolFlags;
+ Byte SystemId[32]; // a-characters. An identification of a system
+ // which can recognize and act upon the content of the Logical
+ // Sectors with logical Sector Numbers 0 to 15 of the volume.
+ Byte VolumeId[32]; // d-characters. An identification of the volume.
+ UInt32 VolumeSpaceSize; // the number of Logical Blocks in which the Volume Space of the volume is recorded
+ Byte EscapeSequence[32];
+ UInt16 VolumeSetSize;
+ UInt16 VolumeSequenceNumber; // the ordinal number of the volume in the Volume Set of which the volume is a member.
+ UInt16 LogicalBlockSize;
+ UInt32 PathTableSize;
+ UInt32 LPathTableLocation;
+ UInt32 LOptionalPathTableLocation;
+ UInt32 MPathTableLocation;
+ UInt32 MOptionalPathTableLocation;
+ CDirRecord RootDirRecord;
+ Byte VolumeSetId[128];
+ Byte PublisherId[128];
+ Byte DataPreparerId[128];
+ Byte ApplicationId[128];
+ Byte CopyrightFileId[37];
+ Byte AbstractFileId[37];
+ Byte BibFileId[37];
+ CDateTime CTime;
+ CDateTime MTime;
+ CDateTime ExpirationTime;
+ CDateTime EffectiveTime;
+ Byte FileStructureVersion; // = 1;
+ Byte ApplicationUse[512];
+
+ bool IsJoliet() const
+ {
+ if ((VolFlags & 1) != 0)
+ return false;
+ Byte b = EscapeSequence[2];
+ return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F &&
+ (b == 0x40 || b == 0x43 || b == 0x45));
+ }
+};
+
+struct CRef
+{
+ CDir *Dir;
+ UInt32 Index;
+};
+
+const UInt32 kBlockSize = 1 << 11;
+
+class CInArchive
+{
+ CMyComPtr<IInStream> _stream;
+ UInt64 _position;
+
+ Byte m_Buffer[kBlockSize];
+ UInt32 m_BufferPos;
+
+ CDir _rootDir;
+ bool _bootIsDefined;
+ CBootRecordDescriptor _bootDesc;
+
+ void Skip(size_t size);
+ void SkipZeros(size_t size);
+ Byte ReadByte();
+ void ReadBytes(Byte *data, UInt32 size);
+ UInt16 ReadUInt16Spec();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32Le();
+ UInt32 ReadUInt32Be();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ UInt32 ReadDigits(int numDigits);
+ void ReadDateTime(CDateTime &d);
+ void ReadRecordingDateTime(CRecordingDateTime &t);
+ void ReadDirRecord2(CDirRecord &r, Byte len);
+ void ReadDirRecord(CDirRecord &r);
+
+ void ReadBootRecordDescriptor(CBootRecordDescriptor &d);
+ void ReadVolumeDescriptor(CVolumeDescriptor &d);
+
+ void SeekToBlock(UInt32 blockIndex);
+ void ReadDir(CDir &d, int level);
+ void CreateRefs(CDir &d);
+
+ void ReadBootInfo();
+ HRESULT Open2();
+public:
+ HRESULT Open(IInStream *inStream);
+ void Clear();
+
+ UInt64 _archiveSize;
+
+ CRecordVector<CRef> Refs;
+ CObjectVector<CVolumeDescriptor> VolDescs;
+ int MainVolDescIndex;
+ UInt32 BlockSize;
+ CObjectVector<CBootInitialEntry> BootEntries;
+ bool IncorrectBigEndian;
+
+
+ bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }
+
+ UInt64 GetBootItemSize(int index) const
+ {
+ const CBootInitialEntry &be = BootEntries[index];
+ UInt64 size = be.GetSize();
+ if (be.BootMediaType == NBootMediaType::k1d2Floppy)
+ size = (1200 << 10);
+ else if (be.BootMediaType == NBootMediaType::k1d44Floppy)
+ size = (1440 << 10);
+ else if (be.BootMediaType == NBootMediaType::k2d88Floppy)
+ size = (2880 << 10);
+ UInt64 startPos = be.LoadRBA * BlockSize;
+ if (startPos < _archiveSize)
+ {
+ if (_archiveSize - startPos < size)
+ size = _archiveSize - startPos;
+ }
+ return size;
+ }
+
+ bool IsSusp;
+ int SuspSkipSize;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoItem.h b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoItem.h
new file mode 100644
index 000000000..f39c2f5d2
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoItem.h
@@ -0,0 +1,141 @@
+// Archive/IsoItem.h
+
+#ifndef __ARCHIVE_ISO_ITEM_H
+#define __ARCHIVE_ISO_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+
+#include "Windows/Time.h"
+
+#include "IsoHeader.h"
+
+namespace NArchive {
+namespace NIso {
+
+struct CRecordingDateTime
+{
+ Byte Year;
+ Byte Month;
+ Byte Day;
+ Byte Hour;
+ Byte Minute;
+ Byte Second;
+ signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
+
+ bool GetFileTime(FILETIME &ft) const
+ {
+ UInt64 value;
+ bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value);
+ if (res)
+ {
+ value -= (UInt64)((Int64)GmtOffset * 15 * 60);
+ value *= 10000000;
+ }
+ ft.dwLowDateTime = (DWORD)value;
+ ft.dwHighDateTime = (DWORD)(value >> 32);
+ return res;
+ }
+};
+
+struct CDirRecord
+{
+ Byte ExtendedAttributeRecordLen;
+ UInt32 ExtentLocation;
+ UInt32 DataLength;
+ CRecordingDateTime DateTime;
+ Byte FileFlags;
+ Byte FileUnitSize;
+ Byte InterleaveGapSize;
+ UInt16 VolSequenceNumber;
+ CByteBuffer FileId;
+ CByteBuffer SystemUse;
+
+ bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; }
+ bool IsSystemItem() const
+ {
+ if (FileId.GetCapacity() != 1)
+ return false;
+ Byte b = *(const Byte *)FileId;
+ return (b == 0 || b == 1);
+ }
+
+ const Byte* FindSuspName(int skipSize, int &lenRes) const
+ {
+ lenRes = 0;
+ const Byte *p = (const Byte *)SystemUse + skipSize;
+ int length = (int)(SystemUse.GetCapacity() - skipSize);
+ while (length >= 5)
+ {
+ int len = p[2];
+ if (p[0] == 'N' && p[1] == 'M' && p[3] == 1)
+ {
+ lenRes = len - 5;
+ return p + 5;
+ }
+ p += len;
+ length -= len;
+ }
+ return 0;
+ }
+
+ int GetLengthCur(bool checkSusp, int skipSize) const
+ {
+ if (checkSusp)
+ {
+ int len;
+ const Byte *res = FindSuspName(skipSize, len);
+ if (res != 0)
+ return len;
+ }
+ return (int)FileId.GetCapacity();
+ }
+
+ const Byte* GetNameCur(bool checkSusp, int skipSize) const
+ {
+ if (checkSusp)
+ {
+ int len;
+ const Byte *res = FindSuspName(skipSize, len);
+ if (res != 0)
+ return res;
+ }
+ return (const Byte *)FileId;
+ }
+
+
+ bool CheckSusp(const Byte *p, int &startPos) const
+ {
+ if (p[0] == 'S' &&
+ p[1] == 'P' &&
+ p[2] == 0x7 &&
+ p[3] == 0x1 &&
+ p[4] == 0xBE &&
+ p[5] == 0xEF)
+ {
+ startPos = p[6];
+ return true;
+ }
+ return false;
+ }
+
+ bool CheckSusp(int &startPos) const
+ {
+ const Byte *p = (const Byte *)SystemUse;
+ int length = (int)SystemUse.GetCapacity();
+ const int kMinLen = 7;
+ if (length < kMinLen)
+ return false;
+ if (CheckSusp(p, startPos))
+ return true;
+ const int kOffset2 = 14;
+ if (length < kOffset2 + kMinLen)
+ return false;
+ return CheckSusp(p + kOffset2, startPos);
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoRegister.cpp
new file mode 100644
index 000000000..67a09c769
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Iso/IsoRegister.cpp
@@ -0,0 +1,13 @@
+// IsoRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "IsoHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NIso::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Iso", L"iso img", 0, 0xE7, { 'C', 'D', '0', '0', '1', 0x1 }, 7, false, CreateArc, 0 };
+
+REGISTER_ARC(Iso)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/LzhHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/LzhHandler.cpp
new file mode 100644
index 000000000..2c4eb9089
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/LzhHandler.cpp
@@ -0,0 +1,775 @@
+// LzhHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../ICoder.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/LzhDecoder.h"
+
+#include "IArchive.h"
+
+#include "Common/ItemNameUtils.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NLzh{
+
+const int kMethodIdSize = 5;
+
+const Byte kExtIdFileName = 0x01;
+const Byte kExtIdDirName = 0x02;
+const Byte kExtIdUnixTime = 0x54;
+
+struct CExtension
+{
+ Byte Type;
+ CByteBuffer Data;
+ AString GetString() const
+ {
+ AString s;
+ for (size_t i = 0; i < Data.GetCapacity(); i++)
+ {
+ char c = (char)Data[i];
+ if (c == 0)
+ break;
+ s += c;
+ }
+ return s;
+ }
+};
+
+struct CItem
+{
+ AString Name;
+ Byte Method[kMethodIdSize];
+ Byte Attributes;
+ Byte Level;
+ Byte OsId;
+ UInt32 PackSize;
+ UInt32 Size;
+ UInt32 ModifiedTime;
+ UInt16 CRC;
+ CObjectVector<CExtension> Extensions;
+
+ bool IsValidMethod() const { return (Method[0] == '-' && Method[1] == 'l' && Method[4] == '-'); }
+ bool IsLhMethod() const {return (IsValidMethod() && Method[2] == 'h'); }
+ bool IsDir() const {return (IsLhMethod() && Method[3] == 'd'); }
+
+ bool IsCopyMethod() const
+ {
+ return (IsLhMethod() && Method[3] == '0') ||
+ (IsValidMethod() && Method[2] == 'z' && Method[3] == '4');
+ }
+
+ bool IsLh1GroupMethod() const
+ {
+ if (!IsLhMethod())
+ return false;
+ switch(Method[3])
+ {
+ case '1':
+ return true;
+ }
+ return false;
+ }
+
+ bool IsLh4GroupMethod() const
+ {
+ if (!IsLhMethod())
+ return false;
+ switch(Method[3])
+ {
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ return true;
+ }
+ return false;
+ }
+
+ int GetNumDictBits() const
+ {
+ if (!IsLhMethod())
+ return 0;
+ switch(Method[3])
+ {
+ case '1': return 12;
+ case '2': return 13;
+ case '3': return 13;
+ case '4': return 12;
+ case '5': return 13;
+ case '6': return 15;
+ case '7': return 16;
+ }
+ return 0;
+ }
+
+ int FindExt(Byte type) const
+ {
+ for (int i = 0; i < Extensions.Size(); i++)
+ if (Extensions[i].Type == type)
+ return i;
+ return -1;
+ }
+ bool GetUnixTime(UInt32 &value) const
+ {
+ int index = FindExt(kExtIdUnixTime);
+ if (index < 0)
+ {
+ if (Level == 2)
+ {
+ value = ModifiedTime;
+ return true;
+ }
+ return false;
+ }
+ const Byte *data = (const Byte *)(Extensions[index].Data);
+ value = GetUi32(data);
+ return true;
+ }
+
+ AString GetDirName() const
+ {
+ int index = FindExt(kExtIdDirName);
+ if (index < 0)
+ return AString();
+ return Extensions[index].GetString();
+ }
+
+ AString GetFileName() const
+ {
+ int index = FindExt(kExtIdFileName);
+ if (index < 0)
+ return Name;
+ return Extensions[index].GetString();
+ }
+
+ AString GetName() const
+ {
+ AString dirName = GetDirName();
+ const char kDirSeparator = CHAR_PATH_SEPARATOR; // '\\';
+ // check kDirSeparator in Linux
+ dirName.Replace((char)(unsigned char)0xFF, kDirSeparator);
+ if (!dirName.IsEmpty() && dirName.Back() != kDirSeparator)
+ dirName += kDirSeparator;
+ return dirName + GetFileName();
+ }
+};
+
+struct CItemEx: public CItem
+{
+ UInt64 DataPosition;
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+ UInt64 m_Position;
+
+ HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
+ HRESULT CheckReadBytes(void *data, UInt32 size);
+public:
+ HRESULT Open(IInStream *inStream);
+ HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
+ HRESULT Skip(UInt64 numBytes);
+};
+
+HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
+{
+ size_t realProcessedSize = size;
+ RINOK(ReadStream(m_Stream, data, &realProcessedSize));
+ processedSize = (UInt32)realProcessedSize;
+ m_Position += processedSize;
+ return S_OK;
+}
+
+HRESULT CInArchive::CheckReadBytes(void *data, UInt32 size)
+{
+ UInt32 processedSize;
+ RINOK(ReadBytes(data, size, processedSize));
+ return (processedSize == size) ? S_OK: S_FALSE;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
+ m_Stream = inStream;
+ return S_OK;
+}
+
+static const Byte *ReadUInt16(const Byte *p, UInt16 &v)
+{
+ v = Get16(p);
+ return p + 2;
+}
+
+static const Byte *ReadString(const Byte *p, size_t size, AString &s)
+{
+ s.Empty();
+ for (size_t i = 0; i < size; i++)
+ {
+ char c = p[i];
+ if (c == 0)
+ break;
+ s += c;
+ }
+ return p + size;
+}
+
+static Byte CalcSum(const Byte *data, size_t size)
+{
+ Byte sum = 0;
+ for (size_t i = 0; i < size; i++)
+ sum = (Byte)(sum + data[i]);
+ return sum;
+}
+
+HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
+{
+ filled = false;
+
+ UInt32 processedSize;
+ Byte startHeader[2];
+ RINOK(ReadBytes(startHeader, 2, processedSize))
+ if (processedSize == 0)
+ return S_OK;
+ if (processedSize == 1)
+ return (startHeader[0] == 0) ? S_OK: S_FALSE;
+ if (startHeader[0] == 0 && startHeader[1] == 0)
+ return S_OK;
+
+ Byte header[256];
+ const UInt32 kBasicPartSize = 22;
+ RINOK(ReadBytes(header, kBasicPartSize, processedSize));
+ if (processedSize != kBasicPartSize)
+ return (startHeader[0] == 0) ? S_OK: S_FALSE;
+
+ const Byte *p = header;
+ memcpy(item.Method, p, kMethodIdSize);
+ if (!item.IsValidMethod())
+ return S_OK;
+ p += kMethodIdSize;
+ item.PackSize = Get32(p);
+ item.Size = Get32(p + 4);
+ item.ModifiedTime = Get32(p + 8);
+ item.Attributes = p[12];
+ item.Level = p[13];
+ p += 14;
+ if (item.Level > 2)
+ return S_FALSE;
+ UInt32 headerSize;
+ if (item.Level < 2)
+ {
+ headerSize = startHeader[0];
+ if (headerSize < kBasicPartSize)
+ return S_FALSE;
+ UInt32 remain = headerSize - kBasicPartSize;
+ RINOK(CheckReadBytes(header + kBasicPartSize, remain));
+ if (startHeader[1] != CalcSum(header, headerSize))
+ return S_FALSE;
+ size_t nameLength = *p++;
+ if ((p - header) + nameLength + 2 > headerSize)
+ return S_FALSE;
+ p = ReadString(p, nameLength, item.Name);
+ }
+ else
+ headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8);
+ p = ReadUInt16(p, item.CRC);
+ if (item.Level != 0)
+ {
+ if (item.Level == 2)
+ {
+ RINOK(CheckReadBytes(header + kBasicPartSize, 2));
+ }
+ if ((size_t)(p - header) + 3 > headerSize)
+ return S_FALSE;
+ item.OsId = *p++;
+ UInt16 nextSize;
+ p = ReadUInt16(p, nextSize);
+ while (nextSize != 0)
+ {
+ if (nextSize < 3)
+ return S_FALSE;
+ if (item.Level == 1)
+ {
+ if (item.PackSize < nextSize)
+ return S_FALSE;
+ item.PackSize -= nextSize;
+ }
+ CExtension ext;
+ RINOK(CheckReadBytes(&ext.Type, 1))
+ nextSize -= 3;
+ ext.Data.SetCapacity(nextSize);
+ RINOK(CheckReadBytes((Byte *)ext.Data, nextSize))
+ item.Extensions.Add(ext);
+ Byte hdr2[2];
+ RINOK(CheckReadBytes(hdr2, 2));
+ ReadUInt16(hdr2, nextSize);
+ }
+ }
+ item.DataPosition = m_Position;
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CInArchive::Skip(UInt64 numBytes)
+{
+ UInt64 newPostion;
+ RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
+ m_Position += numBytes;
+ if (m_Position != newPostion)
+ return E_FAIL;
+ return S_OK;
+}
+
+struct COsPair
+{
+ Byte Id;
+ const char *Name;
+};
+
+static COsPair g_OsPairs[] =
+{
+ { 0, "MS-DOS" },
+ { 'M', "MS-DOS" },
+ { '2', "OS/2" },
+ { '9', "OS9" },
+ { 'K', "OS/68K" },
+ { '3', "OS/386" },
+ { 'H', "HUMAN" },
+ { 'U', "UNIX" },
+ { 'C', "CP/M" },
+ { 'F', "FLEX" },
+ { 'm', "Mac" },
+ { 'R', "Runser" },
+ { 'T', "TownsOS" },
+ { 'X', "XOSK" },
+ { 'w', "Windows 95" },
+ { 'W', "Windows NT" },
+ { 'J', "Java VM" }
+};
+
+static const char *kUnknownOS = "Unknown";
+
+static const char *GetOS(Byte osId)
+{
+ for (int i = 0; i < sizeof(g_OsPairs) / sizeof(g_OsPairs[0]); i++)
+ if (g_OsPairs[i].Id == osId)
+ return g_OsPairs[i].Name;
+ return kUnknownOS;
+}
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ // { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR}
+};
+
+class CCRC
+{
+ UInt16 _value;
+public:
+ static UInt16 Table[256];
+ static void InitTable();
+
+ CCRC(): _value(0) {}
+ void Init() { _value = 0; }
+ void Update(const void *data, size_t size);
+ UInt16 GetDigest() const { return _value; }
+};
+
+static const UInt16 kCRCPoly = 0xA001;
+
+UInt16 CCRC::Table[256];
+
+void CCRC::InitTable()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ for (int j = 0; j < 8; j++)
+ if (r & 1)
+ r = (r >> 1) ^ kCRCPoly;
+ else
+ r >>= 1;
+ CCRC::Table[i] = (UInt16)r;
+ }
+}
+
+class CCRCTableInit
+{
+public:
+ CCRCTableInit() { CCRC::InitTable(); }
+} g_CRCTableInit;
+
+void CCRC::Update(const void *data, size_t size)
+{
+ UInt16 v = _value;
+ const Byte *p = (const Byte *)data;
+ for (; size > 0; size--, p++)
+ v = (UInt16)(Table[((Byte)(v)) ^ *p] ^ (v >> 8));
+ _value = v;
+}
+
+
+class COutStreamWithCRC:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+private:
+ CCRC _crc;
+ CMyComPtr<ISequentialOutStream> _stream;
+public:
+ void Init(ISequentialOutStream *stream)
+ {
+ _stream = stream;
+ _crc.Init();
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return _crc.GetDigest(); }
+ void InitCRC() { _crc.Init(); }
+};
+
+STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result;
+ if (!_stream)
+ {
+ realProcessedSize = size;
+ result = S_OK;
+ }
+ else
+ result = _stream->Write(data, size, &realProcessedSize);
+ _crc.Update(data, realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CObjectVector<CItemEx> _items;
+ CMyComPtr<IInStream> _stream;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+ CHandler();
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+CHandler::CHandler() {}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItemEx &item = _items[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString s = NItemName::WinNameToOSName(MultiByteToUnicodeString(item.GetName(), CP_OEMCP));
+ if (!s.IsEmpty())
+ {
+ if (s[s.Length() - 1] == WCHAR_PATH_SEPARATOR)
+ s.Delete(s.Length() - 1);
+ prop = s;
+ }
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidCRC: prop = (UInt32)item.CRC; break;
+ case kpidHostOS: prop = GetOS(item.OsId); break;
+ case kpidMTime:
+ {
+ FILETIME utc;
+ UInt32 unixTime;
+ if (item.GetUnixTime(unixTime))
+ NTime::UnixTimeToFileTime(unixTime, utc);
+ else
+ {
+ FILETIME localFileTime;
+ if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utc))
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ else
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ prop = utc;
+ break;
+ }
+ // case kpidAttrib: prop = (UInt32)item.Attributes; break;
+ case kpidMethod:
+ {
+ char method2[kMethodIdSize + 1];
+ method2[kMethodIdSize] = 0;
+ memcpy(method2, item.Method, kMethodIdSize);
+ prop = method2;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ _items.Clear();
+ CInArchive archive;
+
+ UInt64 endPos = 0;
+ bool needSetTotal = true;
+
+ if (callback != NULL)
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+
+ RINOK(archive.Open(stream));
+ for (;;)
+ {
+ CItemEx item;
+ bool filled;
+ HRESULT result = archive.GetNextItem(filled, item);
+ if (result == S_FALSE)
+ return S_FALSE;
+ if (result != S_OK)
+ return S_FALSE;
+ if (!filled)
+ break;
+ _items.Add(item);
+ archive.Skip(item.PackSize);
+ if (callback != NULL)
+ {
+ if (needSetTotal)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos));
+ needSetTotal = false;
+ }
+ if (_items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = item.DataPosition;
+ RINOK(callback->SetCompleted(&numFiles, &numBytes));
+ }
+ }
+ }
+ if (_items.IsEmpty())
+ return S_FALSE;
+
+ _stream = stream;
+ }
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ COM_TRY_END
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool testMode = (testModeSpec != 0);
+ UInt64 totalUnPacked = 0, totalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItemEx &item = _items[allFilesMode ? i : indices[i]];
+ totalUnPacked += item.Size;
+ totalPacked += item.PackSize;
+ }
+ RINOK(extractCallback->SetTotal(totalUnPacked));
+
+ UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
+ UInt64 currentItemUnPacked, currentItemPacked;
+
+ NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0;
+ CMyComPtr<ICompressCoder> lzhDecoder;
+ CMyComPtr<ICompressCoder> lzh1Decoder;
+ CMyComPtr<ICompressCoder> arj2Decoder;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
+ currentTotalPacked += currentItemPacked)
+ {
+ currentItemUnPacked = 0;
+ currentItemPacked = 0;
+
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = currentTotalUnPacked;
+ RINOK(lps->SetCur());
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode;
+ askMode = testMode ? NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItemEx &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ continue;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ currentItemUnPacked = item.Size;
+ currentItemPacked = item.PackSize;
+
+ {
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init(realOutStream);
+ realOutStream.Release();
+
+ UInt64 pos;
+ _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
+
+ streamSpec->Init(item.PackSize);
+
+ HRESULT result = S_OK;
+ Int32 opRes = NExtract::NOperationResult::kOK;
+
+ if (item.IsCopyMethod())
+ {
+ result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
+ result = S_FALSE;
+ }
+ else if (item.IsLh4GroupMethod())
+ {
+ if (!lzhDecoder)
+ {
+ lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
+ lzhDecoder = lzhDecoderSpec;
+ }
+ lzhDecoderSpec->SetDictionary(item.GetNumDictBits());
+ result = lzhDecoder->Code(inStream, outStream, NULL, &currentItemUnPacked, progress);
+ }
+ /*
+ else if (item.IsLh1GroupMethod())
+ {
+ if (!lzh1Decoder)
+ {
+ lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder;
+ lzh1Decoder = lzh1DecoderSpec;
+ }
+ lzh1DecoderSpec->SetDictionary(item.GetNumDictBits());
+ result = lzh1Decoder->Code(inStream, outStream, NULL, &currentItemUnPacked, progress);
+ }
+ */
+ else
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ if (result == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(result);
+ if (outStreamSpec->GetCRC() != item.CRC)
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Lzh", L"lzh lha", 0, 6, { '-', 'l' }, 2, false, CreateArc, 0 };
+
+REGISTER_ARC(Lzh)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/LzmaHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/LzmaHandler.cpp
new file mode 100644
index 000000000..a83e6a1ad
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/LzmaHandler.cpp
@@ -0,0 +1,430 @@
+// LzmaHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/CreateCoder.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/LzmaDecoder.h"
+
+#include "Common/DummyOutStream.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NLzma {
+
+static bool CheckDicSize(const Byte *p)
+{
+ UInt32 dicSize = GetUi32(p);
+ for (int i = 1; i <= 30; i++)
+ if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i))
+ return true;
+ return (dicSize == 0xFFFFFFFF);
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+struct CHeader
+{
+ UInt64 Size;
+ Byte FilterID;
+ Byte LzmaProps[5];
+
+ UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); }
+ bool HasSize() const { return (Size != (UInt64)(Int64)-1); }
+ bool Parse(const Byte *buf, bool isThereFilter);
+};
+
+bool CHeader::Parse(const Byte *buf, bool isThereFilter)
+{
+ FilterID = 0;
+ if (isThereFilter)
+ FilterID = buf[0];
+ const Byte *sig = buf + (isThereFilter ? 1 : 0);
+ for (int i = 0; i < 5; i++)
+ LzmaProps[i] = sig[i];
+ Size = GetUi64(sig + 5);
+ return
+ LzmaProps[0] < 5 * 5 * 9 &&
+ FilterID < 2 &&
+ (!HasSize() || Size < ((UInt64)1 << 56)) &&
+ CheckDicSize(LzmaProps + 1);
+}
+
+class CDecoder
+{
+ NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+ CMyComPtr<ICompressCoder> _lzmaDecoder;
+ CMyComPtr<ISequentialOutStream> _bcjStream;
+public:
+ ~CDecoder();
+ HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS
+ bool filtered, ISequentialInStream *inStream);
+
+ HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+
+ UInt64 GetInputProcessedSize() const { return _lzmaDecoderSpec->GetInputProcessedSize(); }
+
+ void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoderSpec->ReleaseInStream(); }
+
+ HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize)
+ { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); }
+};
+
+static const UInt64 k_BCJ = 0x03030103;
+
+HRESULT CDecoder::Create(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ bool filteredMode, ISequentialInStream *inStream)
+{
+ if (!_lzmaDecoder)
+ {
+ _lzmaDecoderSpec = new NCompress::NLzma::CDecoder;
+ _lzmaDecoder = _lzmaDecoderSpec;
+ }
+
+ if (filteredMode)
+ {
+ if (!_bcjStream)
+ {
+ CMyComPtr<ICompressCoder> coder;
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS k_BCJ, coder, false));
+ if (!coder)
+ return E_NOTIMPL;
+ coder.QueryInterface(IID_ISequentialOutStream, &_bcjStream);
+ if (!_bcjStream)
+ return E_NOTIMPL;
+ }
+ }
+
+ return _lzmaDecoderSpec->SetInStream(inStream);
+}
+
+CDecoder::~CDecoder()
+{
+ ReleaseInStream();
+}
+
+HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream,
+ ICompressProgressInfo *progress)
+{
+ if (header.FilterID > 1)
+ return E_NOTIMPL;
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ _lzmaDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+ if (!setDecoderProperties)
+ return E_NOTIMPL;
+ RINOK(setDecoderProperties->SetDecoderProperties2(header.LzmaProps, 5));
+ }
+
+ CMyComPtr<ICompressSetOutStream> setOutStream;
+
+ bool filteredMode = (header.FilterID == 1);
+
+ if (filteredMode)
+ {
+ _bcjStream.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
+ if (!setOutStream)
+ return E_NOTIMPL;
+ RINOK(setOutStream->SetOutStream(outStream));
+ outStream = _bcjStream;
+ }
+
+ const UInt64 *Size = header.HasSize() ? &header.Size : NULL;
+ HRESULT res = _lzmaDecoderSpec->CodeResume(outStream, Size, progress);
+
+ if (filteredMode)
+ {
+ CMyComPtr<IOutStreamFlush> flush;
+ _bcjStream.QueryInterface(IID_IOutStreamFlush, &flush);
+ if (flush)
+ {
+ HRESULT res2 = flush->Flush();
+ if (res == S_OK)
+ res = res2;
+ }
+ HRESULT res2 = setOutStream->ReleaseOutStream();
+ if (res == S_OK)
+ res = res2;
+ }
+ RINOK(res);
+
+ return S_OK;
+}
+
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+ CHeader _header;
+ bool _lzma86;
+ UInt64 _startPosition;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ DECL_EXTERNAL_CODECS_VARS
+ DECL_ISetCompressCodecsInfo
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+
+ CHandler(bool lzma86) { _lzma86 = lzma86; }
+
+ unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); }
+
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+static void DictSizeToString(UInt32 value, char *s)
+{
+ for (int i = 0; i <= 31; i++)
+ if ((UInt32(1) << i) == value)
+ {
+ ::ConvertUInt32ToString(i, s);
+ return;
+ }
+ char c = 'b';
+ if ((value & ((1 << 20) - 1)) == 0)
+ {
+ value >>= 20;
+ c = 'm';
+ }
+ else if ((value & ((1 << 10) - 1)) == 0)
+ {
+ value >>= 10;
+ c = 'k';
+ }
+ ::ConvertUInt32ToString(value, s);
+ int p = MyStringLen(s);
+ s[p++] = c;
+ s[p++] = '\0';
+}
+
+static void MyStrCat(char *d, const char *s)
+{
+ MyStringCopy(d + MyStringLen(d), s);
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidMethod:
+ if (_stream)
+ {
+ char s[64];
+ s[0] = '\0';
+ if (_header.FilterID != 0)
+ MyStrCat(s, "BCJ ");
+ MyStrCat(s, "LZMA:");
+ DictSizeToString(_header.GetDicSize(), s + MyStringLen(s));
+ prop = s;
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *)
+{
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+
+ const UInt32 kBufSize = 1 + 5 + 8 + 1;
+ Byte buf[kBufSize];
+
+ RINOK(ReadStream_FALSE(inStream, buf, kBufSize));
+
+ if (!_header.Parse(buf, _lzma86))
+ return S_FALSE;
+ const Byte *start = buf + GetHeaderSize();
+ if (start[0] != 0)
+ return S_FALSE;
+
+ UInt64 endPos;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
+ _packSize = endPos - _startPosition;
+ _packSizeDefined = true;
+
+ _stream = inStream;
+ _seqStream = inStream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _stream.Release();
+ _seqStream.Release();
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_stream)
+ extractCallback->SetTotal(_packSize);
+
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ }
+
+ CDecoder decoder;
+ HRESULT result = decoder.Create(
+ EXTERNAL_CODECS_VARS
+ _lzma86, _seqStream);
+ RINOK(result);
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ bool firstItem = true;
+
+ for (;;)
+ {
+ lps->OutSize = outStreamSpec->GetSize();
+ lps->InSize = _packSize = decoder.GetInputProcessedSize();
+ _packSizeDefined = true;
+ RINOK(lps->SetCur());
+
+ CHeader st;
+
+ const UInt32 kBufSize = 1 + 5 + 8;
+ Byte buf[kBufSize];
+ const UInt32 headerSize = GetHeaderSize();
+ UInt32 processed;
+ RINOK(decoder.ReadInput(buf, headerSize, &processed));
+ if (processed != headerSize)
+ break;
+
+ if (!st.Parse(buf, _lzma86))
+ break;
+ firstItem = false;
+
+ result = decoder.Code(st, outStream, progress);
+ if (result == E_NOTIMPL)
+ {
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ break;
+ }
+ if (result == S_FALSE)
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ RINOK(result);
+ }
+ if (firstItem)
+ return E_FAIL;
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+static IInArchive *CreateArc() { return new CHandler(false); }
+static IInArchive *CreateArc86() { return new CHandler(true); }
+
+namespace NLzmaAr {
+
+static CArcInfo g_ArcInfo =
+ { L"lzma", L"lzma", 0, 0xA, { 0 }, 0, true, CreateArc, NULL };
+REGISTER_ARC(Lzma)
+
+}
+
+namespace NLzma86Ar {
+
+static CArcInfo g_ArcInfo =
+ { L"lzma86", L"lzma86", 0, 0xB, { 0 }, 0, true, CreateArc86, NULL };
+REGISTER_ARC(Lzma86)
+
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/MachoHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/MachoHandler.cpp
new file mode 100644
index 000000000..a6261f34d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/MachoHandler.cpp
@@ -0,0 +1,500 @@
+// MachoHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
+static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NMacho {
+
+#define MACH_ARCH_ABI64 (1 << 24)
+#define MACH_MACHINE_386 7
+#define MACH_MACHINE_ARM 12
+#define MACH_MACHINE_SPARC 14
+#define MACH_MACHINE_PPC 18
+
+#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC)
+#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386)
+
+#define MACH_CMD_SEGMENT_32 1
+#define MACH_CMD_SEGMENT_64 0x19
+
+#define MACH_SECT_TYPE_MASK 0x000000FF
+#define MACH_SECT_ATTR_MASK 0xFFFFFF00
+
+#define MACH_SECT_ATTR_ZEROFILL 1
+
+static const char *g_SectTypes[] =
+{
+ "REGULAR",
+ "ZEROFILL",
+ "CSTRINGS",
+ "4BYTE_LITERALS",
+ "8BYTE_LITERALS",
+ "LITERAL_POINTERS",
+ "NON_LAZY_SYMBOL_POINTERS",
+ "LAZY_SYMBOL_POINTERS",
+ "SYMBOL_STUBS",
+ "MOD_INIT_FUNC_POINTERS",
+ "MOD_TERM_FUNC_POINTERS",
+ "COALESCED",
+ "GB_ZEROFILL",
+ "INTERPOSING",
+ "16BYTE_LITERALS"
+};
+
+static const char *g_FileTypes[] =
+{
+ "0",
+ "OBJECT",
+ "EXECUTE",
+ "FVMLIB",
+ "CORE",
+ "PRELOAD",
+ "DYLIB",
+ "DYLINKER",
+ "BUNDLE",
+ "DYLIB_STUB",
+ "DSYM"
+};
+
+static const CUInt32PCharPair g_Flags[] =
+{
+ { 31, "PURE_INSTRUCTIONS" },
+ { 30, "NO_TOC" },
+ { 29, "STRIP_STATIC_SYMS" },
+ { 28, "NO_DEAD_STRIP" },
+ { 27, "LIVE_SUPPORT" },
+ { 26, "SELF_MODIFYING_CODE" },
+ { 25, "DEBUG" },
+ { 10, "SOME_INSTRUCTIONS" },
+ { 9, "EXT_RELOC" },
+ { 8, "LOC_RELOC" }
+};
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { MACH_MACHINE_386, "x86" },
+ { MACH_MACHINE_ARM, "ARM" },
+ { MACH_MACHINE_SPARC, "SPARC" },
+ { MACH_MACHINE_PPC, "PowerPC" },
+ { MACH_MACHINE_PPC64, "PowerPC 64-bit" },
+ { MACH_MACHINE_AMD64, "x64" }
+};
+
+static const int kNameSize = 16;
+
+struct CSegment
+{
+ char Name[kNameSize];
+};
+
+struct CSection
+{
+ char Name[kNameSize];
+ char SegName[kNameSize];
+ UInt64 Va;
+ UInt64 Pa;
+ UInt64 VSize;
+ UInt64 PSize;
+
+ UInt32 Flags;
+ int SegmentIndex;
+
+ bool IsDummy;
+
+ CSection(): IsDummy(false) {}
+ // UInt64 GetPackSize() const { return Flags == MACH_SECT_ATTR_ZEROFILL ? 0 : Size; }
+ UInt64 GetPackSize() const { return PSize; }
+};
+
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+ CObjectVector<CSegment> _segments;
+ CObjectVector<CSection> _sections;
+ bool _mode64;
+ bool _be;
+ UInt32 _machine;
+ UInt32 _type;
+ UInt32 _headersSize;
+ UInt64 _totalSize;
+ HRESULT Open2(ISequentialInStream *stream);
+ bool Parse(const Byte *buf, UInt32 size);
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+bool CHandler::Parse(const Byte *buf, UInt32 size)
+{
+ bool mode64 = _mode64;
+ bool be = _be;
+
+ const Byte *bufStart = buf;
+ bool reduceCommands = false;
+ if (size < 512)
+ return false;
+
+ _machine = Get32(buf + 4, be);
+ _type = Get32(buf + 0xC, be);
+
+ UInt32 numCommands = Get32(buf + 0x10, be);
+ UInt32 commandsSize = Get32(buf + 0x14, be);
+ if (commandsSize > size)
+ return false;
+
+ if (commandsSize > (1 << 24) || numCommands > (1 << 18))
+ return false;
+
+ if (numCommands > 16)
+ {
+ reduceCommands = true;
+ numCommands = 16;
+ }
+
+ _headersSize = 0;
+
+ buf += 0x1C;
+ size -= 0x1C;
+
+ if (mode64)
+ {
+ buf += 4;
+ size -= 4;
+ }
+
+ _totalSize = (UInt32)(buf - bufStart);
+ if (commandsSize < size)
+ size = commandsSize;
+
+ for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++)
+ {
+ if (size < 8)
+ return false;
+ UInt32 cmd = Get32(buf, be);
+ UInt32 cmdSize = Get32(buf + 4, be);
+ if (size < cmdSize)
+ return false;
+ if (cmd == MACH_CMD_SEGMENT_32 || cmd == MACH_CMD_SEGMENT_64)
+ {
+ UInt32 offs = (cmd == MACH_CMD_SEGMENT_64) ? 0x48 : 0x38;
+ if (cmdSize < offs)
+ break;
+
+ UInt64 vmAddr, vmSize, phAddr, phSize;
+
+ {
+ if (cmd == MACH_CMD_SEGMENT_64)
+ {
+ vmAddr = Get64(buf + 0x18, be);
+ vmSize = Get64(buf + 0x20, be);
+ phAddr = Get64(buf + 0x28, be);
+ phSize = Get64(buf + 0x30, be);
+ }
+ else
+ {
+ vmAddr = Get32(buf + 0x18, be);
+ vmSize = Get32(buf + 0x1C, be);
+ phAddr = Get32(buf + 0x20, be);
+ phSize = Get32(buf + 0x24, be);
+ }
+ {
+ UInt64 totalSize = phAddr + phSize;
+ if (totalSize > _totalSize)
+ _totalSize = totalSize;
+ }
+ }
+
+ CSegment seg;
+ memcpy(seg.Name, buf + 8, kNameSize);
+ _segments.Add(seg);
+
+ UInt32 numSections = Get32(buf + offs - 8, be);
+ if (numSections > (1 << 8))
+ return false;
+
+ if (numSections == 0)
+ {
+ CSection section;
+ section.IsDummy = true;
+ section.SegmentIndex = _segments.Size() - 1;
+ section.Va = vmAddr;
+ section.PSize = phSize;
+ section.VSize = vmSize;
+ section.Pa = phAddr;
+ section.Flags = 0;
+ _sections.Add(section);
+ }
+ else do
+ {
+ CSection section;
+ UInt32 headerSize = (cmd == MACH_CMD_SEGMENT_64) ? 0x50 : 0x44;
+ const Byte *p = buf + offs;
+ if (cmdSize - offs < headerSize)
+ break;
+ if (cmd == MACH_CMD_SEGMENT_64)
+ {
+ section.Va = Get64(p + 0x20, be);
+ section.VSize = Get64(p + 0x28, be);
+ section.Pa = Get32(p + 0x30, be);
+ section.Flags = Get32(p + 0x40, be);
+ }
+ else
+ {
+ section.Va = Get32(p + 0x20, be);
+ section.VSize = Get32(p + 0x24, be);
+ section.Pa = Get32(p + 0x28, be);
+ section.Flags = Get32(p + 0x38, be);
+ }
+ if (section.Flags == MACH_SECT_ATTR_ZEROFILL)
+ section.PSize = 0;
+ else
+ section.PSize = section.VSize;
+ memcpy(section.Name, p, kNameSize);
+ memcpy(section.SegName, p + kNameSize, kNameSize);
+ section.SegmentIndex = _segments.Size() - 1;
+ _sections.Add(section);
+ offs += headerSize;
+ }
+ while (--numSections);
+
+ if (offs != cmdSize)
+ return false;
+ }
+ buf += cmdSize;
+ size -= cmdSize;
+ }
+ _headersSize = (UInt32)(buf - bufStart);
+ return reduceCommands || (size == 0);
+}
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCpu, VT_BSTR},
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidBigEndian, VT_BOOL},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI4}
+};
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidVa, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _machine, prop); break;
+ case kpidCharacts: TYPE_TO_PROP(g_FileTypes, _type, prop); break;
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _headersSize; break;
+ case kpidBit64: if (_mode64) prop = _mode64; break;
+ case kpidBigEndian: if (_be) prop = _be; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static AString GetName(const char *name)
+{
+ char res[kNameSize + 1];
+ memcpy(res, name, kNameSize);
+ res[kNameSize] = 0;
+ return res;
+}
+
+static AString SectFlagsToString(UInt32 flags)
+{
+ AString res = TypeToString(g_SectTypes, sizeof(g_SectTypes) / sizeof(g_SectTypes[0]),
+ flags & MACH_SECT_TYPE_MASK);
+ AString s = FlagsToString(g_Flags, sizeof(g_Flags) / sizeof(g_Flags[0]),
+ flags & MACH_SECT_ATTR_MASK);
+ if (!s.IsEmpty())
+ {
+ res += ' ';
+ res += s;
+ }
+ return res;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CSection &item = _sections[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ AString s = GetName(_segments[item.SegmentIndex].Name);
+ if (!item.IsDummy)
+ s += GetName(item.Name);
+ StringToProp(s, prop);
+ break;
+ }
+ case kpidSize: /* prop = (UInt64)item.VSize; break; */
+ case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
+ case kpidCharacts: if (!item.IsDummy) StringToProp(SectFlagsToString(item.Flags), prop); break;
+ case kpidOffset: prop = item.Pa; break;
+ case kpidVa: prop = item.Va; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(ISequentialInStream *stream)
+{
+ const UInt32 kBufSize = 1 << 18;
+ const UInt32 kSigSize = 4;
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ size_t processed = kSigSize;
+ RINOK(ReadStream_FALSE(stream, buf, processed));
+ UInt32 sig = GetUi32(buf);
+ bool be, mode64;
+ switch(sig)
+ {
+ case 0xCEFAEDFE: be = true; mode64 = false; break;
+ case 0xCFFAEDFE: be = true; mode64 = true; break;
+ case 0xFEEDFACE: be = false; mode64 = false; break;
+ case 0xFEEDFACF: be = false; mode64 = true; break;
+ default: return S_FALSE;
+ }
+ processed = kBufSize - kSigSize;
+ RINOK(ReadStream(stream, buf + kSigSize, &processed));
+ _mode64 = mode64;
+ _be = be;
+ return Parse(buf, (UInt32)processed + kSigSize) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream));
+ _inStream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _sections.Clear();
+ _segments.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _sections.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _sections.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _sections[allFilesMode ? i : indices[i]].GetPackSize();
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CSection &item = _sections[index];
+ currentItemSize = item.GetPackSize();
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(_inStream->Seek(item.Pa, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"MachO", L"", 0, 0xDF, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Macho)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/MbrHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/MbrHandler.cpp
new file mode 100644
index 000000000..b6d791829
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/MbrHandler.cpp
@@ -0,0 +1,507 @@
+// MbrHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NMbr {
+
+struct CChs
+{
+ Byte Head;
+ Byte SectCyl;
+ Byte Cyl8;
+
+ UInt32 GetSector() const { return SectCyl & 0x3F; }
+ UInt32 GetCyl() const { return ((UInt32)SectCyl >> 6 << 8) | Cyl8; }
+ void ToString(NCOM::CPropVariant &prop) const;
+
+ void Parse(const Byte *p)
+ {
+ Head = p[0];
+ SectCyl = p[1];
+ Cyl8 = p[2];
+ }
+ bool Check() const { return GetSector() > 0; }
+};
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareChs(const CChs &c1, const CChs &c2)
+{
+ RINOZ(MyCompare(c1.GetCyl(), c2.GetCyl()));
+ RINOZ(MyCompare(c1.Head, c2.Head));
+ return MyCompare(c1.GetSector(), c2.GetSector());
+}
+
+static void AddUIntToString(UInt32 val, AString &res)
+{
+ char s[16];
+ ConvertUInt32ToString(val, s);
+ res += s;
+}
+
+void CChs::ToString(NCOM::CPropVariant &prop) const
+{
+ AString s;
+ AddUIntToString(GetCyl(), s);
+ s += '-';
+ AddUIntToString(Head, s);
+ s += '-';
+ AddUIntToString(GetSector(), s);
+ prop = s;
+}
+
+struct CPartition
+{
+ Byte Status;
+ CChs BeginChs;
+ Byte Type;
+ CChs EndChs;
+ UInt32 Lba;
+ UInt32 NumBlocks;
+
+ CPartition() { memset (this, 0, sizeof(*this)); }
+
+ bool IsEmpty() const { return Type == 0; }
+ bool IsExtended() const { return Type == 5 || Type == 0xF; }
+ UInt32 GetLimit() const { return Lba + NumBlocks; }
+ // bool IsActive() const { return Status == 0x80; }
+ UInt64 GetPos() const { return (UInt64)Lba * 512; }
+ UInt64 GetSize() const { return (UInt64)NumBlocks * 512; }
+
+ bool CheckLbaLimits() const { return (UInt32)0xFFFFFFFF - Lba >= NumBlocks; }
+ bool Parse(const Byte *p)
+ {
+ Status = p[0];
+ BeginChs.Parse(p + 1);
+ Type = p[4];
+ EndChs.Parse(p + 5);
+ Lba = GetUi32(p + 8);
+ NumBlocks = GetUi32(p + 12);
+ if (Type == 0)
+ return true;
+ if (Status != 0 && Status != 0x80)
+ return false;
+ return
+ BeginChs.Check() &&
+ EndChs.Check() &&
+ CompareChs(BeginChs, EndChs) <= 0 &&
+ NumBlocks > 0 &&
+ CheckLbaLimits();
+ }
+
+ #ifdef SHOW_DEBUG_INFO
+ void Print() const
+ {
+ NCOM::CPropVariant prop, prop2;
+ BeginChs.ToString(prop);
+ EndChs.ToString(prop2);
+ printf(" %2x %2x %8X %8X %12S %12S", (int)Status, (int)Type, Lba, NumBlocks, prop.bstrVal, prop2.bstrVal);
+ }
+ #endif
+};
+
+struct CPartType
+{
+ UInt32 Id;
+ const char *Ext;
+ const char *Name;
+};
+
+static const char *kFat = "fat";
+
+static const CPartType kPartTypes[] =
+{
+ { 0x01, kFat, "FAT12" },
+ { 0x04, kFat, "FAT16 DOS 3.0+" },
+ { 0x05, 0, "Extended" },
+ { 0x06, kFat, "FAT16 DOS 3.31+" },
+ { 0x07, "ntfs", "NTFS" },
+ { 0x0B, kFat, "FAT32" },
+ { 0x0C, kFat, "FAT32-LBA" },
+ { 0x0E, kFat, "FAT16-LBA" },
+ { 0x0F, 0, "Extended-LBA" },
+ { 0x11, kFat, "FAT12-Hidden" },
+ { 0x14, kFat, "FAT16-Hidden < 32 MB" },
+ { 0x16, kFat, "FAT16-Hidden >= 32 MB" },
+ { 0x1B, kFat, "FAT32-Hidden" },
+ { 0x1C, kFat, "FAT32-LBA-Hidden" },
+ { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" },
+ { 0x82, 0, "Solaris x86 / Linux swap" },
+ { 0x83, 0, "Linux" },
+ { 0xBE, 0, "Solaris 8 boot" },
+ { 0xBF, 0, "New Solaris x86" },
+ { 0xC2, 0, "Linux-Hidden" },
+ { 0xC3, 0, "Linux swap-Hidden" },
+ { 0xEE, 0, "EFI-MBR" },
+ { 0xEE, 0, "EFI" }
+};
+
+static int FindPartType(UInt32 type)
+{
+ for (int i = 0; i < sizeof(kPartTypes) / sizeof(kPartTypes[0]); i++)
+ if (kPartTypes[i].Id == type)
+ return i;
+ return -1;
+}
+
+struct CItem
+{
+ bool IsReal;
+ bool IsPrim;
+ UInt64 Size;
+ CPartition Part;
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CItem> _items;
+ UInt64 _totalSize;
+ CByteBuffer _buffer;
+
+ HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int level);
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int level)
+{
+ if (level >= 128 || _items.Size() >= 128)
+ return S_FALSE;
+
+ const int kNumHeaderParts = 4;
+ CPartition parts[kNumHeaderParts];
+
+ {
+ const UInt32 kSectorSize = 512;
+ _buffer.SetCapacity(kSectorSize);
+ Byte *buf = _buffer;
+ UInt64 newPos = (UInt64)lba << 9;
+ if (newPos + 512 > _totalSize)
+ return S_FALSE;
+ RINOK(stream->Seek(newPos, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+
+ if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+ return S_FALSE;
+
+ for (int i = 0; i < kNumHeaderParts; i++)
+ if (!parts[i].Parse(buf + 0x1BE + 16 * i))
+ return S_FALSE;
+ }
+
+ PRF(printf("\n# %8X", lba));
+
+ UInt32 limLba = lba + 1;
+ if (limLba == 0)
+ return S_FALSE;
+
+ for (int i = 0; i < kNumHeaderParts; i++)
+ {
+ CPartition &part = parts[i];
+
+ if (part.IsEmpty())
+ continue;
+ PRF(printf("\n %2d ", (int)level));
+ #ifdef SHOW_DEBUG_INFO
+ part.Print();
+ #endif
+
+ int numItems = _items.Size();
+ UInt32 newLba = lba + part.Lba;
+
+ if (part.IsExtended())
+ {
+ // if (part.Type == 5) // Check it!
+ newLba = baseLba + part.Lba;
+ if (newLba < limLba)
+ return S_FALSE;
+ HRESULT res = ReadTables(stream, level < 1 ? newLba : baseLba, newLba, level + 1);
+ if (res != S_FALSE && res != S_OK)
+ return res;
+ }
+ if (newLba < limLba)
+ return S_FALSE;
+ part.Lba = newLba;
+ if (!part.CheckLbaLimits())
+ return S_FALSE;
+
+ CItem n;
+ n.Part = part;
+ bool addItem = false;
+ if (numItems == _items.Size())
+ {
+ n.IsPrim = (level == 0);
+ n.IsReal = true;
+ addItem = true;
+ }
+ else
+ {
+ const CItem &back = _items.Back();
+ UInt32 backLimit = back.Part.GetLimit();
+ UInt32 partLimit = part.GetLimit();
+ if (backLimit < partLimit)
+ {
+ n.IsReal = false;
+ n.Part.Lba = backLimit;
+ n.Part.NumBlocks = partLimit - backLimit;
+ addItem = true;
+ }
+ }
+ if (addItem)
+ {
+ if (n.Part.GetLimit() < limLba)
+ return S_FALSE;
+ limLba = n.Part.GetLimit();
+ n.Size = n.Part.GetSize();
+ _items.Add(n);
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &_totalSize));
+ RINOK(ReadTables(stream, 0, 0, 0));
+ if (_items.IsEmpty())
+ return S_FALSE;
+ UInt32 lbaLimit = _items.Back().Part.GetLimit();
+ UInt64 lim = (UInt64)lbaLimit << 9;
+ if (lim < _totalSize)
+ {
+ CItem n;
+ n.Part.Lba = lbaLimit;
+ n.Size = _totalSize - lim;
+ n.IsReal = false;
+ _items.Add(n);
+ }
+ _stream = stream;
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+enum
+{
+ kpidPrimary = kpidUserDefined,
+ kpidBegChs,
+ kpidEndChs
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { L"Primary", kpidPrimary, VT_BOOL},
+ { L"Begin CHS", kpidBegChs, VT_BSTR},
+ { L"End CHS", kpidEndChs, VT_BSTR}
+};
+
+IMP_IInArchive_Props_WITH_NAME
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMainSubfile:
+ {
+ int mainIndex = -1;
+ for (int i = 0; i < _items.Size(); i++)
+ if (_items[i].IsReal)
+ {
+ if (mainIndex >= 0)
+ {
+ mainIndex = -1;
+ break;
+ }
+ mainIndex = i;
+ }
+ if (mainIndex >= 0)
+ prop = (UInt32)mainIndex;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CItem &item = _items[index];
+ const CPartition &part = item.Part;
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ AString s;
+ AddUIntToString(index, s);
+ if (item.IsReal)
+ {
+ int typeIndex = FindPartType(part.Type);
+ s += '.';
+ const char *ext = "img";
+ if (typeIndex >= 0 && kPartTypes[typeIndex].Ext != 0)
+ ext = kPartTypes[typeIndex].Ext;
+ s += ext;
+ }
+ prop = s;
+ break;
+ }
+ case kpidFileSystem:
+ if (item.IsReal)
+ {
+ char s[32];
+ ConvertUInt32ToString(part.Type, s);
+ const char *res = s;
+ int typeIndex = FindPartType(part.Type);
+ if (typeIndex >= 0 && kPartTypes[typeIndex].Name)
+ res = kPartTypes[typeIndex].Name;
+ prop = res;
+ }
+ break;
+ case kpidSize: prop = item.Size; break;;
+ case kpidPackSize: prop = item.Size; break;
+ case kpidOffset: prop = part.GetPos(); break;
+ case kpidPrimary: if (item.IsReal) prop = item.IsPrim; break;
+ case kpidBegChs: if (item.IsReal) part.BeginChs.ToString(prop); break;
+ case kpidEndChs: if (item.IsReal) part.EndChs.ToString(prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ const CPartition &part = item.Part;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ totalSize += item.Size;
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ RINOK(_stream->Seek(part.GetPos(), STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == item.Size ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ return CreateLimitedInStream(_stream, item.Part.GetPos(), item.Size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"MBR", L"mbr", 0, 0xDB, { 1, 1, 0 }, 3, false, CreateArc, 0 };
+
+REGISTER_ARC(Mbr)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/MslzHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/MslzHandler.cpp
new file mode 100644
index 000000000..67495e765
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/MslzHandler.cpp
@@ -0,0 +1,257 @@
+// MslzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "Common/DummyOutStream.h"
+
+namespace NArchive {
+namespace NMslz {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ UInt32 _size;
+ UInt64 _packSize;
+ UString _name;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPath: if (!_name.IsEmpty()) prop = _name; break;
+ case kpidSize: prop = _size; break;
+ case kpidPackSize: prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static const unsigned kSignatureSize = 9;
+static const unsigned kHeaderSize = kSignatureSize + 1 + 4;
+#define MSLZ_SIGNATURE { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41 }
+// old signature: 53 5A 20 88 F0 27 33
+static const Byte signature[kSignatureSize] = MSLZ_SIGNATURE;
+
+static const wchar_t *g_Exts[] =
+{
+ L"dll",
+ L"exe",
+ L"kmd",
+ L"sys"
+};
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ Byte buffer[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buffer, kHeaderSize));
+ if (memcmp(buffer, signature, kSignatureSize) != 0)
+ return S_FALSE;
+ _size = GetUi32(buffer + 10);
+ if (_size > 0xFFFFFFE0)
+ return S_FALSE;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &_packSize));
+
+ if (callback)
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+ if (openVolumeCallback)
+ {
+ NWindows::NCOM::CPropVariant prop;
+ if (openVolumeCallback->GetProperty(kpidName, &prop) == S_OK && prop.vt == VT_BSTR)
+ {
+ UString baseName = prop.bstrVal;
+ if (!baseName.IsEmpty() && baseName.Back() == L'_')
+ {
+ baseName.DeleteBack();
+ Byte replaceByte = buffer[kSignatureSize];
+ if (replaceByte == 0)
+ {
+ for (int i = 0; i < sizeof(g_Exts) / sizeof(g_Exts[0]); i++)
+ {
+ UString s = g_Exts[i];
+ int len = s.Length();
+ Byte b = (Byte)s.Back();
+ s.DeleteBack();
+ if (baseName.Length() >= len &&
+ baseName[baseName.Length() - len] == '.' &&
+ s.CompareNoCase(baseName.Right(len - 1)) == 0)
+ {
+ replaceByte = b;
+ break;
+ }
+ }
+ }
+ if (replaceByte >= 0x20 && replaceByte < 0x80)
+ _name = baseName + (wchar_t)replaceByte;
+ }
+ }
+ }
+ }
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _name.Empty();
+ return S_OK;
+}
+
+// MslzDec is modified LZSS algorithm of Haruhiko Okumura:
+// maxLen = 18; Okumura
+// maxLen = 16; MS
+
+#define PROGRESS_AND_WRITE \
+ if ((dest & kMask) == 0) { RINOK(WriteStream(outStream, buf, kBufSize)); \
+ if ((dest & ((1 << 20) - 1)) == 0) \
+ { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \
+ RINOK(progress->SetRatioInfo(&inSize, &outSize)); }}
+
+static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, ICompressProgressInfo *progress)
+{
+ const unsigned kBufSize = (1 << 12);
+ const unsigned kMask = kBufSize - 1;
+ Byte buf[kBufSize];
+ UInt32 dest = 0;
+ memset(buf, ' ', kBufSize);
+ while (dest < unpackSize)
+ {
+ Byte b;
+ if (!inStream.ReadByte(b))
+ return S_FALSE;
+ for (unsigned mask = (unsigned)b | 0x100; mask > 1 && dest < unpackSize; mask >>= 1)
+ {
+ if (!inStream.ReadByte(b))
+ return S_FALSE;
+ if (mask & 1)
+ {
+ buf[dest++ & kMask] = b;
+ PROGRESS_AND_WRITE
+ }
+ else
+ {
+ Byte b1;
+ if (!inStream.ReadByte(b1))
+ return S_FALSE;
+ const unsigned kMaxLen = 16; // 18 in Okumura's code.
+ unsigned src = (((((unsigned)b1 & 0xF0) << 4) | b) + kMaxLen) & kMask;
+ unsigned len = (b1 & 0xF) + 3;
+ if (len > kMaxLen || dest + len > unpackSize)
+ return S_FALSE;
+ do
+ {
+ buf[dest++ & kMask] = buf[src++ & kMask];
+ PROGRESS_AND_WRITE
+ }
+ while (--len != 0);
+ }
+ }
+ }
+ return WriteStream(outStream, buf, dest & kMask);
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_size);
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ CInBuffer s;
+ if (!s.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ s.SetStream(_stream);
+ s.Init();
+ Byte buffer[kHeaderSize];
+ Int32 opRes = NExtract::NOperationResult::kDataError;
+ if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize)
+ {
+ HRESULT result = MslzDec(s, outStream, _size, progress);
+ if (result == S_OK)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (result != S_FALSE)
+ return result;
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"MsLZ", L"", 0, 0xD5, MSLZ_SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+
+REGISTER_ARC(Mslz)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/MubHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/MubHandler.cpp
new file mode 100644
index 000000000..da4df24c9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/MubHandler.cpp
@@ -0,0 +1,266 @@
+// MubHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get32(p) GetBe32(p)
+
+namespace NArchive {
+namespace NMub {
+
+struct CItem
+{
+ UInt32 Type;
+ UInt32 SubType;
+ UInt64 Offset;
+ UInt64 Size;
+ UInt32 Align;
+ bool IsTail;
+};
+
+const UInt32 kNumFilesMax = 10;
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ UInt64 _startPos;
+ CMyComPtr<IInStream> _stream;
+ UInt32 _numItems;
+ CItem _items[kNumFilesMax + 1];
+ HRESULT Open2(IInStream *stream);
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+#define MACH_ARCH_ABI64 0x1000000
+#define MACH_MACHINE_386 7
+#define MACH_MACHINE_ARM 12
+#define MACH_MACHINE_SPARC 14
+#define MACH_MACHINE_PPC 18
+
+#define MACH_MACHINE_PPC64 (MACH_MACHINE_PPC | MACH_ARCH_ABI64)
+#define MACH_MACHINE_AMD64 (MACH_MACHINE_386 | MACH_ARCH_ABI64)
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ switch(propID)
+ {
+ case kpidExtension:
+ {
+ const wchar_t *ext;
+ if (item.IsTail)
+ ext = L"tail";
+ else
+ {
+ switch(item.Type)
+ {
+ case MACH_MACHINE_386: ext = L"86"; break;
+ case MACH_MACHINE_ARM: ext = L"arm"; break;
+ case MACH_MACHINE_SPARC: ext = L"sparc"; break;
+ case MACH_MACHINE_PPC: ext = L"ppc"; break;
+ case MACH_MACHINE_PPC64: ext = L"ppc64"; break;
+ case MACH_MACHINE_AMD64: ext = L"x64"; break;
+ default: ext = L"unknown"; break;
+ }
+ }
+ prop = ext;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+#define MACH_TYPE_ABI64 (1 << 24)
+#define MACH_SUBTYPE_ABI64 (1 << 31)
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, &_startPos));
+
+ const UInt32 kHeaderSize = 8;
+ const UInt32 kRecordSize = 5 * 4;
+ const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize;
+ Byte buf[kBufSize];
+ size_t processed = kBufSize;
+ RINOK(ReadStream(stream, buf, &processed));
+ if (processed < kHeaderSize)
+ return S_FALSE;
+ UInt32 num = Get32(buf + 4);
+ if (Get32(buf) != 0xCAFEBABE || num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize)
+ return S_FALSE;
+ UInt64 endPosMax = kHeaderSize;
+ for (UInt32 i = 0; i < num; i++)
+ {
+ const Byte *p = buf + kHeaderSize + i * kRecordSize;
+ CItem &sb = _items[i];
+ sb.IsTail = false;
+ sb.Type = Get32(p);
+ sb.SubType = Get32(p + 4);
+ sb.Offset = Get32(p + 8);
+ sb.Size = Get32(p + 12);
+ sb.Align = Get32(p + 16);
+
+ if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 ||
+ (sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 ||
+ sb.Align > 31)
+ return S_FALSE;
+
+ UInt64 endPos = (UInt64)sb.Offset + sb.Size;
+ if (endPos > endPosMax)
+ endPosMax = endPos;
+ }
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ fileSize -= _startPos;
+ _numItems = num;
+ if (fileSize > endPosMax)
+ {
+ CItem &sb = _items[_numItems++];
+ sb.IsTail = true;
+ sb.Type = 0;
+ sb.SubType = 0;
+ sb.Offset = endPosMax;
+ sb.Size = fileSize - endPosMax;
+ sb.Align = 0;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ if (Open2(inStream) != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _numItems = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _numItems;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _numItems;
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ currentTotalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(_stream->Seek(_startPos + item.Offset, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ return CreateLimitedInStream(_stream, _startPos + item.Offset, item.Size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Mub", L"", 0, 0xE2, { 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0 }, 7, false, CreateArc, 0 };
+
+REGISTER_ARC(Mub)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisDecode.cpp
new file mode 100644
index 000000000..0845f965d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisDecode.cpp
@@ -0,0 +1,130 @@
+// NsisDecode.cpp
+
+#include "StdAfx.h"
+
+#include "NsisDecode.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "../../Common/MethodId.h"
+
+#include "../../Compress/BZip2Decoder.h"
+#include "../../Compress/DeflateDecoder.h"
+#include "../../Compress/LzmaDecoder.h"
+
+namespace NArchive {
+namespace NNsis {
+
+static const CMethodId k_BCJ_X86 = 0x03030103;
+
+HRESULT CDecoder::Init(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter)
+{
+ useFilter = false;
+ CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
+
+ if (_decoderInStream)
+ if (method != _method)
+ Release();
+ _method = method;
+ if (!_codecInStream)
+ {
+ switch (method)
+ {
+ // case NMethodType::kCopy: return E_NOTIMPL;
+ case NMethodType::kDeflate: _codecInStream = new NCompress::NDeflate::NDecoder::CNsisCOMCoder(); break;
+ case NMethodType::kBZip2: _codecInStream = new NCompress::NBZip2::CNsisDecoder(); break;
+ case NMethodType::kLZMA: _codecInStream = new NCompress::NLzma::CDecoder(); break;
+ default: return E_NOTIMPL;
+ }
+ }
+
+ if (thereIsFilterFlag)
+ {
+ UInt32 processedSize;
+ BYTE flag;
+ RINOK(inStream->Read(&flag, 1, &processedSize));
+ if (processedSize != 1)
+ return E_FAIL;
+ if (flag > 1)
+ return E_NOTIMPL;
+ useFilter = (flag != 0);
+ }
+
+ if (useFilter)
+ {
+ if (!_filterInStream)
+ {
+ CMyComPtr<ICompressCoder> coder;
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ k_BCJ_X86, coder, false));
+ if (!coder)
+ return E_NOTIMPL;
+ coder.QueryInterface(IID_ISequentialInStream, &_filterInStream);
+ if (!_filterInStream)
+ return E_NOTIMPL;
+ }
+ CMyComPtr<ICompressSetInStream> setInStream;
+ _filterInStream.QueryInterface(IID_ICompressSetInStream, &setInStream);
+ if (!setInStream)
+ return E_NOTIMPL;
+ RINOK(setInStream->SetInStream(_codecInStream));
+ _decoderInStream = _filterInStream;
+ }
+ else
+ _decoderInStream = _codecInStream;
+
+ if (method == NMethodType::kLZMA)
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ _codecInStream.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ static const UInt32 kPropertiesSize = 5;
+ BYTE properties[kPropertiesSize];
+ UInt32 processedSize;
+ RINOK(inStream->Read(properties, kPropertiesSize, &processedSize));
+ if (processedSize != kPropertiesSize)
+ return E_FAIL;
+ RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, kPropertiesSize));
+ }
+ }
+
+ {
+ CMyComPtr<ICompressSetInStream> setInStream;
+ _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream);
+ if (!setInStream)
+ return E_NOTIMPL;
+ RINOK(setInStream->SetInStream(inStream));
+ }
+
+ {
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ _codecInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
+ if (!setOutStreamSize)
+ return E_NOTIMPL;
+ RINOK(setOutStreamSize->SetOutStreamSize(NULL));
+ }
+
+ if (useFilter)
+ {
+ /*
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ _filterInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
+ if (!setOutStreamSize)
+ return E_NOTIMPL;
+ RINOK(setOutStreamSize->SetOutStreamSize(NULL));
+ */
+ }
+
+ return S_OK;
+}
+
+HRESULT CDecoder::Read(void *data, size_t *processedSize)
+{
+ return ReadStream(_decoderInStream, data, processedSize);;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisDecode.h b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisDecode.h
new file mode 100644
index 000000000..36aeb2b14
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisDecode.h
@@ -0,0 +1,47 @@
+// NsisDecode.h
+
+#ifndef __NSIS_DECODE_H
+#define __NSIS_DECODE_H
+
+#include "../../IStream.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace NNsis {
+
+namespace NMethodType
+{
+ enum EEnum
+ {
+ kCopy,
+ kDeflate,
+ kBZip2,
+ kLZMA
+ };
+}
+
+class CDecoder
+{
+ NMethodType::EEnum _method;
+
+ CMyComPtr<ISequentialInStream> _filterInStream;
+ CMyComPtr<ISequentialInStream> _codecInStream;
+ CMyComPtr<ISequentialInStream> _decoderInStream;
+
+public:
+ void Release()
+ {
+ _filterInStream.Release();
+ _codecInStream.Release();
+ _decoderInStream.Release();
+ }
+ HRESULT Init(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter);
+ HRESULT Read(void *data, size_t *processedSize);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisHandler.cpp
new file mode 100644
index 000000000..4058bd2af
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisHandler.cpp
@@ -0,0 +1,510 @@
+// NSisHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "NsisHandler.h"
+
+#define Get32(p) GetUi32(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NNsis {
+
+static const char *kBcjMethod = "BCJ";
+static const char *kUnknownMethod = "Unknown";
+
+static const char *kMethods[] =
+{
+ "Copy",
+ "Deflate",
+ "BZip2",
+ "LZMA"
+};
+
+static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidSolid, VT_BOOL}
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidSolid, VT_BOOL}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ UInt32 dict = 1;
+ bool filter = false;
+ for (int i = 0; i < _archive.Items.Size(); i++)
+ {
+ const CItem &item = _archive.Items[i];
+ filter |= item.UseFilter;
+ if (item.DictionarySize > dict)
+ dict = item.DictionarySize;
+ }
+ prop = GetMethod(filter, dict);
+ break;
+ }
+ case kpidSolid: prop = _archive.IsSolid; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ {
+ if (_archive.Open(
+ EXTERNAL_CODECS_VARS
+ stream, maxCheckStartPosition) != S_OK)
+ return S_FALSE;
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _archive.Clear();
+ _archive.Release();
+ _inStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _archive.Items.Size()
+ #ifdef NSIS_SCRIPT
+ + 1
+ #endif
+ ;
+ return S_OK;
+}
+
+static AString UInt32ToString(UInt32 value)
+{
+ char buffer[16];
+ ConvertUInt32ToString(value, buffer);
+ return buffer;
+}
+
+static AString GetStringForSizeValue(UInt32 value)
+{
+ for (int i = 31; i >= 0; i--)
+ if (((UInt32)1 << i) == value)
+ return UInt32ToString(i);
+ char c = 'b';
+ if (value % (1 << 20) == 0)
+ {
+ value >>= 20;
+ c = 'm';
+ }
+ else if (value % (1 << 10) == 0)
+ {
+ value >>= 10;
+ c = 'k';
+ }
+ return UInt32ToString(value) + c;
+}
+
+AString CHandler::GetMethod(bool useItemFilter, UInt32 dictionary) const
+{
+ NMethodType::EEnum methodIndex = _archive.Method;
+ AString method;
+ if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter)
+ {
+ method += kBcjMethod;
+ method += ' ';
+ }
+ method += (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
+ if (methodIndex == NMethodType::kLZMA)
+ {
+ method += ':';
+ method += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary);
+ }
+ return method;
+}
+
+bool CHandler::GetUncompressedSize(int index, UInt32 &size)
+{
+ size = 0;
+ const CItem &item = _archive.Items[index];
+ if (item.SizeIsDefined)
+ size = item.Size;
+ else if (_archive.IsSolid && item.EstimatedSizeIsDefined)
+ size = item.EstimatedSize;
+ else
+ return false;
+ return true;
+}
+
+bool CHandler::GetCompressedSize(int index, UInt32 &size)
+{
+ size = 0;
+ const CItem &item = _archive.Items[index];
+ if (item.CompressedSizeIsDefined)
+ size = item.CompressedSize;
+ else
+ {
+ if (_archive.IsSolid)
+ {
+ if (index == 0)
+ size = _archive.FirstHeader.GetDataSize();
+ else
+ return false;
+ }
+ else
+ {
+ if (!item.IsCompressed)
+ size = item.Size;
+ else
+ return false;
+ }
+ }
+ return true;
+}
+
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ #ifdef NSIS_SCRIPT
+ if (index >= (UInt32)_archive.Items.Size())
+ {
+ switch(propID)
+ {
+ case kpidPath: prop = L"[NSIS].nsi"; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)_archive.Script.Length(); break;
+ case kpidSolid: prop = false; break;
+ }
+ }
+ else
+ #endif
+ {
+ const CItem &item = _archive.Items[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString s = NItemName::WinNameToOSName(item.GetReducedName(_archive.IsUnicode));
+ if (!s.IsEmpty())
+ prop = (const wchar_t *)s;
+ break;
+ }
+ case kpidSize:
+ {
+ UInt32 size;
+ if (GetUncompressedSize(index, size))
+ prop = (UInt64)size;
+ break;
+ }
+ case kpidPackSize:
+ {
+ UInt32 size;
+ if (GetCompressedSize(index, size))
+ prop = (UInt64)size;
+ break;
+ }
+ case kpidMTime:
+ {
+ if (item.MTime.dwHighDateTime > 0x01000000 &&
+ item.MTime.dwHighDateTime < 0xFF000000)
+ prop = item.MTime;
+ break;
+ }
+ case kpidMethod: prop = GetMethod(item.UseFilter, item.DictionarySize); break;
+ case kpidSolid: prop = _archive.IsSolid; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ GetNumberOfItems(&numItems);
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ #ifdef NSIS_SCRIPT
+ if (index >= (UInt32)_archive.Items.Size())
+ totalSize += _archive.Script.Length();
+ else
+ #endif
+ {
+ UInt32 size;
+ if (_archive.IsSolid)
+ {
+ GetUncompressedSize(index, size);
+ UInt64 pos = _archive.GetPosOfSolidItem(index);
+ if (pos > totalSize)
+ totalSize = pos + size;
+ }
+ else
+ {
+ GetCompressedSize(index, size);
+ totalSize += size;
+ }
+ }
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt32 currentItemSize = 0;
+
+ UInt64 streamPos = 0;
+ if (_archive.IsSolid)
+ {
+ RINOK(_inStream->Seek(_archive.StreamOffset, STREAM_SEEK_SET, NULL));
+ bool useFilter;
+ RINOK(_archive.Decoder.Init(
+ EXTERNAL_CODECS_VARS
+ _inStream, _archive.Method, _archive.FilterFlag, useFilter));
+ }
+
+ CByteBuffer byteBuf;
+ const UInt32 kBufferLength = 1 << 16;
+ byteBuf.SetCapacity(kBufferLength);
+ Byte *buffer = byteBuf;
+
+ CByteBuffer tempBuf;
+
+ bool dataError = false;
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ currentItemSize = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ #ifdef NSIS_SCRIPT
+ if (index >= (UInt32)_archive.Items.Size())
+ {
+ currentItemSize = _archive.Script.Length();
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (!testMode)
+ RINOK(WriteStream(realOutStream, (const char *)_archive.Script, (UInt32)_archive.Script.Length()));
+ }
+ else
+ #endif
+ {
+ const CItem &item = _archive.Items[index];
+
+ if (_archive.IsSolid)
+ GetUncompressedSize(index, currentItemSize);
+ else
+ GetCompressedSize(index, currentItemSize);
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ if (!dataError)
+ {
+ bool needDecompress = false;
+ bool sizeIsKnown = false;
+ UInt32 fullSize = 0;
+
+ bool writeToTemp = false;
+ bool readFromTemp = false;
+
+ if (_archive.IsSolid)
+ {
+ UInt64 pos = _archive.GetPosOfSolidItem(index);
+ while (streamPos < pos)
+ {
+ size_t processedSize = (UInt32)MyMin(pos - streamPos, (UInt64)kBufferLength);
+ HRESULT res = _archive.Decoder.Read(buffer, &processedSize);
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ dataError = true;
+ break;
+ }
+ if (processedSize == 0)
+ {
+ dataError = true;
+ break;
+ }
+ streamPos += processedSize;
+ }
+ if (streamPos == pos)
+ {
+ Byte buffer2[4];
+ size_t processedSize = 4;
+ RINOK(_archive.Decoder.Read(buffer2, &processedSize));
+ if (processedSize != 4)
+ return E_FAIL;
+ streamPos += processedSize;
+ fullSize = Get32(buffer2);
+ sizeIsKnown = true;
+ needDecompress = true;
+
+ if (!testMode && i + 1 < numItems)
+ {
+ UInt64 nextPos = _archive.GetPosOfSolidItem(allFilesMode ? i : indices[i + 1]);
+ if (nextPos < streamPos + fullSize)
+ {
+ tempBuf.Free();
+ tempBuf.SetCapacity(fullSize);
+ writeToTemp = true;
+ }
+ }
+ }
+ else
+ readFromTemp = true;
+ }
+ else
+ {
+ RINOK(_inStream->Seek(_archive.GetPosOfNonSolidItem(index) + 4, STREAM_SEEK_SET, NULL));
+ if (item.IsCompressed)
+ {
+ needDecompress = true;
+ bool useFilter;
+ RINOK(_archive.Decoder.Init(
+ EXTERNAL_CODECS_VARS
+ _inStream, _archive.Method, _archive.FilterFlag, useFilter));
+ // fullSize = Get32(buffer); // It's bug !!!
+ // Test it: what is exact fullSize?
+ fullSize = 0xFFFFFFFF;
+ }
+ else
+ fullSize = item.Size;
+ }
+ if (!dataError)
+ {
+ if (needDecompress)
+ {
+ UInt64 offset = 0;
+ while (!sizeIsKnown || fullSize > 0)
+ {
+ UInt32 curSize = kBufferLength;
+ if (sizeIsKnown && curSize > fullSize)
+ curSize = fullSize;
+ size_t processedSize = curSize;
+ HRESULT res = _archive.Decoder.Read(buffer, &processedSize);
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ dataError = true;
+ break;
+ }
+ if (processedSize == 0)
+ {
+ if (sizeIsKnown)
+ dataError = true;
+ break;
+ }
+
+ if (writeToTemp)
+ memcpy((Byte *)tempBuf + (size_t)offset, buffer, processedSize);
+
+ fullSize -= (UInt32)processedSize;
+ streamPos += processedSize;
+ offset += processedSize;
+
+ UInt64 completed;
+ if (_archive.IsSolid)
+ completed = currentTotalSize + offset;
+ else
+ completed = streamPos;
+ RINOK(extractCallback->SetCompleted(&completed));
+ if (!testMode)
+ RINOK(WriteStream(realOutStream, buffer, processedSize));
+ }
+ }
+ else
+ {
+ if (readFromTemp)
+ {
+ if (!testMode)
+ RINOK(WriteStream(realOutStream, tempBuf, tempBuf.GetCapacity()));
+ }
+ else
+ while (fullSize > 0)
+ {
+ UInt32 curSize = MyMin(fullSize, kBufferLength);
+ UInt32 processedSize;
+ RINOK(_inStream->Read(buffer, curSize, &processedSize));
+ if (processedSize == 0)
+ {
+ dataError = true;
+ break;
+ }
+ fullSize -= processedSize;
+ streamPos += processedSize;
+ if (!testMode)
+ RINOK(WriteStream(realOutStream, buffer, processedSize));
+ }
+ }
+ }
+ }
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(dataError ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisHandler.h
new file mode 100644
index 000000000..6de493df8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisHandler.h
@@ -0,0 +1,43 @@
+// NSisHandler.h
+
+#ifndef __NSIS_HANDLER_H
+#define __NSIS_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+
+#include "NsisIn.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace NNsis {
+
+class CHandler:
+ public IInArchive,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+ CInArchive _archive;
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ bool GetUncompressedSize(int index, UInt32 &size);
+ bool GetCompressedSize(int index, UInt32 &size);
+
+ AString GetMethod(bool useItemFilter, UInt32 dictionary) const;
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+
+ DECL_ISetCompressCodecsInfo
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisIn.cpp
new file mode 100644
index 000000000..407560085
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisIn.cpp
@@ -0,0 +1,1461 @@
+// NsisIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/IntToString.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "NsisIn.h"
+
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NNsis {
+
+Byte kSignature[kSignatureSize] = NSIS_SIGNATURE;
+
+#ifdef NSIS_SCRIPT
+static const char *kCrLf = "\x0D\x0A";
+#endif
+
+#define NS_UN_SKIP_CODE 0xE000
+#define NS_UN_VAR_CODE 0xE001
+#define NS_UN_SHELL_CODE 0xE002
+#define NS_UN_LANG_CODE 0xE003
+#define NS_UN_CODES_START NS_UN_SKIP_CODE
+#define NS_UN_CODES_END NS_UN_LANG_CODE
+
+Byte CInArchive::ReadByte()
+{
+ if (_posInData >= _size)
+ throw 1;
+ return _data[_posInData++];
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ value |= ((UInt32)(ReadByte()) << (8 * i));
+ return value;
+}
+
+void CInArchive::ReadBlockHeader(CBlockHeader &bh)
+{
+ bh.Offset = ReadUInt32();
+ bh.Num = ReadUInt32();
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareItems(void *const *p1, void *const *p2, void * /* param */)
+{
+ const CItem &i1 = **(CItem **)p1;
+ const CItem &i2 = **(CItem **)p2;
+ RINOZ(MyCompare(i1.Pos, i2.Pos));
+ if (i1.IsUnicode)
+ {
+ RINOZ(i1.PrefixU.Compare(i2.PrefixU));
+ RINOZ(i1.NameU.Compare(i2.NameU));
+ }
+ else
+ {
+ RINOZ(i1.PrefixA.Compare(i2.PrefixA));
+ RINOZ(i1.NameA.Compare(i2.NameA));
+ }
+ return 0;
+}
+
+static AString UIntToString(UInt32 v)
+{
+ char sz[32];
+ ConvertUInt64ToString(v, sz);
+ return sz;
+}
+
+static AString IntToString(Int32 v)
+{
+ char sz[32];
+ ConvertInt64ToString(v, sz);
+ return sz;
+}
+
+AString CInArchive::ReadStringA(UInt32 pos) const
+{
+ AString s;
+ if (pos >= _size)
+ return IntToString((Int32)pos);
+ UInt32 offset = GetOffset() + _stringsPos + pos;
+ for (;;)
+ {
+ if (offset >= _size)
+ break; // throw 1;
+ char c = _data[offset++];
+ if (c == 0)
+ break;
+ s += c;
+ }
+ return s;
+}
+
+UString CInArchive::ReadStringU(UInt32 pos) const
+{
+ UString s;
+ UInt32 offset = GetOffset() + _stringsPos + (pos * 2);
+ for (;;)
+ {
+ if (offset >= _size || offset + 1 >= _size)
+ return s; // throw 1;
+ char c0 = _data[offset++];
+ char c1 = _data[offset++];
+ wchar_t c = (c0 | ((wchar_t)c1 << 8));
+ if (c == 0)
+ break;
+ s += c;
+ }
+ return s;
+}
+
+/*
+static AString ParsePrefix(const AString &prefix)
+{
+ AString res = prefix;
+ if (prefix.Length() >= 3)
+ {
+ if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x95 && (Byte)prefix[2] == 0x80)
+ res = "$INSTDIR" + prefix.Mid(3);
+ else if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x96 && (Byte)prefix[2] == 0x80)
+ res = "$OUTDIR" + prefix.Mid(3);
+ }
+ return res;
+}
+*/
+
+#define SYSREGKEY "Software\\Microsoft\\Windows\\CurrentVersion"
+
+/*
+# define CSIDL_PROGRAMS 0x2
+# define CSIDL_PRINTERS 0x4
+# define CSIDL_PERSONAL 0x5
+# define CSIDL_FAVORITES 0x6
+# define CSIDL_STARTUP 0x7
+# define CSIDL_RECENT 0x8
+# define CSIDL_SENDTO 0x9
+# define CSIDL_STARTMENU 0xB
+# define CSIDL_MYMUSIC 0xD
+# define CSIDL_MYVIDEO 0xE
+
+# define CSIDL_DESKTOPDIRECTORY 0x10
+# define CSIDL_NETHOOD 0x13
+# define CSIDL_FONTS 0x14
+# define CSIDL_TEMPLATES 0x15
+# define CSIDL_COMMON_STARTMENU 0x16
+# define CSIDL_COMMON_PROGRAMS 0x17
+# define CSIDL_COMMON_STARTUP 0x18
+# define CSIDL_COMMON_DESKTOPDIRECTORY 0x19
+# define CSIDL_APPDATA 0x1A
+# define CSIDL_PRINTHOOD 0x1B
+# define CSIDL_LOCAL_APPDATA 0x1C
+# define CSIDL_ALTSTARTUP 0x1D
+# define CSIDL_COMMON_ALTSTARTUP 0x1E
+# define CSIDL_COMMON_FAVORITES 0x1F
+
+# define CSIDL_INTERNET_CACHE 0x20
+# define CSIDL_COOKIES 0x21
+# define CSIDL_HISTORY 0x22
+# define CSIDL_COMMON_APPDATA 0x23
+# define CSIDL_WINDOWS 0x24
+# define CSIDL_SYSTEM 0x25
+# define CSIDL_PROGRAM_FILES 0x26
+# define CSIDL_MYPICTURES 0x27
+# define CSIDL_PROFILE 0x28
+# define CSIDL_PROGRAM_FILES_COMMON 0x2B
+# define CSIDL_COMMON_TEMPLATES 0x2D
+# define CSIDL_COMMON_DOCUMENTS 0x2E
+# define CSIDL_COMMON_ADMINTOOLS 0x2F
+
+# define CSIDL_ADMINTOOLS 0x30
+# define CSIDL_COMMON_MUSIC 0x35
+# define CSIDL_COMMON_PICTURES 0x36
+# define CSIDL_COMMON_VIDEO 0x37
+# define CSIDL_RESOURCES 0x38
+# define CSIDL_RESOURCES_LOCALIZED 0x39
+# define CSIDL_CDBURN_AREA 0x3B
+*/
+
+struct CCommandPair
+{
+ int NumParams;
+ const char *Name;
+};
+
+enum
+{
+ // 0
+ EW_INVALID_OPCODE, // zero is invalid. useful for catching errors. (otherwise an all zeroes instruction
+ // does nothing, which is easily ignored but means something is wrong.
+ EW_RET, // return from function call
+ EW_NOP, // Nop/Jump, do nothing: 1, [?new address+1:advance one]
+ EW_ABORT, // Abort: 1 [status]
+ EW_QUIT, // Quit: 0
+ EW_CALL, // Call: 1 [new address+1]
+ EW_UPDATETEXT, // Update status text: 2 [update str, ui_st_updateflag=?ui_st_updateflag:this]
+ EW_SLEEP, // Sleep: 1 [sleep time in milliseconds]
+ EW_BRINGTOFRONT, // BringToFront: 0
+ EW_CHDETAILSVIEW, // SetDetailsView: 2 [listaction,buttonaction]
+
+ // 10
+ EW_SETFILEATTRIBUTES, // SetFileAttributes: 2 [filename, attributes]
+ EW_CREATEDIR, // Create directory: 2, [path, ?update$INSTDIR]
+ EW_IFFILEEXISTS, // IfFileExists: 3, [file name, jump amount if exists, jump amount if not exists]
+ EW_SETFLAG, // Sets a flag: 2 [id, data]
+ EW_IFFLAG, // If a flag: 4 [on, off, id, new value mask]
+ EW_GETFLAG, // Gets a flag: 2 [output, id]
+ EW_RENAME, // Rename: 3 [old, new, rebootok]
+ EW_GETFULLPATHNAME, // GetFullPathName: 2 [output, input, ?lfn:sfn]
+ EW_SEARCHPATH, // SearchPath: 2 [output, filename]
+ EW_GETTEMPFILENAME, // GetTempFileName: 2 [output, base_dir]
+
+ // 20
+ EW_EXTRACTFILE, // File to extract: 6 [overwriteflag, output filename, compressed filedata, filedatetimelow, filedatetimehigh, allow ignore]
+ // overwriteflag: 0x1 = no. 0x0=force, 0x2=try, 0x3=if date is newer
+ EW_DELETEFILE, // Delete File: 2, [filename, rebootok]
+ EW_MESSAGEBOX, // MessageBox: 5,[MB_flags,text,retv1:retv2,moveonretv1:moveonretv2]
+ EW_RMDIR, // RMDir: 2 [path, recursiveflag]
+ EW_STRLEN, // StrLen: 2 [output, input]
+ EW_ASSIGNVAR, // Assign: 4 [variable (0-9) to assign, string to assign, maxlen, startpos]
+ EW_STRCMP, // StrCmp: 5 [str1, str2, jump_if_equal, jump_if_not_equal, case-sensitive?]
+ EW_READENVSTR, // ReadEnvStr/ExpandEnvStrings: 3 [output, string_with_env_variables, IsRead]
+ EW_INTCMP, // IntCmp: 6 [val1, val2, equal, val1<val2, val1>val2, unsigned?]
+ EW_INTOP, // IntOp: 4 [output, input1, input2, op] where op: 0=add, 1=sub, 2=mul, 3=div, 4=bor, 5=band, 6=bxor, 7=bnot input1, 8=lnot input1, 9=lor, 10=land], 11=1%2
+
+ // 30
+ EW_INTFMT, // IntFmt: [output, format, input]
+ EW_PUSHPOP, // Push/Pop/Exchange: 3 [variable/string, ?pop:push, ?exch]
+ EW_FINDWINDOW, // FindWindow: 5, [outputvar, window class,window name, window_parent, window_after]
+ EW_SENDMESSAGE, // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2]
+ EW_ISWINDOW, // IsWindow: 3 [hwnd, jump_if_window, jump_if_notwindow]
+ EW_GETDLGITEM, // GetDlgItem: 3: [outputvar, dialog, item_id]
+ EW_SETCTLCOLORS, // SerCtlColors: 3: [hwnd, pointer to struct colors]
+ EW_SETBRANDINGIMAGE, // SetBrandingImage: 1: [Bitmap file]
+ EW_CREATEFONT, // CreateFont: 5: [handle output, face name, height, weight, flags]
+ EW_SHOWWINDOW, // ShowWindow: 2: [hwnd, show state]
+
+ // 40
+ EW_SHELLEXEC, // ShellExecute program: 4, [shell action, complete commandline, parameters, showwindow]
+ EW_EXECUTE, // Execute program: 3,[complete command line,waitflag,>=0?output errorcode]
+ EW_GETFILETIME, // GetFileTime; 3 [file highout lowout]
+ EW_GETDLLVERSION, // GetDLLVersion: 3 [file highout lowout]
+ EW_REGISTERDLL, // Register DLL: 3,[DLL file name, string ptr of function to call, text to put in display (<0 if none/pass parms), 1 - no unload, 0 - unload]
+ EW_CREATESHORTCUT, // Make Shortcut: 5, [link file, target file, parameters, icon file, iconindex|show mode<<8|hotkey<<16]
+ EW_COPYFILES, // CopyFiles: 3 [source mask, destination location, flags]
+ EW_REBOOT, // Reboot: 0
+ EW_WRITEINI, // Write INI String: 4, [Section, Name, Value, INI File]
+ EW_READINISTR, // ReadINIStr: 4 [output, section, name, ini_file]
+
+ // 50
+ EW_DELREG, // DeleteRegValue/DeleteRegKey: 4, [root key(int), KeyName, ValueName, delkeyonlyifempty]. ValueName is -1 if delete key
+ EW_WRITEREG, // Write Registry value: 5, [RootKey(int),KeyName,ItemName,ItemData,typelen]
+ // typelen=1 for str, 2 for dword, 3 for binary, 0 for expanded str
+ EW_READREGSTR, // ReadRegStr: 5 [output, rootkey(int), keyname, itemname, ==1?int::str]
+ EW_REGENUM, // RegEnum: 5 [output, rootkey, keyname, index, ?key:value]
+ EW_FCLOSE, // FileClose: 1 [handle]
+ EW_FOPEN, // FileOpen: 4 [name, openmode, createmode, outputhandle]
+ EW_FPUTS, // FileWrite: 3 [handle, string, ?int:string]
+ EW_FGETS, // FileRead: 4 [handle, output, maxlen, ?getchar:gets]
+ EW_FSEEK, // FileSeek: 4 [handle, offset, mode, >=0?positionoutput]
+ EW_FINDCLOSE, // FindClose: 1 [handle]
+
+ // 60
+ EW_FINDNEXT, // FindNext: 2 [output, handle]
+ EW_FINDFIRST, // FindFirst: 2 [filespec, output, handleoutput]
+ EW_WRITEUNINSTALLER, // WriteUninstaller: 3 [name, offset, icon_size]
+ EW_LOG, // LogText: 2 [0, text] / LogSet: [1, logstate]
+ EW_SECTIONSET, // SectionSetText: 3: [idx, 0, text]
+ // SectionGetText: 3: [idx, 1, output]
+ // SectionSetFlags: 3: [idx, 2, flags]
+ // SectionGetFlags: 3: [idx, 3, output]
+ EW_INSTTYPESET, // InstTypeSetFlags: 3: [idx, 0, flags]
+ // InstTypeGetFlags: 3: [idx, 1, output]
+ // instructions not actually implemented in exehead, but used in compiler.
+ EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR
+ EW_GETFUNCTIONADDR,
+
+ EW_LOCKWINDOW
+};
+
+#ifdef NSIS_SCRIPT
+static CCommandPair kCommandPairs[] =
+{
+ { 0, "Invalid" },
+ { 0, "Return" },
+ { 1, "Goto" },
+ { 0, "Abort" },
+ { 0, "Quit" },
+ { 1, "Call" },
+ { 2, "UpdateSatusText" },
+ { 1, "Sleep" },
+ { 0, "BringToFront" },
+ { 2, "SetDetailsView" },
+
+ { 2, "SetFileAttributes" },
+ { 2, "SetOutPath" },
+ { 3, "IfFileExists" },
+ { 2, "SetFlag" },
+ { 4, "IfFlag" },
+ { 2, "GetFlag" },
+ { 3, "Rename" },
+ { 2, "GetFullPathName" },
+ { 2, "SearchPath" },
+ { 2, "GetTempFileName" },
+
+ { 6, "File" },
+ { 2, "Delete" },
+ { 5, "MessageBox" },
+ { 2, "RMDir" },
+ { 2, "StrLen" },
+ { 4, "StrCpy" },
+ { 5, "StrCmp" },
+ { 3, "ReadEnvStr" },
+ { 6, "IntCmp" },
+ { 4, "IntOp" },
+
+ { 3, "IntFmt" },
+ { 3, "PushPop" },
+ { 5, "FindWindow" },
+ { 6, "SendMessage" },
+ { 3, "IsWindow" },
+ { 3, "GetDlgItem" },
+ { 3, "SerCtlColors" },
+ { 1, "SetBrandingImage" },
+ { 5, "CreateFont" },
+ { 2, "ShowWindow" },
+
+ { 4, "ShellExecute" },
+ { 3, "Execute" },
+ { 3, "GetFileTime" },
+ { 3, "GetDLLVersion" },
+ { 3, "RegisterDLL" },
+ { 5, "CreateShortCut" },
+ { 3, "CopyFiles" },
+ { 0, "Reboot" },
+ { 4, "WriteINIStr" },
+ { 4, "ReadINIStr" },
+
+ { 4, "DelReg" },
+ { 5, "WriteReg" },
+ { 5, "ReadRegStr" },
+ { 5, "RegEnum" },
+ { 1, "FileClose" },
+ { 4, "FileOpen" },
+ { 3, "FileWrite" },
+ { 4, "FileRead" },
+ { 4, "FileSeek" },
+ { 1, "FindClose" },
+
+ { 2, "FindNext" },
+ { 2, "FindFirst" },
+ { 3, "WriteUninstaller" },
+ { 2, "LogText" },
+ { 3, "Section?etText" },
+ { 3, "InstType?etFlags" },
+ { 6, "GetLabelAddr" },
+ { 2, "GetFunctionAddress" },
+ { 6, "LockWindow" }
+};
+
+#endif
+
+static const char *kShellStrings[] =
+{
+ "",
+ "",
+
+ "SMPROGRAMS",
+ "",
+ "PRINTERS",
+ "DOCUMENTS",
+ "FAVORITES",
+ "SMSTARTUP",
+ "RECENT",
+ "SENDTO",
+ "",
+ "STARTMENU",
+ "",
+ "MUSIC",
+ "VIDEO",
+ "",
+
+ "DESKTOP",
+ "",
+ "",
+ "NETHOOD",
+ "FONTS",
+ "TEMPLATES",
+ "COMMONSTARTMENU",
+ "COMMONFILES",
+ "COMMON_STARTUP",
+ "COMMON_DESKTOPDIRECTORY",
+ "QUICKLAUNCH",
+ "PRINTHOOD",
+ "LOCALAPPDATA",
+ "ALTSTARTUP",
+ "ALTSTARTUP",
+ "FAVORITES",
+
+ "INTERNET_CACHE",
+ "COOKIES",
+ "HISTORY",
+ "APPDATA",
+ "WINDIR",
+ "SYSDIR",
+ "PROGRAMFILES",
+ "PICTURES",
+ "PROFILE",
+ "",
+ "",
+ "COMMONFILES",
+ "",
+ "TEMPLATES",
+ "DOCUMENTS",
+ "ADMINTOOLS",
+
+ "ADMINTOOLS",
+ "",
+ "",
+ "",
+ "",
+ "MUSIC",
+ "PICTURES",
+ "VIDEO",
+ "RESOURCES",
+ "RESOURCES_LOCALIZED",
+ "",
+ "CDBURN_AREA"
+};
+
+static const int kNumShellStrings = sizeof(kShellStrings) / sizeof(kShellStrings[0]);
+
+/*
+# define CMDLINE 20 // everything before here doesn't have trailing slash removal
+# define INSTDIR 21
+# define OUTDIR 22
+# define EXEDIR 23
+# define LANGUAGE 24
+# define TEMP 25
+# define PLUGINSDIR 26
+# define HWNDPARENT 27
+# define _CLICK 28
+# define _OUTDIR 29
+*/
+
+static const char *kVarStrings[] =
+{
+ "CMDLINE",
+ "INSTDIR",
+ "OUTDIR",
+ "EXEDIR",
+ "LANGUAGE",
+ "TEMP",
+ "PLUGINSDIR",
+ "EXEPATH", // test it
+ "EXEFILE", // test it
+ "HWNDPARENT",
+ "_CLICK",
+ "_OUTDIR"
+};
+
+static const int kNumVarStrings = sizeof(kVarStrings) / sizeof(kVarStrings[0]);
+
+
+static AString GetVar(UInt32 index)
+{
+ AString res = "$";
+ if (index < 10)
+ res += UIntToString(index);
+ else if (index < 20)
+ {
+ res += "R";
+ res += UIntToString(index - 10);
+ }
+ else if (index < 20 + kNumVarStrings)
+ res += kVarStrings[index - 20];
+ else
+ {
+ res += "[";
+ res += UIntToString(index);
+ res += "]";
+ }
+ return res;
+}
+
+#define NS_SKIP_CODE 252
+#define NS_VAR_CODE 253
+#define NS_SHELL_CODE 254
+#define NS_LANG_CODE 255
+#define NS_CODES_START NS_SKIP_CODE
+
+static AString GetShellString(int index)
+{
+ AString res = "$";
+ if (index < kNumShellStrings)
+ {
+ const char *sz = kShellStrings[index];
+ if (sz[0] != 0)
+ return res + sz;
+ }
+ res += "SHELL[";
+ res += UIntToString(index);
+ res += "]";
+ return res;
+}
+
+// Based on Dave Laundon's simplified process_string
+AString GetNsisString(const AString &s)
+{
+ AString res;
+ for (int i = 0; i < s.Length();)
+ {
+ unsigned char nVarIdx = s[i++];
+ if (nVarIdx > NS_CODES_START && i + 2 <= s.Length())
+ {
+ int nData = s[i++] & 0x7F;
+ unsigned char c1 = s[i++];
+ nData |= (((int)(c1 & 0x7F)) << 7);
+
+ if (nVarIdx == NS_SHELL_CODE)
+ res += GetShellString(c1);
+ else if (nVarIdx == NS_VAR_CODE)
+ res += GetVar(nData);
+ else if (nVarIdx == NS_LANG_CODE)
+ res += "NS_LANG_CODE";
+ }
+ else if (nVarIdx == NS_SKIP_CODE)
+ {
+ if (i < s.Length())
+ res += s[i++];
+ }
+ else // Normal char
+ res += (char)nVarIdx;
+ }
+ return res;
+}
+
+UString GetNsisString(const UString &s)
+{
+ UString res;
+ for (int i = 0; i < s.Length();)
+ {
+ wchar_t nVarIdx = s[i++];
+ if (nVarIdx > NS_UN_CODES_START && nVarIdx <= NS_UN_CODES_END)
+ {
+ if (i == s.Length())
+ break;
+ int nData = s[i++] & 0x7FFF;
+
+ if (nVarIdx == NS_UN_SHELL_CODE)
+ res += GetUnicodeString(GetShellString(nData >> 8));
+ else if (nVarIdx == NS_UN_VAR_CODE)
+ res += GetUnicodeString(GetVar(nData));
+ else if (nVarIdx == NS_UN_LANG_CODE)
+ res += L"NS_LANG_CODE";
+ }
+ else if (nVarIdx == NS_UN_SKIP_CODE)
+ {
+ if (i == s.Length())
+ break;
+ res += s[i++];
+ }
+ else // Normal char
+ res += (char)nVarIdx;
+ }
+ return res;
+}
+
+AString CInArchive::ReadString2A(UInt32 pos) const
+{
+ return GetNsisString(ReadStringA(pos));
+}
+
+UString CInArchive::ReadString2U(UInt32 pos) const
+{
+ return GetNsisString(ReadStringU(pos));
+}
+
+AString CInArchive::ReadString2(UInt32 pos) const
+{
+ if (IsUnicode)
+ return UnicodeStringToMultiByte(ReadString2U(pos));
+ else
+ return ReadString2A(pos);
+}
+
+AString CInArchive::ReadString2Qw(UInt32 pos) const
+{
+ return "\"" + ReadString2(pos) + "\"";
+}
+
+#define DEL_DIR 1
+#define DEL_RECURSE 2
+#define DEL_REBOOT 4
+// #define DEL_SIMPLE 8
+
+static const int kNumEntryParams = 6;
+
+struct CEntry
+{
+ UInt32 Which;
+ UInt32 Params[kNumEntryParams];
+ AString GetParamsString(int numParams);
+ CEntry()
+ {
+ Which = 0;
+ for (UInt32 j = 0; j < kNumEntryParams; j++)
+ Params[j] = 0;
+ }
+};
+
+AString CEntry::GetParamsString(int numParams)
+{
+ AString s;
+ for (int i = 0; i < numParams; i++)
+ {
+ s += " ";
+ UInt32 v = Params[i];
+ if (v > 0xFFF00000)
+ s += IntToString((Int32)Params[i]);
+ else
+ s += UIntToString(Params[i]);
+ }
+ return s;
+}
+
+#ifdef NSIS_SCRIPT
+
+static AString GetRegRootID(UInt32 val)
+{
+ const char *s;
+ switch(val)
+ {
+ case 0: s = "SHCTX"; break;
+ case 0x80000000: s = "HKCR"; break;
+ case 0x80000001: s = "HKCU"; break;
+ case 0x80000002: s = "HKLM"; break;
+ case 0x80000003: s = "HKU"; break;
+ case 0x80000004: s = "HKPD"; break;
+ case 0x80000005: s = "HKCC"; break;
+ case 0x80000006: s = "HKDD"; break;
+ case 0x80000050: s = "HKPT"; break;
+ case 0x80000060: s = "HKPN"; break;
+ default:
+ return UIntToString(val); break;
+ }
+ return s;
+}
+
+#endif
+
+HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
+{
+ _posInData = bh.Offset + GetOffset();
+ AString prefixA;
+ UString prefixU;
+ for (UInt32 i = 0; i < bh.Num; i++)
+ {
+ CEntry e;
+ e.Which = ReadUInt32();
+ for (UInt32 j = 0; j < kNumEntryParams; j++)
+ e.Params[j] = ReadUInt32();
+ #ifdef NSIS_SCRIPT
+ if (e.Which != EW_PUSHPOP && e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0]))
+ {
+ const CCommandPair &pair = kCommandPairs[e.Which];
+ Script += pair.Name;
+ }
+ #endif
+
+ switch (e.Which)
+ {
+ case EW_CREATEDIR:
+ {
+ if (IsUnicode)
+ {
+ prefixU.Empty();
+ prefixU = ReadString2U(e.Params[0]);
+ }
+ else
+ {
+ prefixA.Empty();
+ prefixA = ReadString2A(e.Params[0]);
+ }
+ #ifdef NSIS_SCRIPT
+ Script += " ";
+ if (IsUnicode)
+ Script += UnicodeStringToMultiByte(prefixU);
+ else
+ Script += prefixA;
+ #endif
+ break;
+ }
+
+ case EW_EXTRACTFILE:
+ {
+ CItem item;
+ item.IsUnicode = IsUnicode;
+ if (IsUnicode)
+ {
+ item.PrefixU = prefixU;
+ item.NameU = ReadString2U(e.Params[1]);
+ }
+ else
+ {
+ item.PrefixA = prefixA;
+ item.NameA = ReadString2A(e.Params[1]);
+ }
+ /* UInt32 overwriteFlag = e.Params[0]; */
+ item.Pos = e.Params[2];
+ item.MTime.dwLowDateTime = e.Params[3];
+ item.MTime.dwHighDateTime = e.Params[4];
+ /* UInt32 allowIgnore = e.Params[5]; */
+ if (Items.Size() > 0)
+ {
+ /*
+ if (item.Pos == Items.Back().Pos)
+ continue;
+ */
+ }
+ Items.Add(item);
+ #ifdef NSIS_SCRIPT
+ Script += " ";
+
+ if (IsUnicode)
+ Script += UnicodeStringToMultiByte(item.NameU);
+ else
+ Script += item.NameA;
+ #endif
+ break;
+ }
+
+
+ #ifdef NSIS_SCRIPT
+ case EW_UPDATETEXT:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += UIntToString(e.Params[1]);
+ break;
+ }
+ case EW_SETFILEATTRIBUTES:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += UIntToString(e.Params[1]);
+ break;
+ }
+ case EW_IFFILEEXISTS:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += UIntToString(e.Params[1]);
+ Script += " ";
+ Script += UIntToString(e.Params[2]);
+ break;
+ }
+ case EW_RENAME:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += UIntToString(e.Params[2]);
+ break;
+ }
+ case EW_GETFULLPATHNAME:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += UIntToString(e.Params[2]);
+ break;
+ }
+ case EW_SEARCHPATH:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ break;
+ }
+ case EW_GETTEMPFILENAME:
+ {
+ AString s;
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ break;
+ }
+
+ case EW_DELETEFILE:
+ {
+ UInt64 flag = e.Params[1];
+ if (flag != 0)
+ {
+ Script += " ";
+ if (flag == DEL_REBOOT)
+ Script += "/REBOOTOK";
+ else
+ Script += UIntToString(e.Params[1]);
+ }
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ break;
+ }
+ case EW_RMDIR:
+ {
+ UInt64 flag = e.Params[1];
+ if (flag != 0)
+ {
+ if ((flag & DEL_REBOOT) != 0)
+ Script += " /REBOOTOK";
+ if ((flag & DEL_RECURSE) != 0)
+ Script += " /r";
+ }
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ break;
+ }
+ case EW_STRLEN:
+ {
+ Script += " ";
+ Script += GetVar(e.Params[0]);;
+ Script += " ";
+ Script += ReadString2Qw(e.Params[1]);
+ break;
+ }
+ case EW_ASSIGNVAR:
+ {
+ Script += " ";
+ Script += GetVar(e.Params[0]);;
+ Script += " ";
+ Script += ReadString2Qw(e.Params[1]);
+ AString maxLen, startOffset;
+ if (e.Params[2] != 0)
+ maxLen = ReadString2(e.Params[2]);
+ if (e.Params[3] != 0)
+ startOffset = ReadString2(e.Params[3]);
+ if (!maxLen.IsEmpty() || !startOffset.IsEmpty())
+ {
+ Script += " ";
+ if (maxLen.IsEmpty())
+ Script += "\"\"";
+ else
+ Script += maxLen;
+ if (!startOffset.IsEmpty())
+ {
+ Script += " ";
+ Script += startOffset;
+ }
+ }
+ break;
+ }
+ case EW_STRCMP:
+ {
+ Script += " ";
+
+ Script += " ";
+ Script += ReadString2Qw(e.Params[0]);
+
+ Script += " ";
+ Script += ReadString2Qw(e.Params[1]);
+
+ for (int j = 2; j < 5; j++)
+ {
+ Script += " ";
+ Script += UIntToString(e.Params[j]);
+ }
+ break;
+ }
+ case EW_INTCMP:
+ {
+ if (e.Params[5] != 0)
+ Script += "U";
+
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+
+ for (int i = 2; i < 5; i++)
+ {
+ Script += " ";
+ Script += UIntToString(e.Params[i]);
+ }
+ break;
+ }
+ case EW_INTOP:
+ {
+ Script += " ";
+ Script += GetVar(e.Params[0]);
+ Script += " ";
+ int numOps = 2;
+ AString op;
+ switch (e.Params[3])
+ {
+ case 0: op = '+'; break;
+ case 1: op = '-'; break;
+ case 2: op = '*'; break;
+ case 3: op = '/'; break;
+ case 4: op = '|'; break;
+ case 5: op = '&'; break;
+ case 6: op = '^'; break;
+ case 7: op = '~'; numOps = 1; break;
+ case 8: op = '!'; numOps = 1; break;
+ case 9: op = "||"; break;
+ case 10: op = "&&"; break;
+ case 11: op = '%'; break;
+ default: op = UIntToString(e.Params[3]);
+ }
+ AString p1 = ReadString2(e.Params[1]);
+ if (numOps == 1)
+ {
+ Script += op;
+ Script += p1;
+ }
+ else
+ {
+ Script += p1;
+ Script += " ";
+ Script += op;
+ Script += " ";
+ Script += ReadString2(e.Params[2]);
+ }
+ break;
+ }
+
+ case EW_PUSHPOP:
+ {
+ int isPop = (e.Params[1] != 0);
+ if (isPop)
+ {
+ Script += "Pop";
+ Script += " ";
+ Script += GetVar(e.Params[0]);;
+ }
+ else
+ {
+ int isExch = (e.Params[2] != 0);
+ if (isExch)
+ {
+ Script += "Exch";
+ }
+ else
+ {
+ Script += "Push";
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ }
+ }
+ break;
+ }
+
+ case EW_SENDMESSAGE:
+ {
+ // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2]
+ Script += " ";
+ // Script += ReadString2(e.Params[0]);
+ // Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += ReadString2(e.Params[2]);
+
+ Script += " ";
+ UInt32 spec = e.Params[5];
+ // if (spec & 1)
+ Script += IntToString(e.Params[3]);
+ // else
+ // Script += ReadString2(e.Params[3]);
+
+ Script += " ";
+ // if (spec & 2)
+ Script += IntToString(e.Params[4]);
+ // else
+ // Script += ReadString2(e.Params[4]);
+
+ if ((Int32)e.Params[0] >= 0)
+ {
+ Script += " ";
+ Script += GetVar(e.Params[1]);
+ }
+
+ spec >>= 2;
+ if (spec != 0)
+ {
+ Script += " /TIMEOUT=";
+ Script += IntToString(spec);
+ }
+ break;
+ }
+
+ case EW_GETDLGITEM:
+ {
+ Script += " ";
+ Script += GetVar(e.Params[0]);;
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += ReadString2(e.Params[2]);
+ break;
+ }
+
+
+ case EW_REGISTERDLL:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += UIntToString(e.Params[2]);
+ break;
+ }
+
+ case EW_CREATESHORTCUT:
+ {
+ AString s;
+
+ Script += " ";
+ Script += ReadString2Qw(e.Params[0]);
+
+ Script += " ";
+ Script += ReadString2Qw(e.Params[1]);
+
+ for (int j = 2; j < 5; j++)
+ {
+ Script += " ";
+ Script += UIntToString(e.Params[j]);
+ }
+ break;
+ }
+
+ /*
+ case EW_DELREG:
+ {
+ AString keyName, valueName;
+ keyName = ReadString2(e.Params[1]);
+ bool isValue = (e.Params[2] != -1);
+ if (isValue)
+ {
+ valueName = ReadString2(e.Params[2]);
+ Script += "Key";
+ }
+ else
+ Script += "Value";
+ Script += " ";
+ Script += UIntToString(e.Params[0]);
+ Script += " ";
+ Script += keyName;
+ if (isValue)
+ {
+ Script += " ";
+ Script += valueName;
+ }
+ Script += " ";
+ Script += UIntToString(e.Params[3]);
+ break;
+ }
+ */
+
+ case EW_WRITEREG:
+ {
+ AString s;
+ switch(e.Params[4])
+ {
+ case 1: s = "Str"; break;
+ case 2: s = "ExpandStr"; break;
+ case 3: s = "Bin"; break;
+ case 4: s = "DWORD"; break;
+ default: s = "?" + UIntToString(e.Params[4]); break;
+ }
+ Script += s;
+ Script += " ";
+ Script += GetRegRootID(e.Params[0]);
+ Script += " ";
+
+ AString keyName, valueName;
+ keyName = ReadString2Qw(e.Params[1]);
+ Script += keyName;
+ Script += " ";
+
+ valueName = ReadString2Qw(e.Params[2]);
+ Script += valueName;
+ Script += " ";
+
+ valueName = ReadString2Qw(e.Params[3]);
+ Script += valueName;
+ Script += " ";
+
+ break;
+ }
+
+ case EW_WRITEUNINSTALLER:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ for (int j = 1; j < 3; j++)
+ {
+ Script += " ";
+ Script += UIntToString(e.Params[j]);
+ }
+ break;
+ }
+
+ default:
+ {
+ int numParams = kNumEntryParams;
+ if (e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0]))
+ {
+ const CCommandPair &pair = kCommandPairs[e.Which];
+ // Script += pair.Name;
+ numParams = pair.NumParams;
+ }
+ else
+ {
+ Script += "Unknown";
+ Script += UIntToString(e.Which);
+ }
+ Script += e.GetParamsString(numParams);
+ }
+ #endif
+ }
+ #ifdef NSIS_SCRIPT
+ Script += kCrLf;
+ #endif
+ }
+
+ {
+ Items.Sort(CompareItems, 0);
+ int i;
+ // if (IsSolid)
+ for (i = 0; i + 1 < Items.Size();)
+ {
+ bool sameName = IsUnicode ?
+ (Items[i].NameU == Items[i + 1].NameU) :
+ (Items[i].NameA == Items[i + 1].NameA);
+ if (Items[i].Pos == Items[i + 1].Pos && sameName)
+ Items.Delete(i + 1);
+ else
+ i++;
+ }
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ UInt32 curPos = item.Pos + 4;
+ for (int nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++)
+ {
+ UInt32 nextPos = Items[nextIndex].Pos;
+ if (curPos <= nextPos)
+ {
+ item.EstimatedSizeIsDefined = true;
+ item.EstimatedSize = nextPos - curPos;
+ break;
+ }
+ }
+ }
+ if (!IsSolid)
+ {
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ RINOK(_stream->Seek(GetPosOfNonSolidItem(i), STREAM_SEEK_SET, NULL));
+ const UInt32 kSigSize = 4 + 1 + 5;
+ BYTE sig[kSigSize];
+ size_t processedSize = kSigSize;
+ RINOK(ReadStream(_stream, sig, &processedSize));
+ if (processedSize < 4)
+ return S_FALSE;
+ UInt32 size = Get32(sig);
+ if ((size & 0x80000000) != 0)
+ {
+ item.IsCompressed = true;
+ // is compressed;
+ size &= ~0x80000000;
+ if (Method == NMethodType::kLZMA)
+ {
+ if (processedSize < 9)
+ return S_FALSE;
+ if (FilterFlag)
+ item.UseFilter = (sig[4] != 0);
+ item.DictionarySize = Get32(sig + 5 + (FilterFlag ? 1 : 0));
+ }
+ }
+ else
+ {
+ item.IsCompressed = false;
+ item.Size = size;
+ item.SizeIsDefined = true;
+ }
+ item.CompressedSize = size;
+ item.CompressedSizeIsDefined = true;
+ }
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::Parse()
+{
+ // UInt32 offset = ReadUInt32();
+ // ???? offset == FirstHeader.HeaderLength
+ /* UInt32 ehFlags = */ ReadUInt32();
+ CBlockHeader bhPages, bhSections, bhEntries, bhStrings, bhLangTables, bhCtlColors, bhData;
+ // CBlockHeader bgFont;
+ ReadBlockHeader(bhPages);
+ ReadBlockHeader(bhSections);
+ ReadBlockHeader(bhEntries);
+ ReadBlockHeader(bhStrings);
+ ReadBlockHeader(bhLangTables);
+ ReadBlockHeader(bhCtlColors);
+ // ReadBlockHeader(bgFont);
+ ReadBlockHeader(bhData);
+
+ _stringsPos = bhStrings.Offset;
+ UInt32 pos = GetOffset() + _stringsPos;
+ int numZeros0 = 0;
+ int numZeros1 = 0;
+ int i;
+ const int kBlockSize = 256;
+ for (i = 0; i < kBlockSize; i++)
+ {
+ if (pos >= _size || pos + 1 >= _size)
+ break;
+ char c0 = _data[pos++];
+ char c1 = _data[pos++];
+ wchar_t c = (c0 | ((wchar_t)c1 << 8));
+
+ if (c >= NS_UN_CODES_START && c < NS_UN_CODES_END)
+ {
+ if (pos >= _size || pos + 1 >= _size)
+ break;
+ pos += 2;
+ numZeros1++;
+ }
+ else
+ {
+ if (c0 == 0 && c1 != 0)
+ numZeros0++;
+ if (c1 == 0)
+ numZeros1++;
+ }
+ // printf("\nnumZeros0 = %2x %2x", _data[pos + 0], _data[pos + 1]);
+ }
+ IsUnicode = (numZeros1 > numZeros0 * 3 + kBlockSize / 16);
+ // printf("\nnumZeros0 = %3d numZeros1 = %3d", numZeros0, numZeros1);
+ return ReadEntries(bhEntries);
+}
+
+static bool IsLZMA(const Byte *p, UInt32 &dictionary)
+{
+ dictionary = Get32(p + 1);
+ return (p[0] == 0x5D && p[1] == 0x00 && p[2] == 0x00 && p[5] == 0x00);
+}
+
+static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag)
+{
+ if (IsLZMA(p, dictionary))
+ {
+ thereIsFlag = false;
+ return true;
+ }
+ if (IsLZMA(p + 1, dictionary))
+ {
+ thereIsFlag = true;
+ return true;
+ }
+ return false;
+}
+
+static bool IsBZip2(const Byte *p)
+{
+ return (p[0] == 0x31 && p[1] < 14);
+}
+
+HRESULT CInArchive::Open2(
+ DECL_EXTERNAL_CODECS_LOC_VARS2
+ )
+{
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &StreamOffset));
+
+ const UInt32 kSigSize = 4 + 1 + 5 + 1; // size, flag, lzma props, lzma first byte
+ BYTE sig[kSigSize];
+ RINOK(ReadStream_FALSE(_stream, sig, kSigSize));
+ UInt64 position;
+ RINOK(_stream->Seek(StreamOffset, STREAM_SEEK_SET, &position));
+
+ _headerIsCompressed = true;
+ IsSolid = true;
+ FilterFlag = false;
+ DictionarySize = 1;
+
+ UInt32 compressedHeaderSize = Get32(sig);
+
+ if (compressedHeaderSize == FirstHeader.HeaderLength)
+ {
+ _headerIsCompressed = false;
+ IsSolid = false;
+ Method = NMethodType::kCopy;
+ }
+ else if (IsLZMA(sig, DictionarySize, FilterFlag))
+ {
+ Method = NMethodType::kLZMA;
+ }
+ else if (IsLZMA(sig + 4, DictionarySize, FilterFlag))
+ {
+ IsSolid = false;
+ Method = NMethodType::kLZMA;
+ }
+ else if (sig[3] == 0x80)
+ {
+ IsSolid = false;
+ if (IsBZip2(sig + 4))
+ Method = NMethodType::kBZip2;
+ else
+ Method = NMethodType::kDeflate;
+ }
+ else if (IsBZip2(sig))
+ {
+ Method = NMethodType::kBZip2;
+ }
+ else
+ {
+ Method = NMethodType::kDeflate;
+ }
+
+ _posInData = 0;
+ if (!IsSolid)
+ {
+ _headerIsCompressed = ((compressedHeaderSize & 0x80000000) != 0);
+ if (_headerIsCompressed)
+ compressedHeaderSize &= ~0x80000000;
+ _nonSolidStartOffset = compressedHeaderSize;
+ RINOK(_stream->Seek(StreamOffset + 4, STREAM_SEEK_SET, NULL));
+ }
+ UInt32 unpackSize = FirstHeader.HeaderLength;
+ if (_headerIsCompressed)
+ {
+ // unpackSize = (1 << 23);
+ _data.SetCapacity(unpackSize);
+ RINOK(Decoder.Init(
+ EXTERNAL_CODECS_LOC_VARS
+ _stream, Method, FilterFlag, UseFilter));
+ size_t processedSize = unpackSize;
+ RINOK(Decoder.Read(_data, &processedSize));
+ if (processedSize != unpackSize)
+ return S_FALSE;
+ _size = processedSize;
+ if (IsSolid)
+ {
+ UInt32 size2 = ReadUInt32();
+ if (size2 < _size)
+ _size = size2;
+ }
+ }
+ else
+ {
+ _data.SetCapacity(unpackSize);
+ _size = (size_t)unpackSize;
+ RINOK(ReadStream_FALSE(_stream, (Byte *)_data, unpackSize));
+ }
+ return Parse();
+}
+
+/*
+NsisExe =
+{
+ ExeStub
+ Archive // must start from 512 * N
+ #ifndef NSIS_CONFIG_CRC_ANAL
+ {
+ Some additional data
+ }
+}
+
+Archive
+{
+ FirstHeader
+ Data
+ #ifdef NSIS_CONFIG_CRC_SUPPORT && FirstHeader.ThereIsCrc()
+ {
+ CRC
+ }
+}
+
+FirstHeader
+{
+ UInt32 Flags;
+ Byte Signature[16];
+ // points to the header+sections+entries+stringtable in the datablock
+ UInt32 HeaderLength;
+ UInt32 ArchiveSize;
+}
+*/
+
+HRESULT CInArchive::Open(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream, const UInt64 *maxCheckStartPosition)
+{
+ Clear();
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ UInt64 maxSize = ((maxCheckStartPosition != 0) ? *maxCheckStartPosition : 0);
+ const UInt32 kStep = 512;
+ Byte buffer[kStep];
+
+ UInt64 position = 0;
+ for (; position <= maxSize; position += kStep)
+ {
+ RINOK(ReadStream_FALSE(inStream, buffer, kStep));
+ if (memcmp(buffer + 4, kSignature, kSignatureSize) == 0)
+ break;
+ }
+ if (position > maxSize)
+ return S_FALSE;
+ const UInt32 kStartHeaderSize = 4 * 7;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &_archiveSize));
+ RINOK(inStream->Seek(position + kStartHeaderSize, STREAM_SEEK_SET, 0));
+ FirstHeader.Flags = Get32(buffer);
+ FirstHeader.HeaderLength = Get32(buffer + kSignatureSize + 4);
+ FirstHeader.ArchiveSize = Get32(buffer + kSignatureSize + 8);
+ if (_archiveSize - position < FirstHeader.ArchiveSize)
+ return S_FALSE;
+
+ try
+ {
+ _stream = inStream;
+ HRESULT res = Open2(EXTERNAL_CODECS_LOC_VARS2);
+ if (res != S_OK)
+ Clear();
+ _stream.Release();
+ return res;
+ }
+ catch(...) { Clear(); return S_FALSE; }
+}
+
+void CInArchive::Clear()
+{
+ #ifdef NSIS_SCRIPT
+ Script.Empty();
+ #endif
+ Items.Clear();
+ _stream.Release();
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisIn.h
new file mode 100644
index 000000000..87ae3f1ca
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisIn.h
@@ -0,0 +1,181 @@
+// NsisIn.h
+
+#ifndef __ARCHIVE_NSIS_IN_H
+#define __ARCHIVE_NSIS_IN_H
+
+#include "Common/Buffer.h"
+#include "Common/MyCom.h"
+#include "Common/StringConvert.h"
+
+#include "NsisDecode.h"
+
+// #define NSIS_SCRIPT
+
+namespace NArchive {
+namespace NNsis {
+
+const int kSignatureSize = 16;
+#define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 0x4E, 0x75, 0x6C, 0x6C, 0x73, 0x6F, 0x66, 0x74, 0x49, 0x6E, 0x73, 0x74}
+
+extern Byte kSignature[kSignatureSize];
+
+const UInt32 kFlagsMask = 0xF;
+namespace NFlags
+{
+ const UInt32 kUninstall = 1;
+ const UInt32 kSilent = 2;
+ const UInt32 kNoCrc = 4;
+ const UInt32 kForceCrc = 8;
+}
+
+struct CFirstHeader
+{
+ UInt32 Flags;
+ UInt32 HeaderLength;
+
+ UInt32 ArchiveSize;
+
+ bool ThereIsCrc() const
+ {
+ if ((Flags & NFlags::kForceCrc ) != 0)
+ return true;
+ return ((Flags & NFlags::kNoCrc) == 0);
+ }
+
+ UInt32 GetDataSize() const { return ArchiveSize - (ThereIsCrc() ? 4 : 0); }
+};
+
+
+struct CBlockHeader
+{
+ UInt32 Offset;
+ UInt32 Num;
+};
+
+struct CItem
+{
+ AString PrefixA;
+ UString PrefixU;
+ AString NameA;
+ UString NameU;
+ FILETIME MTime;
+ bool IsUnicode;
+ bool UseFilter;
+ bool IsCompressed;
+ bool SizeIsDefined;
+ bool CompressedSizeIsDefined;
+ bool EstimatedSizeIsDefined;
+ UInt32 Pos;
+ UInt32 Size;
+ UInt32 CompressedSize;
+ UInt32 EstimatedSize;
+ UInt32 DictionarySize;
+
+ CItem(): IsUnicode(false), UseFilter(false), IsCompressed(true), SizeIsDefined(false),
+ CompressedSizeIsDefined(false), EstimatedSizeIsDefined(false), Size(0), DictionarySize(1) {}
+
+ bool IsINSTDIR() const
+ {
+ return (PrefixA.Length() >= 3 || PrefixU.Length() >= 3);
+ }
+
+ UString GetReducedName(bool unicode) const
+ {
+ UString s;
+ if (unicode)
+ s = PrefixU;
+ else
+ s = MultiByteToUnicodeString(PrefixA);
+ if (s.Length() > 0)
+ if (s[s.Length() - 1] != L'\\')
+ s += L'\\';
+ if (unicode)
+ s += NameU;
+ else
+ s += MultiByteToUnicodeString(NameA);
+ const int len = 9;
+ if (s.Left(len).CompareNoCase(L"$INSTDIR\\") == 0)
+ s = s.Mid(len);
+ return s;
+ }
+};
+
+class CInArchive
+{
+ UInt64 _archiveSize;
+ CMyComPtr<IInStream> _stream;
+
+ Byte ReadByte();
+ UInt32 ReadUInt32();
+ HRESULT Open2(
+ DECL_EXTERNAL_CODECS_LOC_VARS2
+ );
+ void ReadBlockHeader(CBlockHeader &bh);
+ AString ReadStringA(UInt32 pos) const;
+ UString ReadStringU(UInt32 pos) const;
+ AString ReadString2A(UInt32 pos) const;
+ UString ReadString2U(UInt32 pos) const;
+ AString ReadString2(UInt32 pos) const;
+ AString ReadString2Qw(UInt32 pos) const;
+ HRESULT ReadEntries(const CBlockHeader &bh);
+ HRESULT Parse();
+
+ CByteBuffer _data;
+ UInt64 _size;
+
+ size_t _posInData;
+
+ UInt32 _stringsPos;
+
+
+ bool _headerIsCompressed;
+ UInt32 _nonSolidStartOffset;
+public:
+ HRESULT Open(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream, const UInt64 *maxCheckStartPosition);
+ void Clear();
+
+ UInt64 StreamOffset;
+ CDecoder Decoder;
+ CObjectVector<CItem> Items;
+ CFirstHeader FirstHeader;
+ NMethodType::EEnum Method;
+ UInt32 DictionarySize;
+ bool IsSolid;
+ bool UseFilter;
+ bool FilterFlag;
+ bool IsUnicode;
+
+ #ifdef NSIS_SCRIPT
+ AString Script;
+ #endif
+ UInt32 GetOffset() const { return IsSolid ? 4 : 0; }
+ UInt64 GetDataPos(int index)
+ {
+ const CItem &item = Items[index];
+ return GetOffset() + FirstHeader.HeaderLength + item.Pos;
+ }
+
+ UInt64 GetPosOfSolidItem(int index) const
+ {
+ const CItem &item = Items[index];
+ return 4 + FirstHeader.HeaderLength + item.Pos;
+ }
+
+ UInt64 GetPosOfNonSolidItem(int index) const
+ {
+ const CItem &item = Items[index];
+ return StreamOffset + _nonSolidStartOffset + 4 + item.Pos;
+ }
+
+ void Release()
+ {
+ Decoder.Release();
+ }
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisRegister.cpp
new file mode 100644
index 000000000..41dedb0d3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Nsis/NsisRegister.cpp
@@ -0,0 +1,13 @@
+// NsisRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "NsisHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NNsis::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Nsis", L"", 0, 0x9, NSIS_SIGNATURE, NArchive::NNsis::kSignatureSize, false, CreateArc, 0 };
+
+REGISTER_ARC(Nsis)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/NtfsHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/NtfsHandler.cpp
new file mode 100644
index 000000000..505486fc5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/NtfsHandler.cpp
@@ -0,0 +1,1764 @@
+// NtfsHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+// #define SHOW_DEBUG_INFO2
+
+#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2)
+#include <stdio.h>
+#endif
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/DummyOutStream.h"
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#ifdef SHOW_DEBUG_INFO2
+#define PRF2(x) x
+#else
+#define PRF2(x)
+#endif
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(p, dest) dest = Get16(p);
+#define G32(p, dest) dest = Get32(p);
+#define G64(p, dest) dest = Get64(p);
+
+namespace NArchive {
+namespace Ntfs {
+
+static const UInt32 kNumSysRecs = 16;
+static const UInt32 kRecIndex_Volume = 3;
+static const UInt32 kRecIndex_BadClus = 8;
+
+struct CHeader
+{
+ Byte SectorSizeLog;
+ Byte ClusterSizeLog;
+ // Byte MediaType;
+ UInt32 NumHiddenSectors;
+ UInt64 NumClusters;
+ UInt64 MftCluster;
+ UInt64 SerialNumber;
+ UInt16 SectorsPerTrack;
+ UInt16 NumHeads;
+
+ UInt64 GetPhySize() const { return NumClusters << ClusterSizeLog; }
+ UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
+ bool Parse(const Byte *p);
+};
+
+static int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+
+ int codeOffset = 0;
+ switch (p[0])
+ {
+ case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break;
+ case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break;
+ default: return false;
+ }
+ Byte sectorsPerClusterLog;
+
+ if (memcmp(p + 3, "NTFS ", 8) != 0)
+ return false;
+ {
+ int s = GetLog(Get16(p + 11));
+ if (s < 9 || s > 12)
+ return false;
+ SectorSizeLog = (Byte)s;
+ s = GetLog(p[13]);
+ if (s < 0)
+ return false;
+ sectorsPerClusterLog = (Byte)s;
+ ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog;
+ }
+
+ for (int i = 14; i < 21; i++)
+ if (p[i] != 0)
+ return false;
+
+ // MediaType = p[21];
+ if (Get16(p + 22) != 0) // NumFatSectors
+ return false;
+ G16(p + 24, SectorsPerTrack);
+ G16(p + 26, NumHeads);
+ G32(p + 28, NumHiddenSectors);
+ if (Get32(p + 32) != 0) // NumSectors32
+ return false;
+
+ // DriveNumber = p[0x24];
+ if (p[0x25] != 0) // CurrentHead
+ return false;
+ /*
+ NTFS-HDD: p[0x26] = 0x80
+ NTFS-FLASH: p[0x26] = 0
+ */
+ if (p[0x26] != 0x80 && p[0x26] != 0) // ExtendedBootSig
+ return false;
+ if (p[0x27] != 0) // reserved
+ return false;
+ UInt64 numSectors = Get64(p + 0x28);
+ NumClusters = numSectors >> sectorsPerClusterLog;
+
+ G64(p + 0x30, MftCluster);
+ // G64(p + 0x38, Mft2Cluster);
+ G64(p + 0x48, SerialNumber);
+ UInt32 numClustersInMftRec;
+ UInt32 numClustersInIndexBlock;
+ G32(p + 0x40, numClustersInMftRec);
+ G32(p + 0x44, numClustersInIndexBlock);
+ return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256);
+}
+
+struct CMftRef
+{
+ UInt64 Val;
+ UInt64 GetIndex() const { return Val & (((UInt64)1 << 48) - 1); }
+ UInt16 GetNumber() const { return (UInt16)(Val >> 48); }
+ bool IsBaseItself() const { return Val == 0; }
+};
+
+#define ATNAME(n) ATTR_TYPE_ ## n
+#define DEF_ATTR_TYPE(v, n) ATNAME(n) = v
+
+enum
+{
+ DEF_ATTR_TYPE(0x00, UNUSED),
+ DEF_ATTR_TYPE(0x10, STANDARD_INFO),
+ DEF_ATTR_TYPE(0x20, ATTRIBUTE_LIST),
+ DEF_ATTR_TYPE(0x30, FILE_NAME),
+ DEF_ATTR_TYPE(0x40, OBJECT_ID),
+ DEF_ATTR_TYPE(0x50, SECURITY_DESCRIPTOR),
+ DEF_ATTR_TYPE(0x60, VOLUME_NAME),
+ DEF_ATTR_TYPE(0x70, VOLUME_INFO),
+ DEF_ATTR_TYPE(0x80, DATA),
+ DEF_ATTR_TYPE(0x90, INDEX_ROOT),
+ DEF_ATTR_TYPE(0xA0, INDEX_ALLOCATION),
+ DEF_ATTR_TYPE(0xB0, BITMAP),
+ DEF_ATTR_TYPE(0xC0, REPARSE_POINT),
+ DEF_ATTR_TYPE(0xD0, EA_INFO),
+ DEF_ATTR_TYPE(0xE0, EA),
+ DEF_ATTR_TYPE(0xF0, PROPERTY_SET),
+ DEF_ATTR_TYPE(0x100, LOGGED_UTILITY_STREAM),
+ DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE)
+};
+
+static const Byte kFileNameType_Posix = 0;
+static const Byte kFileNameType_Win32 = 1;
+static const Byte kFileNameType_Dos = 2;
+static const Byte kFileNameType_Win32Dos = 3;
+
+struct CFileNameAttr
+{
+ CMftRef ParentDirRef;
+ // UInt64 CTime;
+ // UInt64 MTime;
+ // UInt64 ThisRecMTime;
+ // UInt64 ATime;
+ // UInt64 AllocatedSize;
+ // UInt64 DataSize;
+ // UInt16 PackedEaSize;
+ UString Name;
+ UInt32 Attrib;
+ Byte NameType;
+
+ bool IsDos() const { return NameType == kFileNameType_Dos; }
+ bool Parse(const Byte *p, unsigned size);
+};
+
+static void GetString(const Byte *p, unsigned length, UString &res)
+{
+ wchar_t *s = res.GetBuffer(length);
+ for (unsigned i = 0; i < length; i++)
+ s[i] = Get16(p + i * 2);
+ s[length] = 0;
+ res.ReleaseBuffer();
+}
+
+bool CFileNameAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 0x42)
+ return false;
+ G64(p + 0x00, ParentDirRef.Val);
+ // G64(p + 0x08, CTime);
+ // G64(p + 0x10, MTime);
+ // G64(p + 0x18, ThisRecMTime);
+ // G64(p + 0x20, ATime);
+ // G64(p + 0x28, AllocatedSize);
+ // G64(p + 0x30, DataSize);
+ G32(p + 0x38, Attrib);
+ // G16(p + 0x3C, PackedEaSize);
+ NameType = p[0x41];
+ unsigned length = p[0x40];
+ if (0x42 + length > size)
+ return false;
+ GetString(p + 0x42, length, Name);
+ return true;
+}
+
+struct CSiAttr
+{
+ UInt64 CTime;
+ UInt64 MTime;
+ // UInt64 ThisRecMTime;
+ UInt64 ATime;
+ UInt32 Attrib;
+
+ /*
+ UInt32 MaxVersions;
+ UInt32 Version;
+ UInt32 ClassId;
+ UInt32 OwnerId;
+ UInt32 SecurityId;
+ UInt64 QuotaCharged;
+ */
+
+ bool Parse(const Byte *p, unsigned size);
+};
+
+bool CSiAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 0x24)
+ return false;
+ G64(p + 0x00, CTime);
+ G64(p + 0x08, MTime);
+ // G64(p + 0x10, ThisRecMTime);
+ G64(p + 0x18, ATime);
+ G32(p + 0x20, Attrib);
+ return true;
+}
+
+static const UInt64 kEmptyExtent = (UInt64)(Int64)-1;
+
+struct CExtent
+{
+ UInt64 Virt;
+ UInt64 Phy;
+
+ bool IsEmpty() const { return Phy == kEmptyExtent; }
+};
+
+struct CVolInfo
+{
+ Byte MajorVer;
+ Byte MinorVer;
+ // UInt16 Flags;
+
+ bool Parse(const Byte *p, unsigned size);
+};
+
+bool CVolInfo::Parse(const Byte *p, unsigned size)
+{
+ if (size < 12)
+ return false;
+ MajorVer = p[8];
+ MinorVer = p[9];
+ // Flags = Get16(p + 10);
+ return true;
+}
+
+struct CAttr
+{
+ UInt32 Type;
+ // UInt32 Length;
+ UString Name;
+ // UInt16 Flags;
+ // UInt16 Instance;
+ CByteBuffer Data;
+ Byte NonResident;
+
+ // Non-Resident
+ Byte CompressionUnit;
+ UInt64 LowVcn;
+ UInt64 HighVcn;
+ UInt64 AllocatedSize;
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt64 InitializedSize;
+
+ // Resident
+ // UInt16 ResidentFlags;
+
+ bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; }
+
+ UInt32 Parse(const Byte *p, unsigned size);
+ bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
+ bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
+ bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
+ bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const;
+ UInt64 GetSize() const { return NonResident ? Size : Data.GetCapacity(); }
+ UInt64 GetPackSize() const
+ {
+ if (!NonResident)
+ return Data.GetCapacity();
+ if (CompressionUnit != 0)
+ return PackSize;
+ return AllocatedSize;
+ }
+};
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareAttr(void *const *elem1, void *const *elem2, void *)
+{
+ const CAttr &a1 = *(*((const CAttr **)elem1));
+ const CAttr &a2 = *(*((const CAttr **)elem2));
+ RINOZ(MyCompare(a1.Type, a2.Type));
+ RINOZ(MyCompare(a1.Name, a2.Name));
+ return MyCompare(a1.LowVcn, a2.LowVcn);
+}
+
+UInt32 CAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 4)
+ return 0;
+ G32(p, Type);
+ if (Type == 0xFFFFFFFF)
+ return 4;
+ if (size < 0x18)
+ return 0;
+ PRF(printf(" T=%2X", Type));
+
+ UInt32 length = Get32(p + 0x04);
+ PRF(printf(" L=%3d", length));
+ if (length > size)
+ return 0;
+ NonResident = p[0x08];
+ {
+ int nameLength = p[9];
+ UInt32 nameOffset = Get16(p + 0x0A);
+ if (nameLength != 0)
+ {
+ if (nameOffset + nameLength * 2 > length)
+ return 0;
+ GetString(p + nameOffset, nameLength, Name);
+ PRF(printf(" N=%S", Name));
+ }
+ }
+
+ // G16(p + 0x0C, Flags);
+ // G16(p + 0x0E, Instance);
+ // PRF(printf(" F=%4X", Flags));
+ // PRF(printf(" Inst=%d", Instance));
+
+ UInt32 dataSize;
+ UInt32 offs;
+ if (NonResident)
+ {
+ if (length < 0x40)
+ return 0;
+ PRF(printf(" NR"));
+ G64(p + 0x10, LowVcn);
+ G64(p + 0x18, HighVcn);
+ G64(p + 0x28, AllocatedSize);
+ G64(p + 0x30, Size);
+ G64(p + 0x38, InitializedSize);
+ G16(p + 0x20, offs);
+ CompressionUnit = p[0x22];
+
+ PackSize = Size;
+ if (CompressionUnit != 0)
+ {
+ if (length < 0x48)
+ return 0;
+ G64(p + 0x40, PackSize);
+ PRF(printf(" PS=%I64x", PackSize));
+ }
+
+ // PRF(printf("\n"));
+ PRF(printf(" ASize=%4I64d", AllocatedSize));
+ PRF(printf(" Size=%I64d", Size));
+ PRF(printf(" IS=%I64d", InitializedSize));
+ PRF(printf(" Low=%I64d", LowVcn));
+ PRF(printf(" High=%I64d", HighVcn));
+ PRF(printf(" CU=%d", (int)CompressionUnit));
+ dataSize = length - offs;
+ }
+ else
+ {
+ if (length < 0x18)
+ return 0;
+ PRF(printf(" RES"));
+ dataSize = Get32(p + 0x10);
+ PRF(printf(" dataSize=%3d", dataSize));
+ offs = Get16(p + 0x14);
+ // G16(p + 0x16, ResidentFlags);
+ // PRF(printf(" ResFlags=%4X", ResidentFlags));
+ }
+ if (offs > length || dataSize > length || length - dataSize < offs)
+ return 0;
+ Data.SetCapacity(dataSize);
+ memcpy(Data, p + offs, dataSize);
+ #ifdef SHOW_DEBUG_INFO
+ PRF(printf(" : "));
+ for (unsigned i = 0; i < Data.GetCapacity(); i++)
+ {
+ PRF(printf(" %02X", (int)Data[i]));
+ }
+ #endif
+ return length;
+}
+
+bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const
+{
+ const Byte *p = Data;
+ unsigned size = (unsigned)Data.GetCapacity();
+ UInt64 vcn = LowVcn;
+ UInt64 lcn = 0;
+ UInt64 highVcn1 = HighVcn + 1;
+ if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63)
+ return false;
+
+ extents.DeleteBack();
+
+ PRF2(printf("\n# ParseExtents # LowVcn = %4I64X # HighVcn = %4I64X", LowVcn, HighVcn));
+
+ while (size > 0)
+ {
+ Byte b = *p++;
+ size--;
+ if (b == 0)
+ break;
+ UInt32 num = b & 0xF;
+ if (num == 0 || num > 8 || num > size)
+ return false;
+
+ int i;
+ UInt64 vSize = p[num - 1];
+ for (i = (int)num - 2; i >= 0; i--)
+ vSize = (vSize << 8) | p[i];
+ if (vSize == 0)
+ return false;
+ p += num;
+ size -= num;
+ if ((highVcn1 - vcn) < vSize)
+ return false;
+
+ num = (b >> 4) & 0xF;
+ if (num > 8 || num > size)
+ return false;
+ CExtent e;
+ e.Virt = vcn;
+ if (num == 0)
+ {
+ if (compressionUnit == 0)
+ return false;
+ e.Phy = kEmptyExtent;
+ }
+ else
+ {
+ Int64 v = (signed char)p[num - 1];
+ for (i = (int)num - 2; i >= 0; i--)
+ v = (v << 8) | p[i];
+ p += num;
+ size -= num;
+ lcn += v;
+ if (lcn > numClustersMax)
+ return false;
+ e.Phy = lcn;
+ }
+ extents.Add(e);
+ vcn += vSize;
+ }
+ CExtent e;
+ e.Phy = kEmptyExtent;
+ e.Virt = vcn;
+ extents.Add(e);
+ return (highVcn1 == vcn);
+}
+
+static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
+
+static const int kNumCacheChunksLog = 1;
+static const UInt32 kNumCacheChunks = (1 << kNumCacheChunksLog);
+
+class CInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt64 _curRem;
+ bool _sparseMode;
+ size_t _compressedPos;
+
+ UInt64 _tags[kNumCacheChunks];
+ int _chunkSizeLog;
+ CByteBuffer _inBuf;
+ CByteBuffer _outBuf;
+public:
+ CMyComPtr<IInStream> Stream;
+ UInt64 Size;
+ UInt64 InitializedSize;
+ int BlockSizeLog;
+ int CompressionUnit;
+ bool InUse;
+ CRecordVector<CExtent> Extents;
+
+ HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
+
+ UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); }
+ HRESULT InitAndSeek(int compressionUnit)
+ {
+ CompressionUnit = compressionUnit;
+ if (compressionUnit != 0)
+ {
+ UInt32 cuSize = GetCuSize();
+ _inBuf.SetCapacity(cuSize);
+ _chunkSizeLog = BlockSizeLog + CompressionUnit;
+ _outBuf.SetCapacity(kNumCacheChunks << _chunkSizeLog);
+ }
+ for (int i = 0; i < kNumCacheChunks; i++)
+ _tags[i] = kEmptyTag;
+
+ _sparseMode = false;
+ _curRem = 0;
+ _virtPos = 0;
+ _physPos = 0;
+ const CExtent &e = Extents[0];
+ if (!e.IsEmpty())
+ _physPos = e.Phy << BlockSizeLog;
+ return SeekToPhys();
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen)
+{
+ size_t destSize = 0;
+ while (destSize < destLen)
+ {
+ if (srcLen < 2 || (destSize & 0xFFF) != 0)
+ break;
+ UInt32 v = Get16(src);
+ if (v == 0)
+ break;
+ src += 2;
+ srcLen -= 2;
+ UInt32 comprSize = (v & 0xFFF) + 1;
+ if (comprSize > srcLen)
+ break;
+ srcLen -= comprSize;
+ if ((v & 0x8000) == 0)
+ {
+ if (comprSize != (1 << 12))
+ break;
+ memcpy(dest + destSize, src, comprSize);
+ src += comprSize;
+ destSize += comprSize;
+ }
+ else
+ {
+ if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0)
+ return 0;
+ int numDistBits = 4;
+ UInt32 sbOffset = 0;
+ UInt32 pos = 0;
+
+ do
+ {
+ comprSize--;
+ for (UInt32 mask = src[pos++] | 0x100; mask > 1 && comprSize > 0; mask >>= 1)
+ {
+ if ((mask & 1) == 0)
+ {
+ if (sbOffset >= (1 << 12))
+ return 0;
+ dest[destSize++] = src[pos++];
+ sbOffset++;
+ comprSize--;
+ }
+ else
+ {
+ if (comprSize < 2)
+ return 0;
+ UInt32 v = Get16(src + pos);
+ pos += 2;
+ comprSize -= 2;
+
+ while (((sbOffset - 1) >> numDistBits) != 0)
+ numDistBits++;
+
+ UInt32 len = (v & (0xFFFF >> numDistBits)) + 3;
+ if (sbOffset + len > (1 << 12))
+ return 0;
+ UInt32 dist = (v >> (16 - numDistBits));
+ if (dist >= sbOffset)
+ return 0;
+ Int32 offs = -1 - dist;
+ Byte *p = dest + destSize;
+ for (UInt32 t = 0; t < len; t++)
+ p[t] = p[t + offs];
+ destSize += len;
+ sbOffset += len;
+ }
+ }
+ }
+ while (comprSize > 0);
+ src += pos;
+ }
+ }
+ return destSize;
+}
+
+STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return (Size == _virtPos) ? S_OK: E_FAIL;
+ if (size == 0)
+ return S_OK;
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (_virtPos >= InitializedSize)
+ {
+ memset((Byte *)data, 0, size);
+ _virtPos += size;
+ *processedSize = size;
+ return S_OK;
+ }
+ rem = InitializedSize - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+
+ while (_curRem == 0)
+ {
+ UInt64 cacheTag = _virtPos >> _chunkSizeLog;
+ UInt32 cacheIndex = (UInt32)cacheTag & (kNumCacheChunks - 1);
+ if (_tags[cacheIndex] == cacheTag)
+ {
+ UInt32 chunkSize = (UInt32)1 << _chunkSizeLog;
+ UInt32 offset = (UInt32)_virtPos & (chunkSize - 1);
+ UInt32 cur = MyMin(chunkSize - offset, size);
+ memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur);
+ *processedSize = cur;
+ _virtPos += cur;
+ return S_OK;
+ }
+
+ PRF2(printf("\nVirtPos = %6d", _virtPos));
+
+ UInt32 comprUnitSize = (UInt32)1 << CompressionUnit;
+ UInt64 virtBlock = _virtPos >> BlockSizeLog;
+ UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1);
+
+ int left = 0, right = Extents.Size();
+ for (;;)
+ {
+ int mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (virtBlock2 < Extents[mid].Virt)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ bool isCompressed = false;
+ UInt64 virtBlock2End = virtBlock2 + comprUnitSize;
+ if (CompressionUnit != 0)
+ for (int i = left; i < Extents.Size(); i++)
+ {
+ const CExtent &e = Extents[i];
+ if (e.Virt >= virtBlock2End)
+ break;
+ if (e.IsEmpty())
+ {
+ isCompressed = true;
+ break;
+ }
+ }
+
+ int i;
+ for (i = left; Extents[i + 1].Virt <= virtBlock; i++);
+
+ _sparseMode = false;
+ if (!isCompressed)
+ {
+ const CExtent &e = Extents[i];
+ UInt64 newPos = (e.Phy << BlockSizeLog) + _virtPos - (e.Virt << BlockSizeLog);
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+ UInt64 next = Extents[i + 1].Virt;
+ if (next > virtBlock2End)
+ next &= ~((UInt64)comprUnitSize - 1);
+ next <<= BlockSizeLog;
+ if (next > Size)
+ next = Size;
+ _curRem = next - _virtPos;
+ break;
+ }
+ bool thereArePhy = false;
+ for (int i2 = left; i2 < Extents.Size(); i2++)
+ {
+ const CExtent &e = Extents[i2];
+ if (e.Virt >= virtBlock2End)
+ break;
+ if (!e.IsEmpty())
+ {
+ thereArePhy = true;
+ break;
+ }
+ }
+ if (!thereArePhy)
+ {
+ _curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos;
+ _sparseMode = true;
+ break;
+ }
+
+ size_t offs = 0;
+ UInt64 curVirt = virtBlock2;
+ for (i = left; i < Extents.Size(); i++)
+ {
+ const CExtent &e = Extents[i];
+ if (e.IsEmpty())
+ break;
+ if (e.Virt >= virtBlock2End)
+ return S_FALSE;
+ UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+ UInt64 numChunks = Extents[i + 1].Virt - curVirt;
+ if (curVirt + numChunks > virtBlock2End)
+ numChunks = virtBlock2End - curVirt;
+ size_t compressed = (size_t)numChunks << BlockSizeLog;
+ RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed));
+ curVirt += numChunks;
+ _physPos += compressed;
+ offs += compressed;
+ }
+ size_t destLenMax = GetCuSize();
+ size_t destLen = destLenMax;
+ UInt64 rem = Size - (virtBlock2 << BlockSizeLog);
+ if (destLen > rem)
+ destLen = (size_t)rem;
+
+ Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog);
+ size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs);
+ _tags[cacheIndex] = cacheTag;
+
+ // some files in Vista have destSize > destLen
+ if (destSizeRes < destLen)
+ {
+ memset(dest, 0, destLenMax);
+ if (InUse)
+ return S_FALSE;
+ }
+ }
+ if (size > _curRem)
+ size = (UInt32)_curRem;
+ HRESULT res = S_OK;
+ if (_sparseMode)
+ memset(data, 0, size);
+ else
+ {
+ res = Stream->Read(data, size, &size);
+ _physPos += size;
+ }
+ if (processedSize != NULL)
+ *processedSize = size;
+ _virtPos += size;
+ _curRem -= size;
+ return res;
+}
+
+STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ UInt64 newVirtPos = offset;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: newVirtPos += _virtPos; break;
+ case STREAM_SEEK_END: newVirtPos += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (_virtPos != newVirtPos)
+ _curRem = 0;
+ _virtPos = newVirtPos;
+ if (newPosition)
+ *newPosition = newVirtPos;
+ return S_OK;
+}
+
+class CByteBufStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+public:
+ CByteBuffer Buf;
+ void Init() { _virtPos = 0; }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= Buf.GetCapacity())
+ return (_virtPos == Buf.GetCapacity()) ? S_OK: E_FAIL;
+ UInt64 rem = Buf.GetCapacity() - _virtPos;
+ if (rem < size)
+ size = (UInt32)rem;
+ memcpy(data, Buf + (size_t)_virtPos, size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ _virtPos += size;
+ return S_OK;
+}
+
+STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = Buf.GetCapacity() + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> &attrs,
+ int attrIndex, int attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents)
+{
+ CExtent e;
+ e.Virt = 0;
+ e.Phy = kEmptyExtent;
+ Extents.Add(e);
+ const CAttr &attr0 = attrs[attrIndex];
+
+ if (attr0.AllocatedSize < attr0.Size ||
+ (attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) ||
+ (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0)
+ return S_FALSE;
+
+ for (int i = attrIndex; i < attrIndexLim; i++)
+ if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit))
+ return S_FALSE;
+
+ UInt64 packSizeCalc = 0;
+ for (int k = 0; k < Extents.Size(); k++)
+ {
+ CExtent &e = Extents[k];
+ if (!e.IsEmpty())
+ packSizeCalc += (Extents[k + 1].Virt - e.Virt) << clusterSizeLog;
+ PRF2(printf("\nSize = %4I64X", Extents[k + 1].Virt - e.Virt));
+ PRF2(printf(" Pos = %4I64X", e.Phy));
+ }
+
+ if (attr0.CompressionUnit != 0)
+ {
+ if (packSizeCalc != attr0.PackSize)
+ return S_FALSE;
+ }
+ else
+ {
+ if (packSizeCalc != attr0.AllocatedSize)
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+struct CDataRef
+{
+ int Start;
+ int Num;
+};
+
+static const UInt32 kMagic_FILE = 0x454c4946;
+static const UInt32 kMagic_BAAD = 0x44414142;
+
+struct CMftRec
+{
+ UInt32 Magic;
+ // UInt64 Lsn;
+ UInt16 SeqNumber;
+ UInt16 Flags;
+ // UInt16 LinkCount;
+ // UInt16 NextAttrInstance;
+ CMftRef BaseMftRef;
+ // UInt32 ThisRecNumber;
+ UInt32 MyNumNameLinks;
+
+ CObjectVector<CAttr> DataAttrs;
+ CObjectVector<CFileNameAttr> FileNames;
+ CRecordVector<CDataRef> DataRefs;
+
+ CSiAttr SiAttr;
+
+ void MoveAttrsFrom(CMftRec &src)
+ {
+ DataAttrs += src.DataAttrs;
+ FileNames += src.FileNames;
+ src.DataAttrs.ClearAndFree();
+ src.FileNames.ClearAndFree();
+ }
+
+ UInt64 GetPackSize() const
+ {
+ UInt64 res = 0;
+ for (int i = 0; i < DataRefs.Size(); i++)
+ res += DataAttrs[DataRefs[i].Start].GetPackSize();
+ return res;
+ }
+
+ bool Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs);
+
+ bool IsEmpty() const { return (Magic <= 2); }
+ bool IsFILE() const { return (Magic == kMagic_FILE); }
+ bool IsBAAD() const { return (Magic == kMagic_BAAD); }
+
+ bool InUse() const { return (Flags & 1) != 0; }
+ bool IsDir() const { return (Flags & 2) != 0; }
+
+ void ParseDataNames();
+ HRESULT GetStream(IInStream *mainStream, int dataIndex,
+ int clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const;
+ int GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const;
+
+ UInt64 GetSize(int dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); }
+
+ CMftRec(): MyNumNameLinks(0) {}
+};
+
+void CMftRec::ParseDataNames()
+{
+ DataRefs.Clear();
+ DataAttrs.Sort(CompareAttr, 0);
+
+ for (int i = 0; i < DataAttrs.Size();)
+ {
+ CDataRef ref;
+ ref.Start = i;
+ for (i++; i < DataAttrs.Size(); i++)
+ if (DataAttrs[ref.Start].Name != DataAttrs[i].Name)
+ break;
+ ref.Num = i - ref.Start;
+ DataRefs.Add(ref);
+ }
+}
+
+HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
+ int clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const
+{
+ *destStream = 0;
+ CByteBufStream *streamSpec = new CByteBufStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+
+ if (dataIndex < 0)
+ return E_FAIL;
+
+ if (dataIndex < DataRefs.Size())
+ {
+ const CDataRef &ref = DataRefs[dataIndex];
+ int numNonResident = 0;
+ int i;
+ for (i = ref.Start; i < ref.Start + ref.Num; i++)
+ if (DataAttrs[i].NonResident)
+ numNonResident++;
+
+ const CAttr &attr0 = DataAttrs[ref.Start];
+
+ if (numNonResident != 0 || ref.Num != 1)
+ {
+ if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
+ return S_FALSE;
+ CInStream *streamSpec = new CInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ RINOK(DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, streamSpec->Extents));
+ streamSpec->Size = attr0.Size;
+ streamSpec->InitializedSize = attr0.InitializedSize;
+ streamSpec->Stream = mainStream;
+ streamSpec->BlockSizeLog = clusterSizeLog;
+ streamSpec->InUse = InUse();
+ RINOK(streamSpec->InitAndSeek(attr0.CompressionUnit));
+ *destStream = streamTemp.Detach();
+ return S_OK;
+ }
+ streamSpec->Buf = attr0.Data;
+ }
+ streamSpec->Init();
+ *destStream = streamTemp.Detach();
+ return S_OK;
+}
+
+int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const
+{
+ if (dataIndex < 0)
+ return 0;
+ {
+ const CDataRef &ref = DataRefs[dataIndex];
+ int numNonResident = 0;
+ int i;
+ for (i = ref.Start; i < ref.Start + ref.Num; i++)
+ if (DataAttrs[i].NonResident)
+ numNonResident++;
+
+ const CAttr &attr0 = DataAttrs[ref.Start];
+
+ if (numNonResident != 0 || ref.Num != 1)
+ {
+ if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
+ return 0; // error;
+ CRecordVector<CExtent> extents;
+ if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK)
+ return 0; // error;
+ return extents.Size() - 1;
+ }
+ // if (attr0.Data.GetCapacity() != 0)
+ // return 1;
+ return 0;
+ }
+}
+
+bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber,
+ CObjectVector<CAttr> *attrs)
+{
+ G32(p, Magic);
+ if (!IsFILE())
+ return IsEmpty() || IsBAAD();
+
+ UInt32 usaOffset;
+ UInt32 numUsaItems;
+ G16(p + 0x04, usaOffset);
+ G16(p + 0x06, numUsaItems);
+
+ if ((usaOffset & 1) != 0 || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2 ||
+ numUsaItems == 0 || numUsaItems - 1 != numSectors)
+ return false;
+
+ UInt16 usn = Get16(p + usaOffset);
+ // PRF(printf("\nusn = %d", usn));
+ for (UInt32 i = 1; i < numUsaItems; i++)
+ {
+ void *pp = p + (i << sectorSizeLog) - 2;
+ if (Get16(pp) != usn)
+ return false;
+ SetUi16(pp, Get16(p + usaOffset + i * 2));
+ }
+
+ // G64(p + 0x08, Lsn);
+ G16(p + 0x10, SeqNumber);
+ // G16(p + 0x12, LinkCount);
+ // PRF(printf(" L=%d", LinkCount));
+ UInt32 attrOffs = Get16(p + 0x14);
+ G16(p + 0x16, Flags);
+ PRF(printf(" F=%4X", Flags));
+
+ UInt32 bytesInUse = Get32(p + 0x18);
+ UInt32 bytesAlloc = Get32(p + 0x1C);
+ G64(p + 0x20, BaseMftRef.Val);
+ if (BaseMftRef.Val != 0)
+ {
+ PRF(printf(" BaseRef=%d", (int)BaseMftRef.Val));
+ // return false; // Check it;
+ }
+ // G16(p + 0x28, NextAttrInstance);
+ if (usaOffset >= 0x30)
+ if (Get32(p + 0x2C) != recNumber) // NTFS 3.1+
+ return false;
+
+ UInt32 limit = numSectors << sectorSizeLog;
+ if (attrOffs >= limit || (attrOffs & 7) != 0 || bytesInUse > limit
+ || bytesAlloc != limit)
+ return false;
+
+
+ for (UInt32 t = attrOffs; t < limit;)
+ {
+ CAttr attr;
+ // PRF(printf("\n %2d:", Attrs.Size()));
+ PRF(printf("\n"));
+ UInt32 length = attr.Parse(p + t, limit - t);
+ if (length == 0 || limit - t < length)
+ return false;
+ t += length;
+ if (attr.Type == 0xFFFFFFFF)
+ break;
+ switch(attr.Type)
+ {
+ case ATTR_TYPE_FILE_NAME:
+ {
+ CFileNameAttr fna;
+ if (!attr.ParseFileName(fna))
+ return false;
+ FileNames.Add(fna);
+ PRF(printf(" flags = %4x", (int)fna.NameType));
+ PRF(printf("\n %S", fna.Name));
+ break;
+ }
+ case ATTR_TYPE_STANDARD_INFO:
+ if (!attr.ParseSi(SiAttr))
+ return false;
+ break;
+ case ATTR_TYPE_DATA:
+ DataAttrs.Add(attr);
+ break;
+ default:
+ if (attrs)
+ attrs->Add(attr);
+ break;
+ }
+ }
+
+ return true;
+}
+
+struct CItem
+{
+ int RecIndex;
+ int DataIndex;
+ CMftRef ParentRef;
+ UString Name;
+ UInt32 Attrib;
+
+ bool IsDir() const { return (DataIndex < 0); }
+};
+
+struct CDatabase
+{
+ CHeader Header;
+ CObjectVector<CItem> Items;
+ CObjectVector<CMftRec> Recs;
+ CMyComPtr<IInStream> InStream;
+ IArchiveOpenCallback *OpenCallback;
+
+ CByteBuffer ByteBuf;
+
+ CObjectVector<CAttr> VolAttrs;
+
+ ~CDatabase() { ClearAndClose(); }
+
+ void Clear();
+ void ClearAndClose();
+
+ UString GetItemPath(Int32 index) const;
+ HRESULT Open();
+ HRESULT ReadDir(Int32 parent, UInt32 cluster, int level);
+
+ HRESULT SeekToCluster(UInt64 cluster);
+
+ int FindMtfRec(const CMftRef &ref) const
+ {
+ UInt64 val = ref.GetIndex();
+ int left = 0, right = Items.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ UInt64 midValue = Items[mid].RecIndex;
+ if (val == midValue)
+ return mid;
+ if (val < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+};
+
+HRESULT CDatabase::SeekToCluster(UInt64 cluster)
+{
+ return InStream->Seek(cluster << Header.ClusterSizeLog, STREAM_SEEK_SET, NULL);
+}
+
+void CDatabase::Clear()
+{
+ Items.Clear();
+ Recs.Clear();
+}
+
+void CDatabase::ClearAndClose()
+{
+ Clear();
+ InStream.Release();
+}
+
+#define MY_DIR_PREFIX(x) L"[" x L"]" WSTRING_PATH_SEPARATOR
+
+UString CDatabase::GetItemPath(Int32 index) const
+{
+ const CItem *item = &Items[index];
+ UString name = item->Name;
+ for (int j = 0; j < 256; j++)
+ {
+ CMftRef ref = item->ParentRef;
+ index = FindMtfRec(ref);
+ if (ref.GetIndex() == 5)
+ return name;
+ if (index < 0 || Recs[Items[index].RecIndex].SeqNumber != ref.GetNumber())
+ return MY_DIR_PREFIX(L"UNKNOWN") + name;
+ item = &Items[index];
+ name = item->Name + WCHAR_PATH_SEPARATOR + name;
+ }
+ return MY_DIR_PREFIX(L"BAD") + name;
+}
+
+HRESULT CDatabase::Open()
+{
+ Clear();
+
+ static const UInt32 kHeaderSize = 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
+ if (!Header.Parse(buf))
+ return S_FALSE;
+ UInt64 fileSize;
+ RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize));
+ if (fileSize < Header.GetPhySize())
+ return S_FALSE;
+
+ SeekToCluster(Header.MftCluster);
+
+ CMftRec mftRec;
+ UInt32 numSectorsInRec;
+ int recSizeLog;
+ CMyComPtr<IInStream> mftStream;
+ {
+ UInt32 blockSize = 1 << 12;
+ ByteBuf.SetCapacity(blockSize);
+ RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize));
+
+ UInt32 allocSize = Get32(ByteBuf + 0x1C);
+ recSizeLog = GetLog(allocSize);
+ if (recSizeLog < Header.SectorSizeLog)
+ return false;
+ numSectorsInRec = 1 << (recSizeLog - Header.SectorSizeLog);
+ if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, NULL, 0))
+ return S_FALSE;
+ if (!mftRec.IsFILE())
+ return S_FALSE;
+ mftRec.ParseDataNames();
+ if (mftRec.DataRefs.IsEmpty())
+ return S_FALSE;
+ RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream));
+ if (!mftStream)
+ return S_FALSE;
+ }
+
+ UInt64 mftSize = mftRec.DataAttrs[0].Size;
+ if ((mftSize >> 4) > Header.GetPhySize())
+ return S_FALSE;
+
+ UInt64 numFiles = mftSize >> recSizeLog;
+ if (numFiles > (1 << 30))
+ return S_FALSE;
+ if (OpenCallback)
+ {
+ RINOK(OpenCallback->SetTotal(&numFiles, &mftSize));
+ }
+ const UInt32 kBufSize = (1 << 15);
+ if (kBufSize < (1 << recSizeLog))
+ return S_FALSE;
+
+ ByteBuf.SetCapacity((size_t)kBufSize);
+ Recs.Reserve((int)numFiles);
+ for (UInt64 pos64 = 0;;)
+ {
+ if (OpenCallback)
+ {
+ UInt64 numFiles = Recs.Size();
+ if ((numFiles & 0x3FF) == 0)
+ {
+ RINOK(OpenCallback->SetCompleted(&numFiles, &pos64));
+ }
+ }
+ UInt32 readSize = kBufSize;
+ UInt64 rem = mftSize - pos64;
+ if (readSize > rem)
+ readSize = (UInt32)rem;
+ if (readSize < ((UInt32)1 << recSizeLog))
+ break;
+ RINOK(ReadStream_FALSE(mftStream, ByteBuf, (size_t)readSize));
+ pos64 += readSize;
+ for (int i = 0; ((UInt32)(i + 1) << recSizeLog) <= readSize; i++)
+ {
+ PRF(printf("\n---------------------"));
+ PRF(printf("\n%5d:", Recs.Size()));
+ Byte *p = ByteBuf + ((UInt32)i << recSizeLog);
+ CMftRec rec;
+ if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(),
+ (Recs.Size() == kRecIndex_Volume) ? &VolAttrs: NULL))
+ return S_FALSE;
+ Recs.Add(rec);
+ }
+ }
+
+ int i;
+ for (i = 0; i < Recs.Size(); i++)
+ {
+ CMftRec &rec = Recs[i];
+ if (!rec.BaseMftRef.IsBaseItself())
+ {
+ UInt64 refIndex = rec.BaseMftRef.GetIndex();
+ if (refIndex > (UInt32)Recs.Size())
+ return S_FALSE;
+ CMftRec &refRec = Recs[(int)refIndex];
+ bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself());
+ if (rec.InUse() && refRec.InUse())
+ {
+ if (!moveAttrs)
+ return S_FALSE;
+ }
+ else if (rec.InUse() || refRec.InUse())
+ moveAttrs = false;
+ if (moveAttrs)
+ refRec.MoveAttrsFrom(rec);
+ }
+ }
+
+ for (i = 0; i < Recs.Size(); i++)
+ Recs[i].ParseDataNames();
+
+ for (i = 0; i < Recs.Size(); i++)
+ {
+ CMftRec &rec = Recs[i];
+ if (!rec.IsFILE() || !rec.BaseMftRef.IsBaseItself())
+ continue;
+ int numNames = 0;
+ // printf("\n%4d: ", i);
+ for (int t = 0; t < rec.FileNames.Size(); t++)
+ {
+ const CFileNameAttr &fna = rec.FileNames[t];
+ // printf("%4d %S | ", (int)fna.NameType, fna.Name);
+ if (fna.IsDos())
+ continue;
+ int numDatas = rec.DataRefs.Size();
+
+ // For hard linked files we show substreams only for first Name.
+ if (numDatas > 1 && numNames > 0)
+ numDatas = 1;
+ numNames++;
+
+ if (rec.IsDir())
+ {
+ CItem item;
+ item.Name = fna.Name;
+ item.RecIndex = i;
+ item.DataIndex = -1;
+ item.ParentRef = fna.ParentDirRef;
+ item.Attrib = rec.SiAttr.Attrib | 0x10;
+ // item.Attrib = fna.Attrib;
+ Items.Add(item);
+ }
+ for (int di = 0; di < numDatas; di++)
+ {
+ CItem item;
+ item.Name = fna.Name;
+ item.Attrib = rec.SiAttr.Attrib;
+ const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
+ if (!subName.IsEmpty())
+ {
+ // $BadClus:$Bad is sparse file for all clusters. So we skip it.
+ if (i == kRecIndex_BadClus && subName == L"$Bad")
+ continue;
+ item.Name += L":";
+ item.Name += subName;
+ item.Attrib = fna.Attrib;
+ }
+
+ PRF(printf("\n%3d", i));
+ PRF(printf(" attrib=%2x", rec.SiAttr.Attrib));
+ PRF(printf(" %S", item.Name));
+
+ item.RecIndex = i;
+ item.DataIndex = di;
+ item.ParentRef = fna.ParentDirRef;
+
+ Items.Add(item);
+ rec.MyNumNameLinks++;
+ }
+ }
+ rec.FileNames.ClearAndFree();
+ }
+
+ return S_OK;
+}
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ CDatabase
+{
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ IInStream *stream2;
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+ HRESULT res = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &stream2);
+ *stream = (ISequentialInStream *)stream2;
+ return res;
+ COM_TRY_END
+}
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidLinks, VT_UI4},
+ { NULL, kpidNumBlocks, VT_UI4}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidVolumeName, VT_BSTR},
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+
+ { NULL, kpidSectorSize, VT_UI4},
+ { NULL, kpidId, VT_UI8}
+ // { NULL, kpidSectorsPerTrack, VT_UI4},
+ // { NULL, kpidNumHeads, VT_UI4},
+ // { NULL, kpidHiddenSectors, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void NtfsTimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)t;
+ ft.dwHighDateTime = (DWORD)(t >> 32);
+ prop = ft;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL);
+
+ switch(propID)
+ {
+ case kpidClusterSize: prop = Header.ClusterSize(); break;
+ case kpidPhySize: prop = Header.GetPhySize(); break;
+ /*
+ case kpidHeadersSize:
+ {
+ UInt64 val = 0;
+ for (int i = 0; i < kNumSysRecs; i++)
+ {
+ printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize());
+ if (i == 8)
+ i = i
+ val += Recs[i].GetPackSize();
+ }
+ prop = val;
+ break;
+ }
+ */
+ case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break;break;
+ case kpidVolumeName:
+ {
+ for (int i = 0; i < VolAttrs.Size(); i++)
+ {
+ const CAttr &attr = VolAttrs[i];
+ if (attr.Type == ATTR_TYPE_VOLUME_NAME)
+ {
+ UString name;
+ GetString(attr.Data, (int)attr.Data.GetCapacity() / 2, name);
+ prop = name;
+ break;
+ }
+ }
+ break;
+ }
+ case kpidFileSystem:
+ {
+ AString s = "NTFS";
+ for (int i = 0; i < VolAttrs.Size(); i++)
+ {
+ const CAttr &attr = VolAttrs[i];
+ if (attr.Type == ATTR_TYPE_VOLUME_INFO)
+ {
+ CVolInfo vi;
+ if (attr.ParseVolInfo(vi))
+ {
+ s += ' ';
+ char temp[16];
+ ConvertUInt32ToString(vi.MajorVer, temp);
+ s += temp;
+ s += '.';
+ ConvertUInt32ToString(vi.MinorVer, temp);
+ s += temp;
+ }
+ break;
+ }
+ }
+ prop = s;
+ break;
+ }
+ case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
+ case kpidId: prop = Header.SerialNumber; break;
+ // case kpidMediaType: prop = Header.MediaType; break;
+ // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
+ // case kpidNumHeads: prop = Header.NumHeads; break;
+ // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+
+ const CAttr *data= NULL;
+ if (item.DataIndex >= 0)
+ data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString name = GetItemPath(index);
+ const wchar_t *prefix = NULL;
+ if (!rec.InUse())
+ prefix = MY_DIR_PREFIX(L"DELETED");
+ else if (item.RecIndex < kNumSysRecs)
+ prefix = MY_DIR_PREFIX(L"SYSTEM");
+ if (prefix)
+ name = prefix + name;
+ prop = name;
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break;
+
+ case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break;
+ case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break;
+ case kpidAttrib:
+ prop = item.Attrib;
+ break;
+ case kpidLinks: prop = rec.MyNumNameLinks; break;
+ case kpidSize: if (data) prop = data->GetSize(); break;
+ case kpidPackSize: if (data) prop = data->GetPackSize(); break;
+ case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ OpenCallback = callback;
+ InStream = stream;
+ HRESULT res;
+ try
+ {
+ res = CDatabase::Open();
+ if (res == S_OK)
+ return S_OK;
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ Close();
+ return res;
+ }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ ClearAndClose();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = Items[allFilesMode ? i : indices[i]];
+ const CMftRec &rec = Recs[item.RecIndex];
+ if (!rec.IsDir())
+ totalSize += rec.GetSize(item.DataIndex);
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ CByteBuffer buf;
+ UInt32 clusterSize = Header.ClusterSize();
+ buf.SetCapacity(clusterSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ const CItem &item = Items[index];
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init();
+
+ const CMftRec &rec = Recs[item.RecIndex];
+ const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<IInStream> inStream;
+ HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream);
+ if (hres == S_FALSE)
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres != S_OK && hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ if (/* copyCoderSpec->TotalSize == item.GetSize() && */ hres == S_OK)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ }
+ totalPackSize += data.GetPackSize();
+ totalSize += data.GetSize();
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = Items.Size();
+ return S_OK;
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"NTFS", L"ntfs img", 0, 0xD9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }, 9, false, CreateArc, 0 };
+
+REGISTER_ARC(Fat)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/PeHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/PeHandler.cpp
new file mode 100644
index 000000000..c64067aa5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/PeHandler.cpp
@@ -0,0 +1,1752 @@
+// PeHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/DynamicBuffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariantUtils.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NPe {
+
+#define NUM_SCAN_SECTIONS_MAX (1 << 6)
+
+#define PE_SIG 0x00004550
+#define PE_OptHeader_Magic_32 0x10B
+#define PE_OptHeader_Magic_64 0x20B
+
+static AString GetDecString(UInt32 v)
+{
+ char sz[32];
+ ConvertUInt64ToString(v, sz);
+ return sz;
+}
+
+struct CVersion
+{
+ UInt16 Major;
+ UInt16 Minor;
+
+ void Parse(const Byte *buf);
+ AString GetString() const { return GetDecString(Major) + '.' + GetDecString(Minor); }
+};
+
+void CVersion::Parse(const Byte *p)
+{
+ Major = Get16(p);
+ Minor = Get16(p + 2);
+}
+
+static const UInt32 kHeaderSize = 4 + 20;
+
+struct CHeader
+{
+ UInt16 NumSections;
+ UInt32 Time;
+ UInt32 PointerToSymbolTable;
+ UInt32 NumSymbols;
+ UInt16 OptHeaderSize;
+ UInt16 Flags;
+ UInt16 Machine;
+
+ bool Parse(const Byte *buf);
+};
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (Get32(p) != PE_SIG)
+ return false;
+ p += 4;
+ Machine = Get16(p + 0);
+ NumSections = Get16(p + 2);
+ Time = Get32(p + 4);
+ PointerToSymbolTable = Get32(p + 8);
+ NumSymbols = Get32(p + 12);
+ OptHeaderSize = Get16(p + 16);
+ Flags = Get16(p + 18);
+ return true;
+}
+
+struct CDirLink
+{
+ UInt32 Va;
+ UInt32 Size;
+ void Parse(const Byte *p);
+};
+
+void CDirLink::Parse(const Byte *p)
+{
+ Va = Get32(p);
+ Size = Get32(p + 4);
+}
+
+enum
+{
+ kDirLink_Certificate = 4,
+ kDirLink_Debug = 6
+};
+
+struct CDebugEntry
+{
+ UInt32 Flags;
+ UInt32 Time;
+ CVersion Ver;
+ UInt32 Type;
+ UInt32 Size;
+ UInt32 Va;
+ UInt32 Pa;
+
+ void Parse(const Byte *p);
+};
+
+void CDebugEntry::Parse(const Byte *p)
+{
+ Flags = Get32(p);
+ Time = Get32(p + 4);
+ Ver.Parse(p + 8);
+ Type = Get32(p + 12);
+ Size = Get32(p + 16);
+ Va = Get32(p + 20);
+ Pa = Get32(p + 24);
+}
+
+static const UInt32 kNumDirItemsMax = 16;
+
+struct COptHeader
+{
+ UInt16 Magic;
+ Byte LinkerVerMajor;
+ Byte LinkerVerMinor;
+
+ UInt32 CodeSize;
+ UInt32 InitDataSize;
+ UInt32 UninitDataSize;
+
+ // UInt32 AddressOfEntryPoint;
+ // UInt32 BaseOfCode;
+ // UInt32 BaseOfData32;
+ UInt64 ImageBase;
+
+ UInt32 SectAlign;
+ UInt32 FileAlign;
+
+ CVersion OsVer;
+ CVersion ImageVer;
+ CVersion SubsysVer;
+
+ UInt32 ImageSize;
+ UInt32 HeadersSize;
+ UInt32 CheckSum;
+ UInt16 SubSystem;
+ UInt16 DllCharacts;
+
+ UInt64 StackReserve;
+ UInt64 StackCommit;
+ UInt64 HeapReserve;
+ UInt64 HeapCommit;
+
+ UInt32 NumDirItems;
+ CDirLink DirItems[kNumDirItemsMax];
+
+ bool Is64Bit() const { return Magic == PE_OptHeader_Magic_64; }
+ bool Parse(const Byte *p, UInt32 size);
+
+ int GetNumFileAlignBits() const
+ {
+ for (int i = 9; i <= 16; i++)
+ if (((UInt32)1 << i) == FileAlign)
+ return i;
+ return -1;
+ }
+};
+
+bool COptHeader::Parse(const Byte *p, UInt32 size)
+{
+ Magic = Get16(p);
+ switch (Magic)
+ {
+ case PE_OptHeader_Magic_32:
+ case PE_OptHeader_Magic_64:
+ break;
+ default:
+ return false;
+ }
+ LinkerVerMajor = p[2];
+ LinkerVerMinor = p[3];
+
+ bool hdr64 = Is64Bit();
+
+ CodeSize = Get32(p + 4);
+ InitDataSize = Get32(p + 8);
+ UninitDataSize = Get32(p + 12);
+
+ // AddressOfEntryPoint = Get32(p + 16);
+ // BaseOfCode = Get32(p + 20);
+ // BaseOfData32 = hdr64 ? 0: Get32(p + 24);
+ ImageBase = hdr64 ? GetUi64(p + 24) : Get32(p + 28);
+
+ SectAlign = Get32(p + 32);
+ FileAlign = Get32(p + 36);
+
+ OsVer.Parse(p + 40);
+ ImageVer.Parse(p + 44);
+ SubsysVer.Parse(p + 48);
+
+ // reserved = Get32(p + 52);
+
+ ImageSize = Get32(p + 56);
+ HeadersSize = Get32(p + 60);
+ CheckSum = Get32(p + 64);
+ SubSystem = Get16(p + 68);
+ DllCharacts = Get16(p + 70);
+
+ if (hdr64)
+ {
+ StackReserve = Get64(p + 72);
+ StackCommit = Get64(p + 80);
+ HeapReserve = Get64(p + 88);
+ HeapCommit = Get64(p + 96);
+ }
+ else
+ {
+ StackReserve = Get32(p + 72);
+ StackCommit = Get32(p + 76);
+ HeapReserve = Get32(p + 80);
+ HeapCommit = Get32(p + 84);
+ }
+ UInt32 pos = (hdr64 ? 108 : 92);
+ NumDirItems = Get32(p + pos);
+ pos += 4;
+ if (pos + 8 * NumDirItems != size)
+ return false;
+ for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++)
+ DirItems[i].Parse(p + pos + i * 8);
+ return true;
+}
+
+static const UInt32 kSectionSize = 40;
+
+struct CSection
+{
+ AString Name;
+
+ UInt32 VSize;
+ UInt32 Va;
+ UInt32 PSize;
+ UInt32 Pa;
+ UInt32 Flags;
+ UInt32 Time;
+ // UInt16 NumRelocs;
+ bool IsDebug;
+ bool IsRealSect;
+ bool IsAdditionalSection;
+
+ CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {}
+ UInt64 GetPackSize() const { return PSize; }
+
+ void UpdateTotalSize(UInt32 &totalSize)
+ {
+ UInt32 t = Pa + PSize;
+ if (t > totalSize)
+ totalSize = t;
+ }
+ void Parse(const Byte *p);
+};
+
+static bool operator <(const CSection &a1, const CSection &a2) { return (a1.Pa < a2.Pa) || ((a1.Pa == a2.Pa) && (a1.PSize < a2.PSize)) ; }
+static bool operator ==(const CSection &a1, const CSection &a2) { return (a1.Pa == a2.Pa) && (a1.PSize == a2.PSize); }
+
+static AString GetName(const Byte *name)
+{
+ const int kNameSize = 8;
+ AString res;
+ char *p = res.GetBuffer(kNameSize);
+ memcpy(p, name, kNameSize);
+ p[kNameSize] = 0;
+ res.ReleaseBuffer();
+ return res;
+}
+
+void CSection::Parse(const Byte *p)
+{
+ Name = GetName(p);
+ VSize = Get32(p + 8);
+ Va = Get32(p + 12);
+ PSize = Get32(p + 16);
+ Pa = Get32(p + 20);
+ // NumRelocs = Get16(p + 32);
+ Flags = Get32(p + 36);
+}
+
+static const CUInt32PCharPair g_HeaderCharacts[] =
+{
+ { 1, "Executable" },
+ { 13, "DLL" },
+ { 8, "32-bit" },
+ { 5, "LargeAddress" },
+ { 0, "NoRelocs" },
+ { 2, "NoLineNums" },
+ { 3, "NoLocalSyms" },
+ { 4, "AggressiveWsTrim" },
+ { 9, "NoDebugInfo" },
+ { 10, "RemovableRun" },
+ { 11, "NetRun" },
+ { 12, "System" },
+ { 14, "UniCPU" },
+ { 7, "Little-Endian" },
+ { 15, "Big-Endian" }
+};
+
+static const CUInt32PCharPair g_DllCharacts[] =
+{
+ { 6, "Relocated" },
+ { 7, "Integrity" },
+ { 8, "NX-Compatible" },
+ { 9, "NoIsolation" },
+ { 10, "NoSEH" },
+ { 11, "NoBind" },
+ { 13, "WDM" },
+ { 15, "TerminalServerAware" }
+};
+
+static const CUInt32PCharPair g_SectFlags[] =
+{
+ { 3, "NoPad" },
+ { 5, "Code" },
+ { 6, "InitializedData" },
+ { 7, "UninitializedData" },
+ { 9, "Comments" },
+ { 11, "Remove" },
+ { 12, "COMDAT" },
+ { 15, "GP" },
+ { 24, "ExtendedRelocations" },
+ { 25, "Discardable" },
+ { 26, "NotCached" },
+ { 27, "NotPaged" },
+ { 28, "Shared" },
+ { 29, "Execute" },
+ { 30, "Read" },
+ { 31, "Write" }
+};
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { 0x014C, "x86" },
+ { 0x0162, "MIPS-R3000" },
+ { 0x0166, "MIPS-R4000" },
+ { 0x0168, "MIPS-R10000" },
+ { 0x0169, "MIPS-V2" },
+ { 0x0184, "Alpha" },
+ { 0x01A2, "SH3" },
+ { 0x01A3, "SH3-DSP" },
+ { 0x01A4, "SH3E" },
+ { 0x01A6, "SH4" },
+ { 0x01A8, "SH5" },
+ { 0x01C0, "ARM" },
+ { 0x01C2, "ARM-Thumb" },
+ { 0x01F0, "PPC" },
+ { 0x01F1, "PPC-FP" },
+ { 0x0200, "IA-64" },
+ { 0x0284, "Alpha-64" },
+ { 0x0200, "IA-64" },
+ { 0x0366, "MIPSFPU" },
+ { 0x8664, "x64" },
+ { 0x0EBC, "EFI" }
+};
+
+static const CUInt32PCharPair g_SubSystems[] =
+{
+ { 0, "Unknown" },
+ { 1, "Native" },
+ { 2, "Windows GUI" },
+ { 3, "Windows CUI" },
+ { 7, "Posix" },
+ { 9, "Windows CE" },
+ { 10, "EFI" },
+ { 11, "EFI Boot" },
+ { 12, "EFI Runtime" },
+ { 13, "EFI ROM" },
+ { 14, "XBOX" }
+};
+
+static const wchar_t *g_ResTypes[] =
+{
+ NULL,
+ L"CURSOR",
+ L"BITMAP",
+ L"ICON",
+ L"MENU",
+ L"DIALOG",
+ L"STRING",
+ L"FONTDIR",
+ L"FONT",
+ L"ACCELERATOR",
+ L"RCDATA",
+ L"MESSAGETABLE",
+ L"GROUP_CURSOR",
+ NULL,
+ L"GROUP_ICON",
+ NULL,
+ L"VERSION",
+ L"DLGINCLUDE",
+ NULL,
+ L"PLUGPLAY",
+ L"VXD",
+ L"ANICURSOR",
+ L"ANIICON",
+ L"HTML",
+ L"MANIFEST"
+};
+
+const UInt32 kFlag = (UInt32)1 << 31;
+const UInt32 kMask = ~kFlag;
+
+struct CTableItem
+{
+ UInt32 Offset;
+ UInt32 ID;
+};
+
+
+const UInt32 kBmpHeaderSize = 14;
+const UInt32 kIconHeaderSize = 22;
+
+struct CResItem
+{
+ UInt32 Type;
+ UInt32 ID;
+ UInt32 Lang;
+
+ UInt32 Size;
+ UInt32 Offset;
+
+ UInt32 HeaderSize;
+ Byte Header[kIconHeaderSize]; // it must be enough for max size header.
+ bool Enabled;
+
+ bool IsNameEqual(const CResItem &item) const { return Lang == item.Lang; }
+ UInt32 GetSize() const { return Size + HeaderSize; }
+ bool IsBmp() const { return Type == 2; }
+ bool IsIcon() const { return Type == 3; }
+ bool IsString() const { return Type == 6; }
+ bool IsRcData() const { return Type == 10; }
+ bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; }
+};
+
+struct CStringItem
+{
+ UInt32 Lang;
+ UInt32 Size;
+ CByteDynamicBuffer Buf;
+
+ void AddChar(Byte c);
+ void AddWChar(UInt16 c);
+};
+
+void CStringItem::AddChar(Byte c)
+{
+ Buf.EnsureCapacity(Size + 2);
+ Buf[Size++] = c;
+ Buf[Size++] = 0;
+}
+
+void CStringItem::AddWChar(UInt16 c)
+{
+ if (c == '\n')
+ {
+ AddChar('\\');
+ c = 'n';
+ }
+ Buf.EnsureCapacity(Size + 2);
+ SetUi16(Buf + Size, c);
+ Size += 2;
+}
+
+struct CMixItem
+{
+ int SectionIndex;
+ int ResourceIndex;
+ int StringIndex;
+
+ bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0; };
+};
+
+struct CUsedBitmap
+{
+ CByteBuffer Buf;
+public:
+ void Alloc(size_t size)
+ {
+ size = (size + 7) / 8;
+ Buf.SetCapacity(size);
+ memset(Buf, 0, size);
+ }
+ void Free()
+ {
+ Buf.SetCapacity(0);
+ }
+ bool SetRange(size_t from, int size)
+ {
+ for (int i = 0; i < size; i++)
+ {
+ size_t pos = (from + i) >> 3;
+ Byte mask = (Byte)(1 << ((from + i) & 7));
+ Byte b = Buf[pos];
+ if ((b & mask) != 0)
+ return false;
+ Buf[pos] = b | mask;
+ }
+ return true;
+ }
+};
+
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CSection> _sections;
+ UInt32 _peOffset;
+ CHeader _header;
+ COptHeader _optHeader;
+ UInt32 _totalSize;
+ UInt32 _totalSizeLimited;
+ Int32 _mainSubfile;
+
+ CRecordVector<CResItem> _items;
+ CObjectVector<CStringItem> _strings;
+
+ CByteBuffer _buf;
+ bool _oneLang;
+ UString _resourceFileName;
+ CUsedBitmap _usedRes;
+ bool _parseResources;
+
+ CRecordVector<CMixItem> _mixItems;
+
+ HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ bool Parse(const Byte *buf, UInt32 size);
+
+ void AddResNameToString(UString &s, UInt32 id) const;
+ UString GetLangPrefix(UInt32 lang);
+ HRESULT ReadString(UInt32 offset, UString &dest) const;
+ HRESULT ReadTable(UInt32 offset, CRecordVector<CTableItem> &items);
+ bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size);
+ HRESULT OpenResources(int sectIndex, IInStream *stream, IArchiveOpenCallback *callback);
+ void CloseResources();
+
+
+ bool CheckItem(const CSection &sect, const CResItem &item, size_t offset) const
+ {
+ return item.Offset >= sect.Va && offset <= _buf.GetCapacity() && _buf.GetCapacity() - offset >= item.Size;
+ }
+
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+bool CHandler::Parse(const Byte *buf, UInt32 size)
+{
+ UInt32 i;
+ if (size < 512)
+ return false;
+ _peOffset = Get32(buf + 0x3C);
+ if (_peOffset >= 0x1000 || _peOffset + 512 > size || (_peOffset & 7) != 0)
+ return false;
+
+ UInt32 pos = _peOffset;
+ if (!_header.Parse(buf + pos))
+ return false;
+ if (_header.OptHeaderSize > 512 || _header.NumSections > NUM_SCAN_SECTIONS_MAX)
+ return false;
+ pos += kHeaderSize;
+
+ if (!_optHeader.Parse(buf + pos, _header.OptHeaderSize))
+ return false;
+
+ pos += _header.OptHeaderSize;
+ _totalSize = pos;
+
+ for (i = 0; i < _header.NumSections; i++, pos += kSectionSize)
+ {
+ CSection sect;
+ if (pos + kSectionSize > size)
+ return false;
+ sect.Parse(buf + pos);
+ sect.IsRealSect = true;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ return true;
+}
+
+enum
+{
+ kpidSectAlign = kpidUserDefined,
+ kpidFileAlign,
+ kpidLinkerVer,
+ kpidOsVer,
+ kpidImageVer,
+ kpidSubsysVer,
+ kpidCodeSize,
+ kpidImageSize,
+ kpidInitDataSize,
+ kpidUnInitDataSize,
+ kpidHeadersSizeUnInitDataSize,
+ kpidSubSystem,
+ kpidDllCharacts,
+ kpidStackReserve,
+ kpidStackCommit,
+ kpidHeapReserve,
+ kpidHeapCommit,
+ kpidImageBase
+ // kpidAddressOfEntryPoint,
+ // kpidBaseOfCode,
+ // kpidBaseOfData32,
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCpu, VT_BSTR},
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidPhySize, VT_UI4},
+ { NULL, kpidHeadersSize, VT_UI4},
+ { NULL, kpidChecksum, VT_UI4},
+ { L"Image Size", kpidImageSize, VT_UI4},
+ { L"Section Alignment", kpidSectAlign, VT_UI4},
+ { L"File Alignment", kpidFileAlign, VT_UI4},
+ { L"Code Size", kpidCodeSize, VT_UI4},
+ { L"Initialized Data Size", kpidInitDataSize, VT_UI4},
+ { L"Uninitialized Data Size", kpidUnInitDataSize, VT_UI4},
+ { L"Linker Version", kpidLinkerVer, VT_BSTR},
+ { L"OS Version", kpidOsVer, VT_BSTR},
+ { L"Image Version", kpidImageVer, VT_BSTR},
+ { L"Subsystem Version", kpidSubsysVer, VT_BSTR},
+ { L"Subsystem", kpidSubSystem, VT_BSTR},
+ { L"DLL Characteristics", kpidDllCharacts, VT_BSTR},
+ { L"Stack Reserve", kpidStackReserve, VT_UI8},
+ { L"Stack Commit", kpidStackCommit, VT_UI8},
+ { L"Heap Reserve", kpidHeapReserve, VT_UI8},
+ { L"Heap Commit", kpidHeapCommit, VT_UI8},
+ { L"Image Base", kpidImageBase, VT_UI8}
+ // { L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
+ // { L"Base Of Code", kpidBaseOfCode, VT_UI8},
+ // { L"Base Of Data", kpidBaseOfData32, VT_UI8},
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidVa, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void VerToProp(const CVersion &v, NCOM::CPropVariant &prop)
+{
+ StringToProp(v.GetString(), prop);
+}
+
+void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
+{
+ if (unixTime != 0)
+ {
+ FILETIME ft;
+ NTime::UnixTimeToFileTime(unixTime, ft);
+ prop = ft;
+ }
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSectAlign: prop = _optHeader.SectAlign; break;
+ case kpidFileAlign: prop = _optHeader.FileAlign; break;
+ case kpidLinkerVer:
+ {
+ CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor };
+ VerToProp(v, prop);
+ break;
+ }
+
+ case kpidOsVer: VerToProp(_optHeader.OsVer, prop); break;
+ case kpidImageVer: VerToProp(_optHeader.ImageVer, prop); break;
+ case kpidSubsysVer: VerToProp(_optHeader.SubsysVer, prop); break;
+ case kpidCodeSize: prop = _optHeader.CodeSize; break;
+ case kpidInitDataSize: prop = _optHeader.InitDataSize; break;
+ case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break;
+ case kpidImageSize: prop = _optHeader.ImageSize; break;
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _optHeader.HeadersSize; break;
+ case kpidChecksum: prop = _optHeader.CheckSum; break;
+
+ case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
+ case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break;
+ case kpidSubSystem: PAIR_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;
+
+ case kpidMTime:
+ case kpidCTime: TimeToProp(_header.Time, prop); break;
+ case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
+ case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break;
+ case kpidStackReserve: prop = _optHeader.StackReserve; break;
+ case kpidStackCommit: prop = _optHeader.StackCommit; break;
+ case kpidHeapReserve: prop = _optHeader.HeapReserve; break;
+ case kpidHeapCommit: prop = _optHeader.HeapCommit; break;
+
+ case kpidImageBase: prop = _optHeader.ImageBase; break;
+ // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
+ // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
+ // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break;
+
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::AddResNameToString(UString &s, UInt32 id) const
+{
+ if ((id & kFlag) != 0)
+ {
+ UString name;
+ if (ReadString(id & kMask, name) == S_OK)
+ {
+ if (name.IsEmpty())
+ s += L"[]";
+ else
+ {
+ if (name.Length() > 1 && name[0] == '"' && name.Back() == '"')
+ name = name.Mid(1, name.Length() - 2);
+ s += name;
+ }
+ return;
+ }
+ }
+ wchar_t sz[32];
+ ConvertUInt32ToString(id, sz);
+ s += sz;
+}
+
+UString CHandler::GetLangPrefix(UInt32 lang)
+{
+ UString s = _resourceFileName;
+ s += WCHAR_PATH_SEPARATOR;
+ if (!_oneLang)
+ {
+ AddResNameToString(s, lang);
+ s += WCHAR_PATH_SEPARATOR;
+ }
+ return s;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CMixItem &mixItem = _mixItems[index];
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ switch(propID)
+ {
+ case kpidPath: prop = GetLangPrefix(item.Lang) + L"string.txt"; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size; break;
+ }
+ }
+ else if (mixItem.ResourceIndex < 0)
+ {
+ const CSection &item = _sections[mixItem.SectionIndex];
+ switch(propID)
+ {
+ case kpidPath: StringToProp(item.Name, prop); break;
+ case kpidSize: prop = (UInt64)item.VSize; break;
+ case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
+ case kpidOffset: prop = item.Pa; break;
+ case kpidVa: if (item.IsRealSect) prop = item.Va; break;
+ case kpidMTime:
+ case kpidCTime:
+ TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break;
+ case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break;
+ }
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString s = GetLangPrefix(item.Lang);
+ {
+ const wchar_t *p = NULL;
+ if (item.Type < sizeof(g_ResTypes) / sizeof(g_ResTypes[0]))
+ p = g_ResTypes[item.Type];
+ if (p != 0)
+ s += p;
+ else
+ AddResNameToString(s, item.Type);
+ }
+ s += WCHAR_PATH_SEPARATOR;
+ AddResNameToString(s, item.ID);
+ if (item.HeaderSize != 0)
+ {
+ if (item.IsBmp())
+ s += L".bmp";
+ else if (item.IsIcon())
+ s += L".ico";
+ }
+ prop = s;
+ break;
+ }
+ case kpidSize: prop = (UInt64)item.GetSize(); break;
+ case kpidPackSize: prop = (UInt64)item.Size; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
+{
+ thereIsSection = false;
+ const CDirLink &debugLink = _optHeader.DirItems[kDirLink_Debug];
+ if (debugLink.Size == 0)
+ return S_OK;
+ const unsigned kEntrySize = 28;
+ UInt32 numItems = debugLink.Size / kEntrySize;
+ if (numItems * kEntrySize != debugLink.Size || numItems > 16)
+ return S_FALSE;
+
+ UInt64 pa = 0;
+ int i;
+ for (i = 0; i < _sections.Size(); i++)
+ {
+ const CSection &sect = _sections[i];
+ if (sect.Va < debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize)
+ {
+ pa = sect.Pa + (debugLink.Va - sect.Va);
+ break;
+ }
+ }
+ if (i == _sections.Size())
+ {
+ return S_OK;
+ // Exe for ARM requires S_OK
+ // return S_FALSE;
+ }
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(debugLink.Size);
+ Byte *buf = buffer;
+
+ RINOK(stream->Seek(pa, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(stream, buf, debugLink.Size));
+
+ for (i = 0; i < (int)numItems; i++)
+ {
+ CDebugEntry de;
+ de.Parse(buf);
+
+ if (de.Size == 0)
+ continue;
+
+ CSection sect;
+ sect.Name = ".debug" + GetDecString(i);
+
+ sect.IsDebug = true;
+ sect.Time = de.Time;
+ sect.Va = de.Va;
+ sect.Pa = de.Pa;
+ sect.PSize = sect.VSize = de.Size;
+ UInt32 totalSize = sect.Pa + sect.PSize;
+ if (totalSize > _totalSize)
+ {
+ _totalSize = totalSize;
+ _sections.Add(sect);
+ thereIsSection = true;
+ }
+ buf += kEntrySize;
+ }
+
+ return S_OK;
+}
+
+HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const
+{
+ if ((offset & 1) != 0 || offset >= _buf.GetCapacity())
+ return S_FALSE;
+ size_t rem = _buf.GetCapacity() - offset;
+ if (rem < 2)
+ return S_FALSE;
+ unsigned length = Get16(_buf + offset);
+ if ((rem - 2) / 2 < length)
+ return S_FALSE;
+ dest.Empty();
+ offset += 2;
+ for (unsigned i = 0; i < length; i++)
+ dest += (wchar_t)Get16(_buf + offset + i * 2);
+ return S_OK;
+}
+
+HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items)
+{
+ if ((offset & 3) != 0 || offset >= _buf.GetCapacity())
+ return S_FALSE;
+ size_t rem = _buf.GetCapacity() - offset;
+ if (rem < 16)
+ return S_FALSE;
+ items.Clear();
+ unsigned numNameItems = Get16(_buf + offset + 12);
+ unsigned numIdItems = Get16(_buf + offset + 14);
+ unsigned numItems = numNameItems + numIdItems;
+ if ((rem - 16) / 8 < numItems)
+ return S_FALSE;
+ if (!_usedRes.SetRange(offset, 16 + numItems * 8))
+ return S_FALSE;
+ offset += 16;
+ _oneLang = true;
+ unsigned i;
+ for (i = 0; i < numItems; i++)
+ {
+ CTableItem item;
+ const Byte *buf = _buf + offset;
+ offset += 8;
+ item.ID = Get32(buf + 0);
+ if (((item.ID & kFlag) != 0) != (i < numNameItems))
+ return S_FALSE;
+ item.Offset = Get32(buf + 4);
+ items.Add(item);
+ }
+ return S_OK;
+}
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 30;
+static const int kNumResItemsMax = (UInt32)1 << 23;
+static const int kNumStringLangsMax = 128;
+
+// BITMAPINFOHEADER
+struct CBitmapInfoHeader
+{
+ // UInt32 HeaderSize;
+ UInt32 XSize;
+ Int32 YSize;
+ UInt16 Planes;
+ UInt16 BitCount;
+ UInt32 Compression;
+ UInt32 SizeImage;
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+static const UInt32 kBitmapInfoHeader_Size = 0x28;
+
+bool CBitmapInfoHeader::Parse(const Byte *p, size_t size)
+{
+ if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size)
+ return false;
+ XSize = Get32(p + 4);
+ YSize = (Int32)Get32(p + 8);
+ Planes = Get16(p + 12);
+ BitCount = Get16(p + 14);
+ Compression = Get32(p + 16);
+ SizeImage = Get32(p + 20);
+ return true;
+}
+
+static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount)
+{
+ return ((xSize * bitCount + 7) / 8 + 3) / 4 * 4 * ySize;
+}
+
+static UInt32 SetBitmapHeader(Byte *dest, const Byte *src, UInt32 size)
+{
+ CBitmapInfoHeader h;
+ if (!h.Parse(src, size))
+ return 0;
+ if (h.YSize < 0)
+ h.YSize = -h.YSize;
+ if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 || h.BitCount > 32 ||
+ h.Compression != 0) // BI_RGB
+ return 0;
+ if (h.SizeImage == 0)
+ h.SizeImage = GetImageSize(h.XSize, h.YSize, h.BitCount);
+ UInt32 totalSize = kBmpHeaderSize + size;
+ UInt32 offBits = totalSize - h.SizeImage;
+ // BITMAPFILEHEADER
+ SetUi16(dest, 0x4D42);
+ SetUi32(dest + 2, totalSize);
+ SetUi32(dest + 6, 0);
+ SetUi32(dest + 10, offBits);
+ return kBmpHeaderSize;
+}
+
+static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size)
+{
+ CBitmapInfoHeader h;
+ if (!h.Parse(src, size))
+ return 0;
+ if (h.YSize < 0)
+ h.YSize = -h.YSize;
+ if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 ||
+ h.Compression != 0) // BI_RGB
+ return 0;
+
+ UInt32 numBitCount = h.BitCount;
+ if (numBitCount != 1 &&
+ numBitCount != 4 &&
+ numBitCount != 8 &&
+ numBitCount != 24 &&
+ numBitCount != 32)
+ return 0;
+
+ if ((h.YSize & 1) != 0)
+ return 0;
+ h.YSize /= 2;
+ if (h.XSize > 0x100 || h.YSize > 0x100)
+ return 0;
+
+ UInt32 imageSize;
+ // imageSize is not correct if AND mask array contains zeros
+ // in this case it is equal image1Size
+
+ // UInt32 imageSize = h.SizeImage;
+ // if (imageSize == 0)
+ // {
+ UInt32 image1Size = GetImageSize(h.XSize, h.YSize, h.BitCount);
+ UInt32 image2Size = GetImageSize(h.XSize, h.YSize, 1);
+ imageSize = image1Size + image2Size;
+ // }
+ UInt32 numColors = 0;
+ if (numBitCount < 16)
+ numColors = 1 << numBitCount;
+
+ SetUi16(dest, 0); // Reserved
+ SetUi16(dest + 2, 1); // RES_ICON
+ SetUi16(dest + 4, 1); // ResCount
+
+ dest[6] = (Byte)h.XSize; // Width
+ dest[7] = (Byte)h.YSize; // Height
+ dest[8] = (Byte)numColors; // ColorCount
+ dest[9] = 0; // Reserved
+
+ SetUi32(dest + 10, 0); // Reserved1 / Reserved2
+
+ UInt32 numQuadsBytes = numColors * 4;
+ UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize;
+ SetUi32(dest + 14, BytesInRes);
+ SetUi32(dest + 18, kIconHeaderSize);
+
+ /*
+ Description = DWORDToString(xSize) +
+ kDelimiterChar + DWORDToString(ySize) +
+ kDelimiterChar + DWORDToString(numBitCount);
+ */
+ return kIconHeaderSize;
+}
+
+bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size)
+{
+ if ((size & 1) != 0)
+ return false;
+
+ int i;
+ for (i = 0; i < _strings.Size(); i++)
+ if (_strings[i].Lang == lang)
+ break;
+ if (i == _strings.Size())
+ {
+ if (_strings.Size() >= kNumStringLangsMax)
+ return false;
+ CStringItem item;
+ item.Size = 0;
+ item.Lang = lang;
+ i = _strings.Add(item);
+ }
+
+ CStringItem &item = _strings[i];
+ id = (id - 1) << 4;
+ UInt32 pos = 0;
+ for (i = 0; i < 16; i++)
+ {
+ if (size - pos < 2)
+ return false;
+ UInt32 len = Get16(src + pos);
+ pos += 2;
+ if (len != 0)
+ {
+ if (size - pos < len * 2)
+ return false;
+ char temp[32];
+ ConvertUInt32ToString(id + i, temp);
+ size_t tempLen = strlen(temp);
+ size_t j;
+ for (j = 0; j < tempLen; j++)
+ item.AddChar(temp[j]);
+ item.AddChar('\t');
+ for (j = 0; j < len; j++, pos += 2)
+ item.AddWChar(Get16(src + pos));
+ item.AddChar(0x0D);
+ item.AddChar(0x0A);
+ }
+ }
+ return (size == pos);
+}
+
+HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpenCallback *callback)
+{
+ const CSection &sect = _sections[sectionIndex];
+ size_t fileSize = sect.PSize; // Maybe we need sect.VSize here !!!
+ if (fileSize > kFileSizeMax)
+ return S_FALSE;
+ {
+ UInt64 fileSize64 = fileSize;
+ if (callback)
+ RINOK(callback->SetTotal(NULL, &fileSize64));
+ RINOK(stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
+ _buf.SetCapacity(fileSize);
+ for (size_t pos = 0; pos < fileSize;)
+ {
+ UInt64 offset64 = pos;
+ if (callback)
+ RINOK(callback->SetCompleted(NULL, &offset64))
+ size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20));
+ RINOK(ReadStream_FALSE(stream, _buf + pos, rem));
+ pos += rem;
+ }
+ }
+
+ _usedRes.Alloc(fileSize);
+ CRecordVector<CTableItem> specItems;
+ RINOK(ReadTable(0, specItems));
+
+ _oneLang = true;
+ bool stringsOk = true;
+ size_t maxOffset = 0;
+ for (int i = 0; i < specItems.Size(); i++)
+ {
+ const CTableItem &item1 = specItems[i];
+ if ((item1.Offset & kFlag) == 0)
+ return S_FALSE;
+
+ CRecordVector<CTableItem> specItems2;
+ RINOK(ReadTable(item1.Offset & kMask, specItems2));
+
+ for (int j = 0; j < specItems2.Size(); j++)
+ {
+ const CTableItem &item2 = specItems2[j];
+ if ((item2.Offset & kFlag) == 0)
+ return S_FALSE;
+
+ CRecordVector<CTableItem> specItems3;
+ RINOK(ReadTable(item2.Offset & kMask, specItems3));
+
+ CResItem item;
+ item.Type = item1.ID;
+ item.ID = item2.ID;
+
+ for (int k = 0; k < specItems3.Size(); k++)
+ {
+ if (_items.Size() >= kNumResItemsMax)
+ return S_FALSE;
+ const CTableItem &item3 = specItems3[k];
+ if ((item3.Offset & kFlag) != 0)
+ return S_FALSE;
+ if (item3.Offset >= _buf.GetCapacity() || _buf.GetCapacity() - item3.Offset < 16)
+ return S_FALSE;
+ const Byte *buf = _buf + item3.Offset;
+ item.Lang = item3.ID;
+ item.Offset = Get32(buf + 0);
+ item.Size = Get32(buf + 4);
+ // UInt32 codePage = Get32(buf + 8);
+ if (Get32(buf + 12) != 0)
+ return S_FALSE;
+ if (!_items.IsEmpty() && _oneLang && !item.IsNameEqual(_items.Back()))
+ _oneLang = false;
+
+ item.HeaderSize = 0;
+
+ size_t offset = item.Offset - sect.Va;
+ if (offset > maxOffset)
+ maxOffset = offset;
+ if (offset + item.Size > maxOffset)
+ maxOffset = offset + item.Size;
+
+ if (CheckItem(sect, item, offset))
+ {
+ const Byte *data = _buf + offset;
+ if (item.IsBmp())
+ item.HeaderSize = SetBitmapHeader(item.Header, data, item.Size);
+ else if (item.IsIcon())
+ item.HeaderSize = SetIconHeader(item.Header, data, item.Size);
+ else if (item.IsString())
+ {
+ if (stringsOk)
+ stringsOk = ParseStringRes(item.ID, item.Lang, data, item.Size);
+ }
+ }
+
+ item.Enabled = true;
+ _items.Add(item);
+ }
+ }
+ }
+
+ if (stringsOk && !_strings.IsEmpty())
+ {
+ int i;
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CResItem &item = _items[i];
+ if (item.IsString())
+ item.Enabled = false;
+ }
+ for (i = 0; i < _strings.Size(); i++)
+ {
+ if (_strings[i].Size == 0)
+ continue;
+ CMixItem mixItem;
+ mixItem.ResourceIndex = -1;
+ mixItem.StringIndex = i;
+ mixItem.SectionIndex = sectionIndex;
+ _mixItems.Add(mixItem);
+ }
+ }
+
+ _usedRes.Free();
+
+ int numBits = _optHeader.GetNumFileAlignBits();
+ if (numBits >= 0)
+ {
+ UInt32 mask = (1 << numBits) - 1;
+ size_t end = ((maxOffset + mask) & ~mask);
+ if (end < sect.VSize && end <= sect.PSize)
+ {
+ CSection sect2;
+ sect2.Flags = 0;
+
+ // we skip Zeros to start of aligned block
+ size_t i;
+ for (i = maxOffset; i < end; i++)
+ if (_buf[i] != 0)
+ break;
+ if (i == end)
+ maxOffset = end;
+
+ sect2.Pa = sect.Pa + (UInt32)maxOffset;
+ sect2.Va = sect.Va + (UInt32)maxOffset;
+ sect2.PSize = sect.VSize - (UInt32)maxOffset;
+ sect2.VSize = sect2.PSize;
+ sect2.Name = ".rsrc_1";
+ sect2.Time = 0;
+ sect2.IsAdditionalSection = true;
+ _sections.Add(sect2);
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ const UInt32 kBufSize = 1 << 18;
+ const UInt32 kSigSize = 2;
+
+ _mainSubfile = -1;
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ size_t processed = kSigSize;
+ RINOK(ReadStream_FALSE(stream, buf, processed));
+ if (buf[0] != 'M' || buf[1] != 'Z')
+ return S_FALSE;
+ processed = kBufSize - kSigSize;
+ RINOK(ReadStream(stream, buf + kSigSize, &processed));
+ processed += kSigSize;
+ if (!Parse(buf, (UInt32)processed))
+ return S_FALSE;
+ bool thereISDebug;
+ RINOK(LoadDebugSections(stream, thereISDebug));
+
+ const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
+ if (certLink.Size != 0)
+ {
+ CSection sect;
+ sect.Name = "CERTIFICATE";
+ sect.Va = 0;
+ sect.Pa = certLink.Va;
+ sect.PSize = sect.VSize = certLink.Size;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ if (thereISDebug)
+ {
+ const UInt32 kAlign = 1 << 12;
+ UInt32 alignPos = _totalSize & (kAlign - 1);
+ if (alignPos != 0)
+ {
+ UInt32 size = kAlign - alignPos;
+ RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL));
+ buffer.Free();
+ buffer.SetCapacity(kAlign);
+ Byte *buf = buffer;
+ size_t processed = size;
+ RINOK(ReadStream(stream, buf, &processed));
+ size_t i;
+ for (i = 0; i < processed; i++)
+ {
+ if (buf[i] != 0)
+ break;
+ }
+ if (processed < size && processed < 100)
+ _totalSize += (UInt32)processed;
+ else if (((_totalSize + i) & 0x1FF) == 0 || processed < size)
+ _totalSize += (UInt32)i;
+ }
+ }
+
+ if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= 512)
+ {
+ if (_header.NumSymbols >= (1 << 24))
+ return S_FALSE;
+ CSection sect;
+ sect.Name = "COFF_SYMBOLS";
+ UInt32 size = _header.NumSymbols * 18;
+ RINOK(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL));
+ Byte buf[4];
+ RINOK(ReadStream_FALSE(stream, buf, 4));
+ UInt32 size2 = Get32(buf);
+ if (size2 >= (1 << 28))
+ return S_FALSE;
+ size += size2;
+
+ sect.Va = 0;
+ sect.Pa = _header.PointerToSymbolTable;
+ sect.PSize = sect.VSize = size;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ if (fileSize > _totalSize)
+ return S_FALSE;
+ _totalSizeLimited = (_totalSize < fileSize) ? _totalSize : (UInt32)fileSize;
+
+ {
+ CObjectVector<CSection> sections = _sections;
+ sections.Sort();
+ UInt32 limit = (1 << 12);
+ int num = 0;
+ int numSections = sections.Size();
+ for (int i = 0; i < numSections; i++)
+ {
+ const CSection &s = sections[i];
+ if (s.Pa > limit)
+ {
+ CSection s2;
+ s2.Pa = s2.Va = limit;
+ s2.PSize = s2.VSize = s.Pa - limit;
+ s2.IsAdditionalSection = true;
+ s2.Name = '[';
+ s2.Name += GetDecString(num++);
+ s2.Name += ']';
+ _sections.Add(s2);
+ limit = s.Pa;
+ }
+ UInt32 next = s.Pa + s.PSize;
+ if (next < s.Pa)
+ break;
+ if (next >= limit)
+ limit = next;
+ }
+ }
+
+ _parseResources = true;
+
+ UInt64 mainSize = 0, mainSize2 = 0;
+ int i;
+ for (i = 0; i < _sections.Size(); i++)
+ {
+ const CSection &sect = _sections[i];
+ CMixItem mixItem;
+ mixItem.SectionIndex = i;
+ if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty())
+ {
+ HRESULT res = OpenResources(i, stream, callback);
+ if (res == S_OK)
+ {
+ _resourceFileName = GetUnicodeString(sect.Name);
+ for (int j = 0; j < _items.Size(); j++)
+ {
+ const CResItem &item = _items[j];
+ if (item.Enabled)
+ {
+ mixItem.ResourceIndex = j;
+ mixItem.StringIndex = -1;
+ if (item.IsRcDataOrUnknown())
+ {
+ if (item.Size >= mainSize)
+ {
+ mainSize2 = mainSize;
+ mainSize = item.Size;
+ _mainSubfile = _mixItems.Size();
+ }
+ else if (item.Size >= mainSize2)
+ mainSize2 = item.Size;
+ }
+ _mixItems.Add(mixItem);
+ }
+ }
+ if (sect.PSize > sect.VSize)
+ {
+ int numBits = _optHeader.GetNumFileAlignBits();
+ if (numBits >= 0)
+ {
+ UInt32 mask = (1 << numBits) - 1;
+ UInt32 end = ((sect.VSize + mask) & ~mask);
+
+ if (sect.PSize > end)
+ {
+ CSection sect2;
+ sect2.Flags = 0;
+ sect2.Pa = sect.Pa + end;
+ sect2.Va = sect.Va + end;
+ sect2.PSize = sect.PSize - end;
+ sect2.VSize = sect2.PSize;
+ sect2.Name = ".rsrc_2";
+ sect2.Time = 0;
+ sect2.IsAdditionalSection = true;
+ _sections.Add(sect2);
+ }
+ }
+ }
+ continue;
+ }
+ if (res != S_FALSE)
+ return res;
+ CloseResources();
+ }
+ mixItem.StringIndex = -1;
+ mixItem.ResourceIndex = -1;
+ if (sect.IsAdditionalSection)
+ {
+ if (sect.PSize >= mainSize)
+ {
+ mainSize2 = mainSize;
+ mainSize = sect.PSize;
+ _mainSubfile = _mixItems.Size();
+ }
+ else
+ mainSize2 = sect.PSize;
+ }
+ _mixItems.Add(mixItem);
+ }
+
+ if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2)
+ _mainSubfile = -1;
+
+ for (i = 0; i < _mixItems.Size(); i++)
+ {
+ const CMixItem &mixItem = _mixItems[i];
+ if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_")
+ {
+ _mainSubfile = i;
+ break;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res)
+{
+ // size &= ~1;
+ const UInt32 kBufSize = 1 << 23;
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ UInt32 sum = 0;
+ UInt32 pos = 0;
+ for (;;)
+ {
+ UInt32 rem = size - pos;
+ if (rem > kBufSize)
+ rem = kBufSize;
+ if (rem == 0)
+ break;
+ size_t processed = rem;
+ RINOK(ReadStream(stream, buf, &processed));
+
+ /*
+ for (; processed < rem; processed++)
+ buf[processed] = 0;
+ */
+
+ if ((processed & 1) != 0)
+ buf[processed] = 0;
+
+ for (int j = 0; j < 4; j++)
+ {
+ UInt32 p = excludePos + j;
+ if (pos <= p && p < pos + processed)
+ buf[p - pos] = 0;
+ }
+
+ for (size_t i = 0; i < processed; i += 2)
+ {
+ sum += Get16(buf + i);
+ sum = (sum + (sum >> 16)) & 0xFFFF;
+ }
+ pos += (UInt32)processed;
+ if (rem != processed)
+ break;
+ }
+ sum += pos;
+ res = sum;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream, callback));
+ _stream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::CloseResources()
+{
+ _usedRes.Free();
+ _items.Clear();
+ _strings.Clear();
+ _buf.SetCapacity(0);
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _sections.Clear();
+ _mixItems.Clear();
+ CloseResources();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _mixItems.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _mixItems.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]];
+ if (mixItem.StringIndex >= 0)
+ totalSize += _strings[mixItem.StringIndex].Size;
+ else if (mixItem.ResourceIndex < 0)
+ totalSize += _sections[mixItem.SectionIndex].GetPackSize();
+ else
+ totalSize += _items[mixItem.ResourceIndex].GetSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ bool checkSumOK = true;
+ if (_optHeader.CheckSum != 0 && (int)numItems == _mixItems.Size())
+ {
+ UInt32 checkSum = 0;
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ CalcCheckSum(_stream, _totalSizeLimited, _peOffset + kHeaderSize + 64, checkSum);
+ checkSumOK = (checkSum == _optHeader.CheckSum);
+ }
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ const CMixItem &mixItem = _mixItems[index];
+
+ const CSection &sect = _sections[mixItem.SectionIndex];
+ bool isOk = true;
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ currentItemSize = item.Size;
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (outStream)
+ RINOK(WriteStream(outStream, item.Buf, item.Size));
+ }
+ else if (mixItem.ResourceIndex < 0)
+ {
+ currentItemSize = sect.GetPackSize();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(_stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ isOk = (copyCoderSpec->TotalSize == currentItemSize);
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ currentItemSize = item.GetSize();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ size_t offset = item.Offset - sect.Va;
+ if (!CheckItem(sect, item, offset))
+ isOk = false;
+ else if (outStream)
+ {
+ if (item.HeaderSize != 0)
+ RINOK(WriteStream(outStream, item.Header, item.HeaderSize));
+ RINOK(WriteStream(outStream, _buf + offset, item.Size));
+ }
+ }
+
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(isOk ?
+ checkSumOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+
+ const CMixItem &mixItem = _mixItems[index];
+ const CSection &sect = _sections[mixItem.SectionIndex];
+ if (mixItem.IsSectionItem())
+ return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream);
+
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+ CReferenceBuf *referenceBuf = new CReferenceBuf;
+ CMyComPtr<IUnknown> ref = referenceBuf;
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ referenceBuf->Buf.SetCapacity(item.Size);
+ memcpy(referenceBuf->Buf, item.Buf, item.Size);
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ size_t offset = item.Offset - sect.Va;
+ if (!CheckItem(sect, item, offset))
+ return S_FALSE;
+ if (item.HeaderSize == 0)
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp2 = streamSpec;
+ streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this);
+ *stream = streamTemp2.Detach();
+ return S_OK;
+ }
+ referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size);
+ memcpy(referenceBuf->Buf, item.Header, item.HeaderSize);
+ memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size);
+ }
+ inStreamSpec->Init(referenceBuf);
+
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"PE", L"exe dll sys", 0, 0xDD, { 'P', 'E', 0, 0 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Pe)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/PpmdHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/PpmdHandler.cpp
new file mode 100644
index 000000000..9b2ef0482
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/PpmdHandler.cpp
@@ -0,0 +1,456 @@
+/* PpmdHandler.c -- PPMd format handler
+2010-03-10 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.H (2001) / var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/Alloc.h"
+#include "../../../C/Ppmd7.h"
+#include "../../../C/Ppmd8.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NPpmd {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static const UInt32 kBufSize = (1 << 20);
+
+struct CBuf
+{
+ Byte *Buf;
+
+ CBuf(): Buf(0) {}
+ ~CBuf() { ::MidFree(Buf); }
+ bool Alloc()
+ {
+ if (!Buf)
+ Buf = (Byte *)::MidAlloc(kBufSize);
+ return (Buf != 0);
+ }
+};
+
+static const UInt32 kHeaderSize = 16;
+static const UInt32 kSignature = 0x84ACAF8F;
+static const unsigned kNewHeaderVer = 8;
+
+struct CItem
+{
+ UInt32 Attrib;
+ UInt32 Time;
+ AString Name;
+
+ unsigned Order;
+ unsigned MemInMB;
+ unsigned Ver;
+ unsigned Restor;
+
+ HRESULT ReadHeader(ISequentialInStream *s, UInt32 &headerSize);
+ bool IsSupported() const { return Ver == 7 || (Ver == 8 && Restor <= 1); }
+};
+
+HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize)
+{
+ Byte h[kHeaderSize];
+ RINOK(ReadStream_FALSE(s, h, kHeaderSize));
+ if (GetUi32(h) != kSignature)
+ return S_FALSE;
+ Attrib = GetUi32(h + 4);
+ Time = GetUi32(h + 12);
+
+ unsigned info = GetUi16(h + 8);
+ Order = (info & 0xF) + 1;
+ MemInMB = ((info >> 4) & 0xFF) + 1;
+ Ver = info >> 12;
+
+ UInt32 nameLen = GetUi16(h + 10);
+ Restor = nameLen >> 14;
+ if (Restor > 2)
+ return S_FALSE;
+ if (Ver >= kNewHeaderVer)
+ nameLen &= 0x3FFF;
+ if (nameLen > (1 << 9))
+ return S_FALSE;
+ char *name = Name.GetBuffer(nameLen + 1);
+ HRESULT res = ReadStream_FALSE(s, name, nameLen);
+ name[nameLen] = 0;
+ headerSize = kHeaderSize + nameLen;
+ Name.ReleaseBuffer();
+ return res;
+}
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public CMyUnknownImp
+{
+ CItem _item;
+ UInt32 _headerSize;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<ISequentialInStream> _stream;
+
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+static void UIntToString(AString &s, const char *prefix, unsigned value)
+{
+ s += prefix;
+ char temp[16];
+ ::ConvertUInt32ToString((UInt32)value, temp);
+ s += temp;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPath: prop = MultiByteToUnicodeString(_item.Name, CP_ACP); break;
+ case kpidMTime:
+ {
+ FILETIME utc;
+ if (NTime::DosTimeToFileTime(_item.Time, utc))
+ prop = utc;
+ break;
+ }
+ case kpidAttrib: prop = _item.Attrib; break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidMethod:
+ {
+ AString s = "PPMd";
+ s += (char)('A' + _item.Ver);
+ UIntToString(s, ":o", _item.Order);
+ UIntToString(s, ":mem", _item.MemInMB);
+ s += 'm';
+ if (_item.Ver >= kNewHeaderVer && _item.Restor != 0)
+ UIntToString(s, ":r", _item.Restor);
+ prop = s;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
+{
+ return OpenSeq(stream);
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ Close();
+ res = _item.ReadHeader(stream, _headerSize);
+ }
+ catch(...) { res = S_FALSE; }
+ if (res == S_OK)
+ _stream = stream;
+ else
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _stream.Release();
+ return S_OK;
+}
+
+static const UInt32 kTopValue = (1 << 24);
+static const UInt32 kBot = (1 << 15);
+
+struct CRangeDecoder
+{
+ IPpmd7_RangeDec s;
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ CByteInBufWrap *Stream;
+
+public:
+ bool Init()
+ {
+ Code = 0;
+ Low = 0;
+ Range = 0xFFFFFFFF;
+ for (int i = 0; i < 4; i++)
+ Code = (Code << 8) | Stream->ReadByte();
+ return Code < 0xFFFFFFFF;
+ }
+
+ void Normalize()
+ {
+ while ((Low ^ (Low + Range)) < kTopValue ||
+ Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1))
+ {
+ Code = (Code << 8) | Stream->ReadByte();
+ Range <<= 8;
+ Low <<= 8;
+ }
+ }
+
+ CRangeDecoder();
+};
+
+
+extern "C" {
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ return p->Code / (p->Range /= total);
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ start *= p->Range;
+ p->Low += start;
+ p->Code -= start;
+ p->Range *= size;
+ p->Normalize();
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ if (p->Code / (p->Range >>= 14) < size0)
+ {
+ Range_Decode(p, 0, size0);
+ return 0;
+ }
+ else
+ {
+ Range_Decode(p, size0, (1 << 14) - size0);
+ return 1;
+ }
+}
+
+}
+
+CRangeDecoder::CRangeDecoder()
+{
+ s.GetThreshold = Range_GetThreshold;
+ s.Decode = Range_Decode;
+ s.DecodeBit = Range_DecodeBit;
+}
+
+struct CPpmdCpp
+{
+ unsigned Ver;
+ CRangeDecoder _rc;
+ CPpmd7 _ppmd7;
+ CPpmd8 _ppmd8;
+
+ CPpmdCpp(unsigned version)
+ {
+ Ver = version;
+ Ppmd7_Construct(&_ppmd7);
+ Ppmd8_Construct(&_ppmd8);
+ }
+
+ ~CPpmdCpp()
+ {
+ Ppmd7_Free(&_ppmd7, &g_BigAlloc);
+ Ppmd8_Free(&_ppmd8, &g_BigAlloc);
+ }
+
+ bool Alloc(UInt32 memInMB)
+ {
+ memInMB <<= 20;
+ if (Ver == 7)
+ return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0;
+ return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0;
+ }
+
+ void Init(unsigned order, unsigned restor)
+ {
+ if (Ver == 7)
+ Ppmd7_Init(&_ppmd7, order);
+ else
+ Ppmd8_Init(&_ppmd8, order, restor);;
+ }
+
+ bool InitRc(CByteInBufWrap *inStream)
+ {
+ if (Ver == 7)
+ {
+ _rc.Stream = inStream;
+ return _rc.Init();
+ }
+ else
+ {
+ _ppmd8.Stream.In = &inStream->p;
+ return Ppmd8_RangeDec_Init(&_ppmd8) != 0;
+ }
+ }
+
+ bool IsFinishedOK()
+ {
+ if (Ver == 7)
+ return Ppmd7z_RangeDec_IsFinishedOK(&_rc);
+ return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8);
+ }
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ // extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CByteInBufWrap inBuf;
+ if (!inBuf.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ inBuf.Stream = _stream;
+
+ CBuf outBuf;
+ if (!outBuf.Alloc())
+ return E_OUTOFMEMORY;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ CPpmdCpp ppmd(_item.Ver);
+ if (!ppmd.Alloc(_item.MemInMB))
+ return E_OUTOFMEMORY;
+ Int32 opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ if (_item.IsSupported())
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ ppmd.Init(_item.Order, _item.Restor);
+ inBuf.Init();
+ UInt64 outSize = 0;
+ if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK)
+ for (;;)
+ {
+ lps->InSize = _packSize = inBuf.GetProcessed();
+ lps->OutSize = outSize;
+ RINOK(lps->SetCur());
+
+ size_t i;
+ int sym = 0;
+
+ if (ppmd.Ver == 7)
+ {
+ for (i = 0; i < kBufSize; i++)
+ {
+ sym = Ppmd7_DecodeSymbol(&ppmd._ppmd7, &ppmd._rc.s);
+ if (inBuf.Extra || sym < 0)
+ break;
+ outBuf.Buf[i] = (Byte)sym;
+ }
+ }
+ else
+ {
+ for (i = 0; i < kBufSize; i++)
+ {
+ sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8);
+ if (inBuf.Extra || sym < 0)
+ break;
+ outBuf.Buf[i] = (Byte)sym;
+ }
+ }
+
+ outSize += i;
+ _packSize = _headerSize + inBuf.GetProcessed();
+ _packSizeDefined = true;
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, outBuf.Buf, i));
+ }
+ if (sym < 0)
+ {
+ if (sym == -1 && ppmd.IsFinishedOK())
+ opRes = NExtract::NOperationResult::kOK;
+ break;
+ }
+ }
+ RINOK(inBuf.Res);
+ }
+ realOutStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Ppmd", L"pmd", 0, 0xD, { 0x8F, 0xAF, 0xAC, 0x84 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Ppmd)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHandler.cpp
new file mode 100644
index 000000000..5d072d34d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -0,0 +1,869 @@
+// RarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantUtils.h"
+#include "Windows/Time.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+#include "../../Common/MethodId.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../../Crypto/Rar20Crypto.h"
+#include "../../Crypto/RarAes.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "RarHandler.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NRar {
+
+static const wchar_t *kHostOS[] =
+{
+ L"MS DOS",
+ L"OS/2",
+ L"Win32",
+ L"Unix",
+ L"Mac OS",
+ L"BeOS"
+};
+
+static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
+
+static const wchar_t *kUnknownOS = L"Unknown";
+
+static const CUInt32PCharPair k_Flags[] =
+{
+ { 0, "Volume" },
+ { 1, "Comment" },
+ { 2, "Lock" },
+ { 3, "Solid" },
+ { 4, "NewVolName" }, // pack_comment in old versuons
+ { 5, "Authenticity" },
+ { 6, "Recovery" },
+ { 7, "BlockEncryption" },
+ { 8, "FirstVolume" },
+ { 9, "EncryptVer" }
+};
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+
+ { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidSolid, VT_BOOL},
+ { NULL, kpidCommented, VT_BOOL},
+ { NULL, kpidSplitBefore, VT_BOOL},
+ { NULL, kpidSplitAfter, VT_BOOL},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidUnpackVer, VT_UI1}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidSolid, VT_BOOL},
+ { NULL, kpidNumBlocks, VT_UI4},
+ // { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidIsVolume, VT_BOOL},
+ { NULL, kpidNumVolumes, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8}
+ // { NULL, kpidCommented, VT_BOOL}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+UInt64 CHandler::GetPackSize(int refIndex) const
+{
+ const CRefItem &refItem = _refItems[refIndex];
+ UInt64 totalPackSize = 0;
+ for (int i = 0; i < refItem.NumItems; i++)
+ totalPackSize += _items[refItem.ItemIndex + i].PackSize;
+ return totalPackSize;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSolid: prop = _archiveInfo.IsSolid(); break;
+ case kpidCharacts: FLAGS_TO_PROP(k_Flags, _archiveInfo.Flags, prop); break;
+ // case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names.
+ case kpidIsVolume: prop = _archiveInfo.IsVolume(); break;
+ case kpidNumVolumes: prop = (UInt32)_archives.Size(); break;
+ case kpidOffset: if (_archiveInfo.StartPosition != 0) prop = _archiveInfo.StartPosition; break;
+ // case kpidCommented: prop = _archiveInfo.IsCommented(); break;
+ case kpidNumBlocks:
+ {
+ UInt32 numBlocks = 0;
+ for (int i = 0; i < _refItems.Size(); i++)
+ if (!IsSolid(i))
+ numBlocks++;
+ prop = (UInt32)numBlocks;
+ break;
+ }
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _refItems.Size();
+ return S_OK;
+}
+
+static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result)
+{
+ if (!DosTimeToFileTime(rarTime.DosTime, result))
+ return false;
+ UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime;
+ value += (UInt64)rarTime.LowSecond * 10000000;
+ value += ((UInt64)rarTime.SubTime[2] << 16) +
+ ((UInt64)rarTime.SubTime[1] << 8) +
+ ((UInt64)rarTime.SubTime[0]);
+ result.dwLowDateTime = (DWORD)value;
+ result.dwHighDateTime = DWORD(value >> 32);
+ return true;
+}
+
+static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME localFileTime, utcFileTime;
+ if (RarTimeToFileTime(rarTime, localFileTime))
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ }
+ else
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ prop = utcFileTime;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CRefItem &refItem = _refItems[index];
+ const CItemEx &item = _items[refItem.ItemIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString u;
+ if (item.HasUnicodeName() && !item.UnicodeName.IsEmpty())
+ u = item.UnicodeName;
+ else
+ u = MultiByteToUnicodeString(item.Name, CP_OEMCP);
+ prop = (const wchar_t *)NItemName::WinNameToOSName(u);
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = GetPackSize(index); break;
+ case kpidMTime: RarTimeToProp(item.MTime, prop); break;
+ case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break;
+ case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break;
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidSolid: prop = IsSolid(index); break;
+ case kpidCommented: prop = item.IsCommented(); break;
+ case kpidSplitBefore: prop = item.IsSplitBefore(); break;
+ case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break;
+ case kpidCRC:
+ {
+ const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
+ prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC);
+ break;
+ }
+ case kpidUnpackVer: prop = item.UnPackVersion; break;
+ case kpidMethod:
+ {
+ UString method;
+ if (item.Method >= Byte('0') && item.Method <= Byte('5'))
+ {
+ method = L"m";
+ wchar_t temp[32];
+ ConvertUInt64ToString(item.Method - Byte('0'), temp);
+ method += temp;
+ if (!item.IsDir())
+ {
+ method += L":";
+ ConvertUInt64ToString(16 + item.GetDictSize(), temp);
+ method += temp;
+ }
+ }
+ else
+ {
+ wchar_t temp[32];
+ ConvertUInt64ToString(item.Method, temp);
+ method += temp;
+ }
+ prop = method;
+ break;
+ }
+ case kpidHostOS: prop = (item.HostOS < kNumHostOSes) ? (kHostOS[item.HostOS]) : kUnknownOS; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CVolumeName
+{
+ bool _first;
+ bool _newStyle;
+ UString _unchangedPart;
+ UString _changedPart;
+ UString _afterPart;
+public:
+ CVolumeName(): _newStyle(true) {};
+
+ bool InitName(const UString &name, bool newStyle)
+ {
+ _first = true;
+ _newStyle = newStyle;
+ int dotPos = name.ReverseFind('.');
+ UString basePart = name;
+ if (dotPos >= 0)
+ {
+ UString ext = name.Mid(dotPos + 1);
+ if (ext.CompareNoCase(L"rar") == 0)
+ {
+ _afterPart = name.Mid(dotPos);
+ basePart = name.Left(dotPos);
+ }
+ else if (ext.CompareNoCase(L"exe") == 0)
+ {
+ _afterPart = L".rar";
+ basePart = name.Left(dotPos);
+ }
+ else if (!_newStyle)
+ {
+ if (ext.CompareNoCase(L"000") == 0 ||
+ ext.CompareNoCase(L"001") == 0 ||
+ ext.CompareNoCase(L"r00") == 0 ||
+ ext.CompareNoCase(L"r01") == 0)
+ {
+ _afterPart.Empty();
+ _first = false;
+ _changedPart = ext;
+ _unchangedPart = name.Left(dotPos + 1);
+ return true;
+ }
+ }
+ }
+
+ if (!_newStyle)
+ {
+ _afterPart.Empty();
+ _unchangedPart = basePart + UString(L".");
+ _changedPart = L"r00";
+ return true;
+ }
+
+ int numLetters = 1;
+ if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0")
+ {
+ while (numLetters < basePart.Length())
+ {
+ if (basePart[basePart.Length() - numLetters - 1] != '0')
+ break;
+ numLetters++;
+ }
+ }
+ else
+ return false;
+ _unchangedPart = basePart.Left(basePart.Length() - numLetters);
+ _changedPart = basePart.Right(numLetters);
+ return true;
+ }
+
+ UString GetNextName()
+ {
+ UString newName;
+ if (_newStyle || !_first)
+ {
+ int i;
+ int numLetters = _changedPart.Length();
+ for (i = numLetters - 1; i >= 0; i--)
+ {
+ wchar_t c = _changedPart[i];
+ if (c == L'9')
+ {
+ c = L'0';
+ newName = c + newName;
+ if (i == 0)
+ newName = UString(L'1') + newName;
+ continue;
+ }
+ c++;
+ newName = UString(c) + newName;
+ i--;
+ for (; i >= 0; i--)
+ newName = _changedPart[i] + newName;
+ break;
+ }
+ _changedPart = newName;
+ }
+ _first = false;
+ return _unchangedPart + _changedPart + _afterPart;
+ }
+};
+
+HRESULT CHandler::Open2(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback)
+{
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openCallback;
+
+ CVolumeName seqName;
+
+ UInt64 totalBytes = 0;
+ UInt64 curBytes = 0;
+
+ if (openCallback)
+ {
+ openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
+ openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ }
+
+ for (;;)
+ {
+ CMyComPtr<IInStream> inStream;
+ if (!_archives.IsEmpty())
+ {
+ if (!openVolumeCallback)
+ break;
+
+ if (_archives.Size() == 1)
+ {
+ if (!_archiveInfo.IsVolume())
+ break;
+ UString baseName;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
+ if (prop.vt != VT_BSTR)
+ break;
+ baseName = prop.bstrVal;
+ }
+ seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName());
+ }
+
+ UString fullName = seqName.GetNextName();
+ HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
+ if (result == S_FALSE)
+ break;
+ if (result != S_OK)
+ return result;
+ if (!stream)
+ break;
+ }
+ else
+ inStream = stream;
+
+ UInt64 endPos = 0;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ if (openCallback)
+ {
+ totalBytes += endPos;
+ RINOK(openCallback->SetTotal(NULL, &totalBytes));
+ }
+
+ NArchive::NRar::CInArchive archive;
+ RINOK(archive.Open(inStream, maxCheckStartPosition));
+
+ if (_archives.IsEmpty())
+ archive.GetArchiveInfo(_archiveInfo);
+
+ CItemEx item;
+ for (;;)
+ {
+ if (archive.m_Position > endPos)
+ {
+ AddErrorMessage("Unexpected end of archive");
+ break;
+ }
+ bool decryptionError;
+ AString errorMessageLoc;
+ HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError, errorMessageLoc);
+ if (errorMessageLoc)
+ AddErrorMessage(errorMessageLoc);
+ if (result == S_FALSE)
+ {
+ if (decryptionError && _items.IsEmpty())
+ return S_FALSE;
+ break;
+ }
+ RINOK(result);
+ if (item.IgnoreItem())
+ continue;
+
+ bool needAdd = true;
+ if (item.IsSplitBefore())
+ {
+ if (!_refItems.IsEmpty())
+ {
+ CRefItem &refItem = _refItems.Back();
+ refItem.NumItems++;
+ needAdd = false;
+ }
+ }
+ if (needAdd)
+ {
+ CRefItem refItem;
+ refItem.ItemIndex = _items.Size();
+ refItem.NumItems = 1;
+ refItem.VolumeIndex = _archives.Size();
+ _refItems.Add(refItem);
+ }
+ _items.Add(item);
+ if (openCallback && _items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = curBytes + item.Position;
+ RINOK(openCallback->SetCompleted(&numFiles, &numBytes));
+ }
+ }
+ curBytes += endPos;
+ _archives.Add(archive);
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ HRESULT res = Open2(stream, maxCheckStartPosition, openCallback);
+ if (res != S_OK)
+ Close();
+ return res;
+ }
+ catch(const CInArchiveException &) { Close(); return S_FALSE; }
+ catch(...) { Close(); throw; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ COM_TRY_BEGIN
+ _errorMessage.Empty();
+ _refItems.Clear();
+ _items.Clear();
+ _archives.Clear();
+ return S_OK;
+ COM_TRY_END
+}
+
+struct CMethodItem
+{
+ Byte RarUnPackVersion;
+ CMyComPtr<ICompressCoder> Coder;
+};
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ UInt64 censoredTotalUnPacked = 0,
+ // censoredTotalPacked = 0,
+ importantTotalUnPacked = 0;
+ // importantTotalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _refItems.Size();
+ if (numItems == 0)
+ return S_OK;
+ int lastIndex = 0;
+ CRecordVector<int> importantIndexes;
+ CRecordVector<bool> extractStatuses;
+
+ for (UInt32 t = 0; t < numItems; t++)
+ {
+ int index = allFilesMode ? t : indices[t];
+ const CRefItem &refItem = _refItems[index];
+ const CItemEx &item = _items[refItem.ItemIndex];
+ censoredTotalUnPacked += item.Size;
+ // censoredTotalPacked += item.PackSize;
+ int j;
+ for (j = lastIndex; j <= index; j++)
+ // if (!_items[_refItems[j].ItemIndex].IsSolid())
+ if (!IsSolid(j))
+ lastIndex = j;
+ for (j = lastIndex; j <= index; j++)
+ {
+ const CRefItem &refItem = _refItems[j];
+ const CItemEx &item = _items[refItem.ItemIndex];
+
+ // const CItemEx &item = _items[j];
+
+ importantTotalUnPacked += item.Size;
+ // importantTotalPacked += item.PackSize;
+ importantIndexes.Add(j);
+ extractStatuses.Add(j == index);
+ }
+ lastIndex = index + 1;
+ }
+
+ RINOK(extractCallback->SetTotal(importantTotalUnPacked));
+ UInt64 currentImportantTotalUnPacked = 0;
+ UInt64 currentImportantTotalPacked = 0;
+ UInt64 currentUnPackSize, currentPackSize;
+
+ CObjectVector<CMethodItem> methodItems;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CFilterCoder *filterStreamSpec = new CFilterCoder;
+ CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
+
+ NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL;
+ CMyComPtr<ICompressFilter> rar20CryptoDecoder;
+ NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL;
+ CMyComPtr<ICompressFilter> rar29CryptoDecoder;
+
+ CFolderInStream *folderInStreamSpec = NULL;
+ CMyComPtr<ISequentialInStream> folderInStream;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ bool solidStart = true;
+ for (int i = 0; i < importantIndexes.Size(); i++,
+ currentImportantTotalUnPacked += currentUnPackSize,
+ currentImportantTotalPacked += currentPackSize)
+ {
+ lps->InSize = currentImportantTotalPacked;
+ lps->OutSize = currentImportantTotalUnPacked;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+
+ Int32 askMode;
+ if (extractStatuses[i])
+ askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ else
+ askMode = NExtract::NAskMode::kSkip;
+
+ UInt32 index = importantIndexes[i];
+
+ const CRefItem &refItem = _refItems[index];
+ const CItemEx &item = _items[refItem.ItemIndex];
+
+ currentUnPackSize = item.Size;
+
+ currentPackSize = GetPackSize(index);
+
+ if (item.IgnoreItem())
+ continue;
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (!IsSolid(index))
+ solidStart = true;
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ bool mustBeProcessedAnywhere = false;
+ if (i < importantIndexes.Size() - 1)
+ {
+ // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];
+ // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex];
+ // mustBeProcessedAnywhere = nextItemInfo.IsSolid();
+ mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);
+ }
+
+ if (!mustBeProcessedAnywhere && !testMode && !realOutStream)
+ continue;
+
+ if (!realOutStream && !testMode)
+ askMode = NExtract::NAskMode::kSkip;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ /*
+ for (int partIndex = 0; partIndex < 1; partIndex++)
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+
+ // item redefinition
+ const CItemEx &item = _items[refItem.ItemIndex + partIndex];
+
+ NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex];
+
+ inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),
+ item.PackSize));
+ */
+ if (!folderInStream)
+ {
+ folderInStreamSpec = new CFolderInStream;
+ folderInStream = folderInStreamSpec;
+ }
+
+ folderInStreamSpec->Init(&_archives, &_items, refItem);
+
+ UInt64 packSize = currentPackSize;
+
+ // packedPos += item.PackSize;
+ // unpackedPos += 0;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ if (item.IsEncrypted())
+ {
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ if (item.UnPackVersion >= 29)
+ {
+ if (!rar29CryptoDecoder)
+ {
+ rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;
+ rar29CryptoDecoder = rar29CryptoDecoderSpec;
+ // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder));
+ }
+ rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
+ CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
+ RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
+ &cryptoProperties));
+ RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
+ filterStreamSpec->Filter = rar29CryptoDecoder;
+ }
+ else if (item.UnPackVersion >= 20)
+ {
+ if (!rar20CryptoDecoder)
+ {
+ rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;
+ rar20CryptoDecoder = rar20CryptoDecoderSpec;
+ // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder));
+ }
+ filterStreamSpec->Filter = rar20CryptoDecoder;
+ }
+ else
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword,
+ &cryptoSetPassword));
+
+ if (!getTextPassword)
+ extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password));
+ if (item.UnPackVersion >= 29)
+ {
+ CByteBuffer buffer;
+ UString unicodePassword(password);
+ const UInt32 sizeInBytes = unicodePassword.Length() * 2;
+ buffer.SetCapacity(sizeInBytes);
+ for (int i = 0; i < unicodePassword.Length(); i++)
+ {
+ wchar_t c = unicodePassword[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+ RINOK(cryptoSetPassword->CryptoSetPassword(
+ (const Byte *)buffer, sizeInBytes));
+ }
+ else
+ {
+ AString oemPassword = UnicodeStringToMultiByte(
+ (const wchar_t *)password, CP_OEMCP);
+ RINOK(cryptoSetPassword->CryptoSetPassword(
+ (const Byte *)(const char *)oemPassword, oemPassword.Length()));
+ }
+ }
+ else
+ {
+ RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
+ }
+ filterStreamSpec->SetInStream(folderInStream);
+ inStream = filterStream;
+ }
+ else
+ {
+ inStream = folderInStream;
+ }
+ CMyComPtr<ICompressCoder> commonCoder;
+ switch(item.Method)
+ {
+ case '0':
+ {
+ commonCoder = copyCoder;
+ break;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ {
+ /*
+ if (item.UnPackVersion >= 29)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ */
+ int m;
+ for (m = 0; m < methodItems.Size(); m++)
+ if (methodItems[m].RarUnPackVersion == item.UnPackVersion)
+ break;
+ if (m == methodItems.Size())
+ {
+ CMethodItem mi;
+ mi.RarUnPackVersion = item.UnPackVersion;
+
+ mi.Coder.Release();
+ if (item.UnPackVersion <= 30)
+ {
+ UInt32 methodID = 0x040300;
+ if (item.UnPackVersion < 20)
+ methodID += 1;
+ else if (item.UnPackVersion < 29)
+ methodID += 2;
+ else
+ methodID += 3;
+ RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, mi.Coder, false));
+ }
+
+ if (mi.Coder == 0)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+
+ m = methodItems.Add(mi);
+ }
+ CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder;
+
+ CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
+ RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,
+ &compressSetDecoderProperties));
+
+ Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
+ if (solidStart)
+ {
+ isSolid = false;
+ solidStart = false;
+ }
+
+
+ RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1));
+
+ commonCoder = decoder;
+ break;
+ }
+ default:
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress);
+ if (item.IsEncrypted())
+ filterStreamSpec->ReleaseInStream();
+ if (result == S_FALSE)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ if (result != S_OK)
+ return result;
+
+ /*
+ if (refItem.NumItems == 1 &&
+ !item.IsSplitBefore() && !item.IsSplitAfter())
+ */
+ {
+ const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
+ bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(crcOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError));
+ }
+ /*
+ else
+ {
+ bool crcOK = true;
+ for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++)
+ {
+ const CItemEx &item = _items[refItem.ItemIndex + partIndex];
+ if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])
+ {
+ crcOK = false;
+ break;
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(crcOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError));
+ }
+ */
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHandler.h
new file mode 100644
index 000000000..792668273
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHandler.h
@@ -0,0 +1,66 @@
+// Rar/Handler.h
+
+#ifndef __RAR_HANDLER_H
+#define __RAR_HANDLER_H
+
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "RarIn.h"
+#include "RarVolumeInStream.h"
+
+namespace NArchive {
+namespace NRar {
+
+class CHandler:
+ public IInArchive,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+ CRecordVector<CRefItem> _refItems;
+ CObjectVector<CItemEx> _items;
+ CObjectVector<CInArchive> _archives;
+ NArchive::NRar::CInArchiveInfo _archiveInfo;
+ AString _errorMessage;
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ UInt64 GetPackSize(int refIndex) const;
+
+ bool IsSolid(int refIndex)
+ {
+ const CItemEx &item = _items[_refItems[refIndex].ItemIndex];
+ if (item.UnPackVersion < 20)
+ {
+ if (_archiveInfo.IsSolid())
+ return (refIndex > 0);
+ return false;
+ }
+ return item.IsSolid();
+ }
+ void AddErrorMessage(const AString &s)
+ {
+ if (!_errorMessage.IsEmpty())
+ _errorMessage += '\n';
+ _errorMessage += s;
+ }
+
+ HRESULT Open2(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+
+ DECL_ISetCompressCodecsInfo
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHeader.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHeader.cpp
new file mode 100644
index 000000000..94481e025
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHeader.cpp
@@ -0,0 +1,21 @@
+// Archive/Rar/Headers.cpp
+
+#include "StdAfx.h"
+
+#include "RarHeader.h"
+
+namespace NArchive{
+namespace NRar{
+namespace NHeader{
+
+Byte kMarker[kMarkerSize] = {0x52 + 1, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
+
+class CMarkerInitializer
+{
+public:
+ CMarkerInitializer() { kMarker[0]--; };
+};
+
+static CMarkerInitializer markerInitializer;
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHeader.h b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHeader.h
new file mode 100644
index 000000000..5c21a2ac0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarHeader.h
@@ -0,0 +1,205 @@
+// Archive/RarHeader.h
+
+#ifndef __ARCHIVE_RAR_HEADER_H
+#define __ARCHIVE_RAR_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NRar {
+namespace NHeader {
+
+const int kMarkerSize = 7;
+extern Byte kMarker[kMarkerSize];
+
+const int kArchiveSolid = 0x1;
+
+namespace NBlockType
+{
+ enum EBlockType
+ {
+ kMarker = 0x72,
+ kArchiveHeader,
+ kFileHeader,
+ kCommentHeader,
+ kOldAuthenticity,
+ kOldSubBlock,
+ kRecoveryRecord,
+ kAuthenticity,
+ kSubBlock,
+ kEndOfArchive
+ };
+}
+
+namespace NArchive
+{
+ const UInt16 kVolume = 1;
+ const UInt16 kComment = 2;
+ const UInt16 kLock = 4;
+ const UInt16 kSolid = 8;
+ const UInt16 kNewVolName = 0x10; // ('volname.partN.rar')
+ const UInt16 kAuthenticity = 0x20;
+ const UInt16 kRecovery = 0x40;
+ const UInt16 kBlockEncryption = 0x80;
+ const UInt16 kFirstVolume = 0x100; // (set only by RAR 3.0 and later)
+ const UInt16 kEncryptVer = 0x200; // RAR 3.6 there is EncryptVer Byte in End of MainHeader
+
+ const int kHeaderSizeMin = 7;
+
+ const int kArchiveHeaderSize = 13;
+
+ const int kBlockHeadersAreEncrypted = 0x80;
+
+}
+
+namespace NFile
+{
+ const int kSplitBefore = 1 << 0;
+ const int kSplitAfter = 1 << 1;
+ const int kEncrypted = 1 << 2;
+ const int kComment = 1 << 3;
+ const int kSolid = 1 << 4;
+
+ const int kDictBitStart = 5;
+ const int kNumDictBits = 3;
+ const int kDictMask = (1 << kNumDictBits) - 1;
+ const int kDictDirectoryValue = 0x7;
+
+ const int kSize64Bits = 1 << 8;
+ const int kUnicodeName = 1 << 9;
+ const int kSalt = 1 << 10;
+ const int kOldVersion = 1 << 11;
+ const int kExtTime = 1 << 12;
+ // const int kExtFlags = 1 << 13;
+ // const int kSkipIfUnknown = 1 << 14;
+
+ const int kLongBlock = 1 << 15;
+
+ /*
+ struct CBlock
+ {
+ // UInt16 HeadCRC;
+ // Byte Type;
+ // UInt16 Flags;
+ // UInt16 HeadSize;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ };
+ */
+
+ /*
+ struct CBlock32
+ {
+ UInt16 HeadCRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ UInt16 GetRealCRC(const void *aName, UInt32 aNameSize,
+ bool anExtraDataDefined = false, Byte *anExtraData = 0) const;
+ };
+ struct CBlock64
+ {
+ UInt16 HeadCRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 PackSizeLow;
+ UInt32 UnPackSizeLow;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ UInt32 PackSizeHigh;
+ UInt32 UnPackSizeHigh;
+ UInt16 GetRealCRC(const void *aName, UInt32 aNameSize) const;
+ };
+ */
+
+ const int kLabelFileAttribute = 0x08;
+ const int kWinFileDirectoryAttributeMask = 0x10;
+
+ enum CHostOS
+ {
+ kHostMSDOS = 0,
+ kHostOS2 = 1,
+ kHostWin32 = 2,
+ kHostUnix = 3,
+ kHostMacOS = 4,
+ kHostBeOS = 5
+ };
+}
+
+namespace NBlock
+{
+ const UInt16 kLongBlock = 1 << 15;
+ struct CBlock
+ {
+ UInt16 CRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ // UInt32 DataSize;
+ };
+}
+
+/*
+struct CSubBlock
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 DataSize;
+ UInt16 SubType;
+ Byte Level; // Reserved : Must be 0
+};
+
+struct CCommentBlock
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt16 UnpSize;
+ Byte UnpVer;
+ Byte Method;
+ UInt16 CommCRC;
+};
+
+
+struct CProtectHeader
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 DataSize;
+ Byte Version;
+ UInt16 RecSectors;
+ UInt32 TotalBlocks;
+ Byte Mark[8];
+};
+*/
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarIn.cpp
new file mode 100644
index 000000000..e4c23752c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarIn.cpp
@@ -0,0 +1,478 @@
+// Archive/RarIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "Common/StringConvert.h"
+#include "Common/UTFConvert.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/FindSignature.h"
+
+#include "RarIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NRar {
+
+static const char *k_UnexpectedEnd = "Unexpected end of archive";
+static const char *k_DecryptionError = "Decryption Error";
+
+void CInArchive::ThrowExceptionWithCode(
+ CInArchiveException::CCauseType cause)
+{
+ throw CInArchiveException(cause);
+}
+
+HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit)
+{
+ try
+ {
+ Close();
+ HRESULT res = Open2(inStream, searchHeaderSizeLimit);
+ if (res == S_OK)
+ return res;
+ Close();
+ return res;
+ }
+ catch(...) { Close(); throw; }
+}
+
+void CInArchive::Close()
+{
+ m_Stream.Release();
+}
+
+HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize)
+{
+ if (m_CryptoMode)
+ {
+ size_t size = *resSize;
+ *resSize = 0;
+ const Byte *bufData = m_DecryptedDataAligned;
+ UInt32 bufSize = m_DecryptedDataSize;
+ size_t i;
+ for (i = 0; i < size && m_CryptoPos < bufSize; i++)
+ ((Byte *)data)[i] = bufData[m_CryptoPos++];
+ *resSize = i;
+ return S_OK;
+ }
+ return ReadStream(m_Stream, data, resSize);
+}
+
+bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
+{
+ size_t processed = size;
+ if (ReadBytesSpec(data, &processed) != S_OK)
+ return false;
+ return processed == size;
+}
+
+HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ m_CryptoMode = false;
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition));
+ m_Position = m_StreamStartPosition;
+
+ UInt64 arcStartPos;
+ RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
+ searchHeaderSizeLimit, arcStartPos));
+ m_Position = arcStartPos + NHeader::kMarkerSize;
+ RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
+ Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1];
+
+ RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize));
+ AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize);
+
+
+ UInt32 blockSize = Get16(buf + 5);
+
+ _header.EncryptVersion = 0;
+ _header.Flags = Get16(buf + 3);
+
+ UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize;
+ if (_header.IsThereEncryptVer())
+ {
+ if (blockSize <= headerSize)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1));
+ AddToSeekValue(1);
+ _header.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize];
+ headerSize += 1;
+ }
+ if (blockSize < headerSize ||
+ buf[2] != NHeader::NBlockType::kArchiveHeader ||
+ (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF))
+ return S_FALSE;
+
+ size_t commentSize = blockSize - headerSize;
+ _comment.SetCapacity(commentSize);
+ RINOK(ReadStream_FALSE(stream, _comment, commentSize));
+ AddToSeekValue(commentSize);
+ m_Stream = stream;
+ _header.StartPosition = arcStartPos;
+ return S_OK;
+}
+
+void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const
+{
+ archiveInfo = _header;
+}
+
+static void DecodeUnicodeFileName(const char *name, const Byte *encName,
+ int encSize, wchar_t *unicodeName, int maxDecSize)
+{
+ int encPos = 0;
+ int decPos = 0;
+ int flagBits = 0;
+ Byte flags = 0;
+ Byte highByte = encName[encPos++];
+ while (encPos < encSize && decPos < maxDecSize)
+ {
+ if (flagBits == 0)
+ {
+ flags = encName[encPos++];
+ flagBits = 8;
+ }
+ switch(flags >> 6)
+ {
+ case 0:
+ unicodeName[decPos++] = encName[encPos++];
+ break;
+ case 1:
+ unicodeName[decPos++] = (wchar_t)(encName[encPos++] + (highByte << 8));
+ break;
+ case 2:
+ unicodeName[decPos++] = (wchar_t)(encName[encPos] + (encName[encPos + 1] << 8));
+ encPos += 2;
+ break;
+ case 3:
+ {
+ int length = encName[encPos++];
+ if (length & 0x80)
+ {
+ Byte correction = encName[encPos++];
+ for (length = (length & 0x7f) + 2;
+ length > 0 && decPos < maxDecSize; length--, decPos++)
+ unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8));
+ }
+ else
+ for (length += 2; length > 0 && decPos < maxDecSize; length--, decPos++)
+ unicodeName[decPos] = name[decPos];
+ }
+ break;
+ }
+ flags <<= 2;
+ flagBits -= 2;
+ }
+ unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0;
+}
+
+void CInArchive::ReadName(CItemEx &item, int nameSize)
+{
+ item.UnicodeName.Empty();
+ if (nameSize > 0)
+ {
+ m_NameBuffer.EnsureCapacity(nameSize + 1);
+ char *buffer = (char *)m_NameBuffer;
+
+ for (int i = 0; i < nameSize; i++)
+ buffer[i] = ReadByte();
+
+ int mainLen;
+ for (mainLen = 0; mainLen < nameSize; mainLen++)
+ if (buffer[mainLen] == '\0')
+ break;
+ buffer[mainLen] = '\0';
+ item.Name = buffer;
+
+ if(item.HasUnicodeName())
+ {
+ if(mainLen < nameSize)
+ {
+ int unicodeNameSizeMax = MyMin(nameSize, (0x400));
+ _unicodeNameBuffer.EnsureCapacity(unicodeNameSizeMax + 1);
+ DecodeUnicodeFileName(buffer, (const Byte *)buffer + mainLen + 1,
+ nameSize - (mainLen + 1), _unicodeNameBuffer, unicodeNameSizeMax);
+ item.UnicodeName = _unicodeNameBuffer;
+ }
+ else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName))
+ item.UnicodeName.Empty();
+ }
+ }
+ else
+ item.Name.Empty();
+}
+
+Byte CInArchive::ReadByte()
+{
+ if (m_CurPos >= m_PosLimit)
+ throw CInArchiveException(CInArchiveException::kIncorrectArchive);
+ return m_CurData[m_CurPos++];
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = ReadByte();
+ value |= (UInt16(b) << (8 * i));
+ }
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b = ReadByte();
+ value |= (UInt32(b) << (8 * i));
+ }
+ return value;
+}
+
+void CInArchive::ReadTime(Byte mask, CRarTime &rarTime)
+{
+ rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
+ int numDigits = (mask & 3);
+ rarTime.SubTime[0] = rarTime.SubTime[1] = rarTime.SubTime[2] = 0;
+ for (int i = 0; i < numDigits; i++)
+ rarTime.SubTime[3 - numDigits + i] = ReadByte();
+}
+
+void CInArchive::ReadHeaderReal(CItemEx &item)
+{
+ item.Flags = m_BlockHeader.Flags;
+ item.PackSize = ReadUInt32();
+ item.Size = ReadUInt32();
+ item.HostOS = ReadByte();
+ item.FileCRC = ReadUInt32();
+ item.MTime.DosTime = ReadUInt32();
+ item.UnPackVersion = ReadByte();
+ item.Method = ReadByte();
+ int nameSize = ReadUInt16();
+ item.Attrib = ReadUInt32();
+
+ item.MTime.LowSecond = 0;
+ item.MTime.SubTime[0] =
+ item.MTime.SubTime[1] =
+ item.MTime.SubTime[2] = 0;
+
+ if((item.Flags & NHeader::NFile::kSize64Bits) != 0)
+ {
+ item.PackSize |= ((UInt64)ReadUInt32() << 32);
+ item.Size |= ((UInt64)ReadUInt32() << 32);
+ }
+
+ ReadName(item, nameSize);
+
+ if (item.HasSalt())
+ for (int i = 0; i < sizeof(item.Salt); i++)
+ item.Salt[i] = ReadByte();
+
+ // some rar archives have HasExtTime flag without field.
+ if (m_CurPos < m_PosLimit && item.HasExtTime())
+ {
+ Byte accessMask = (Byte)(ReadByte() >> 4);
+ Byte b = ReadByte();
+ Byte modifMask = (Byte)(b >> 4);
+ Byte createMask = (Byte)(b & 0xF);
+ if ((modifMask & 8) != 0)
+ ReadTime(modifMask, item.MTime);
+ item.CTimeDefined = ((createMask & 8) != 0);
+ if (item.CTimeDefined)
+ {
+ item.CTime.DosTime = ReadUInt32();
+ ReadTime(createMask, item.CTime);
+ }
+ item.ATimeDefined = ((accessMask & 8) != 0);
+ if (item.ATimeDefined)
+ {
+ item.ATime.DosTime = ReadUInt32();
+ ReadTime(accessMask, item.ATime);
+ }
+ }
+
+ UInt16 fileHeaderWithNameSize = (UInt16)m_CurPos;
+
+ item.Position = m_Position;
+ item.MainPartSize = fileHeaderWithNameSize;
+ item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize);
+
+ if (m_CryptoMode)
+ item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF);
+ else
+ item.AlignSize = 0;
+ AddToSeekValue(m_BlockHeader.HeadSize);
+}
+
+void CInArchive::AddToSeekValue(UInt64 addValue)
+{
+ m_Position += addValue;
+}
+
+HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage)
+{
+ decryptionError = false;
+ for (;;)
+ {
+ SeekInArchive(m_Position);
+ if (!m_CryptoMode && (_header.Flags &
+ NHeader::NArchive::kBlockHeadersAreEncrypted) != 0)
+ {
+ m_CryptoMode = false;
+ if (getTextPassword == 0)
+ return S_FALSE;
+ if (!m_RarAES)
+ {
+ m_RarAESSpec = new NCrypto::NRar29::CDecoder;
+ m_RarAES = m_RarAESSpec;
+ }
+ m_RarAESSpec->SetRar350Mode(_header.IsEncryptOld());
+
+ // Salt
+ const UInt32 kSaltSize = 8;
+ Byte salt[kSaltSize];
+ if(!ReadBytesAndTestSize(salt, kSaltSize))
+ return S_FALSE;
+ m_Position += kSaltSize;
+ RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize))
+ // Password
+ CMyComBSTR password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password))
+ UString unicodePassword(password);
+
+ CByteBuffer buffer;
+ const UInt32 sizeInBytes = unicodePassword.Length() * 2;
+ buffer.SetCapacity(sizeInBytes);
+ for (int i = 0; i < unicodePassword.Length(); i++)
+ {
+ wchar_t c = unicodePassword[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+
+ RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+
+ const UInt32 kDecryptedBufferSize = (1 << 12);
+ if (m_DecryptedData.GetCapacity() == 0)
+ {
+ const UInt32 kAlign = 16;
+ m_DecryptedData.SetCapacity(kDecryptedBufferSize + kAlign);
+ m_DecryptedDataAligned = (Byte *)((ptrdiff_t)((Byte *)m_DecryptedData + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
+ }
+ RINOK(m_RarAES->Init());
+ size_t decryptedDataSizeT = kDecryptedBufferSize;
+ RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT));
+ m_DecryptedDataSize = (UInt32)decryptedDataSizeT;
+ m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize);
+
+ m_CryptoMode = true;
+ m_CryptoPos = 0;
+ }
+
+ m_FileHeaderData.EnsureCapacity(7);
+ size_t processed = 7;
+ RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed));
+ if (processed != 7)
+ {
+ if (processed != 0)
+ errorMessage = k_UnexpectedEnd;
+ return S_FALSE;
+ }
+
+ m_CurData = (Byte *)m_FileHeaderData;
+ m_CurPos = 0;
+ m_PosLimit = 7;
+ m_BlockHeader.CRC = ReadUInt16();
+ m_BlockHeader.Type = ReadByte();
+ m_BlockHeader.Flags = ReadUInt16();
+ m_BlockHeader.HeadSize = ReadUInt16();
+
+ if (m_BlockHeader.HeadSize < 7)
+ ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive);
+
+ if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive)
+ return S_FALSE;
+
+ if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader)
+ {
+ m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize);
+ m_CurData = (Byte *)m_FileHeaderData;
+ m_PosLimit = m_BlockHeader.HeadSize;
+ if (!ReadBytesAndTestSize(m_CurData + m_CurPos, m_BlockHeader.HeadSize - 7))
+ {
+ errorMessage = k_UnexpectedEnd;
+ return S_FALSE;
+ }
+
+ ReadHeaderReal(item);
+ if ((CrcCalc(m_CurData + 2,
+ m_BlockHeader.HeadSize - item.CommentSize - 2) & 0xFFFF) != m_BlockHeader.CRC)
+ ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError);
+
+ FinishCryptoBlock();
+ m_CryptoMode = false;
+ SeekInArchive(m_Position); // Move Position to compressed Data;
+ AddToSeekValue(item.PackSize); // m_Position points to next header;
+ return S_OK;
+ }
+ if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10))
+ {
+ decryptionError = true;
+ errorMessage = k_DecryptionError;
+ return S_FALSE;
+ }
+ if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0)
+ {
+ m_FileHeaderData.EnsureCapacity(7 + 4);
+ m_CurData = (Byte *)m_FileHeaderData;
+ if (!ReadBytesAndTestSize(m_CurData + m_CurPos, 4))
+ {
+ errorMessage = k_UnexpectedEnd;
+ return S_FALSE;
+ }
+ m_PosLimit = 7 + 4;
+ UInt32 dataSize = ReadUInt32();
+ AddToSeekValue(dataSize);
+ if (m_CryptoMode && dataSize > (1 << 27))
+ {
+ decryptionError = true;
+ errorMessage = k_DecryptionError;
+ return S_FALSE;
+ }
+ m_CryptoPos = m_BlockHeader.HeadSize;
+ }
+ else
+ m_CryptoPos = 0;
+ AddToSeekValue(m_BlockHeader.HeadSize);
+ FinishCryptoBlock();
+ m_CryptoMode = false;
+ }
+}
+
+void CInArchive::SeekInArchive(UInt64 position)
+{
+ m_Stream->Seek(position, STREAM_SEEK_SET, NULL);
+}
+
+ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
+{
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ SeekInArchive(position);
+ streamSpec->SetStream(m_Stream);
+ streamSpec->Init(size);
+ return inStream.Detach();
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarIn.h
new file mode 100644
index 000000000..a6998db26
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarIn.h
@@ -0,0 +1,123 @@
+// RarIn.h
+
+#ifndef __ARCHIVE_RAR_IN_H
+#define __ARCHIVE_RAR_IN_H
+
+#include "Common/DynamicBuffer.h"
+#include "Common/MyCom.h"
+
+#include "../../ICoder.h"
+#include "../../IStream.h"
+
+#include "../../Common/StreamObjects.h"
+
+#include "../../Crypto/RarAes.h"
+
+#include "RarHeader.h"
+#include "RarItem.h"
+
+namespace NArchive {
+namespace NRar {
+
+class CInArchiveException
+{
+public:
+ enum CCauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kArchiveHeaderCRCError,
+ kFileHeaderCRCError,
+ kIncorrectArchive
+ }
+ Cause;
+ CInArchiveException(CCauseType cause) : Cause(cause) {}
+};
+
+
+struct CInArchiveInfo
+{
+ UInt32 Flags;
+ Byte EncryptVersion;
+ UInt64 StartPosition;
+
+ bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; }
+ bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; }
+ bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; }
+ bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; }
+ bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; }
+ bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; }
+ bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); }
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+
+ UInt64 m_StreamStartPosition;
+
+ CInArchiveInfo _header;
+ CDynamicBuffer<char> m_NameBuffer;
+ CDynamicBuffer<wchar_t> _unicodeNameBuffer;
+
+ CByteBuffer _comment;
+
+ void ReadName(CItemEx &item, int nameSize);
+ void ReadHeaderReal(CItemEx &item);
+
+ HRESULT ReadBytesSpec(void *data, size_t *size);
+ bool ReadBytesAndTestSize(void *data, UInt32 size);
+
+ HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+
+ void ThrowExceptionWithCode(CInArchiveException::CCauseType cause);
+ void ThrowUnexpectedEndOfArchiveException();
+
+ void AddToSeekValue(UInt64 addValue);
+
+ CDynamicBuffer<Byte> m_FileHeaderData;
+
+ NHeader::NBlock::CBlock m_BlockHeader;
+
+ NCrypto::NRar29::CDecoder *m_RarAESSpec;
+ CMyComPtr<ICompressFilter> m_RarAES;
+
+ Byte *m_CurData; // it must point to start of Rar::Block
+ UInt32 m_CurPos;
+ UInt32 m_PosLimit;
+ Byte ReadByte();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ void ReadTime(Byte mask, CRarTime &rarTime);
+
+ CBuffer<Byte> m_DecryptedData;
+ Byte *m_DecryptedDataAligned;
+ UInt32 m_DecryptedDataSize;
+
+ bool m_CryptoMode;
+ UInt32 m_CryptoPos;
+ void FinishCryptoBlock()
+ {
+ if (m_CryptoMode)
+ while ((m_CryptoPos & 0xF) != 0)
+ {
+ m_CryptoPos++;
+ m_Position++;
+ }
+ }
+
+public:
+ UInt64 m_Position;
+
+ HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit);
+ void Close();
+ HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage);
+
+ void GetArchiveInfo(CInArchiveInfo &archiveInfo) const;
+
+ void SeekInArchive(UInt64 position);
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarItem.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarItem.cpp
new file mode 100644
index 000000000..9216ae57b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarItem.cpp
@@ -0,0 +1,55 @@
+// RarItem.cpp
+
+#include "StdAfx.h"
+
+#include "RarItem.h"
+
+namespace NArchive{
+namespace NRar{
+
+bool CItem::IgnoreItem() const
+{
+ switch(HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0);
+ }
+ return false;
+}
+
+bool CItem::IsDir() const
+{
+ if (GetDictSize() == NHeader::NFile::kDictDirectoryValue)
+ return true;
+ switch(HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ return true;
+ }
+ return false;
+}
+
+UInt32 CItem::GetWinAttributes() const
+{
+ UInt32 winAttributes;
+ switch(HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ winAttributes = Attrib;
+ break;
+ default:
+ winAttributes = 0; // must be converted from unix value;
+ }
+ if (IsDir())
+ winAttributes |= NHeader::NFile::kWinFileDirectoryAttributeMask;
+ return winAttributes;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarItem.h b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarItem.h
new file mode 100644
index 000000000..4aa4d8667
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarItem.h
@@ -0,0 +1,79 @@
+// RarItem.h
+
+#ifndef __ARCHIVE_RAR_ITEM_H
+#define __ARCHIVE_RAR_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+
+#include "RarHeader.h"
+
+namespace NArchive{
+namespace NRar{
+
+struct CRarTime
+{
+ UInt32 DosTime;
+ Byte LowSecond;
+ Byte SubTime[3];
+};
+
+struct CItem
+{
+ UInt64 Size;
+ UInt64 PackSize;
+
+ CRarTime CTime;
+ CRarTime ATime;
+ CRarTime MTime;
+
+ UInt32 FileCRC;
+ UInt32 Attrib;
+
+ UInt16 Flags;
+ Byte HostOS;
+ Byte UnPackVersion;
+ Byte Method;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+
+ AString Name;
+ UString UnicodeName;
+
+ Byte Salt[8];
+
+ bool IsEncrypted() const { return (Flags & NHeader::NFile::kEncrypted) != 0; }
+ bool IsSolid() const { return (Flags & NHeader::NFile::kSolid) != 0; }
+ bool IsCommented() const { return (Flags & NHeader::NFile::kComment) != 0; }
+ bool IsSplitBefore() const { return (Flags & NHeader::NFile::kSplitBefore) != 0; }
+ bool IsSplitAfter() const { return (Flags & NHeader::NFile::kSplitAfter) != 0; }
+ bool HasSalt() const { return (Flags & NHeader::NFile::kSalt) != 0; }
+ bool HasExtTime() const { return (Flags & NHeader::NFile::kExtTime) != 0; }
+ bool HasUnicodeName()const { return (Flags & NHeader::NFile::kUnicodeName) != 0; }
+ bool IsOldVersion() const { return (Flags & NHeader::NFile::kOldVersion) != 0; }
+
+ UInt32 GetDictSize() const { return (Flags >> NHeader::NFile::kDictBitStart) & NHeader::NFile::kDictMask; }
+ bool IsDir() const;
+ bool IgnoreItem() const;
+ UInt32 GetWinAttributes() const;
+
+ CItem(): CTimeDefined(false), ATimeDefined(false) {}
+};
+
+class CItemEx: public CItem
+{
+public:
+ UInt64 Position;
+ UInt16 MainPartSize;
+ UInt16 CommentSize;
+ UInt16 AlignSize;
+ UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; };
+ // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; };
+ UInt64 GetCommentPosition() const { return Position + MainPartSize; };
+ UInt64 GetDataPosition() const { return GetCommentPosition() + CommentSize + AlignSize; };
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarRegister.cpp
new file mode 100644
index 000000000..2bcf569ef
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarRegister.cpp
@@ -0,0 +1,13 @@
+// RarRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "RarHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NRar::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Rar", L"rar r00", 0, 3, {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}, 7, false, CreateArc, 0, };
+
+REGISTER_ARC(Rar)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp
new file mode 100644
index 000000000..25194f915
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp
@@ -0,0 +1,78 @@
+// RarVolumeInStream.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "RarVolumeInStream.h"
+
+namespace NArchive {
+namespace NRar {
+
+void CFolderInStream::Init(
+ CObjectVector<CInArchive> *archives,
+ const CObjectVector<CItemEx> *items,
+ const CRefItem &refItem)
+{
+ _archives = archives;
+ _items = items;
+ _refItem = refItem;
+ _curIndex = 0;
+ CRCs.Clear();
+ _fileIsOpen = false;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+ while (_curIndex < _refItem.NumItems)
+ {
+ const CItemEx &item = (*_items)[_refItem.ItemIndex + _curIndex];
+ _stream.Attach((*_archives)[_refItem.VolumeIndex + _curIndex].
+ CreateLimitedStream(item.GetDataPosition(), item.PackSize));
+ _curIndex++;
+ _fileIsOpen = true;
+ _crc = CRC_INIT_VAL;
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT CFolderInStream::CloseStream()
+{
+ CRCs.Add(CRC_GET_DIGEST(_crc));
+ _stream.Release();
+ _fileIsOpen = false;
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 localProcessedSize;
+ RINOK(_stream->Read(
+ ((Byte *)data) + realProcessedSize, size, &localProcessedSize));
+ _crc = CrcUpdate(_crc, ((Byte *)data) + realProcessedSize, localProcessedSize);
+ if (localProcessedSize == 0)
+ {
+ RINOK(CloseStream());
+ continue;
+ }
+ realProcessedSize += localProcessedSize;
+ size -= localProcessedSize;
+ break;
+ }
+ else
+ {
+ RINOK(OpenStream());
+ }
+ }
+ if (processedSize != 0)
+ *processedSize = realProcessedSize;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarVolumeInStream.h b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarVolumeInStream.h
new file mode 100644
index 000000000..78d95b10f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Rar/RarVolumeInStream.h
@@ -0,0 +1,49 @@
+// RarVolumeInStream.h
+
+#ifndef __RAR_VOLUME_IN_STREAM_H
+#define __RAR_VOLUME_IN_STREAM_H
+
+#include "../../IStream.h"
+#include "RarIn.h"
+
+namespace NArchive {
+namespace NRar {
+
+struct CRefItem
+{
+ int VolumeIndex;
+ int ItemIndex;
+ int NumItems;
+};
+
+class CFolderInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+private:
+ CObjectVector<CInArchive> *_archives;
+ const CObjectVector<CItemEx> *_items;
+ CRefItem _refItem;
+ int _curIndex;
+ UInt32 _crc;
+ bool _fileIsOpen;
+ CMyComPtr<ISequentialInStream> _stream;
+
+ HRESULT OpenStream();
+ HRESULT CloseStream();
+public:
+ void Init(CObjectVector<CInArchive> *archives,
+ const CObjectVector<CItemEx> *items,
+ const CRefItem &refItem);
+
+ CRecordVector<UInt32> CRCs;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/RpmHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/RpmHandler.cpp
new file mode 100644
index 000000000..1d31d4514
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/RpmHandler.cpp
@@ -0,0 +1,292 @@
+// RpmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+using namespace NWindows;
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+
+namespace NArchive {
+namespace NRpm {
+
+/* Reference: lib/signature.h of rpm package */
+#define RPMSIG_NONE 0 /* Do not change! */
+/* The following types are no longer generated */
+#define RPMSIG_PGP262_1024 1 /* No longer generated */ /* 256 byte */
+/* These are the new-style signatures. They are Header structures. */
+/* Inside them we can put any number of any type of signature we like. */
+
+#define RPMSIG_HEADERSIG 5 /* New Header style signature */
+
+const UInt32 kLeadSize = 96;
+struct CLead
+{
+ unsigned char Magic[4];
+ unsigned char Major; // not supported ver1, only support 2,3 and lator
+ unsigned char Minor;
+ UInt16 Type;
+ UInt16 ArchNum;
+ char Name[66];
+ UInt16 OSNum;
+ UInt16 SignatureType;
+ char Reserved[16]; // pad to 96 bytes -- 8 byte aligned
+ bool MagicCheck() const
+ { return Magic[0] == 0xed && Magic[1] == 0xab && Magic[2] == 0xee && Magic[3] == 0xdb; };
+};
+
+const UInt32 kEntryInfoSize = 16;
+/*
+struct CEntryInfo
+{
+ int Tag;
+ int Type;
+ int Offset; // Offset from beginning of data segment, only defined on disk
+ int Count;
+};
+*/
+
+// case: SignatureType == RPMSIG_HEADERSIG
+const UInt32 kCSigHeaderSigSize = 16;
+struct CSigHeaderSig
+{
+ unsigned char Magic[4];
+ UInt32 Reserved;
+ UInt32 IndexLen; // count of index entries
+ UInt32 DataLen; // number of bytes
+ bool MagicCheck()
+ { return Magic[0] == 0x8e && Magic[1] == 0xad && Magic[2] == 0xe8 && Magic[3] == 0x01; };
+ UInt32 GetLostHeaderLen()
+ { return IndexLen * kEntryInfoSize + DataLen; };
+};
+
+static HRESULT RedSigHeaderSig(IInStream *inStream, CSigHeaderSig &h)
+{
+ char dat[kCSigHeaderSigSize];
+ char *cur = dat;
+ RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize));
+ memcpy(h.Magic, cur, 4);
+ cur += 4;
+ cur += 4;
+ h.IndexLen = Get32(cur);
+ cur += 4;
+ h.DataLen = Get32(cur);
+ return S_OK;
+}
+
+HRESULT OpenArchive(IInStream *inStream)
+{
+ UInt64 pos;
+ char leadData[kLeadSize];
+ char *cur = leadData;
+ CLead lead;
+ RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize));
+ memcpy(lead.Magic, cur, 4);
+ cur += 4;
+ lead.Major = *cur++;
+ lead.Minor = *cur++;
+ lead.Type = Get16(cur);
+ cur += 2;
+ lead.ArchNum = Get16(cur);
+ cur += 2;
+ memcpy(lead.Name, cur, sizeof(lead.Name));
+ cur += sizeof(lead.Name);
+ lead.OSNum = Get16(cur);
+ cur += 2;
+ lead.SignatureType = Get16(cur);
+ cur += 2;
+
+ if (!lead.MagicCheck() || lead.Major < 3)
+ return S_FALSE;
+
+ CSigHeaderSig sigHeader, header;
+ if (lead.SignatureType == RPMSIG_NONE)
+ {
+ ;
+ }
+ else if (lead.SignatureType == RPMSIG_PGP262_1024)
+ {
+ UInt64 pos;
+ RINOK(inStream->Seek(256, STREAM_SEEK_CUR, &pos));
+ }
+ else if (lead.SignatureType == RPMSIG_HEADERSIG)
+ {
+ RINOK(RedSigHeaderSig(inStream, sigHeader));
+ if (!sigHeader.MagicCheck())
+ return S_FALSE;
+ UInt32 len = sigHeader.GetLostHeaderLen();
+ RINOK(inStream->Seek(len, STREAM_SEEK_CUR, &pos));
+ if ((pos % 8) != 0)
+ {
+ RINOK(inStream->Seek((pos / 8 + 1) * 8 - pos,
+ STREAM_SEEK_CUR, &pos));
+ }
+ }
+ else
+ return S_FALSE;
+
+ RINOK(RedSigHeaderSig(inStream, header));
+ if (!header.MagicCheck())
+ return S_FALSE;
+ int headerLen = header.GetLostHeaderLen();
+ if (headerLen == -1)
+ return S_FALSE;
+ RINOK(inStream->Seek(headerLen, STREAM_SEEK_CUR, &pos));
+ return S_OK;
+}
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ UInt64 _pos;
+ UInt64 _size;
+ Byte _sig[4];
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID) { case kpidMainSubfile: prop = (UInt32)0; break; }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ if (OpenArchive(inStream) != S_OK)
+ return S_FALSE;
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_pos));
+ RINOK(ReadStream_FALSE(inStream, _sig, sizeof(_sig) / sizeof(_sig[0])));
+ UInt64 endPosition;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPosition));
+ _size = endPosition - _pos;
+ _stream = inStream;
+ return S_OK;
+ }
+ catch(...) { return S_FALSE; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSize:
+ case kpidPackSize:
+ prop = _size;
+ break;
+ case kpidExtension:
+ {
+ char s[32];
+ MyStringCopy(s, "cpio.");
+ const char *ext;
+ if (_sig[0] == 0x1F && _sig[1] == 0x8B)
+ ext = "gz";
+ else if (_sig[0] == 'B' && _sig[1] == 'Z' && _sig[2] == 'h')
+ ext = "bz2";
+ else
+ ext = "lzma";
+ MyStringCopy(s + MyStringLen(s), ext);
+ prop = s;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ RINOK(extractCallback->SetTotal(_size));
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &outStream, askMode));
+ if (!testMode && !outStream)
+ return S_OK;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ RINOK(_stream->Seek(_pos, STREAM_SEEK_SET, NULL));
+ RINOK(copyCoder->Code(_stream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ return CreateLimitedInStream(_stream, _pos, _size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NRpm::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Rpm", L"rpm", 0, 0xEB, { 0xED, 0xAB, 0xEE, 0xDB}, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Rpm)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/SplitHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/SplitHandler.cpp
new file mode 100644
index 000000000..5d84de4ed
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/SplitHandler.cpp
@@ -0,0 +1,366 @@
+// SplitHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/MultiStream.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NSplit {
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidNumVolumes, VT_UI4}
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ UString _subName;
+ CObjectVector<CMyComPtr<IInStream> > _streams;
+ CRecordVector<UInt64> _sizes;
+ UInt64 _totalSize;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidNumVolumes: prop = (UInt32)_streams.Size(); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+struct CSeqName
+{
+ UString _unchangedPart;
+ UString _changedPart;
+ bool _splitStyle;
+
+ UString GetNextName()
+ {
+ UString newName;
+ if (_splitStyle)
+ {
+ int i;
+ int numLetters = _changedPart.Length();
+ for (i = numLetters - 1; i >= 0; i--)
+ {
+ wchar_t c = _changedPart[i];
+ if (c == 'z')
+ {
+ c = 'a';
+ newName = c + newName;
+ continue;
+ }
+ else if (c == 'Z')
+ {
+ c = 'A';
+ newName = c + newName;
+ continue;
+ }
+ c++;
+ if ((c == 'z' || c == 'Z') && i == 0)
+ {
+ _unchangedPart += c;
+ wchar_t newChar = (c == 'z') ? L'a' : L'A';
+ newName.Empty();
+ numLetters++;
+ for (int k = 0; k < numLetters; k++)
+ newName += newChar;
+ break;
+ }
+ newName = c + newName;
+ i--;
+ for (; i >= 0; i--)
+ newName = _changedPart[i] + newName;
+ break;
+ }
+ }
+ else
+ {
+ int i;
+ int numLetters = _changedPart.Length();
+ for (i = numLetters - 1; i >= 0; i--)
+ {
+ wchar_t c = _changedPart[i];
+ if (c == L'9')
+ {
+ c = L'0';
+ newName = c + newName;
+ if (i == 0)
+ newName = UString(L'1') + newName;
+ continue;
+ }
+ c++;
+ newName = c + newName;
+ i--;
+ for (; i >= 0; i--)
+ newName = _changedPart[i] + newName;
+ break;
+ }
+ }
+ _changedPart = newName;
+ return _unchangedPart + _changedPart;
+ }
+};
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ Close();
+ if (openArchiveCallback == 0)
+ return S_FALSE;
+ // try
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
+ if (openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback,
+ &openVolumeCallback) != S_OK)
+ return S_FALSE;
+
+ UString name;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
+ if (prop.vt != VT_BSTR)
+ return S_FALSE;
+ name = prop.bstrVal;
+ }
+
+ int dotPos = name.ReverseFind('.');
+ UString prefix, ext;
+ if (dotPos >= 0)
+ {
+ prefix = name.Left(dotPos + 1);
+ ext = name.Mid(dotPos + 1);
+ }
+ else
+ ext = name;
+ UString extBig = ext;
+ extBig.MakeUpper();
+
+ CSeqName seqName;
+
+ int numLetters = 2;
+ bool splitStyle = false;
+ if (extBig.Right(2) == L"AA")
+ {
+ splitStyle = true;
+ while (numLetters < extBig.Length())
+ {
+ if (extBig[extBig.Length() - numLetters - 1] != 'A')
+ break;
+ numLetters++;
+ }
+ }
+ else if (ext.Right(2) == L"01")
+ {
+ while (numLetters < extBig.Length())
+ {
+ if (extBig[extBig.Length() - numLetters - 1] != '0')
+ break;
+ numLetters++;
+ }
+ if (numLetters != ext.Length())
+ return S_FALSE;
+ }
+ else
+ return S_FALSE;
+
+ _streams.Add(stream);
+
+ seqName._unchangedPart = prefix + ext.Left(extBig.Length() - numLetters);
+ seqName._changedPart = ext.Right(numLetters);
+ seqName._splitStyle = splitStyle;
+
+ if (prefix.Length() < 1)
+ _subName = L"file";
+ else
+ _subName = prefix.Left(prefix.Length() - 1);
+
+ _totalSize = 0;
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ _totalSize += size;
+ _sizes.Add(size);
+
+ if (openArchiveCallback != NULL)
+ {
+ UInt64 numFiles = _streams.Size();
+ RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
+ }
+
+ for (;;)
+ {
+ UString fullName = seqName.GetNextName();
+ CMyComPtr<IInStream> nextStream;
+ HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
+ if (result == S_FALSE)
+ break;
+ if (result != S_OK)
+ return result;
+ if (!stream)
+ break;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ _totalSize += size;
+ _sizes.Add(size);
+ _streams.Add(nextStream);
+ if (openArchiveCallback != NULL)
+ {
+ UInt64 numFiles = _streams.Size();
+ RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
+ }
+ }
+ }
+ /*
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ */
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _sizes.Clear();
+ _streams.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _streams.IsEmpty() ? 0 : 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPath: prop = _subName; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = _totalSize;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ UInt64 currentTotalSize = 0;
+ RINOK(extractCallback->SetTotal(_totalSize));
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &outStream, askMode));
+ if (!testMode && !outStream)
+ return S_OK;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (int i = 0; i < _streams.Size(); i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ IInStream *inStream = _streams[i];
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ currentTotalSize += copyCoderSpec->TotalSize;
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ if (index != 0)
+ return E_INVALIDARG;
+ *stream = 0;
+ CMultiStream *streamSpec = new CMultiStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ for (int i = 0; i < _streams.Size(); i++)
+ {
+ CMultiStream::CSubStreamInfo subStreamInfo;
+ subStreamInfo.Stream = _streams[i];
+ subStreamInfo.Size = _sizes[i];
+ streamSpec->Streams.Add(subStreamInfo);
+ }
+ streamSpec->Init();
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+{ L"Split", L"001", 0, 0xEA, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Split)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/SquashfsHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/SquashfsHandler.cpp
new file mode 100644
index 000000000..2cc1219ad
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -0,0 +1,2155 @@
+// SquashfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariantUtils.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+#include "../Compress/LzmaDecoder.h"
+
+namespace NArchive {
+namespace NSquashfs {
+
+static const UInt32 kNumFilesMax = (1 << 28);
+static const unsigned kNumDirLevelsMax = (1 << 10);
+
+// Layout: Header, Data, inodes, Directories, Fragments, UIDs, GIDs
+
+/*
+#define Get16(p) (be ? GetBe16(p) : GetUi16(p))
+#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
+#define Get64(p) (be ? GetBe64(p) : GetUi64(p))
+*/
+
+UInt16 Get16b(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
+UInt32 Get32b(const Byte *p, bool be) { return be ? GetBe32(p) : GetUi32(p); }
+UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); }
+
+#define Get16(p) Get16b(p, be)
+#define Get32(p) Get32b(p, be)
+#define Get64(p) Get64b(p, be)
+
+#define LE_16(offs, dest) dest = GetUi16(p + (offs));
+#define LE_32(offs, dest) dest = GetUi32(p + (offs));
+#define LE_64(offs, dest) dest = GetUi64(p + (offs));
+
+#define GET_16(offs, dest) dest = Get16(p + (offs));
+#define GET_32(offs, dest) dest = Get32(p + (offs));
+#define GET_64(offs, dest) dest = Get64(p + (offs));
+
+static const UInt32 kSignatureSize = 4;
+#define SIGNATURE { 'h', 's', 'q', 's' }
+static const UInt32 kSignature32_LE = 0x73717368;
+static const UInt32 kSignature32_BE = 0x68737173;
+static const UInt32 kSignature32_LZ = 0x71736873;
+
+#define kMethod_ZLIB 1
+#define kMethod_LZMA 2
+#define kMethod_LZO 3
+
+static const char *k_Methods[] =
+{
+ "Unknown",
+ "ZLIB",
+ "LZMA",
+ "LZO"
+};
+
+static const UInt32 kMetadataBlockSizeLog = 13;
+static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog);
+
+#define MY_S_IFIFO 0x1000
+#define MY_S_IFCHR 0x2000
+#define MY_S_IFDIR 0x4000
+#define MY_S_IFBLK 0x6000
+#define MY_S_IFREG 0x8000
+#define MY_S_IFLNK 0xA000
+#define MY_S_IFSOCK 0xC000
+
+enum
+{
+ kType_IPC,
+ kType_DIR,
+ kType_FILE,
+ kType_LNK,
+ kType_BLK,
+ kType_CHR,
+ kType_FIFO,
+ kType_SOCK
+};
+
+static const UInt32 k_TypeToMode[] =
+{
+ 0,
+ MY_S_IFDIR, MY_S_IFREG, MY_S_IFLNK, MY_S_IFBLK, MY_S_IFCHR, MY_S_IFIFO, MY_S_IFSOCK,
+ MY_S_IFDIR, MY_S_IFREG, MY_S_IFLNK, MY_S_IFBLK, MY_S_IFCHR, MY_S_IFIFO, MY_S_IFSOCK
+};
+
+
+enum
+{
+ kFlag_UNC_INODES,
+ kFlag_UNC_DATA,
+ kFlag_CHECK,
+ kFlag_UNC_FRAGS,
+ kFlag_NO_FRAGS,
+ kFlag_ALWAYS_FRAG,
+ kFlag_DUPLICATE,
+ kFlag_EXPORT
+};
+
+static const CUInt32PCharPair k_Flags[] =
+{
+ { kFlag_UNC_INODES, "UNCOMPRESSED_INODES" },
+ { kFlag_UNC_DATA, "UNCOMPRESSED_DATA" },
+ { kFlag_CHECK, "CHECK" },
+ { kFlag_UNC_FRAGS, "UNCOMPRESSED_FRAGMENTS" },
+ { kFlag_NO_FRAGS, "NO_FRAGMENTS" },
+ { kFlag_ALWAYS_FRAG, "ALWAYS_FRAGMENTS" },
+ { kFlag_DUPLICATE, "DUPLICATES_REMOVED" },
+ { kFlag_EXPORT, "EXPORTABLE" }
+};
+
+static const UInt32 kNotCompressedBit16 = (1 << 15);
+static const UInt32 kNotCompressedBit32 = (1 << 24);
+
+#define GET_COMPRESSED_BLOCK_SIZE(size) ((size) & ~kNotCompressedBit32)
+#define IS_COMPRESSED_BLOCK(size) (((size) & kNotCompressedBit32) == 0)
+
+static const UInt32 kHeaderSize1 = 0x33;
+static const UInt32 kHeaderSize2 = 0x3F;
+static const UInt32 kHeaderSize3 = 0x77;
+static const UInt32 kHeaderSize4 = 0x60;
+
+struct CHeader
+{
+ bool be;
+ bool SeveralMethods;
+ Byte NumUids;
+ Byte NumGids;
+
+ UInt32 NumInodes;
+ UInt32 CTime;
+ UInt32 BlockSize;
+ UInt32 NumFrags;
+ UInt16 Method;
+ UInt16 BlockSizeLog;
+ UInt16 Flags;
+ UInt16 NumIDs;
+ UInt16 Major;
+ UInt16 Minor;
+ UInt64 RootInode;
+ UInt64 Size;
+ UInt64 UidTable;
+ UInt64 GidTable;
+ UInt64 XattrIdTable;
+ UInt64 InodeTable;
+ UInt64 DirTable;
+ UInt64 FragTable;
+ UInt64 LookupTable;
+
+ void Parse3(const Byte *p)
+ {
+ Method = kMethod_ZLIB;
+ GET_32 (0x08, Size);
+ GET_32 (0x0C, UidTable);
+ GET_32 (0x10, GidTable);
+ GET_32 (0x14, InodeTable);
+ GET_32 (0x18, DirTable);
+ GET_16 (0x20, BlockSize);
+ GET_16 (0x22, BlockSizeLog);
+ Flags = p[0x24];
+ NumUids = p[0x25];
+ NumGids = p[0x26];
+ GET_32 (0x27, CTime);
+ GET_64 (0x2B, RootInode);
+ NumFrags = 0;
+ FragTable = UidTable;
+
+ if (Major >= 2)
+ {
+ GET_32 (0x33, BlockSize);
+ GET_32 (0x37, NumFrags);
+ GET_32 (0x3B, FragTable);
+ if (Major == 3)
+ {
+ GET_64 (0x3F, Size);
+ GET_64 (0x47, UidTable);
+ GET_64 (0x4F, GidTable);
+ GET_64 (0x57, InodeTable);
+ GET_64 (0x5F, DirTable);
+ GET_64 (0x67, FragTable);
+ GET_64 (0x6F, LookupTable);
+ }
+ }
+ }
+
+ void Parse4(const Byte *p)
+ {
+ LE_32 (0x08, CTime);
+ LE_32 (0x0C, BlockSize);
+ LE_32 (0x10, NumFrags);
+ LE_16 (0x14, Method);
+ LE_16 (0x16, BlockSizeLog);
+ LE_16 (0x18, Flags);
+ LE_16 (0x1A, NumIDs);
+ LE_64 (0x20, RootInode);
+ LE_64 (0x28, Size);
+ LE_64 (0x30, UidTable);
+ LE_64 (0x38, XattrIdTable);
+ LE_64 (0x40, InodeTable);
+ LE_64 (0x48, DirTable);
+ LE_64 (0x50, FragTable);
+ LE_64 (0x58, LookupTable);
+ GidTable = 0;
+ }
+
+ bool Parse(const Byte *p)
+ {
+ be = false;
+ SeveralMethods = false;
+ switch (GetUi32(p))
+ {
+ case kSignature32_LE: break;
+ case kSignature32_BE: be = true; break;
+ case kSignature32_LZ: SeveralMethods = true; break;
+ default: return false;
+ }
+ GET_32 (4, NumInodes);
+ GET_16 (0x1C, Major);
+ GET_16 (0x1E, Minor);
+ if (Major <= 3)
+ Parse3(p);
+ else
+ {
+ if (be)
+ return false;
+ Parse4(p);
+ }
+ return
+ InodeTable < DirTable &&
+ DirTable <= FragTable &&
+ FragTable <= Size &&
+ UidTable <= Size &&
+ BlockSizeLog >= 12 &&
+ BlockSizeLog < 31 &&
+ BlockSize == ((UInt32)1 << BlockSizeLog);
+ }
+
+ bool IsSupported() const { return Major > 0 && Major <= 4 && BlockSizeLog <= 23; }
+ bool IsOldVersion() const { return Major < 4; }
+ bool NeedCheckData() const { return (Flags & (1 << kFlag_CHECK)) != 0; }
+ unsigned GetFileNameOffset() const { return Major <= 2 ? 3 : (Major == 3 ? 5 : 8); }
+ unsigned GetSymLinkOffset() const { return Major <= 1 ? 5: (Major <= 2 ? 6: (Major == 3 ? 18 : 24)); }
+ unsigned GetSpecGuidIndex() const { return Major <= 1 ? 0xF: 0xFF; }
+};
+
+static const UInt32 kFrag_Empty = (UInt32)(Int32)-1;
+// static const UInt32 kXattr_Empty = (UInt32)(Int32)-1;
+
+struct CNode
+{
+ UInt16 Type;
+ UInt16 Mode;
+ UInt16 Uid;
+ UInt16 Gid;
+ UInt32 Frag;
+ UInt32 Offset;
+ // UInt32 MTime;
+ // UInt32 Number;
+ // UInt32 NumLinks;
+ // UInt32 RDev;
+ // UInt32 Xattr;
+ // UInt32 Parent;
+
+ UInt64 FileSize;
+ UInt64 StartBlock;
+ // UInt64 Sparse;
+
+ UInt32 Parse1(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse2(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse3(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse4(const Byte *p, UInt32 size, const CHeader &_h);
+
+ bool IsDir() const { return (Type == kType_DIR || Type == kType_DIR + 7); }
+ bool IsLink() const { return (Type == kType_LNK || Type == kType_LNK + 7); }
+ UInt64 GetSize() const { return IsDir() ? 0 : FileSize; }
+
+ bool ThereAreFrags() const { return Frag != kFrag_Empty; }
+ UInt64 GetNumBlocks(const CHeader &_h) const
+ {
+ return (FileSize >> _h.BlockSizeLog) +
+ (!ThereAreFrags() && (FileSize & (_h.BlockSize - 1)) != 0);
+ }
+};
+
+UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ bool be = _h.be;
+ if (size < 4)
+ return 0;
+ UInt16 t = Get16(p);
+ if (be)
+ {
+ Type = t >> 12;
+ Mode = t & 0xFFF;
+ Uid = p[2] >> 4;
+ Gid = p[2] & 0xF;
+ }
+ else
+ {
+ Type = t & 0xF;
+ Mode = t >> 4;
+ Uid = p[2] & 0xF;
+ Gid = p[2] >> 4;
+ }
+
+ // Xattr = kXattr_Empty;
+ // MTime = 0;
+ FileSize = 0;
+ StartBlock = 0;
+ Frag = kFrag_Empty;
+
+ if (Type == 0)
+ {
+ Byte t = p[3];
+ if (be)
+ {
+ Type = t >> 4;
+ Offset = t & 0xF;
+ }
+ else
+ {
+ Type = t & 0xF;
+ Offset = t >> 4;
+ }
+ return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0;
+ }
+
+ Type--;
+ Uid += (Type / 5) * 16;
+ Type = (Type % 5) + 1;
+
+ if (Type == kType_FILE)
+ {
+ if (size < 15)
+ return 0;
+ // GET_32 (3, MTime);
+ GET_32 (7, StartBlock);
+ UInt32 t;
+ GET_32 (11, t);
+ FileSize = t;
+ UInt32 numBlocks = t >> _h.BlockSizeLog;
+ if ((t & (_h.BlockSize - 1)) != 0)
+ numBlocks++;
+ UInt32 pos = numBlocks * 2 + 15;
+ return (pos <= size) ? pos : 0;
+ }
+
+ if (Type == kType_DIR)
+ {
+ if (size < 14)
+ return 0;
+ UInt32 t = Get32(p + 3);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ // GET_32 (7, MTime);
+ GET_32 (10, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ return 14;
+ }
+
+ if (size < 5)
+ return 0;
+
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (3, len);
+ FileSize = len;
+ len += 5;
+ return (len <= size) ? len : 0;
+ }
+
+ // GET_32 (3, RDev);
+ return 5;
+}
+
+UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ bool be = _h.be;
+ if (size < 4)
+ return 0;
+ UInt16 t = Get16(p);
+ if (be)
+ {
+ Type = t >> 12;
+ Mode = t & 0xFFF;
+ }
+ else
+ {
+ Type = t & 0xF;
+ Mode = t >> 4;
+ }
+ Uid = p[2];
+ Gid = p[3];
+
+ // Xattr = kXattr_Empty;
+
+ if (Type == kType_FILE)
+ {
+ if (size < 24)
+ return 0;
+ // GET_32 (4, MTime);
+ GET_32 (8, StartBlock);
+ GET_32 (12, Frag);
+ GET_32 (16, Offset);
+ UInt32 t;
+ GET_32 (20, t);
+ FileSize = t;
+ UInt32 numBlocks = t >> _h.BlockSizeLog;
+ if (!ThereAreFrags() && (t & (_h.BlockSize - 1)) != 0)
+ numBlocks++;
+ UInt32 pos = numBlocks * 4 + 24;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ FileSize = 0;
+ // MTime = 0;
+ StartBlock = 0;
+ Frag = kFrag_Empty;
+
+ if (Type == kType_DIR)
+ {
+ if (size < 15)
+ return 0;
+ UInt32 t = Get32(p + 4);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ // GET_32 (8, MTime);
+ GET_32 (11, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ return 15;
+ }
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 18)
+ return 0;
+ UInt32 t = Get32(p + 4);
+ UInt32 t2 = Get16(p + 7);
+ if (be)
+ {
+ FileSize = t >> 5;
+ Offset = t2 & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFFFF;
+ Offset = t2 >> 3;
+ }
+ // GET_32 (9, MTime);
+ GET_32 (12, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ UInt32 iCount;
+ GET_16 (16, iCount);
+ UInt32 pos = 18;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // 27 bits: index
+ // 29 bits: startBlock
+ if (pos + 8 > size)
+ return 0;
+ pos += 8 + (UInt32)p[pos + 7] + 1; // nameSize
+ if (pos > size)
+ return 0;
+ }
+ return pos;
+ }
+
+ if (Type == kType_FIFO || Type == kType_SOCK)
+ return 4;
+
+ if (size < 6)
+ return 0;
+
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (4, len);
+ FileSize = len;
+ len += 6;
+ return (len <= size) ? len : 0;
+ }
+
+ if (Type == kType_BLK || Type == kType_CHR)
+ {
+ // GET_16 (4, RDev);
+ return 6;
+ }
+
+ return 0;
+}
+
+UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ bool be = _h.be;
+ if (size < 12)
+ return 0;
+ UInt16 t = Get16(p);
+ if (be)
+ {
+ Type = t >> 12;
+ Mode = t & 0xFFF;
+ }
+ else
+ {
+ Type = t & 0xF;
+ Mode = t >> 4;
+ }
+ Uid = p[2];
+ Gid = p[3];
+ // GET_32 (4, MTime);
+ // GET_32 (8, Number);
+ // Xattr = kXattr_Empty;
+ FileSize = 0;
+ StartBlock = 0;
+
+ if (Type == kType_FILE || Type == kType_FILE + 7)
+ {
+ UInt32 offset;
+ if (Type == kType_FILE)
+ {
+ if (size < 32)
+ return 0;
+ GET_64 (12, StartBlock);
+ GET_32 (20, Frag);
+ GET_32 (24, Offset);
+ GET_32 (28, FileSize);
+ offset = 32;
+ }
+ else
+ {
+ if (size < 40)
+ return 0;
+ // GET_32 (12, NumLinks);
+ GET_64 (16, StartBlock);
+ GET_32 (24, Frag);
+ GET_32 (28, Offset);
+ GET_64 (32, FileSize);
+ offset = 40;
+ }
+ UInt64 pos = GetNumBlocks(_h) * 4 + offset;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ if (size < 16)
+ return 0;
+ // GET_32 (12, NumLinks);
+
+ if (Type == kType_DIR)
+ {
+ if (size < 28)
+ return 0;
+ UInt32 t = Get32(p + 16);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ GET_32 (20, StartBlock);
+ // GET_32 (24, Parent);
+ return 28;
+ }
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 31)
+ return 0;
+ UInt32 t = Get32(p + 16);
+ UInt32 t2 = Get16(p + 19);
+ if (be)
+ {
+ FileSize = t >> 5;
+ Offset = t2 & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFFFF;
+ Offset = t2 >> 3;
+ }
+ GET_32 (21, StartBlock);
+ UInt32 iCount;
+ GET_16 (25, iCount);
+ // GET_32 (27, Parent);
+ UInt32 pos = 31;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // UInt32 index
+ // UInt32 startBlock
+ if (pos + 9 > size)
+ return 0;
+ pos += 9 + (unsigned)p[pos + 8] + 1; // nameSize
+ if (pos > size)
+ return 0;
+ }
+ return pos;
+ }
+
+ if (Type == kType_FIFO || Type == kType_SOCK)
+ return 16;
+
+ if (size < 18)
+ return 0;
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (16, len);
+ FileSize = len;
+ len += 18;
+ return (len <= size) ? len : 0;
+ }
+
+ if (Type == kType_BLK || Type == kType_CHR)
+ {
+ // GET_16 (16, RDev);
+ return 18;
+ }
+
+ return 0;
+}
+
+UInt32 CNode::Parse4(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ if (size < 20)
+ return 0;
+ LE_16 (0, Type);
+ LE_16 (2, Mode);
+ LE_16 (4, Uid);
+ LE_16 (6, Gid);
+ // LE_32 (8, MTime);
+ // LE_32 (12, Number);
+
+ // Xattr = kXattr_Empty;
+ FileSize = 0;
+ StartBlock = 0;
+
+ if (Type == kType_FILE || Type == kType_FILE + 7)
+ {
+ UInt32 offset;
+ if (Type == kType_FILE)
+ {
+ if (size < 32)
+ return 0;
+ LE_32 (16, StartBlock);
+ LE_32 (20, Frag);
+ LE_32 (24, Offset);
+ LE_32 (28, FileSize);
+ offset = 32;
+ }
+ else
+ {
+ if (size < 56)
+ return 0;
+ LE_64 (16, StartBlock);
+ LE_64 (24, FileSize);
+ // LE_64 (32, Sparse);
+ // LE_32 (40, NumLinks);
+ LE_32 (44, Frag);
+ LE_32 (48, Offset);
+ // LE_32 (52, Xattr);
+ offset = 56;
+ }
+ UInt64 pos = GetNumBlocks(_h) * 4 + offset;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ if (Type == kType_DIR)
+ {
+ if (size < 32)
+ return 0;
+ LE_32 (16, StartBlock);
+ // LE_32 (20, NumLinks);
+ LE_16 (24, FileSize);
+ LE_16 (26, Offset);
+ // LE_32 (28, Parent);
+ return 32;
+ }
+
+ // LE_32 (16, NumLinks);
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 40)
+ return 0;
+ LE_32 (20, FileSize);
+ LE_32 (24, StartBlock);
+ // LE_32 (28, Parent);
+ UInt32 iCount;
+ LE_16 (32, iCount);
+ LE_16 (34, Offset);
+ // LE_32 (36, Xattr);
+
+ UInt32 pos = 40;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // UInt32 index
+ // UInt32 startBlock
+ if (pos + 12 > size)
+ return 0;
+ UInt32 nameLen = GetUi32(p + pos + 8);
+ pos += 12 + nameLen + 1;
+ if (pos > size || nameLen > (1 << 10))
+ return 0;
+ }
+ return pos;
+ }
+
+ unsigned offset = 20;
+ switch(Type)
+ {
+ case kType_FIFO: case kType_FIFO + 7:
+ case kType_SOCK: case kType_SOCK + 7:
+ break;
+ case kType_LNK: case kType_LNK + 7:
+ {
+ if (size < 24)
+ return 0;
+ UInt32 len;
+ LE_32 (20, len);
+ FileSize = len;
+ offset = len + 24;
+ if (size < offset || len > (1 << 30))
+ return 0;
+ break;
+ }
+ case kType_BLK: case kType_BLK + 7:
+ case kType_CHR: case kType_CHR + 7:
+ if (size < 24)
+ return 0;
+ // LE_32 (20, RDev);
+ offset = 24;
+ break;
+ default:
+ return 0;
+ }
+
+ if (Type >= 8)
+ {
+ if (size < offset + 4)
+ return 0;
+ // LE_32 (offset, Xattr);
+ offset += 4;
+ }
+ return offset;
+}
+
+struct CItem
+{
+ int Node;
+ int Parent;
+ UInt32 Ptr;
+};
+
+struct CData
+{
+ CByteBuffer Data;
+ CRecordVector<UInt32> PackPos;
+ CRecordVector<UInt32> UnpackPos; // additional item at the end contains TotalUnpackSize
+
+ UInt32 GetNumBlocks() const { return PackPos.Size(); }
+ void Clear()
+ {
+ Data.Free();
+ PackPos.Clear();
+ UnpackPos.Clear();
+ }
+};
+
+struct CFrag
+{
+ UInt64 StartBlock;
+ UInt32 Size;
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CRecordVector<CItem> _items;
+ CRecordVector<CNode> _nodes;
+ CRecordVector<UInt32> _nodesPos;
+ CRecordVector<UInt32> _blockToNode;
+ CData _inodesData;
+ CData _dirs;
+ CRecordVector<CFrag> _frags;
+ // CByteBuffer _uids;
+ // CByteBuffer _gids;
+ CHeader _h;
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _sizeCalculated;
+
+ IArchiveOpenCallback *_openCallback;
+
+ int _nodeIndex;
+ CRecordVector<bool> _blockCompressed;
+ CRecordVector<UInt64> _blockOffsets;
+
+ CByteBuffer _cachedBlock;
+ UInt64 _cachedBlockStartPos;
+ UInt32 _cachedPackBlockSize;
+ UInt32 _cachedUnpackBlockSize;
+
+ CLimitedSequentialInStream *_limitedInStreamSpec;
+ CMyComPtr<ISequentialInStream> _limitedInStream;
+
+ CBufPtrSeqOutStream *_outStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outStream;
+
+ NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+ CMyComPtr<ICompressCoder> _lzmaDecoder;
+
+ NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+ CMyComPtr<ICompressCoder> _zlibDecoder;
+
+ CByteBuffer _inputBuffer;
+
+ CDynBufSeqOutStream *_dynOutStreamSpec;
+ CMyComPtr<ISequentialOutStream> _dynOutStream;
+
+ void ClearCache()
+ {
+ _cachedBlockStartPos = 0;
+ _cachedPackBlockSize = 0;
+ _cachedUnpackBlockSize = 0;
+ }
+
+ HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize,
+ UInt32 inSize, UInt32 outSizeMax);
+ HRESULT ReadMetadataBlock(UInt32 &packSize);
+ HRESULT ReadData(CData &data, UInt64 start, UInt64 end);
+
+ HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex);
+ HRESULT ScanInodes(UInt64 ptr);
+ // HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids);
+ HRESULT Open2(IInStream *inStream);
+ AString GetPath(int index) const;
+ bool GetPackSize(int index, UInt64 &res, bool fillOffsets);
+
+public:
+ CHandler();
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+};
+
+CHandler::CHandler()
+{
+ _limitedInStreamSpec = new CLimitedSequentialInStream;
+ _limitedInStream = _limitedInStreamSpec;
+
+ _outStreamSpec = new CBufPtrSeqOutStream();
+ _outStream = _outStreamSpec;
+
+ _dynOutStreamSpec = new CDynBufSeqOutStream;
+ _dynOutStream = _dynOutStreamSpec;
+}
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidPosixAttrib, VT_UI4}
+ // { NULL, kpidUser, VT_BSTR},
+ // { NULL, kpidGroup, VT_BSTR},
+ // { NULL, kpidLinks, VT_UI4},
+ // { NULL, kpidOffset, VT_UI4}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidBlock, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidBigEndian, VT_BOOL},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidCharacts, VT_BSTR}
+ // { NULL, kpidNumBlocks, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
+{
+ SizeT destRem = *destLen;
+ SizeT srcRem = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ const Byte *destStart = dest;
+ const Byte *srcStart = src;
+ unsigned mode = 2;
+
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b = *src;
+ if (b > 17)
+ {
+ src++;
+ srcRem--;
+ b -= 17;
+ mode = (b < 4 ? 0 : 1);
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ do
+ *dest++ = *src++;
+ while (--b);
+ }
+ }
+
+ for (;;)
+ {
+ if (srcRem < 3)
+ return S_FALSE;
+ UInt32 b = *src++;
+ srcRem--;
+ UInt32 len, back;
+ if (b >= 64)
+ {
+ srcRem--;
+ back = ((b >> 2) & 7) + ((UInt32)*src++ << 3);
+ len = (b >> 5) + 1;
+ }
+ else if (b < 16)
+ {
+ if (mode == 2)
+ {
+ if (b == 0)
+ {
+ for (b = 15;; b += 255)
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b2 = *src++;
+ srcRem--;
+ if (b2 != 0)
+ {
+ b += b2;
+ break;
+ }
+ }
+ }
+ b += 3;
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ mode = 1;
+ do
+ *dest++ = *src++;
+ while (--b);
+ continue;
+ }
+ srcRem--;
+ back = (b >> 2) + (*src++ << 2);
+ len = 2;
+ if (mode == 1)
+ {
+ back += (1 << 11);
+ len = 3;
+ }
+ }
+ else
+ {
+ UInt32 bOld = b;
+ b = (b < 32 ? 7 : 31);
+ len = bOld & b;
+ if (len == 0)
+ {
+ for (len = b;; len += 255)
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b2 = *src++;
+ srcRem--;
+ if (b2 != 0)
+ {
+ len += b2;
+ break;
+ }
+ }
+ }
+ len += 2;
+ if (srcRem < 2)
+ return S_FALSE;
+ b = *src;
+ back = (b >> 2) + ((UInt32)src[1] << 6);
+ src += 2;
+ srcRem -= 2;
+ if (bOld < 32)
+ {
+ if (back == 0)
+ {
+ *destLen = dest - destStart;
+ *srcLen = src - srcStart;
+ return S_OK;
+ }
+ back += ((bOld & 8) << 11) + (1 << 14) - 1;
+ }
+ }
+ back++;
+ if (len > destRem || (size_t)(dest - destStart) < back)
+ return S_FALSE;
+ destRem -= len;
+ Byte *destTemp = dest - back;
+ dest += len;
+ do
+ {
+ *(destTemp + back) = *destTemp;
+ destTemp++;
+ }
+ while (--len);
+ b &= 3;
+ if (b == 0)
+ {
+ mode = 2;
+ continue;
+ }
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ mode = 0;
+ *dest++ = *src++;
+ if (b > 1)
+ {
+ *dest++ = *src++;
+ if (b > 2)
+ *dest++ = *src++;
+ }
+ }
+}
+
+HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, UInt32 inSize, UInt32 outSizeMax)
+{
+ if (outBuf)
+ {
+ *outBufWasWritten = false;
+ *outBufWasWrittenSize = 0;
+ }
+ UInt32 method = _h.Method;
+ if (_h.SeveralMethods)
+ {
+ Byte props[1];
+ RINOK(ReadStream_FALSE(_stream, props, 1));
+ method = (props[0] == 0x5D ? kMethod_LZMA : kMethod_ZLIB);
+ RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL));
+ }
+
+ if (method == kMethod_LZO)
+ {
+ if (_inputBuffer.GetCapacity() < inSize)
+ {
+ _inputBuffer.Free();
+ _inputBuffer.SetCapacity(inSize);
+ }
+ RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize));
+
+ Byte *dest = outBuf;
+ if (!outBuf)
+ {
+ dest = _dynOutStreamSpec->GetBufPtrForWriting(outSizeMax);
+ if (!dest)
+ return E_OUTOFMEMORY;
+ }
+ SizeT destLen = outSizeMax, srcLen = inSize;
+ RINOK(LzoDecode(dest, &destLen, _inputBuffer, &srcLen));
+ if (inSize != srcLen)
+ return S_FALSE;
+ if (outBuf)
+ {
+ *outBufWasWritten = true;
+ *outBufWasWrittenSize = (UInt32)destLen;
+ }
+ else
+ _dynOutStreamSpec->UpdateSize(destLen);
+ }
+ else if (method == kMethod_LZMA)
+ {
+ if (!_lzmaDecoder)
+ {
+ _lzmaDecoderSpec = new NCompress::NLzma::CDecoder();
+ _lzmaDecoderSpec->FinishStream = true;
+ _lzmaDecoder = _lzmaDecoderSpec;
+ }
+ const UInt32 kPropsSize = 5 + 8;
+ Byte props[kPropsSize];
+ ReadStream_FALSE(_limitedInStream, props, kPropsSize);
+ RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, 5));
+ UInt64 outSize = GetUi64(props + 5);
+ if (outSize > outSizeMax)
+ return S_FALSE;
+ RINOK(_lzmaDecoder->Code(_limitedInStream, outStream, NULL, &outSize, NULL));
+ if (inSize != kPropsSize + _lzmaDecoderSpec->GetInputProcessedSize())
+ return S_FALSE;
+ }
+ else
+ {
+ if (!_zlibDecoder)
+ {
+ _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+ _zlibDecoder = _zlibDecoderSpec;
+ }
+ RINOK(_zlibDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL));
+ if (inSize != _zlibDecoderSpec->GetInputProcessedSize())
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
+{
+ Byte temp[3];
+ unsigned offset = _h.NeedCheckData() ? 3 : 2;
+ if (offset > packSize)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(_stream, temp, offset));
+ // if (NeedCheckData && Major < 4) checkByte must be = 0xFF
+ bool be = _h.be;
+ UInt32 size = Get16(temp);
+ bool isCompressed = ((size & kNotCompressedBit16) == 0);
+ if (size != kNotCompressedBit16)
+ size &= ~kNotCompressedBit16;
+
+ if (size > kMetadataBlockSize || offset + size > packSize)
+ return S_FALSE;
+ packSize = offset + size;
+ if (isCompressed)
+ {
+ _limitedInStreamSpec->Init(size);
+ RINOK(Decompress(_dynOutStream, NULL, NULL, NULL, size, kMetadataBlockSize));
+ }
+ else
+ {
+ // size != 0 here
+ Byte *buf = _dynOutStreamSpec->GetBufPtrForWriting(size);
+ if (!buf)
+ return E_OUTOFMEMORY;
+ RINOK(ReadStream_FALSE(_stream, buf, size));
+ _dynOutStreamSpec->UpdateSize(size);
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end)
+{
+ if (end < start || end - start >= ((UInt64)1 << 32))
+ return S_FALSE;
+ UInt32 size = (UInt32)(end - start);
+ RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL));
+ _dynOutStreamSpec->Init();
+ UInt32 packPos = 0;
+ while (packPos != size)
+ {
+ data.PackPos.Add(packPos);
+ data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize());
+ if (packPos > size)
+ return S_FALSE;
+ UInt32 packSize = size - packPos;
+ RINOK(ReadMetadataBlock(packSize));
+ if (_dynOutStreamSpec->GetSize() >= ((UInt64)1 << 32))
+ return S_FALSE;
+ packPos += packSize;
+ }
+ data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize());
+ _dynOutStreamSpec->CopyToBuffer(data.Data);
+ return S_OK;
+}
+
+struct CTempItem
+{
+ UInt32 StartBlock;
+ // UInt32 iNodeNumber1;
+ UInt32 Offset;
+ // UInt16 iNodeNumber2;
+ UInt16 Type;
+};
+
+HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex)
+{
+ if (level > kNumDirLevelsMax)
+ return S_FALSE;
+
+ int blockIndex = _inodesData.PackPos.FindInSorted(startBlock);
+ if (blockIndex < 0)
+ return S_FALSE;
+ UInt32 unpackPos = _inodesData.UnpackPos[blockIndex] + offset;
+ if (unpackPos < offset)
+ return S_FALSE;
+
+ nodeIndex = _nodesPos.FindInSorted(unpackPos, _blockToNode[blockIndex], _blockToNode[blockIndex + 1]);
+ // nodeIndex = _nodesPos.FindInSorted(unpackPos);
+ if (nodeIndex < 0)
+ return S_FALSE;
+
+ const CNode &n = _nodes[nodeIndex];
+ if (!n.IsDir())
+ return S_OK;
+ blockIndex = _dirs.PackPos.FindInSorted((UInt32)n.StartBlock);
+ if (blockIndex < 0)
+ return S_FALSE;
+ unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset;
+ if (unpackPos < n.Offset || unpackPos > _dirs.Data.GetCapacity())
+ return S_FALSE;
+
+ UInt32 rem = (UInt32)_dirs.Data.GetCapacity() - unpackPos;
+ const Byte *p = _dirs.Data + unpackPos;
+ UInt32 fileSize = (UInt32)n.FileSize;
+
+ if (fileSize > rem)
+ return S_FALSE;
+ rem = fileSize;
+ if (_h.Major >= 3)
+ {
+ if (rem < 3)
+ return S_FALSE;
+ rem -= 3;
+ }
+
+ CRecordVector<CTempItem> tempItems;
+ while (rem != 0)
+ {
+ bool be = _h.be;
+ UInt32 count;
+ CTempItem tempItem;
+ if (_h.Major <= 2)
+ {
+ if (rem < 4)
+ return S_FALSE;
+ count = p[0];
+ tempItem.StartBlock = Get32(p);
+ if (be)
+ tempItem.StartBlock &= 0xFFFFFF;
+ else
+ tempItem.StartBlock >>= 8;
+ p += 4;
+ rem -= 4;
+ }
+ else
+ {
+ if (_h.Major == 3)
+ {
+ if (rem < 9)
+ return S_FALSE;
+ count = p[0];
+ p += 1;
+ rem -= 1;
+ }
+ else
+ {
+ if (rem < 12)
+ return S_FALSE;
+ count = GetUi32(p);
+ p += 4;
+ rem -= 4;
+ }
+ GET_32 (0, tempItem.StartBlock);
+ // GET_32 (4, tempItem.iNodeNumber1);
+ p += 8;
+ rem -= 8;
+ }
+ count++;
+
+ for (UInt32 i = 0; i < count; i++)
+ {
+ if (rem == 0)
+ return S_FALSE;
+
+ UInt32 nameOffset = _h.GetFileNameOffset();
+ if (rem < nameOffset)
+ return S_FALSE;
+
+ if ((UInt32)_items.Size() >= kNumFilesMax)
+ return S_FALSE;
+ if (_openCallback)
+ {
+ UInt64 numFiles = _items.Size();
+ if ((numFiles & 0xFFFF) == 0)
+ {
+ RINOK(_openCallback->SetCompleted(&numFiles, NULL));
+ }
+ }
+
+ CItem item;
+ item.Ptr = (UInt32)(p - _dirs.Data);
+
+ UInt32 size;
+ if (_h.IsOldVersion())
+ {
+ UInt32 t = Get16(p);
+ if (be)
+ {
+ tempItem.Offset = t >> 3;
+ tempItem.Type = (UInt16)(t & 0x7);
+ }
+ else
+ {
+ tempItem.Offset = t & 0x1FFF;
+ tempItem.Type = (UInt16)(t >> 13);
+ }
+ size = (UInt32)p[2];
+ /*
+ if (_h.Major > 2)
+ tempItem.iNodeNumber2 = Get16(p + 3);
+ */
+ }
+ else
+ {
+ GET_16 (0, tempItem.Offset);
+ // GET_16 (2, tempItem.iNodeNumber2);
+ GET_16 (4, tempItem.Type);
+ GET_16 (6, size);
+ }
+ p += nameOffset;
+ rem -= nameOffset;
+ size++;
+ if (rem < size)
+ return S_FALSE;
+ p += size;
+ rem -= size;
+ item.Parent = parent;
+ _items.Add(item);
+ tempItems.Add(tempItem);
+ }
+ }
+
+ int startItemIndex = _items.Size() - tempItems.Size();
+ for (int i = 0; i < tempItems.Size(); i++)
+ {
+ const CTempItem &tempItem = tempItems[i];
+ int index = startItemIndex + i;
+ CItem &item = _items[index];
+ RINOK(OpenDir(index, tempItem.StartBlock, tempItem.Offset, level + 1, item.Node));
+ }
+
+ return S_OK;
+}
+
+/*
+HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids)
+{
+ size_t size = num * 4;
+ ids.SetCapacity(size);
+ RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(_stream, ids, size);
+}
+*/
+
+HRESULT CHandler::Open2(IInStream *inStream)
+{
+ {
+ Byte buf[kHeaderSize3];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize3));
+ if (!_h.Parse(buf))
+ return S_FALSE;
+ if (!_h.IsSupported())
+ return E_NOTIMPL;
+
+ switch (_h.Method)
+ {
+ case kMethod_ZLIB:
+ case kMethod_LZMA:
+ case kMethod_LZO:
+ break;
+ default:
+ return E_NOTIMPL;
+ }
+ }
+
+ _stream = inStream;
+
+ if (_h.NumFrags != 0)
+ {
+ if (_h.NumFrags > kNumFilesMax)
+ return S_FALSE;
+ _frags.Reserve(_h.NumFrags);
+ CByteBuffer data;
+ unsigned bigFrag = (_h.Major > 2);
+
+ unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag);
+ UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog;
+ size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag);
+ data.SetCapacity(numBlocksBytes);
+ RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
+ bool be = _h.be;
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4);
+ RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
+ _dynOutStreamSpec->Init();
+ UInt32 packSize = kMetadataBlockSize + 3;
+ RINOK(ReadMetadataBlock(packSize));
+ UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
+ if (unpackSize != kMetadataBlockSize)
+ if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1)))
+ return S_FALSE;
+ const Byte *buf = _dynOutStreamSpec->GetBuffer();
+ for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;)
+ {
+ CFrag frag;
+ if (bigFrag)
+ {
+ frag.StartBlock = Get64(buf + j);
+ frag.Size = Get32(buf + j + 8);
+ // some archives contain nonzero in unused (buf + j + 12)
+ j += 16;
+ }
+ else
+ {
+ frag.StartBlock = Get32(buf + j);
+ frag.Size = Get32(buf + j + 4);
+ j += 8;
+ }
+ _frags.Add(frag);
+ }
+ }
+ if ((UInt32)_frags.Size() != _h.NumFrags)
+ return S_FALSE;
+ }
+
+ // RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL));
+
+ RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable));
+ RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable));
+
+ UInt64 absOffset = _h.RootInode >> 16;
+ if (absOffset >= ((UInt64)1 << 32))
+ return S_FALSE;
+ {
+ UInt32 pos = 0;
+ UInt32 totalSize = (UInt32)_inodesData.Data.GetCapacity();
+ _nodesPos.Reserve(_h.NumInodes);
+ _nodes.Reserve(_h.NumInodes);
+ // we use _blockToNode for binary search seed optimizations
+ _blockToNode.Reserve(_inodesData.GetNumBlocks() + 1);
+ int curBlock = 0;
+ for (UInt32 i = 0; i < _h.NumInodes; i++)
+ {
+ CNode n;
+ const Byte *p = _inodesData.Data + pos;
+ UInt32 size = totalSize - pos;
+
+ switch(_h.Major)
+ {
+ case 1: size = n.Parse1(p, size, _h); break;
+ case 2: size = n.Parse2(p, size, _h); break;
+ case 3: size = n.Parse3(p, size, _h); break;
+ default: size = n.Parse4(p, size, _h); break;
+ }
+ if (size == 0)
+ return S_FALSE;
+ while (pos >= _inodesData.UnpackPos[curBlock])
+ {
+ _blockToNode.Add(_nodesPos.Size());
+ curBlock++;
+ }
+ _nodesPos.Add(pos);
+ _nodes.Add(n);
+ pos += size;
+ }
+ _blockToNode.Add(_nodesPos.Size());
+ if (pos != totalSize)
+ return S_FALSE;
+ }
+ int rootNodeIndex;
+ RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex));
+
+ /*
+ if (_h.Major < 4)
+ {
+ RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids));
+ RINOK(ReadUids(_h.GidTable, _h.NumGids, _gids));
+ }
+ else
+ {
+ UInt32 size = _h.NumIDs * 4;
+ _uids.SetCapacity(size);
+
+ UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize;
+ UInt32 numBlocksBytes = numBlocks << 3;
+ CByteBuffer data;
+ data.SetCapacity(numBlocksBytes);
+ RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt64 offset = GetUi64(data + i * 8);
+ UInt32 unpackSize, packSize;
+ RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
+ RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
+ if (unpackSize != kMetadataBlockSize)
+ if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1)))
+ return S_FALSE;
+ }
+ }
+ */
+
+ {
+ const UInt32 alignSize = 1 << 12;
+ Byte buf[alignSize];
+ RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL));
+ UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1);
+ _sizeCalculated = _h.Size;
+ if (rem != 0)
+ {
+ if (ReadStream_FALSE(_stream, buf, rem) == S_OK)
+ {
+ size_t i;
+ for (i = 0; i < rem && buf[i] == 0; i++);
+ if (i == rem)
+ _sizeCalculated = _h.Size + rem;
+ }
+ }
+ }
+ return S_OK;
+}
+
+AString CHandler::GetPath(int index) const
+{
+ unsigned len = 0;
+ int indexMem = index;
+ bool be = _h.be;
+ do
+ {
+ const CItem &item = _items[index];
+ index = item.Parent;
+ const Byte *p = _dirs.Data + item.Ptr;
+ unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1;
+ p += _h.GetFileNameOffset();
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ len += i + 1;
+ }
+ while (index >= 0);
+ len--;
+
+ AString path;
+ char *dest = path.GetBuffer(len) + len;
+ index = indexMem;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ index = item.Parent;
+
+ const Byte *p = _dirs.Data + item.Ptr;
+ unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1;
+ p += _h.GetFileNameOffset();
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ dest -= i;
+ memcpy(dest, p, i);
+ if (index < 0)
+ break;
+ *(--dest) = CHAR_PATH_SEPARATOR;
+ }
+ path.ReleaseBuffer(len);
+ return path;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ _limitedInStreamSpec->SetStream(stream);
+ HRESULT res;
+ try
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ _openCallback = callback;
+ res = Open2(stream);
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ if (res != S_OK)
+ {
+ Close();
+ return res;
+ }
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _limitedInStreamSpec->ReleaseStream();
+ _stream.Release();
+
+ _items.Clear();
+ _nodes.Clear();
+ _nodesPos.Clear();
+ _blockToNode.Clear();
+ _frags.Clear();
+ _inodesData.Clear();
+ _dirs.Clear();
+
+ // _uids.Free();
+ // _gids.Free();;
+
+ _cachedBlock.Free();
+ ClearCache();
+
+ return S_OK;
+}
+
+bool CHandler::GetPackSize(int index, UInt64 &totalPack, bool fillOffsets)
+{
+ totalPack = 0;
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ UInt32 ptr = _nodesPos[item.Node];
+ const Byte *p = _inodesData.Data + ptr;
+ bool be = _h.be;
+
+ UInt32 type = node.Type;
+ UInt32 offset;
+ if (node.IsLink() || node.FileSize == 0)
+ {
+ totalPack = node.FileSize;
+ return true;
+ }
+
+ UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h);
+
+ if (fillOffsets)
+ {
+ _blockOffsets.Clear();
+ _blockCompressed.Clear();
+ _blockOffsets.Add(totalPack);
+ }
+
+ if (_h.Major <= 1)
+ {
+ offset = 15;
+ p += offset;
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt32 t = Get16(p + i * 2);
+ if (fillOffsets)
+ _blockCompressed.Add((t & kNotCompressedBit16) == 0);
+ if (t != kNotCompressedBit16)
+ t &= ~kNotCompressedBit16;
+ totalPack += t;
+ if (fillOffsets)
+ _blockOffsets.Add(totalPack);
+ }
+ }
+ else
+ {
+ if (_h.Major <= 2)
+ offset = 24;
+ else if (type == kType_FILE)
+ offset = 32;
+ else if (type == kType_FILE + 7)
+ offset = (_h.Major <= 3 ? 40 : 56);
+ else
+ return false;
+
+ p += offset;
+
+ for (UInt64 i = 0; i < numBlocks; i++)
+ {
+ UInt32 t = Get32(p + i * 4);
+ if (fillOffsets)
+ _blockCompressed.Add(IS_COMPRESSED_BLOCK(t));
+ UInt32 size = GET_COMPRESSED_BLOCK_SIZE(t);
+ if (size > _h.BlockSize)
+ return false;
+ totalPack += size;
+ if (fillOffsets)
+ _blockOffsets.Add(totalPack);
+ }
+
+ if (node.ThereAreFrags())
+ {
+ if (node.Frag >= (UInt32)_frags.Size())
+ return false;
+ const CFrag &frag = _frags[node.Frag];
+ if (node.Offset == 0)
+ {
+ UInt32 size = GET_COMPRESSED_BLOCK_SIZE(frag.Size);
+ if (size > _h.BlockSize)
+ return false;
+ totalPack += size;
+ }
+ }
+ }
+ return true;
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ const char *s;
+ if (_h.SeveralMethods)
+ s = "LZMA ZLIB";
+ else
+ {
+ s = k_Methods[0];
+ if (_h.Method < sizeof(k_Methods) / sizeof(k_Methods[0]))
+ s = k_Methods[_h.Method];
+ }
+ prop = s;
+ break;
+ }
+ case kpidFileSystem:
+ {
+ AString res = "SquashFS";
+ if (_h.SeveralMethods)
+ res += "-LZMA";
+ res += ' ';
+ char s[16];
+ ConvertUInt32ToString(_h.Major, s);
+ res += s;
+ res += '.';
+ ConvertUInt32ToString(_h.Minor, s);
+ res += s;
+ prop = res;
+ break;
+ }
+ case kpidBlock: prop = _h.BlockSize; break;
+ case kpidBigEndian: prop = _h.be; break;
+ case kpidCTime:
+ if (_h.CTime != 0)
+ {
+ FILETIME ft;
+ NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft);
+ prop = ft;
+ }
+ break;
+ case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
+ // case kpidNumBlocks: prop = _h.NumFrags; break;
+ case kpidPhySize: prop = _sizeCalculated; break;
+ case kpidHeadersSize:
+ if (_sizeCalculated >= _h.InodeTable)
+ prop = _sizeCalculated - _h.InodeTable;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ bool isDir = node.IsDir();
+ bool be = _h.be;
+
+ switch(propID)
+ {
+ case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
+ case kpidIsDir: prop = isDir; break;
+ // case kpidOffset: if (!node.IsLink()) prop = (UInt64)node.StartBlock; break;
+ case kpidSize: if (!isDir) prop = node.GetSize(); break;
+ case kpidPackSize:
+ if (!isDir)
+ {
+ UInt64 size;
+ if (GetPackSize(index, size, false))
+ prop = size;
+ }
+ break;
+ case kpidMTime:
+ {
+ UInt32 offset = 0;
+ switch(_h.Major)
+ {
+ case 1:
+ if (node.Type == kType_FILE)
+ offset = 3;
+ else if (node.Type == kType_DIR)
+ offset = 7;
+ break;
+ case 2:
+ if (node.Type == kType_FILE)
+ offset = 4;
+ else if (node.Type == kType_DIR)
+ offset = 8;
+ else if (node.Type == kType_DIR + 7)
+ offset = 9;
+ break;
+ case 3: offset = 4; break;
+ case 4: offset = 8; break;
+ }
+ if (offset != 0)
+ {
+ const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset;
+ FILETIME ft;
+ NWindows::NTime::UnixTimeToFileTime(Get32(p), ft);
+ prop = ft;
+ }
+ break;
+ }
+ case kpidPosixAttrib:
+ {
+ if (node.Type != 0 && node.Type < sizeof(k_TypeToMode) / sizeof(k_TypeToMode[0]))
+ prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
+ break;
+ }
+ /*
+ case kpidUser:
+ {
+ UInt32 offset = node.Uid * 4;
+ if (offset < _uids.GetCapacity())
+ prop = (UInt32)Get32(_uids + offset);
+ break;
+ }
+ case kpidGroup:
+ {
+ if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex())
+ {
+ UInt32 offset = node.Uid * 4;
+ if (offset < _uids.GetCapacity())
+ prop = (UInt32)Get32(_uids + offset);
+ }
+ else
+ {
+ UInt32 offset = node.Gid * 4;
+ if (offset < _gids.GetCapacity())
+ prop = (UInt32)Get32(_gids + offset);
+ }
+ break;
+ }
+ */
+ /*
+ case kpidLinks:
+ if (_h.Major >= 3 && node.Type != kType_FILE)
+ prop = node.NumLinks;
+ break;
+ */
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CSquashfsInStream: public CCachedInStream
+{
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+public:
+ CHandler *Handler;
+};
+
+HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ return Handler->ReadBlock(blockIndex, dest, blockSize);
+}
+
+HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ const CNode &node = _nodes[_nodeIndex];
+ UInt64 blockOffset;
+ UInt32 packBlockSize;
+ UInt32 offsetInBlock = 0;
+ bool compressed;
+ if (blockIndex < _blockCompressed.Size())
+ {
+ compressed = _blockCompressed[(int)blockIndex];
+ blockOffset = _blockOffsets[(int)blockIndex];
+ packBlockSize = (UInt32)(_blockOffsets[(int)blockIndex + 1] - blockOffset);
+ blockOffset += node.StartBlock;
+ }
+ else
+ {
+ if (!node.ThereAreFrags())
+ return S_FALSE;
+ const CFrag &frag = _frags[node.Frag];
+ offsetInBlock = node.Offset;
+ blockOffset = frag.StartBlock;
+ packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size);
+ compressed = IS_COMPRESSED_BLOCK(frag.Size);
+ }
+
+ if (packBlockSize == 0)
+ {
+ // sparse file ???
+ memset(dest, 0, blockSize);
+ return S_OK;
+ }
+
+ if (blockOffset != _cachedBlockStartPos ||
+ packBlockSize != _cachedPackBlockSize)
+ {
+ ClearCache();
+ RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL));
+ _limitedInStreamSpec->Init(packBlockSize);
+
+ if (compressed)
+ {
+ _outStreamSpec->Init((Byte *)_cachedBlock, _h.BlockSize);
+ bool outBufWasWritten;
+ UInt32 outBufWasWrittenSize;
+ HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize);
+ if (outBufWasWritten)
+ _cachedUnpackBlockSize = outBufWasWrittenSize;
+ else
+ _cachedUnpackBlockSize = (UInt32)_outStreamSpec->GetPos();
+ RINOK(res);
+ }
+ else
+ {
+ RINOK(ReadStream_FALSE(_limitedInStream, _cachedBlock, packBlockSize));
+ _cachedUnpackBlockSize = packBlockSize;
+ }
+ _cachedBlockStartPos = blockOffset;
+ _cachedPackBlockSize = packBlockSize;
+ }
+ if (offsetInBlock + blockSize > _cachedUnpackBlockSize)
+ return S_FALSE;
+ memcpy(dest, _cachedBlock + offsetInBlock, blockSize);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _items[allFilesMode ? i : indices[i]];
+ const CNode &node = _nodes[item.Node];
+ totalSize += node.GetSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ // const Byte *p = _data + item.Offset;
+
+ if (node.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ UInt64 unpackSize = node.GetSize();
+ totalSize += unpackSize;
+ UInt64 packSize;
+ if (GetPackSize(index, packSize, false))
+ totalPackSize += packSize;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ CMyComPtr<IInStream> inStream;
+ HRESULT hres = GetStream(index, &inSeqStream);
+ if (inSeqStream)
+ inSeqStream.QueryInterface(IID_IInStream, &inStream);
+ if (hres == S_FALSE || !inStream)
+ {
+ if (hres == E_OUTOFMEMORY)
+ return hres;
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ }
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres != S_OK && hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ if (copyCoderSpec->TotalSize == unpackSize && hres == S_OK)
+ res = NExtract::NOperationResult::kOK;
+ else
+ {
+ res = res;
+ }
+ }
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+
+ if (node.IsDir())
+ return E_FAIL;
+
+ const Byte *p = _inodesData.Data + _nodesPos[item.Node];
+
+ if (node.FileSize == 0 || node.IsLink())
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ if (node.IsLink())
+ streamSpec->Init(p + _h.GetSymLinkOffset(), (size_t)node.FileSize);
+ else
+ streamSpec->Init(NULL, 0);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+
+ UInt64 packSize;
+ if (!GetPackSize(index, packSize, true))
+ return S_FALSE;
+
+ _nodeIndex = item.Node;
+
+ size_t cacheSize = _h.BlockSize;
+ if (_cachedBlock.GetCapacity() != cacheSize)
+ {
+ ClearCache();
+ _cachedBlock.SetCapacity(cacheSize);
+ }
+
+ CSquashfsInStream *streamSpec = new CSquashfsInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Handler = this;
+ unsigned cacheSizeLog = 22;
+ if (cacheSizeLog <= _h.BlockSizeLog)
+ cacheSizeLog = _h.BlockSizeLog + 1;
+ if (!streamSpec->Alloc(_h.BlockSizeLog, cacheSizeLog - _h.BlockSizeLog))
+ return E_OUTOFMEMORY;
+ streamSpec->Init(node.FileSize);
+ *stream = streamTemp.Detach();
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NSquashfs::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"SquashFS", L"squashfs", 0, 0xD2, SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+
+REGISTER_ARC(Cramfs)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/SwfHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/SwfHandler.cpp
new file mode 100644
index 000000000..dfc0326d1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/SwfHandler.cpp
@@ -0,0 +1,706 @@
+// SwfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+#include "../Compress/ZlibEncoder.h"
+
+#include "Common/DummyOutStream.h"
+
+#include "DeflateProps.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NSwfc {
+
+static const UInt32 kHeaderSize = 8;
+
+static const Byte SWF_UNCOMPRESSED = 'F';
+static const Byte SWF_COMPRESSED = 'C';
+static const Byte SWF_MIN_COMPRESSED_VER = 6;
+
+struct CItem
+{
+ Byte Buf[kHeaderSize];
+
+ UInt32 GetSize() const { return GetUi32(Buf + 4); }
+ bool IsSwf(Byte c) const { return (Buf[0] == c && Buf[1] == 'W' && Buf[2] == 'S' && Buf[3] < 32); }
+ bool IsUncompressed() const { return IsSwf(SWF_UNCOMPRESSED); }
+ bool IsCompressed() const { return IsSwf(SWF_COMPRESSED); }
+
+ void MakeUncompressed() { Buf[0] = SWF_UNCOMPRESSED; }
+ void MakeCompressed()
+ {
+ Buf[0] = SWF_COMPRESSED;
+ if (Buf[3] < SWF_MIN_COMPRESSED_VER)
+ Buf[3] = SWF_MIN_COMPRESSED_VER;
+ }
+
+ HRESULT ReadHeader(ISequentialInStream *stream) { return ReadStream_FALSE(stream, Buf, kHeaderSize); }
+ HRESULT WriteHeader(ISequentialOutStream *stream) { return WriteStream(stream, Buf, kHeaderSize); }
+};
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IOutArchive,
+ public ISetProperties,
+ public CMyUnknownImp
+{
+ CItem _item;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<ISequentialInStream> _seqStream;
+ CMyComPtr<IInStream> _stream;
+
+ CDeflateProps _method;
+
+public:
+ MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSize: prop = (UInt64)_item.GetSize(); break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
+{
+ RINOK(OpenSeq(stream));
+ _stream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ HRESULT res = _item.ReadHeader(stream);
+ if (res == S_OK)
+ if (_item.IsCompressed())
+ _seqStream = stream;
+ else
+ res = S_FALSE;
+ return res;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_item.GetSize());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ NCompress::NZlib::CDecoder *_decoderSpec = new NCompress::NZlib::CDecoder;
+ CMyComPtr<ICompressCoder> _decoder = _decoderSpec;
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ lps->InSize = kHeaderSize;
+ lps->OutSize = outStreamSpec->GetSize();
+ RINOK(lps->SetCur());
+
+ CItem item = _item;
+ item.MakeUncompressed();
+ RINOK(item.WriteHeader(outStream));
+ if (_stream)
+ RINOK(_stream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL));
+ HRESULT result = _decoderSpec->Code(_seqStream, outStream, NULL, NULL, progress);
+ Int32 opRes = NExtract::NOperationResult::kDataError;
+ if (result == S_OK)
+ {
+ if (_item.GetSize() == outStreamSpec->GetSize())
+ {
+ _packSizeDefined = true;
+ _packSize = _decoderSpec->GetInputProcessedSize() + kHeaderSize;
+ opRes = NExtract::NOperationResult::kOK;
+ }
+ }
+ else if (result != S_FALSE)
+ return result;
+
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+static HRESULT UpdateArchive(ISequentialOutStream *outStream,
+ UInt64 size, CDeflateProps &deflateProps,
+ IArchiveUpdateCallback *updateCallback)
+{
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetTotal(size));
+ RINOK(updateCallback->SetCompleted(&complexity));
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+
+ CItem item;
+ HRESULT res = item.ReadHeader(fileInStream);
+ if (res == S_FALSE)
+ return E_INVALIDARG;
+ RINOK(res);
+ if (!item.IsUncompressed() || size != item.GetSize())
+ return E_INVALIDARG;
+
+ item.MakeCompressed();
+ item.WriteHeader(outStream);
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ NCompress::NZlib::CEncoder *encoderSpec = new NCompress::NZlib::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+ encoderSpec->Create();
+ RINOK(deflateProps.SetCoderProperties(encoderSpec->DeflateEncoderSpec));
+ RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress));
+ if (encoderSpec->GetInputProcessedSize() + kHeaderSize != size)
+ return E_INVALIDARG;
+ return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
+}
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
+ if (prop.vt == VT_BOOL)
+ {
+ if (prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ return UpdateArchive(outStream, size, _method, updateCallback);
+ }
+
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+
+ if (!_seqStream)
+ return E_NOTIMPL;
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+ else
+ _item.WriteHeader(outStream);
+ return NCompress::CopyStream(_seqStream, outStream, NULL);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ return _method.SetProperties(names, values, numProps);
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"SWFc", L"swf", L"~.swf", 0xD8, { 'C', 'W', 'S' }, 3, true, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Swfc)
+
+}
+
+namespace NSwf {
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 30;
+static const int kNumTagsMax = (UInt32)1 << 23;
+
+struct CTag
+{
+ UInt32 Type;
+ CByteBuffer Buf;
+};
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public CMyUnknownImp
+{
+ CObjectVector<CTag> _tags;
+ NSwfc::CItem _item;
+ UInt64 _packSize;
+
+ HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback);
+ HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback);
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq)
+ INTERFACE_IInArchive(;)
+
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidComment, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _tags.Size();
+ return S_OK;
+}
+
+static const char *g_TagDesc[92] =
+{
+ "End",
+ "ShowFrame",
+ "DefineShape",
+ NULL,
+ "PlaceObject",
+ "RemoveObject",
+ "DefineBits",
+ "DefineButton",
+ "JPEGTables",
+ "SetBackgroundColor",
+ "DefineFont",
+ "DefineText",
+ "DoAction",
+ "DefineFontInfo",
+ "DefineSound",
+ "StartSound",
+ NULL,
+ "DefineButtonSound",
+ "SoundStreamHead",
+ "SoundStreamBlock",
+ "DefineBitsLossless",
+ "DefineBitsJPEG2",
+ "DefineShape2",
+ "DefineButtonCxform",
+ "Protect",
+ NULL,
+ "PlaceObject2",
+ NULL,
+ "RemoveObject2",
+ NULL,
+ NULL,
+ NULL,
+ "DefineShape3",
+ "DefineText2",
+ "DefineButton2",
+ "DefineBitsJPEG3",
+ "DefineBitsLossless2",
+ "DefineEditText",
+ NULL,
+ "DefineSprite",
+ NULL,
+ "41",
+ NULL,
+ "FrameLabel",
+ NULL,
+ "SoundStreamHead2",
+ "DefineMorphShape",
+ NULL,
+ "DefineFont2",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ExportAssets",
+ "ImportAssets",
+ "EnableDebugger",
+ "DoInitAction",
+ "DefineVideoStream",
+ "VideoFrame",
+ "DefineFontInfo2",
+ NULL,
+ "EnableDebugger2",
+ "ScriptLimits",
+ "SetTabIndex",
+ NULL,
+ NULL,
+ "FileAttributes",
+ "PlaceObject3",
+ "ImportAssets2",
+ NULL,
+ "DefineFontAlignZones",
+ "CSMTextSettings",
+ "DefineFont3",
+ "SymbolClass",
+ "Metadata",
+ "DefineScalingGrid",
+ NULL,
+ NULL,
+ NULL,
+ "DoABC",
+ "DefineShape4",
+ "DefineMorphShape2",
+ NULL,
+ "DefineSceneAndFrameLabelData",
+ "DefineBinaryData",
+ "DefineFontName",
+ "StartSound2",
+ "DefineBitsJPEG4",
+ "DefineFont4"
+};
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ const CTag &tag = _tags[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ char s[32];
+ ConvertUInt32ToString(index, s);
+ size_t i = strlen(s);
+ s[i++] = '.';
+ ConvertUInt32ToString(tag.Type, s + i);
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)tag.Buf.GetCapacity(); break;
+ case kpidComment:
+ if (tag.Type < sizeof(g_TagDesc) / sizeof(g_TagDesc[0]))
+ {
+ const char *s = g_TagDesc[tag.Type];
+ if (s != NULL)
+ prop = s;
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ return OpenSeq2(stream, callback);
+}
+
+static UInt16 Read16(CInBuffer &stream)
+{
+ UInt16 res = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b;
+ if (!stream.ReadByte(b))
+ throw 1;
+ res |= (UInt16)b << (i * 8);
+ }
+ return res;
+}
+
+static UInt32 Read32(CInBuffer &stream)
+{
+ UInt32 res = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b;
+ if (!stream.ReadByte(b))
+ throw 1;
+ res |= (UInt32)b << (i * 8);
+ }
+ return res;
+}
+
+struct CBitReader
+{
+ CInBuffer *stream;
+ unsigned NumBits;
+ Byte Val;
+
+ CBitReader(): NumBits(0), Val(0) {}
+
+ UInt32 ReadBits(unsigned numBits);
+};
+
+UInt32 CBitReader::ReadBits(unsigned numBits)
+{
+ UInt32 res = 0;
+ while (numBits > 0)
+ {
+ if (NumBits == 0)
+ {
+ Val = stream->ReadByte();
+ NumBits = 8;
+ }
+ if (numBits <= NumBits)
+ {
+ res <<= numBits;
+ NumBits -= numBits;
+ res |= (Val >> NumBits);
+ Val &= (1 << NumBits) - 1;
+ break;
+ }
+ else
+ {
+ res <<= NumBits;
+ res |= Val;
+ numBits -= NumBits;
+ NumBits = 0;
+ }
+ }
+ return res;
+}
+
+HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback)
+{
+ RINOK(_item.ReadHeader(stream))
+ if (!_item.IsUncompressed())
+ return S_FALSE;
+
+ CInBuffer s;
+ if (!s.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ s.SetStream(stream);
+ s.Init();
+ {
+ CBitReader br;
+ br.stream = &s;
+ unsigned numBits = br.ReadBits(5);
+ /* UInt32 xMin = */ br.ReadBits(numBits);
+ /* UInt32 xMax = */ br.ReadBits(numBits);
+ /* UInt32 yMin = */ br.ReadBits(numBits);
+ /* UInt32 yMax = */ br.ReadBits(numBits);
+ }
+ /* UInt32 frameDelay = */ Read16(s);
+ /* UInt32 numFrames = */ Read16(s);
+
+ _tags.Clear();
+ UInt64 offsetPrev = 0;
+ for (;;)
+ {
+ UInt32 pair = Read16(s);
+ UInt32 type = pair >> 6;
+ UInt32 length = pair & 0x3F;
+ if (length == 0x3F)
+ length = Read32(s);
+ if (type == 0)
+ break;
+ UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderSize + length;
+ if (offset > kFileSizeMax || _tags.Size() >= kNumTagsMax)
+ return S_FALSE;
+ _tags.Add(CTag());
+ CTag &tag = _tags.Back();
+ tag.Type = type;
+ tag.Buf.SetCapacity(length);
+ if (s.ReadBytes(tag.Buf, length) != length)
+ return S_FALSE;
+ if (callback && offset >= offsetPrev + (1 << 20))
+ {
+ UInt64 numItems = _tags.Size();
+ RINOK(callback->SetCompleted(&numItems, &offset));
+ offsetPrev = offset;
+ }
+ }
+ _packSize = s.GetProcessedSize() + NSwfc::kHeaderSize;
+ return S_OK;
+}
+
+HRESULT CHandler::OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback)
+{
+ HRESULT res;
+ try { res = OpenSeq3(stream, callback); }
+ catch(...) { res = S_FALSE; }
+ return res;
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ return OpenSeq2(stream, NULL);
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _tags.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _tags[allFilesMode ? i : indices[i]].Buf.GetCapacity();
+ extractCallback->SetTotal(totalSize);
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ totalSize = 0;
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CByteBuffer &buf = _tags[index].Buf;
+ totalSize += buf.GetCapacity();
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (outStream)
+ RINOK(WriteStream(outStream, buf, buf.GetCapacity()));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"SWF", L"swf", 0, 0xD7, { 'F', 'W', 'S' }, 3, true, CreateArc, 0 };
+
+REGISTER_ARC(Swf)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp
new file mode 100644
index 000000000..4db0cae82
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -0,0 +1,386 @@
+// TarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "TarHandler.h"
+#include "TarIn.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NTar {
+
+static const char *kUnexpectedEnd = "Unexpected end of archive";
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidPosixAttrib, VT_UI4},
+ { NULL, kpidUser, VT_BSTR},
+ { NULL, kpidGroup, VT_BSTR},
+ { NULL, kpidLink, VT_BSTR}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
+ case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
+{
+ item.HeaderPos = _phySize;
+ RINOK(ReadItem(stream, filled, item, _errorMessage));
+ _phySize += item.HeaderSize;
+ _headersSize += item.HeaderSize;
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ UInt64 endPos = 0;
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+
+ _phySizeDefined = true;
+ for (;;)
+ {
+ CItemEx item;
+ bool filled;
+ RINOK(ReadItem2(stream, filled, item));
+ if (!filled)
+ break;
+ _items.Add(item);
+
+ RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize));
+ if (_phySize > endPos)
+ {
+ _errorMessage = kUnexpectedEnd;
+ break;
+ }
+ /*
+ if (_phySize == endPos)
+ {
+ _errorMessage = "There are no trailing zero-filled records";
+ break;
+ }
+ */
+ if (callback != NULL)
+ {
+ if (_items.Size() == 1)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos));
+ }
+ if (_items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ RINOK(callback->SetCompleted(&numFiles, &_phySize));
+ }
+ }
+ }
+
+ if (_items.Size() == 0)
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ if (!callback)
+ return S_FALSE;
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+ if (!openVolumeCallback)
+ return S_FALSE;
+ NCOM::CPropVariant prop;
+ if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK)
+ return S_FALSE;
+ if (prop.vt != VT_BSTR)
+ return S_FALSE;
+ UString baseName = prop.bstrVal;
+ baseName = baseName.Right(4);
+ if (baseName.CompareNoCase(L".tar") != 0)
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ RINOK(Open2(stream, openArchiveCallback));
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _errorMessage.Empty();
+ _phySizeDefined = false;
+ _phySize = 0;
+ _headersSize = 0;
+ _curIndex = 0;
+ _latestIsRead = false;
+ _items.Clear();
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1);
+ return S_OK;
+}
+
+CHandler::CHandler()
+{
+ copyCoderSpec = new NCompress::CCopyCoder();
+ copyCoder = copyCoderSpec;
+}
+
+HRESULT CHandler::SkipTo(UInt32 index)
+{
+ while (_curIndex < index || !_latestIsRead)
+ {
+ if (_latestIsRead)
+ {
+ UInt64 packSize = _latestItem.GetPackSize();
+ RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
+ _phySize += copyCoderSpec->TotalSize;
+ if (copyCoderSpec->TotalSize != packSize)
+ {
+ _errorMessage = kUnexpectedEnd;
+ return S_FALSE;
+ }
+ _latestIsRead = false;
+ _curIndex++;
+ }
+ else
+ {
+ bool filled;
+ RINOK(ReadItem2(_seqStream, filled, _latestItem));
+ if (!filled)
+ {
+ _phySizeDefined = true;
+ return E_INVALIDARG;
+ }
+ _latestIsRead = true;
+ }
+ }
+ return S_OK;
+}
+
+static UString TarStringToUnicode(const AString &s)
+{
+ return MultiByteToUnicodeString(s, CP_OEMCP);
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CItemEx *item;
+ if (_stream)
+ item = &_items[index];
+ else
+ {
+ if (index < _curIndex)
+ return E_INVALIDARG;
+ else
+ {
+ RINOK(SkipTo(index));
+ item = &_latestItem;
+ }
+ }
+
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
+ case kpidIsDir: prop = item->IsDir(); break;
+ case kpidSize: prop = item->GetUnpackSize(); break;
+ case kpidPackSize: prop = item->GetPackSize(); break;
+ case kpidMTime:
+ if (item->MTime != 0)
+ {
+ FILETIME ft;
+ NTime::UnixTimeToFileTime(item->MTime, ft);
+ prop = ft;
+ }
+ break;
+ case kpidPosixAttrib: prop = item->Mode; break;
+ case kpidUser: prop = TarStringToUnicode(item->User); break;
+ case kpidGroup: prop = TarStringToUnicode(item->Group); break;
+ case kpidLink: prop = TarStringToUnicode(item->LinkName); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ ISequentialInStream *stream = _seqStream;
+ bool seqMode = (_stream == NULL);
+ if (!seqMode)
+ stream = _stream;
+
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (_stream && numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize();
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(stream);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems || seqMode; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItemEx *item;
+ if (seqMode)
+ {
+ HRESULT res = SkipTo(index);
+ if (res == E_INVALIDARG)
+ break;
+ RINOK(res);
+ item = &_latestItem;
+ }
+ else
+ item = &_items[index];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ UInt64 unpackSize = item->GetUnpackSize();
+ totalSize += unpackSize;
+ totalPackSize += item->GetPackSize();
+ if (item->IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ bool skipMode = false;
+ if (!testMode && !realOutStream)
+ {
+ if (!seqMode)
+ continue;
+ skipMode = true;
+ askMode = NExtract::NAskMode::kSkip;
+ }
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
+
+ if (item->IsLink())
+ {
+ RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
+ }
+ else
+ {
+ if (!seqMode)
+ {
+ RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
+ }
+ streamSpec->Init(item->GetPackSize());
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ }
+ if (seqMode)
+ {
+ _latestIsRead = false;
+ _curIndex++;
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(outStreamSpec->GetRem() == 0 ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItemEx &item = _items[index];
+ if (item.IsLink())
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+ return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.h
new file mode 100644
index 000000000..b19670616
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandler.h
@@ -0,0 +1,61 @@
+// TarHandler.h
+
+#ifndef __TAR_HANDLER_H
+#define __TAR_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IInArchiveGetStream,
+ public IOutArchive,
+ public CMyUnknownImp
+{
+ CObjectVector<CItemEx> _items;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ UInt32 _curIndex;
+ bool _latestIsRead;
+ CItemEx _latestItem;
+
+ UInt64 _phySize;
+ UInt64 _headersSize;
+ bool _phySizeDefined;
+ AString _errorMessage;
+
+ NCompress::CCopyCoder *copyCoderSpec;
+ CMyComPtr<ICompressCoder> copyCoder;
+
+ HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ HRESULT SkipTo(UInt32 index);
+
+public:
+ MY_UNKNOWN_IMP4(
+ IInArchive,
+ IArchiveOpenSeq,
+ IInArchiveGetStream,
+ IOutArchive
+ )
+
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+
+ CHandler();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
new file mode 100644
index 000000000..ffdf2b136
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -0,0 +1,122 @@
+// TarHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "TarHandler.h"
+#include "TarUpdate.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NTar {
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+{
+ *type = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res)
+{
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propId, &prop));
+ if (prop.vt == VT_BSTR)
+ res = UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP);
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback)
+{
+ COM_TRY_BEGIN
+ if ((_stream && !_errorMessage.IsEmpty()) || _seqStream)
+ return E_NOTIMPL;
+ CObjectVector<CUpdateItem> updateItems;
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData;
+ Int32 newProps;
+ UInt32 indexInArchive;
+ if (!callback)
+ return E_FAIL;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+ ui.NewProps = IntToBool(newProps);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArchive = indexInArchive;
+ ui.IndexInClient = i;
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Mode = 0777 | (ui.IsDir ? 0040000 : 0100000);
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Mode = prop.ulVal;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidMTime, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Time = 0;
+ else if (prop.vt != VT_FILETIME)
+ return E_INVALIDARG;
+ else if (!NTime::FileTimeToUnixTime(prop.filetime, ui.Time))
+ ui.Time = 0;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop));
+ if (prop.vt == VT_BSTR)
+ ui.Name = UnicodeStringToMultiByte(NItemName::MakeLegalName(prop.bstrVal), CP_OEMCP);
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ if (ui.IsDir)
+ ui.Name += '/';
+ }
+ RINOK(GetPropString(callback, i, kpidUser, ui.User));
+ RINOK(GetPropString(callback, i, kpidGroup, ui.Group));
+ }
+ if (IntToBool(newData))
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ ui.Size = prop.uhVal.QuadPart;
+ /*
+ // now we support GNU extension for big files
+ if (ui.Size >= ((UInt64)1 << 33))
+ return E_INVALIDARG;
+ */
+ }
+ updateItems.Add(ui);
+ }
+ return UpdateArchive(_stream, outStream, _items, updateItems, callback);
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHeader.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHeader.cpp
new file mode 100644
index 000000000..3275b284c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHeader.cpp
@@ -0,0 +1,25 @@
+// Archive/Tar/Header.h
+
+#include "StdAfx.h"
+
+#include "TarHeader.h"
+
+namespace NArchive {
+namespace NTar {
+namespace NFileHeader {
+
+ // The checksum field is filled with this while the checksum is computed.
+ const char *kCheckSumBlanks = " "; // 8 blanks, no null
+
+ const char *kLongLink = "././@LongLink";
+ const char *kLongLink2 = "@LongLink";
+
+ // The magic field is filled with this if uname and gname are valid.
+ namespace NMagic
+ {
+ const char *kUsTar = "ustar"; // 5 chars
+ const char *kGNUTar = "GNUtar "; // 7 chars and a null
+ const char *kEmpty = "\0\0\0\0\0\0\0\0"; // 7 chars and a null
+ }
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHeader.h b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHeader.h
new file mode 100644
index 000000000..0b78bdc26
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarHeader.h
@@ -0,0 +1,108 @@
+// Archive/Tar/Header.h
+
+#ifndef __ARCHIVE_TAR_HEADER_H
+#define __ARCHIVE_TAR_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NTar {
+
+namespace NFileHeader
+{
+ const int kRecordSize = 512;
+ const int kNameSize = 100;
+ const int kUserNameSize = 32;
+ const int kGroupNameSize = 32;
+ const int kPrefixSize = 155;
+
+ /*
+ struct CHeader
+ {
+ char Name[kNameSize];
+ char Mode[8];
+ char UID[8];
+ char GID[8];
+ char Size[12];
+ char ModificationTime[12];
+ char CheckSum[8];
+ char LinkFlag;
+ char LinkName[kNameSize];
+ char Magic[8];
+ char UserName[kUserNameSize];
+ char GroupName[kGroupNameSize];
+ char DeviceMajor[8];
+ char DeviceMinor[8];
+ char Prefix[155];
+ };
+ union CRecord
+ {
+ CHeader Header;
+ Byte Padding[kRecordSize];
+ };
+ */
+
+ namespace NMode
+ {
+ const int kSetUID = 04000; // Set UID on execution
+ const int kSetGID = 02000; // Set GID on execution
+ const int kSaveText = 01000; // Save text (sticky bit)
+ }
+
+ namespace NFilePermissions
+ {
+ const int kUserRead = 00400; // read by owner
+ const int kUserWrite = 00200; // write by owner
+ const int kUserExecute = 00100; // execute/search by owner
+ const int kGroupRead = 00040; // read by group
+ const int kGroupWrite = 00020; // write by group
+ const int kGroupExecute = 00010; // execute/search by group
+ const int kOtherRead = 00004; // read by other
+ const int kOtherWrite = 00002; // write by other
+ const int kOtherExecute = 00001; // execute/search by other
+ }
+
+
+ // The linkflag defines the type of file
+ namespace NLinkFlag
+ {
+ const char kOldNormal = '\0'; // Normal disk file, Unix compatible
+ const char kNormal = '0'; // Normal disk file
+ const char kLink = '1'; // Link to previously dumped file
+ const char kSymbolicLink = '2'; // Symbolic link
+ const char kCharacter = '3'; // Character special file
+ const char kBlock = '4'; // Block special file
+ const char kDirectory = '5'; // Directory
+ const char kFIFO = '6'; // FIFO special file
+ const char kContiguous = '7'; // Contiguous file
+
+ const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
+ data: list of files created by the --incremental (-G) option
+ Each file name is preceded by either
+ - 'Y' (file should be in this archive)
+ - 'N' (file is a directory, or is not stored in the archive.)
+ Each file name is terminated by a null + an additional null after
+ the last file name. */
+
+ }
+ // Further link types may be defined later.
+
+ // The checksum field is filled with this while the checksum is computed.
+ extern const char *kCheckSumBlanks;// = " "; // 8 blanks, no null
+
+ extern const char *kLongLink; // = "././@LongLink";
+ extern const char *kLongLink2; // = "@LongLink";
+
+ // The magic field is filled with this if uname and gname are valid.
+ namespace NMagic
+ {
+ extern const char *kUsTar; // = "ustar"; // 5 chars
+ extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null
+ extern const char *kEmpty; // = "GNUtar "; // 7 chars and a null
+ }
+
+}
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarIn.cpp
new file mode 100644
index 000000000..5ceaa509d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -0,0 +1,207 @@
+// TarIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/StringToInt.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "TarIn.h"
+
+namespace NArchive {
+namespace NTar {
+
+static void MyStrNCpy(char *dest, const char *src, int size)
+{
+ for (int i = 0; i < size; i++)
+ {
+ char c = src[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+}
+
+static bool OctalToNumber(const char *srcString, int size, UInt64 &res)
+{
+ char sz[32];
+ MyStrNCpy(sz, srcString, size);
+ sz[size] = 0;
+ const char *end;
+ int i;
+ for (i = 0; sz[i] == ' '; i++);
+ res = ConvertOctStringToUInt64(sz + i, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool OctalToNumber32(const char *srcString, int size, UInt32 &res)
+{
+ UInt64 res64;
+ if (!OctalToNumber(srcString, size, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+static bool IsRecordLast(const char *buf)
+{
+ for (int i = 0; i < NFileHeader::kRecordSize; i++)
+ if (buf[i] != 0)
+ return false;
+ return true;
+}
+
+static void ReadString(const char *s, int size, AString &result)
+{
+ char temp[NFileHeader::kRecordSize + 1];
+ MyStrNCpy(temp, s, size);
+ temp[size] = '\0';
+ result = temp;
+}
+
+static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
+{
+ char buf[NFileHeader::kRecordSize];
+ char *p = buf;
+
+ error.Empty();
+ filled = false;
+
+ bool thereAreEmptyRecords = false;
+ for (;;)
+ {
+ size_t processedSize = NFileHeader::kRecordSize;
+ RINOK(ReadStream(stream, buf, &processedSize));
+ if (processedSize == 0)
+ {
+ if (!thereAreEmptyRecords )
+ error = "There are no trailing zero-filled records";
+ return S_OK;
+ }
+ if (processedSize != NFileHeader::kRecordSize)
+ {
+ error = "There is no correct record at the end of archive";
+ return S_OK;
+ }
+ item.HeaderSize += NFileHeader::kRecordSize;
+ if (!IsRecordLast(buf))
+ break;
+ thereAreEmptyRecords = true;
+ }
+ if (thereAreEmptyRecords)
+ {
+ error = "There are data after end of archive";
+ return S_OK;
+ }
+
+ ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
+
+ RIF(OctalToNumber32(p, 8, item.Mode)); p += 8;
+
+ if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8;
+ if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8;
+
+ if (GetBe32(p) == (UInt32)1 << 31)
+ {
+ // GNU extension
+ item.Size = GetBe64(p + 4);
+ }
+ else
+ {
+ RIF(OctalToNumber(p, 12, item.Size));
+ }
+ p += 12;
+ RIF(OctalToNumber32(p, 12, item.MTime)); p += 12;
+
+ UInt32 checkSum;
+ RIF(OctalToNumber32(p, 8, checkSum));
+ memcpy(p, NFileHeader::kCheckSumBlanks, 8); p += 8;
+
+ item.LinkFlag = *p++;
+
+ ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize;
+
+ memcpy(item.Magic, p, 8); p += 8;
+
+ ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
+ ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
+
+ item.DeviceMajorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMajor)); p += 8;
+ item.DeviceMinorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMinor)); p += 8;
+
+ AString prefix;
+ ReadString(p, NFileHeader::kPrefixSize, prefix);
+ p += NFileHeader::kPrefixSize;
+ if (!prefix.IsEmpty() && item.IsMagic() &&
+ (item.LinkFlag != 'L' /* || prefix != "00000000000" */ ))
+ item.Name = prefix + AString('/') + item.Name;
+
+ if (item.LinkFlag == NFileHeader::NLinkFlag::kLink)
+ item.Size = 0;
+
+ UInt32 checkSumReal = 0;
+ for (int i = 0; i < NFileHeader::kRecordSize; i++)
+ checkSumReal += (Byte)buf[i];
+
+ if (checkSumReal != checkSum)
+ return S_FALSE;
+
+ filled = true;
+ return S_OK;
+}
+
+HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
+{
+ item.HeaderSize = 0;
+ bool flagL = false;
+ bool flagK = false;
+ AString nameL;
+ AString nameK;
+ for (;;)
+ {
+ RINOK(GetNextItemReal(stream, filled, item, error));
+ if (!filled)
+ return S_OK;
+ if (item.LinkFlag == 'L' || // NEXT file has a long name
+ item.LinkFlag == 'K') // NEXT file has a long linkname
+ {
+ AString *name;
+ if (item.LinkFlag == 'L')
+ { if (flagL) return S_FALSE; flagL = true; name = &nameL; }
+ else
+ { if (flagK) return S_FALSE; flagK = true; name = &nameK; }
+
+ if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
+ item.Name.Compare(NFileHeader::kLongLink2) != 0)
+ return S_FALSE;
+ if (item.Size > (1 << 14))
+ return S_FALSE;
+ int packSize = (int)item.GetPackSize();
+ char *buf = name->GetBuffer(packSize);
+ RINOK(ReadStream_FALSE(stream, buf, packSize));
+ item.HeaderSize += packSize;
+ buf[(size_t)item.Size] = '\0';
+ name->ReleaseBuffer();
+ continue;
+ }
+ if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
+ {
+ // pax Extended Header
+ }
+ else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
+ {
+ // GNU Extensions to the Archive Format
+ }
+ else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
+ return S_FALSE;
+ if (flagL) item.Name = nameL;
+ if (flagK) item.LinkName = nameK;
+ return S_OK;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarIn.h
new file mode 100644
index 000000000..a5491ebe4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarIn.h
@@ -0,0 +1,17 @@
+// TarIn.h
+
+#ifndef __ARCHIVE_TAR_IN_H
+#define __ARCHIVE_TAR_IN_H
+
+#include "../../IStream.h"
+
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarItem.h b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarItem.h
new file mode 100644
index 000000000..859e66dd8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarItem.h
@@ -0,0 +1,72 @@
+// TarItem.h
+
+#ifndef __ARCHIVE_TAR_ITEM_H
+#define __ARCHIVE_TAR_ITEM_H
+
+#include "../Common/ItemNameUtils.h"
+
+#include "TarHeader.h"
+
+namespace NArchive {
+namespace NTar {
+
+struct CItem
+{
+ AString Name;
+ UInt64 Size;
+
+ UInt32 Mode;
+ UInt32 UID;
+ UInt32 GID;
+ UInt32 MTime;
+ UInt32 DeviceMajor;
+ UInt32 DeviceMinor;
+
+ AString LinkName;
+ AString User;
+ AString Group;
+
+ char Magic[8];
+ char LinkFlag;
+ bool DeviceMajorDefined;
+ bool DeviceMinorDefined;
+
+ bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
+ UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; }
+
+ bool IsDir() const
+ {
+ switch(LinkFlag)
+ {
+ case NFileHeader::NLinkFlag::kDirectory:
+ case NFileHeader::NLinkFlag::kDumpDir:
+ return true;
+ case NFileHeader::NLinkFlag::kOldNormal:
+ case NFileHeader::NLinkFlag::kNormal:
+ return NItemName::HasTailSlash(Name, CP_OEMCP);
+ }
+ return false;
+ }
+
+ bool IsMagic() const
+ {
+ for (int i = 0; i < 5; i++)
+ if (Magic[i] != NFileHeader::NMagic::kUsTar[i])
+ return false;
+ return true;
+ }
+
+ UInt64 GetPackSize() const { return (Size + 0x1FF) & (~((UInt64)0x1FF)); }
+};
+
+struct CItemEx: public CItem
+{
+ UInt64 HeaderPos;
+ unsigned HeaderSize;
+ UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
+ UInt64 GetFullSize() const { return HeaderSize + Size; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarOut.cpp
new file mode 100644
index 000000000..e542a3b2f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarOut.cpp
@@ -0,0 +1,187 @@
+// TarOut.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "TarOut.h"
+
+namespace NArchive {
+namespace NTar {
+
+HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size)
+{
+ return WriteStream(m_Stream, buffer, size);
+}
+
+void COutArchive::Create(ISequentialOutStream *outStream)
+{
+ m_Stream = outStream;
+}
+
+static AString MakeOctalString(UInt64 value)
+{
+ char s[32];
+ ConvertUInt64ToString(value, s, 8);
+ return AString(s) + ' ';
+}
+
+static void MyStrNCpy(char *dest, const char *src, int size)
+{
+ for (int i = 0; i < size; i++)
+ {
+ char c = src[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+}
+
+static bool MakeOctalString8(char *s, UInt32 value)
+{
+ AString tempString = MakeOctalString(value);
+
+ const int kMaxSize = 8;
+ if (tempString.Length() >= kMaxSize)
+ return false;
+ int numSpaces = kMaxSize - (tempString.Length() + 1);
+ for(int i = 0; i < numSpaces; i++)
+ s[i] = ' ';
+ MyStringCopy(s + numSpaces, (const char *)tempString);
+ return true;
+}
+
+static void MakeOctalString12(char *s, UInt64 value)
+{
+ AString tempString = MakeOctalString(value);
+ const int kMaxSize = 12;
+ if (tempString.Length() > kMaxSize)
+ {
+ // GNU extension;
+ s[0] = (char)(Byte)0x80;
+ s[1] = s[2] = s[3] = 0;
+ for (int i = 0; i < 8; i++, value <<= 8)
+ s[4 + i] = (char)(value >> 56);
+ return;
+ }
+ int numSpaces = kMaxSize - tempString.Length();
+ for(int i = 0; i < numSpaces; i++)
+ s[i] = ' ';
+ memmove(s + numSpaces, (const char *)tempString, tempString.Length());
+}
+
+static bool CopyString(char *dest, const AString &src, int maxSize)
+{
+ if (src.Length() >= maxSize)
+ return false;
+ MyStringCopy(dest, (const char *)src);
+ return true;
+}
+
+#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; }
+
+HRESULT COutArchive::WriteHeaderReal(const CItem &item)
+{
+ char record[NFileHeader::kRecordSize];
+ char *cur = record;
+ int i;
+ for (i = 0; i < NFileHeader::kRecordSize; i++)
+ record[i] = 0;
+
+ // RETURN_IF_NOT_TRUE(CopyString(header.Name, item.Name, NFileHeader::kNameSize));
+ if (item.Name.Length() > NFileHeader::kNameSize)
+ return E_FAIL;
+ MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
+ cur += NFileHeader::kNameSize;
+
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8;
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;
+
+ MakeOctalString12(cur, item.Size); cur += 12;
+ MakeOctalString12(cur, item.MTime); cur += 12;
+
+ memmove(cur, NFileHeader::kCheckSumBlanks, 8);
+ cur += 8;
+
+ *cur++ = item.LinkFlag;
+
+ RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));
+ cur += NFileHeader::kNameSize;
+
+ memmove(cur, item.Magic, 8);
+ cur += 8;
+
+ RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));
+ cur += NFileHeader::kUserNameSize;
+ RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize));
+ cur += NFileHeader::kGroupNameSize;
+
+
+ if (item.DeviceMajorDefined)
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor));
+ cur += 8;
+
+ if (item.DeviceMinorDefined)
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMinor));
+ cur += 8;
+
+
+ UInt32 checkSumReal = 0;
+ for(i = 0; i < NFileHeader::kRecordSize; i++)
+ checkSumReal += Byte(record[i]);
+
+ RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal));
+
+ return WriteBytes(record, NFileHeader::kRecordSize);
+}
+
+HRESULT COutArchive::WriteHeader(const CItem &item)
+{
+ int nameSize = item.Name.Length();
+ if (nameSize < NFileHeader::kNameSize)
+ return WriteHeaderReal(item);
+
+ CItem modifiedItem = item;
+ int nameStreamSize = nameSize + 1;
+ modifiedItem.Size = nameStreamSize;
+ modifiedItem.LinkFlag = 'L';
+ modifiedItem.Name = NFileHeader::kLongLink;
+ modifiedItem.LinkName.Empty();
+ RINOK(WriteHeaderReal(modifiedItem));
+ RINOK(WriteBytes(item.Name, nameStreamSize));
+ RINOK(FillDataResidual(nameStreamSize));
+
+ modifiedItem = item;
+ modifiedItem.Name = item.Name.Left(NFileHeader::kNameSize - 1);
+ return WriteHeaderReal(modifiedItem);
+}
+
+HRESULT COutArchive::FillDataResidual(UInt64 dataSize)
+{
+ UInt32 lastRecordSize = UInt32(dataSize & (NFileHeader::kRecordSize - 1));
+ if (lastRecordSize == 0)
+ return S_OK;
+ UInt32 residualSize = NFileHeader::kRecordSize - lastRecordSize;
+ Byte residualBytes[NFileHeader::kRecordSize];
+ for (UInt32 i = 0; i < residualSize; i++)
+ residualBytes[i] = 0;
+ return WriteBytes(residualBytes, residualSize);
+}
+
+HRESULT COutArchive::WriteFinishHeader()
+{
+ Byte record[NFileHeader::kRecordSize];
+ int i;
+ for (i = 0; i < NFileHeader::kRecordSize; i++)
+ record[i] = 0;
+ for (i = 0; i < 2; i++)
+ {
+ RINOK(WriteBytes(record, NFileHeader::kRecordSize));
+ }
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarOut.h b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarOut.h
new file mode 100644
index 000000000..ef837869b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarOut.h
@@ -0,0 +1,28 @@
+// Archive/TarOut.h
+
+#ifndef __ARCHIVE_TAR_OUT_H
+#define __ARCHIVE_TAR_OUT_H
+
+#include "TarItem.h"
+
+#include "Common/MyCom.h"
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NTar {
+
+class COutArchive
+{
+ CMyComPtr<ISequentialOutStream> m_Stream;
+ HRESULT WriteBytes(const void *buffer, UInt32 size);
+public:
+ void Create(ISequentialOutStream *outStream);
+ HRESULT WriteHeaderReal(const CItem &item);
+ HRESULT WriteHeader(const CItem &item);
+ HRESULT FillDataResidual(UInt64 dataSize);
+ HRESULT WriteFinishHeader();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarRegister.cpp
new file mode 100644
index 000000000..e21c0aac4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarRegister.cpp
@@ -0,0 +1,18 @@
+// TarRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "TarHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NTar::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NTar::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+{ L"tar", L"tar", 0, 0xEE, { 'u', 's', 't', 'a', 'r' }, 5, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Tar)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarUpdate.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarUpdate.cpp
new file mode 100644
index 000000000..c16332189
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarUpdate.cpp
@@ -0,0 +1,139 @@
+// TarUpdate.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "TarOut.h"
+#include "TarUpdate.h"
+
+namespace NArchive {
+namespace NTar {
+
+HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
+ const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ COutArchive outArchive;
+ outArchive.Create(outStream);
+
+ UInt64 complexity = 0;
+
+ int i;
+ for(i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ complexity += ui.Size;
+ else
+ complexity += inputItems[ui.IndexInArchive].GetFullSize();
+ }
+
+ RINOK(updateCallback->SetTotal(complexity));
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
+ streamSpec->SetStream(inStream);
+
+ complexity = 0;
+
+ for(i = 0; i < updateItems.Size(); i++)
+ {
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur());
+
+ const CUpdateItem &ui = updateItems[i];
+ CItem item;
+ if (ui.NewProps)
+ {
+ item.Mode = ui.Mode;
+ item.Name = ui.Name;
+ item.User = ui.User;
+ item.Group = ui.Group;
+ if (ui.IsDir)
+ {
+ item.LinkFlag = NFileHeader::NLinkFlag::kDirectory;
+ item.Size = 0;
+ }
+ else
+ {
+ item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
+ item.Size = ui.Size;
+ }
+ item.MTime = ui.Time;
+ item.DeviceMajorDefined = false;
+ item.DeviceMinorDefined = false;
+ item.UID = 0;
+ item.GID = 0;
+ memmove(item.Magic, NFileHeader::NMagic::kEmpty, 8);
+ }
+ else
+ item = inputItems[ui.IndexInArchive];
+
+ if (ui.NewData)
+ {
+ item.Size = ui.Size;
+ if (item.Size == (UInt64)(Int64)-1)
+ return E_INVALIDARG;
+ }
+ else
+ item.Size = inputItems[ui.IndexInArchive].Size;
+
+ if (ui.NewData)
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res != S_FALSE)
+ {
+ RINOK(res);
+ RINOK(outArchive.WriteHeader(item));
+ if (!ui.IsDir)
+ {
+ RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != item.Size)
+ return E_FAIL;
+ RINOK(outArchive.FillDataResidual(item.Size));
+ }
+ }
+ complexity += ui.Size;
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+ else
+ {
+ const CItemEx &existItem = inputItems[ui.IndexInArchive];
+ UInt64 size;
+ if (ui.NewProps)
+ {
+ RINOK(outArchive.WriteHeader(item));
+ RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
+ size = existItem.Size;
+ }
+ else
+ {
+ RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL));
+ size = existItem.GetFullSize();
+ }
+ streamSpec->Init(size);
+
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != size)
+ return E_FAIL;
+ RINOK(outArchive.FillDataResidual(existItem.Size));
+ complexity += size;
+ }
+ }
+ return outArchive.WriteFinishHeader();
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarUpdate.h b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarUpdate.h
new file mode 100644
index 000000000..fb217d196
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Tar/TarUpdate.h
@@ -0,0 +1,34 @@
+// TarUpdate.h
+
+#ifndef __TAR_UPDATE_H
+#define __TAR_UPDATE_H
+
+#include "../IArchive.h"
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+struct CUpdateItem
+{
+ int IndexInArchive;
+ int IndexInClient;
+ UInt32 Time;
+ UInt32 Mode;
+ UInt64 Size;
+ AString Name;
+ AString User;
+ AString Group;
+ bool NewData;
+ bool NewProps;
+ bool IsDir;
+};
+
+HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ IArchiveUpdateCallback *updateCallback);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfHandler.cpp
new file mode 100644
index 000000000..c70852728
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfHandler.cpp
@@ -0,0 +1,451 @@
+// UdfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "UdfHandler.h"
+
+namespace NArchive {
+namespace NUdf {
+
+void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop)
+{
+ UInt64 numSecs;
+ const Byte *d = t.Data;
+ if (!NWindows::NTime::GetSecondsSince1601(t.GetYear(), d[4], d[5], d[6], d[7], d[8], numSecs))
+ return;
+ if (t.IsLocal())
+ numSecs -= t.GetMinutesOffset() * 60;
+ FILETIME ft;
+ UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10;
+ ft.dwLowDateTime = (UInt32)v;
+ ft.dwHighDateTime = (UInt32)(v >> 32);
+ prop = ft;
+}
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME}
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidCTime, VT_FILETIME}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidComment:
+ {
+ UString comment = _archive.GetComment();
+ if (!comment.IsEmpty())
+ prop = comment;
+ break;
+ }
+
+ case kpidClusterSize:
+ if (_archive.LogVols.Size() > 0)
+ {
+ UInt32 blockSize = _archive.LogVols[0].BlockSize;
+ int i;
+ for (i = 1; i < _archive.LogVols.Size(); i++)
+ if (_archive.LogVols[i].BlockSize != blockSize)
+ break;
+ if (i == _archive.LogVols.Size())
+ prop = blockSize;
+ }
+ break;
+
+ case kpidCTime:
+ if (_archive.LogVols.Size() == 1)
+ {
+ const CLogVol &vol = _archive.LogVols[0];
+ if (vol.FileSets.Size() >= 1)
+ UdfTimeToFileTime(vol.FileSets[0].RecodringTime, prop);
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+ UInt64 _numFiles;
+ UInt64 _numBytes;
+public:
+ HRESULT SetTotal(UInt64 numBytes);
+ HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes);
+ HRESULT SetCompleted();
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback), _numFiles(0), _numBytes(0) {}
+};
+
+HRESULT CProgressImp::SetTotal(UInt64 numBytes)
+{
+ if (_callback)
+ return _callback->SetTotal(NULL, &numBytes);
+ return S_OK;
+}
+
+HRESULT CProgressImp::SetCompleted(UInt64 numFiles, UInt64 numBytes)
+{
+ _numFiles = numFiles;
+ _numBytes = numBytes;
+ return SetCompleted();
+}
+
+HRESULT CProgressImp::SetCompleted()
+{
+ if (_callback)
+ return _callback->SetCompleted(&_numFiles, &_numBytes);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ CProgressImp progressImp(callback);
+ RINOK(_archive.Open(stream, &progressImp));
+ bool showVolName = (_archive.LogVols.Size() > 1);
+ for (int volIndex = 0; volIndex < _archive.LogVols.Size(); volIndex++)
+ {
+ const CLogVol &vol = _archive.LogVols[volIndex];
+ bool showFileSetName = (vol.FileSets.Size() > 1);
+ for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++)
+ {
+ const CFileSet &fs = vol.FileSets[fsIndex];
+ for (int i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++)
+ {
+ CRef2 ref2;
+ ref2.Vol = volIndex;
+ ref2.Fs = fsIndex;
+ ref2.Ref = i;
+ _refs2.Add(ref2);
+ }
+ }
+ }
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _archive.Clear();
+ _refs2.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _refs2.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ {
+ const CRef2 &ref2 = _refs2[index];
+ const CLogVol &vol = _archive.LogVols[ref2.Vol];
+ const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ switch(propID)
+ {
+ case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref,
+ _archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: if (!item.IsDir()) prop = (UInt64)item.Size; break;
+ case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break;
+ case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break;
+ case kpidATime: UdfTimeToFileTime(item.ATime, prop); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+struct CSeekExtent
+{
+ UInt64 Phy;
+ UInt64 Virt;
+};
+
+class CExtentsStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _phyPos;
+ UInt64 _virtPos;
+ bool _needStartSeek;
+
+ HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); }
+
+public:
+ CMyComPtr<IInStream> Stream;
+ CRecordVector<CSeekExtent> Extents;
+
+ MY_UNKNOWN_IMP1(IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ void ReleaseStream() { Stream.Release(); }
+
+ void Init()
+ {
+ _virtPos = 0;
+ _phyPos = 0;
+ _needStartSeek = true;
+ }
+
+};
+
+
+STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size > 0)
+ {
+ UInt64 totalSize = Extents.Back().Virt;
+ if (_virtPos >= totalSize)
+ return (_virtPos == totalSize) ? S_OK : E_FAIL;
+ int left = 0, right = Extents.Size() - 1;
+ for (;;)
+ {
+ int mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (_virtPos < Extents[mid].Virt)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ const CSeekExtent &extent = Extents[left];
+ UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);
+ if (_needStartSeek || _phyPos != phyPos)
+ {
+ _needStartSeek = false;
+ _phyPos = phyPos;
+ RINOK(SeekToPhys());
+ }
+
+ UInt64 rem = Extents[left + 1].Virt - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+
+ HRESULT res = Stream->Read(data, size, &size);
+ _phyPos += size;
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return res;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = Extents.Back().Virt + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ *stream = 0;
+
+ const CRef2 &ref2 = _refs2[index];
+ const CLogVol &vol = _archive.LogVols[ref2.Vol];
+ const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ UInt64 size = item.Size;
+
+ if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || ! _archive.CheckItemExtents(ref2.Vol, item))
+ return E_NOTIMPL;
+
+ if (item.IsInline)
+ {
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ CReferenceBuf *referenceBuf = new CReferenceBuf;
+ CMyComPtr<IUnknown> ref = referenceBuf;
+ referenceBuf->Buf = item.InlineData;
+ inStreamSpec->Init(referenceBuf);
+ *stream = inStream.Detach();
+ return S_OK;
+ }
+
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ extentStreamSpec->Stream = _inStream;
+
+ UInt64 virtOffset = 0;
+ for (int extentIndex = 0; extentIndex < item.Extents.Size(); extentIndex++)
+ {
+ const CMyExtent &extent = item.Extents[extentIndex];
+ UInt32 len = extent.GetLen();
+ if (len == 0)
+ continue;
+ if (size < len)
+ return S_FALSE;
+
+ int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex;
+ UInt32 logBlockNumber = extent.Pos;
+ const CPartition &partition = _archive.Partitions[partitionIndex];
+ UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) +
+ (UInt64)logBlockNumber * vol.BlockSize;
+
+ CSeekExtent se;
+ se.Phy = offset;
+ se.Virt = virtOffset;
+ virtOffset += len;
+ extentStreamSpec->Extents.Add(se);
+
+ size -= len;
+ }
+ if (size != 0)
+ return S_FALSE;
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virtOffset;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _refs2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ const CRef2 &ref2 = _refs2[index];
+ const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ const CRef2 &ref2 = _refs2[index];
+ const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ currentTotalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(item.Size);
+ Int32 opRes;
+ CMyComPtr<ISequentialInStream> udfInStream;
+ HRESULT res = GetStream(index, &udfInStream);
+ if (res == E_NOTIMPL)
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ else if (res != S_OK)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(copyCoder->Code(udfInStream, outStream, NULL, NULL, progress));
+ opRes = outStreamSpec->IsFinishedOK() ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError;
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfHandler.h
new file mode 100644
index 000000000..f513727d7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfHandler.h
@@ -0,0 +1,37 @@
+// Udf/Handler.h
+
+#ifndef __UDF_HANDLER_H
+#define __UDF_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+
+#include "UdfIn.h"
+
+namespace NArchive {
+namespace NUdf {
+
+struct CRef2
+{
+ int Vol;
+ int Fs;
+ int Ref;
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+ CInArchive _archive;
+ CRecordVector<CRef2> _refs2;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp
new file mode 100644
index 000000000..60d5fc2ad
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -0,0 +1,876 @@
+// Archive/UdfIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "UdfIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NUdf {
+
+const int kNumPartitionsMax = 64;
+const int kNumLogVolumesMax = 64;
+const int kNumRecureseLevelsMax = 1 << 10;
+const int kNumItemsMax = 1 << 27;
+const int kNumFilesMax = 1 << 28;
+const int kNumRefsMax = 1 << 28;
+const UInt32 kNumExtentsMax = (UInt32)1 << 30;
+const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33;
+const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33;
+
+void MY_FAST_CALL Crc16GenerateTable(void);
+
+#define CRC16_INIT_VAL 0
+#define CRC16_GET_DIGEST(crc) (crc)
+#define CRC16_UPDATE_BYTE(crc, b) (g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))
+
+#define kCrc16Poly 0x1021
+UInt16 g_Crc16Table[256];
+
+void MY_FAST_CALL Crc16GenerateTable(void)
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = (i << 8);
+ for (int j = 8; j > 0; j--)
+ r = ((r & 0x8000) ? ((r << 1) ^ kCrc16Poly) : (r << 1)) & 0xFFFF;
+ g_Crc16Table[i] = (UInt16)r;
+ }
+}
+
+UInt16 MY_FAST_CALL Crc16_Update(UInt16 v, const void *data, size_t size)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 ; size--, p++)
+ v = CRC16_UPDATE_BYTE(v, *p);
+ return v;
+}
+
+UInt16 MY_FAST_CALL Crc16Calc(const void *data, size_t size)
+{
+ return Crc16_Update(CRC16_INIT_VAL, data, size);
+}
+
+struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit;
+
+void CDString128::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
+
+void CDString::Parse(const Byte *p, unsigned size)
+{
+ Data.SetCapacity(size);
+ memcpy(Data, p, size);
+}
+
+static UString ParseDString(const Byte *data, int size)
+{
+ UString res;
+ wchar_t *p;
+ if (size > 0)
+ {
+ Byte type = data[0];
+ if (type == 8)
+ {
+ p = res.GetBuffer((int)size + 1);
+ for (int i = 1; i < size; i++)
+ {
+ wchar_t c = data[i];
+ if (c == 0)
+ break;
+ *p++ = c;
+ }
+ }
+ else if (type == 16)
+ {
+ p = res.GetBuffer((int)size / 2 + 1);
+ for (int i = 1; i + 2 <= size; i += 2)
+ {
+ wchar_t c = ((wchar_t)data[i] << 8) | data[i + 1];
+ if (c == 0)
+ break;
+ *p++ = c;
+ }
+ }
+ else
+ return L"[unknow]";
+ *p++ = 0;
+ res.ReleaseBuffer();
+ }
+ return res;
+}
+
+UString CDString:: GetString() const { return ParseDString(Data, (int)Data.GetCapacity()); }
+UString CDString128::GetString() const
+{
+ int size = Data[sizeof(Data) - 1];
+ return ParseDString(Data, MyMin(size, (int)(sizeof(Data) - 1)));
+}
+
+void CTime::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
+
+/*
+void CRegId::Parse(const Byte *buf)
+{
+ Flags = buf[0];
+ memcpy(Id, buf + 1, sizeof(Id));
+ memcpy(Suffix, buf + 24, sizeof(Suffix));
+}
+*/
+
+// ECMA 3/7.1
+
+struct CExtent
+{
+ UInt32 Len;
+ UInt32 Pos;
+
+ void Parse(const Byte *buf);
+};
+
+void CExtent::Parse(const Byte *buf)
+{
+ Len = Get32(buf);
+ Pos = Get32(buf + 4);
+}
+
+// ECMA 3/7.2
+
+struct CTag
+{
+ UInt16 Id;
+ UInt16 Version;
+ // Byte Checksum;
+ // UInt16 SerialNumber;
+ // UInt16 Crc;
+ // UInt16 CrcLen;
+ // UInt32 TagLocation;
+
+ HRESULT Parse(const Byte *buf, size_t size);
+};
+
+HRESULT CTag::Parse(const Byte *buf, size_t size)
+{
+ if (size < 16)
+ return S_FALSE;
+ Byte sum = 0;
+ int i;
+ for (i = 0; i < 4; i++) sum = sum + buf[i];
+ for (i = 5; i < 16; i++) sum = sum + buf[i];
+ if (sum != buf[4] || buf[5] != 0) return S_FALSE;
+
+ Id = Get16(buf);
+ Version = Get16(buf + 2);
+ // SerialNumber = Get16(buf + 6);
+ UInt16 crc = Get16(buf + 8);
+ UInt16 crcLen = Get16(buf + 10);
+ // TagLocation = Get32(buf + 12);
+
+ if (size >= 16 + (size_t)crcLen)
+ if (crc == Crc16Calc(buf + 16, crcLen))
+ return S_OK;
+ return S_FALSE;
+}
+
+// ECMA 3/7.2.1
+
+enum EDescriptorType
+{
+ DESC_TYPE_SpoaringTable = 0, // UDF
+ DESC_TYPE_PrimVol = 1,
+ DESC_TYPE_AnchorVolPtr = 2,
+ DESC_TYPE_VolPtr = 3,
+ DESC_TYPE_ImplUseVol = 4,
+ DESC_TYPE_Partition = 5,
+ DESC_TYPE_LogicalVol = 6,
+ DESC_TYPE_UnallocSpace = 7,
+ DESC_TYPE_Terminating = 8,
+ DESC_TYPE_LogicalVolIntegrity = 9,
+ DESC_TYPE_FileSet = 256,
+ DESC_TYPE_FileId = 257,
+ DESC_TYPE_AllocationExtent = 258,
+ DESC_TYPE_Indirect = 259,
+ DESC_TYPE_Terminal = 260,
+ DESC_TYPE_File = 261,
+ DESC_TYPE_ExtendedAttrHeader = 262,
+ DESC_TYPE_UnallocatedSpace = 263,
+ DESC_TYPE_SpaceBitmap = 264,
+ DESC_TYPE_PartitionIntegrity = 265,
+ DESC_TYPE_ExtendedFile = 266
+};
+
+
+void CLogBlockAddr::Parse(const Byte *buf)
+{
+ Pos = Get32(buf);
+ PartitionRef = Get16(buf + 4);
+}
+
+void CShortAllocDesc::Parse(const Byte *buf)
+{
+ Len = Get32(buf);
+ Pos = Get32(buf + 4);
+}
+
+/*
+void CADImpUse::Parse(const Byte *buf)
+{
+ Flags = Get16(buf);
+ UdfUniqueId = Get32(buf + 2);
+}
+*/
+
+void CLongAllocDesc::Parse(const Byte *buf)
+{
+ Len = Get32(buf);
+ Location.Parse(buf + 4);
+ // memcpy(ImplUse, buf + 10, sizeof(ImplUse));
+ // adImpUse.Parse(ImplUse);
+}
+
+bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const
+{
+ const CLogVol &vol = LogVols[volIndex];
+ const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
+ UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize;
+ return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize);
+}
+
+bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const
+{
+ for (int i = 0; i < item.Extents.Size(); i++)
+ {
+ const CMyExtent &e = item.Extents[i];
+ if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen()))
+ return false;
+ }
+ return true;
+}
+
+HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf)
+{
+ if (!CheckExtent(volIndex, partitionRef, blockPos, len))
+ return S_FALSE;
+ const CLogVol &vol = LogVols[volIndex];
+ const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
+ RINOK(_stream->Seek(((UInt64)partition.Pos << SecLogSize) +
+ (UInt64)blockPos * vol.BlockSize, STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(_stream, buf, len);
+}
+
+HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf)
+{
+ return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf);
+}
+
+HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf)
+{
+ if (item.Size >= (UInt32)1 << 30)
+ return S_FALSE;
+ if (item.IsInline)
+ {
+ buf = item.InlineData;
+ return S_OK;
+ }
+ buf.SetCapacity((size_t)item.Size);
+ size_t pos = 0;
+ for (int i = 0; i < item.Extents.Size(); i++)
+ {
+ const CMyExtent &e = item.Extents[i];
+ UInt32 len = e.GetLen();
+ RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos));
+ pos += len;
+ }
+ return S_OK;
+}
+
+
+void CIcbTag::Parse(const Byte *p)
+{
+ // PriorDirectNum = Get32(p);
+ // StrategyType = Get16(p + 4);
+ // StrategyParam = Get16(p + 6);
+ // MaxNumOfEntries = Get16(p + 8);
+ FileType = p[11];
+ // ParentIcb.Parse(p + 12);
+ Flags = Get16(p + 18);
+}
+
+void CItem::Parse(const Byte *p)
+{
+ // Uid = Get32(p + 36);
+ // Gid = Get32(p + 40);
+ // Permissions = Get32(p + 44);
+ // FileLinkCount = Get16(p + 48);
+ // RecordFormat = p[50];
+ // RecordDisplayAttr = p[51];
+ // RecordLen = Get32(p + 52);
+ Size = Get64(p + 56);
+ NumLogBlockRecorded = Get64(p + 64);
+ ATime.Parse(p + 72);
+ MTime.Parse(p + 84);
+ // AttrtTime.Parse(p + 96);
+ // CheckPoint = Get32(p + 108);
+ // ExtendedAttrIcb.Parse(p + 112);
+ // ImplId.Parse(p + 128);
+ // UniqueId = Get64(p + 160);
+}
+
+// 4/14.4
+struct CFileId
+{
+ // UInt16 FileVersion;
+ Byte FileCharacteristics;
+ // CByteBuffer ImplUse;
+ CDString Id;
+ CLongAllocDesc Icb;
+
+ bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; }
+ HRESULT Parse(const Byte *p, size_t size, size_t &processed);
+};
+
+HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed)
+{
+ processed = 0;
+ if (size < 38)
+ return S_FALSE;
+ CTag tag;
+ RINOK(tag.Parse(p, size));
+ if (tag.Id != DESC_TYPE_FileId)
+ return S_FALSE;
+ // FileVersion = Get16(p + 16);
+ FileCharacteristics = p[18];
+ unsigned idLen = p[19];
+ Icb.Parse(p + 20);
+ unsigned impLen = Get16(p + 36);
+ if (size < 38 + idLen + impLen)
+ return S_FALSE;
+ // ImplUse.SetCapacity(impLen);
+ processed = 38;
+ // memcpy(ImplUse, p + processed, impLen);
+ processed += impLen;
+ Id.Parse(p + processed, idLen);
+ processed += idLen;
+ for (;(processed & 3) != 0; processed++)
+ if (p[processed] != 0)
+ return S_FALSE;
+ return (processed <= size) ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)
+{
+ if (Files.Size() % 100 == 0)
+ RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes));
+ if (numRecurseAllowed-- == 0)
+ return S_FALSE;
+ CFile &file = Files.Back();
+ const CLogVol &vol = LogVols[volIndex];
+ CPartition &partition = Partitions[vol.PartitionMaps[lad.Location.PartitionRef].PartitionIndex];
+
+ UInt32 key = lad.Location.Pos;
+ UInt32 value;
+ const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1;
+ if (partition.Map.Find(key, value))
+ {
+ if (value == kRecursedErrorValue)
+ return S_FALSE;
+ file.ItemIndex = value;
+ }
+ else
+ {
+ value = Items.Size();
+ file.ItemIndex = (int)value;
+ if (partition.Map.Set(key, kRecursedErrorValue))
+ return S_FALSE;
+ RINOK(ReadItem(volIndex, fsIndex, lad, numRecurseAllowed));
+ if (!partition.Map.Set(key, value))
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)
+{
+ if (Items.Size() > kNumItemsMax)
+ return S_FALSE;
+ Items.Add(CItem());
+ CItem &item = Items.Back();
+
+ const CLogVol &vol = LogVols[volIndex];
+
+ if (lad.GetLen() != vol.BlockSize)
+ return S_FALSE;
+
+ CByteBuffer buf;
+ size_t size = lad.GetLen();
+ buf.SetCapacity(size);
+ RINOK(Read(volIndex, lad, buf));
+
+ CTag tag;
+ const Byte *p = buf;
+ RINOK(tag.Parse(p, size));
+ if (tag.Id != DESC_TYPE_File)
+ return S_FALSE;
+
+ item.IcbTag.Parse(p + 16);
+ if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR &&
+ item.IcbTag.FileType != ICB_FILE_TYPE_FILE)
+ return S_FALSE;
+
+ item.Parse(p);
+
+ _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size;
+
+ UInt32 extendedAttrLen = Get32(p + 168);
+ UInt32 allocDescriptorsLen = Get32(p + 172);
+
+ if ((extendedAttrLen & 3) != 0)
+ return S_FALSE;
+ int pos = 176;
+ if (extendedAttrLen > size - pos)
+ return S_FALSE;
+ /*
+ if (extendedAttrLen != 16)
+ {
+ if (extendedAttrLen < 24)
+ return S_FALSE;
+ CTag attrTag;
+ RINOK(attrTag.Parse(p + pos, size));
+ if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader)
+ return S_FALSE;
+ // UInt32 implAttrLocation = Get32(p + pos + 16);
+ // UInt32 applicationlAttrLocation = Get32(p + pos + 20);
+ }
+ */
+ pos += extendedAttrLen;
+
+ int desctType = item.IcbTag.GetDescriptorType();
+ if (allocDescriptorsLen > size - pos)
+ return S_FALSE;
+ if (desctType == ICB_DESC_TYPE_INLINE)
+ {
+ item.IsInline = true;
+ item.InlineData.SetCapacity(allocDescriptorsLen);
+ memcpy(item.InlineData, p + pos, allocDescriptorsLen);
+ }
+ else
+ {
+ item.IsInline = false;
+ if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG)
+ return S_FALSE;
+ for (UInt32 i = 0; i < allocDescriptorsLen;)
+ {
+ CMyExtent e;
+ if (desctType == ICB_DESC_TYPE_SHORT)
+ {
+ if (i + 8 > allocDescriptorsLen)
+ return S_FALSE;
+ CShortAllocDesc sad;
+ sad.Parse(p + pos + i);
+ e.Pos = sad.Pos;
+ e.Len = sad.Len;
+ e.PartitionRef = lad.Location.PartitionRef;
+ i += 8;
+ }
+ else
+ {
+ if (i + 16 > allocDescriptorsLen)
+ return S_FALSE;
+ CLongAllocDesc ladNew;
+ ladNew.Parse(p + pos + i);
+ e.Pos = ladNew.Location.Pos;
+ e.PartitionRef = ladNew.Location.PartitionRef;
+ e.Len = ladNew.Len;
+ i += 16;
+ }
+ item.Extents.Add(e);
+ }
+ }
+
+ if (item.IcbTag.IsDir())
+ {
+ if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
+ return S_FALSE;
+ CByteBuffer buf;
+ RINOK(ReadFromFile(volIndex, item, buf));
+ item.Size = 0;
+ item.Extents.ClearAndFree();
+ item.InlineData.Free();
+
+ const Byte *p = buf;
+ size = buf.GetCapacity();
+ size_t processedTotal = 0;
+ for (; processedTotal < size;)
+ {
+ size_t processedCur;
+ CFileId fileId;
+ RINOK(fileId.Parse(p + processedTotal, size - processedTotal, processedCur));
+ if (!fileId.IsItLinkParent())
+ {
+ CFile file;
+ // file.FileVersion = fileId.FileVersion;
+ // file.FileCharacteristics = fileId.FileCharacteristics;
+ // file.ImplUse = fileId.ImplUse;
+ file.Id = fileId.Id;
+
+ _fileNameLengthTotal += file.Id.Data.GetCapacity();
+ if (_fileNameLengthTotal > kFileNameLengthTotalMax)
+ return S_FALSE;
+
+ item.SubFiles.Add(Files.Size());
+ if (Files.Size() > kNumFilesMax)
+ return S_FALSE;
+ Files.Add(file);
+ RINOK(ReadFileItem(volIndex, fsIndex, fileId.Icb, numRecurseAllowed));
+ }
+ processedTotal += processedCur;
+ }
+ }
+ else
+ {
+ if ((UInt32)item.Extents.Size() > kNumExtentsMax - _numExtents)
+ return S_FALSE;
+ _numExtents += item.Extents.Size();
+
+ if (item.InlineData.GetCapacity() > kInlineExtentsSizeMax - _inlineExtentsSize)
+ return S_FALSE;
+ _inlineExtentsSize += item.InlineData.GetCapacity();
+ }
+
+ return S_OK;
+}
+
+HRESULT CInArchive::FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed)
+{
+ if (_numRefs % 10000 == 0)
+ {
+ RINOK(_progress->SetCompleted());
+ }
+ if (numRecurseAllowed-- == 0)
+ return S_FALSE;
+ if (_numRefs >= kNumRefsMax)
+ return S_FALSE;
+ _numRefs++;
+ CRef ref;
+ ref.FileIndex = fileIndex;
+ ref.Parent = parent;
+ parent = fs.Refs.Size();
+ fs.Refs.Add(ref);
+ const CItem &item = Items[Files[fileIndex].ItemIndex];
+ for (int i = 0; i < item.SubFiles.Size(); i++)
+ {
+ RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed));
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::Open2()
+{
+ Clear();
+
+ UInt64 fileSize;
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize));
+
+ // Some UDFs contain additional 2 KB of zeros, so we also check 12, corrected to 11.
+ const int kSecLogSizeMax = 12;
+ Byte buf[1 << kSecLogSizeMax];
+ Byte kSizesLog[] = { 11, 8, 12 };
+
+ for (int i = 0;; i++)
+ {
+ if (i == sizeof(kSizesLog) / sizeof(kSizesLog[0]))
+ return S_FALSE;
+ SecLogSize = kSizesLog[i];
+ Int32 bufSize = 1 << SecLogSize;
+ if (bufSize > fileSize)
+ return S_FALSE;
+ RINOK(_stream->Seek(-bufSize, STREAM_SEEK_END, NULL));
+ RINOK(ReadStream_FALSE(_stream, buf, bufSize));
+ CTag tag;
+ if (tag.Parse(buf, bufSize) == S_OK)
+ if (tag.Id == DESC_TYPE_AnchorVolPtr)
+ break;
+ }
+ if (SecLogSize == 12)
+ SecLogSize = 11;
+
+ CExtent extentVDS;
+ extentVDS.Parse(buf + 16);
+
+ for (UInt32 location = extentVDS.Pos; ; location++)
+ {
+ size_t bufSize = 1 << SecLogSize;
+ size_t pos = 0;
+ RINOK(_stream->Seek((UInt64)location << SecLogSize, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(_stream, buf, bufSize));
+ CTag tag;
+ RINOK(tag.Parse(buf + pos, bufSize - pos));
+ if (tag.Id == DESC_TYPE_Terminating)
+ break;
+ if (tag.Id == DESC_TYPE_Partition)
+ {
+ if (Partitions.Size() >= kNumPartitionsMax)
+ return S_FALSE;
+ CPartition partition;
+ // UInt32 volDescSeqNumer = Get32(buf + 16);
+ // partition.Flags = Get16(buf + 20);
+ partition.Number = Get16(buf + 22);
+ // partition.ContentsId.Parse(buf + 24);
+
+ // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse));
+ // ContentsUse is Partition Header Description.
+
+ // partition.AccessType = Get32(buf + 184);
+ partition.Pos = Get32(buf + 188);
+ partition.Len = Get32(buf + 192);
+ // partition.ImplId.Parse(buf + 196);
+ // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse));
+
+ Partitions.Add(partition);
+ }
+ else if (tag.Id == DESC_TYPE_LogicalVol)
+ {
+ if (LogVols.Size() >= kNumLogVolumesMax)
+ return S_FALSE;
+ CLogVol vol;
+ vol.Id.Parse(buf + 84);
+ vol.BlockSize = Get32(buf + 212);
+ // vol.DomainId.Parse(buf + 216);
+
+ if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30))
+ return S_FALSE;
+
+ // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse));
+ vol.FileSetLocation.Parse(buf + 248);
+
+ // UInt32 mapTableLength = Get32(buf + 264);
+ UInt32 numPartitionMaps = Get32(buf + 268);
+ if (numPartitionMaps > kNumPartitionsMax)
+ return S_FALSE;
+ // vol.ImplId.Parse(buf + 272);
+ // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse));
+ size_t pos = 440;
+ for (UInt32 i = 0; i < numPartitionMaps; i++)
+ {
+ if (pos + 2 > bufSize)
+ return S_FALSE;
+ CPartitionMap pm;
+ pm.Type = buf[pos];
+ // pm.Length = buf[pos + 1];
+ Byte len = buf[pos + 1];
+
+ if (pos + len > bufSize)
+ return S_FALSE;
+
+ // memcpy(pm.Data, buf + pos + 2, pm.Length - 2);
+ if (pm.Type == 1)
+ {
+ if (pos + 6 > bufSize)
+ return S_FALSE;
+ // pm.VolSeqNumber = Get16(buf + pos + 2);
+ pm.PartitionNumber = Get16(buf + pos + 4);
+ }
+ else
+ return S_FALSE;
+ pos += len;
+ vol.PartitionMaps.Add(pm);
+ }
+ LogVols.Add(vol);
+ }
+ }
+
+ UInt64 totalSize = 0;
+
+ int volIndex;
+ for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
+ {
+ CLogVol &vol = LogVols[volIndex];
+ for (int pmIndex = 0; pmIndex < vol.PartitionMaps.Size(); pmIndex++)
+ {
+ CPartitionMap &pm = vol.PartitionMaps[pmIndex];
+ int i;
+ for (i = 0; i < Partitions.Size(); i++)
+ {
+ CPartition &part = Partitions[i];
+ if (part.Number == pm.PartitionNumber)
+ {
+ if (part.VolIndex >= 0)
+ return S_FALSE;
+ pm.PartitionIndex = i;
+ part.VolIndex = volIndex;
+
+ totalSize += (UInt64)part.Len << SecLogSize;
+ break;
+ }
+ }
+ if (i == Partitions.Size())
+ return S_FALSE;
+ }
+ }
+
+ RINOK(_progress->SetTotal(totalSize));
+
+ for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
+ {
+ CLogVol &vol = LogVols[volIndex];
+
+ CLongAllocDesc nextExtent = vol.FileSetLocation;
+ // while (nextExtent.ExtentLen != 0)
+ // for (int i = 0; i < 1; i++)
+ {
+ if (nextExtent.GetLen() < 512)
+ return S_FALSE;
+ CByteBuffer buf;
+ buf.SetCapacity(nextExtent.GetLen());
+ RINOK(Read(volIndex, nextExtent, buf));
+ const Byte *p = buf;
+ size_t size = nextExtent.GetLen();
+
+ CTag tag;
+ RINOK(tag.Parse(p, size));
+ if (tag.Id != DESC_TYPE_FileSet)
+ return S_FALSE;
+
+ CFileSet fs;
+ fs.RecodringTime.Parse(p + 16);
+ // fs.InterchangeLevel = Get16(p + 18);
+ // fs.MaxInterchangeLevel = Get16(p + 20);
+ // fs.FileSetNumber = Get32(p + 40);
+ // fs.FileSetDescNumber = Get32(p + 44);
+
+ // fs.Id.Parse(p + 304);
+ // fs.CopyrightId.Parse(p + 336);
+ // fs.AbstractId.Parse(p + 368);
+
+ fs.RootDirICB.Parse(p + 400);
+ // fs.DomainId.Parse(p + 416);
+
+ // fs.SystemStreamDirICB.Parse(p + 464);
+
+ vol.FileSets.Add(fs);
+
+ // nextExtent.Parse(p + 448);
+ }
+
+ for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++)
+ {
+ CFileSet &fs = vol.FileSets[fsIndex];
+ int fileIndex = Files.Size();
+ Files.Add(CFile());
+ RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecureseLevelsMax));
+ RINOK(FillRefs(fs, fileIndex, -1, kNumRecureseLevelsMax));
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress)
+{
+ _progress = progress;
+ _stream = inStream;
+ HRESULT res;
+ try { res = Open2(); }
+ catch(...) { Clear(); res = S_FALSE; }
+ _stream.Release();
+ return res;
+}
+
+void CInArchive::Clear()
+{
+ Partitions.Clear();
+ LogVols.Clear();
+ Items.Clear();
+ Files.Clear();
+ _fileNameLengthTotal = 0;
+ _numRefs = 0;
+ _numExtents = 0;
+ _inlineExtentsSize = 0;
+ _processedProgressBytes = 0;
+}
+
+UString CInArchive::GetComment() const
+{
+ UString res;
+ for (int i = 0; i < LogVols.Size(); i++)
+ {
+ if (i > 0)
+ res += L" ";
+ res += LogVols[i].GetName();
+ }
+ return res;
+}
+
+static UString GetSpecName(const UString &name)
+{
+ UString name2 = name;
+ name2.Trim();
+ if (name2.IsEmpty())
+ {
+ /*
+ wchar_t s[32];
+ ConvertUInt64ToString(id, s);
+ return L"[" + (UString)s + L"]";
+ */
+ return L"[]";
+ }
+ return name;
+}
+
+static void UpdateWithName(UString &res, const UString &addString)
+{
+ if (res.IsEmpty())
+ res = addString;
+ else
+ res = addString + WCHAR_PATH_SEPARATOR + res;
+}
+
+UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex,
+ bool showVolName, bool showFsName) const
+{
+ // showVolName = true;
+ const CLogVol &vol = LogVols[volIndex];
+ const CFileSet &fs = vol.FileSets[fsIndex];
+
+ UString name;
+
+ for (;;)
+ {
+ const CRef &ref = fs.Refs[refIndex];
+ refIndex = ref.Parent;
+ if (refIndex < 0)
+ break;
+ UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName()));
+ }
+
+ if (showFsName)
+ {
+ wchar_t s[32];
+ ConvertUInt64ToString(fsIndex, s);
+ UString newName = L"File Set ";
+ newName += s;
+ UpdateWithName(name, newName);
+ }
+
+ if (showVolName)
+ {
+ wchar_t s[32];
+ ConvertUInt64ToString(volIndex, s);
+ UString newName = s;
+ UString newName2 = vol.GetName();
+ if (newName2.IsEmpty())
+ newName2 = L"Volume";
+ newName += L'-';
+ newName += newName2;
+ UpdateWithName(name, newName);
+ }
+ return name;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.h
new file mode 100644
index 000000000..46b9a7e85
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfIn.h
@@ -0,0 +1,375 @@
+// Archive/UdfIn.h -- UDF / ECMA-167
+
+#ifndef __ARCHIVE_UDF_IN_H
+#define __ARCHIVE_UDF_IN_H
+
+#include "Common/MyCom.h"
+#include "Common/IntToString.h"
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+#include "Common/MyMap.h"
+
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NUdf {
+
+// ---------- ECMA Part 1 ----------
+
+// ECMA 1/7.2.12
+
+/*
+struct CDString32
+{
+ Byte Data[32];
+ void Parse(const Byte *buf);
+ // UString GetString() const;
+};
+*/
+
+struct CDString128
+{
+ Byte Data[128];
+ void Parse(const Byte *buf);
+ UString GetString() const;
+};
+
+struct CDString
+{
+ CByteBuffer Data;
+ void Parse(const Byte *p, unsigned size);
+ UString GetString() const;
+};
+
+
+// ECMA 1/7.3
+
+struct CTime
+{
+ Byte Data[12];
+
+ unsigned GetType() const { return Data[1] >> 4; }
+ bool IsLocal() const { return GetType() == 1; }
+ int GetMinutesOffset() const
+ {
+ int t = (Data[0] | ((UInt16)Data[1] << 8)) & 0xFFF;
+ if ((t >> 11) != 0)
+ t -= (1 << 12);
+ return (t > (60 * 24) || t < -(60 * 24)) ? 0 : t;
+ }
+ unsigned GetYear() const { return (Data[2] | ((UInt16)Data[3] << 8)); }
+ void Parse(const Byte *buf);
+};
+
+
+// ECMA 1/7.4
+
+/*
+struct CRegId
+{
+ Byte Flags;
+ char Id[23];
+ char Suffix[8];
+
+ void Parse(const Byte *buf);
+};
+*/
+
+// ---------- ECMA Part 3: Volume Structure ----------
+
+// ECMA 3/10.5
+
+struct CPartition
+{
+ // UInt16 Flags;
+ UInt16 Number;
+ // CRegId ContentsId;
+ // Byte ContentsUse[128];
+ // UInt32 AccessType;
+
+ UInt32 Pos;
+ UInt32 Len;
+
+ // CRegId ImplId;
+ // Byte ImplUse[128];
+
+ int VolIndex;
+ CMap32 Map;
+
+ CPartition(): VolIndex(-1) {}
+
+ // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); }
+ // bool IsAllocated() const { return ((Flags & 1) != 0); }
+};
+
+struct CLogBlockAddr
+{
+ UInt32 Pos;
+ UInt16 PartitionRef;
+
+ void Parse(const Byte *buf);
+};
+
+enum EShortAllocDescType
+{
+ SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0,
+ SHORT_ALLOC_DESC_TYPE_NotRecordedButAllocated = 1,
+ SHORT_ALLOC_DESC_TYPE_NotRecordedAndNotAllocated = 2,
+ SHORT_ALLOC_DESC_TYPE_NextExtent = 3
+};
+
+struct CShortAllocDesc
+{
+ UInt32 Len;
+ UInt32 Pos;
+
+ // 4/14.14.1
+ // UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ // UInt32 GetType() const { return Len >> 30; }
+ // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+ void Parse(const Byte *buf);
+};
+
+/*
+struct CADImpUse
+{
+ UInt16 Flags;
+ UInt32 UdfUniqueId;
+ void Parse(const Byte *buf);
+};
+*/
+
+struct CLongAllocDesc
+{
+ UInt32 Len;
+ CLogBlockAddr Location;
+
+ // Byte ImplUse[6];
+ // CADImpUse adImpUse; // UDF
+
+ UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ UInt32 GetType() const { return Len >> 30; }
+ bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+ void Parse(const Byte *buf);
+};
+
+struct CPartitionMap
+{
+ Byte Type;
+ // Byte Len;
+
+ // Type - 1
+ // UInt16 VolSeqNumber;
+ UInt16 PartitionNumber;
+
+ // Byte Data[256];
+
+ int PartitionIndex;
+};
+
+// ECMA 4/14.6
+
+enum EIcbFileType
+{
+ ICB_FILE_TYPE_DIR = 4,
+ ICB_FILE_TYPE_FILE = 5
+};
+
+enum EIcbDescriptorType
+{
+ ICB_DESC_TYPE_SHORT = 0,
+ ICB_DESC_TYPE_LONG = 1,
+ ICB_DESC_TYPE_EXTENDED = 2,
+ ICB_DESC_TYPE_INLINE = 3
+};
+
+struct CIcbTag
+{
+ // UInt32 PriorDirectNum;
+ // UInt16 StrategyType;
+ // UInt16 StrategyParam;
+ // UInt16 MaxNumOfEntries;
+ Byte FileType;
+ // CLogBlockAddr ParentIcb;
+ UInt16 Flags;
+
+ bool IsDir() const { return FileType == ICB_FILE_TYPE_DIR; }
+ int GetDescriptorType() const { return Flags & 3; }
+ void Parse(const Byte *p);
+};
+
+// const Byte FILEID_CHARACS_Existance = (1 << 0);
+const Byte FILEID_CHARACS_Parent = (1 << 3);
+
+struct CFile
+{
+ // UInt16 FileVersion;
+ // Byte FileCharacteristics;
+ // CByteBuffer ImplUse;
+ CDString Id;
+
+ CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {}
+ int ItemIndex;
+ UString GetName() const { return Id.GetString(); }
+};
+
+struct CMyExtent
+{
+ UInt32 Pos;
+ UInt32 Len;
+ int PartitionRef;
+
+ UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ UInt32 GetType() const { return Len >> 30; }
+ bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+};
+
+struct CItem
+{
+ CIcbTag IcbTag;
+
+ // UInt32 Uid;
+ // UInt32 Gid;
+ // UInt32 Permissions;
+ // UInt16 FileLinkCount;
+ // Byte RecordFormat;
+ // Byte RecordDisplayAttr;
+ // UInt32 RecordLen;
+ UInt64 Size;
+ UInt64 NumLogBlockRecorded;
+ CTime ATime;
+ CTime MTime;
+ // CTime AttrtTime;
+ // UInt32 CheckPoint;
+ // CLongAllocDesc ExtendedAttrIcb;
+ // CRegId ImplId;
+ // UInt64 UniqueId;
+
+ bool IsInline;
+ CByteBuffer InlineData;
+ CRecordVector<CMyExtent> Extents;
+ CRecordVector<int> SubFiles;
+
+ void Parse(const Byte *buf);
+
+ bool IsRecAndAlloc() const
+ {
+ for (int i = 0; i < Extents.Size(); i++)
+ if (!Extents[i].IsRecAndAlloc())
+ return false;
+ return true;
+ }
+
+ UInt64 GetChunksSumSize() const
+ {
+ if (IsInline)
+ return InlineData.GetCapacity();
+ UInt64 size = 0;
+ for (int i = 0; i < Extents.Size(); i++)
+ size += Extents[i].GetLen();
+ return size;
+ }
+
+ bool CheckChunkSizes() const { return GetChunksSumSize() == Size; }
+
+ bool IsDir() const { return IcbTag.IsDir(); }
+};
+
+struct CRef
+{
+ int Parent;
+ int FileIndex;
+};
+
+
+// ECMA 4 / 14.1
+struct CFileSet
+{
+ CTime RecodringTime;
+ // UInt16 InterchangeLevel;
+ // UInt16 MaxInterchangeLevel;
+ // UInt32 FileSetNumber;
+ // UInt32 FileSetDescNumber;
+ // CDString32 Id;
+ // CDString32 CopyrightId;
+ // CDString32 AbstractId;
+
+ CLongAllocDesc RootDirICB;
+ // CRegId DomainId;
+ // CLongAllocDesc SystemStreamDirICB;
+
+ CRecordVector<CRef> Refs;
+};
+
+
+// ECMA 3/10.6
+
+struct CLogVol
+{
+ CDString128 Id;
+ UInt32 BlockSize;
+ // CRegId DomainId;
+
+ // Byte ContentsUse[16];
+ CLongAllocDesc FileSetLocation; // UDF
+
+ // CRegId ImplId;
+ // Byte ImplUse[128];
+
+ CObjectVector<CPartitionMap> PartitionMaps;
+ CObjectVector<CFileSet> FileSets;
+
+ UString GetName() const { return Id.GetString(); }
+};
+
+struct CProgressVirt
+{
+ virtual HRESULT SetTotal(UInt64 numBytes) PURE;
+ virtual HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) PURE;
+ virtual HRESULT SetCompleted() PURE;
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> _stream;
+ CProgressVirt *_progress;
+
+ HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf);
+ HRESULT Read(int volIndex, const CLongAllocDesc &lad, Byte *buf);
+ HRESULT ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf);
+
+ HRESULT ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed);
+ HRESULT ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed);
+
+ HRESULT Open2();
+ HRESULT FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed);
+
+ UInt64 _processedProgressBytes;
+
+ UInt64 _fileNameLengthTotal;
+ int _numRefs;
+ UInt32 _numExtents;
+ UInt64 _inlineExtentsSize;
+ bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const;
+public:
+ HRESULT Open(IInStream *inStream, CProgressVirt *progress);
+ void Clear();
+
+ CObjectVector<CPartition> Partitions;
+ CObjectVector<CLogVol> LogVols;
+
+ CObjectVector<CItem> Items;
+ CObjectVector<CFile> Files;
+
+ int SecLogSize;
+
+ UString GetComment() const;
+ UString GetItemPath(int volIndex, int fsIndex, int refIndex,
+ bool showVolName, bool showFsName) const;
+
+ bool CheckItemExtents(int volIndex, const CItem &item) const;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfRegister.cpp
new file mode 100644
index 000000000..1b08d120b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Udf/UdfRegister.cpp
@@ -0,0 +1,13 @@
+// UdfRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "UdfHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NUdf::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Udf", L"iso img", 0, 0xE0, { 0, 'N', 'S', 'R', '0' }, 5, false, CreateArc, 0 };
+
+REGISTER_ARC(Udf)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/VhdHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/VhdHandler.cpp
new file mode 100644
index 000000000..9d1c928e6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/VhdHandler.cpp
@@ -0,0 +1,734 @@
+// VhdHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+#define G32(p, dest) dest = Get32(p);
+#define G64(p, dest) dest = Get64(p);
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NVhd {
+
+static const UInt32 kUnusedBlock = 0xFFFFFFFF;
+
+static const UInt32 kDiskType_Fixed = 2;
+static const UInt32 kDiskType_Dynamic = 3;
+static const UInt32 kDiskType_Diff = 4;
+
+static const char *kDiskTypes[] =
+{
+ "0",
+ "1",
+ "Fixed",
+ "Dynamic",
+ "Differencing"
+};
+
+struct CFooter
+{
+ // UInt32 Features;
+ // UInt32 FormatVersion;
+ UInt64 DataOffset;
+ UInt32 CTime;
+ UInt32 CreatorApp;
+ UInt32 CreatorVersion;
+ UInt32 CreatorHostOS;
+ // UInt64 OriginalSize;
+ UInt64 CurrentSize;
+ UInt32 DiskGeometry;
+ UInt32 Type;
+ Byte Id[16];
+ Byte SavedState;
+
+ bool IsFixed() const { return Type == kDiskType_Fixed; }
+ bool ThereIsDynamic() const { return Type == kDiskType_Dynamic || Type == kDiskType_Diff; }
+ // bool IsSupported() const { return Type == kDiskType_Fixed || Type == kDiskType_Dynamic || Type == kDiskType_Diff; }
+ UInt32 NumCyls() const { return DiskGeometry >> 16; }
+ UInt32 NumHeads() const { return (DiskGeometry >> 8) & 0xFF; }
+ UInt32 NumSectorsPerTrack() const { return DiskGeometry & 0xFF; }
+ AString GetTypeString() const;
+ bool Parse(const Byte *p);
+};
+
+AString CFooter::GetTypeString() const
+{
+ if (Type < sizeof(kDiskTypes) / sizeof(kDiskTypes[0]))
+ return kDiskTypes[Type];
+ char s[16];
+ ConvertUInt32ToString(Type, s);
+ return s;
+}
+
+static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, unsigned zeroOffset)
+{
+ UInt32 sum = 0;
+ unsigned i;
+ for (i = 0; i < checkSumOffset; i++)
+ sum += p[i];
+ for (i = checkSumOffset + 4; i < size; i++)
+ sum += p[i];
+ if (~sum != Get32(p + checkSumOffset))
+ return false;
+ for (i = zeroOffset; i < size; i++)
+ if (p[i] != 0)
+ return false;
+ return true;
+}
+
+bool CFooter::Parse(const Byte *p)
+{
+ if (memcmp(p, "conectix", 8) != 0)
+ return false;
+ // G32(p + 0x08, Features);
+ // G32(p + 0x0C, FormatVersion);
+ G64(p + 0x10, DataOffset);
+ G32(p + 0x18, CTime);
+ G32(p + 0x1C, CreatorApp);
+ G32(p + 0x20, CreatorVersion);
+ G32(p + 0x24, CreatorHostOS);
+ // G64(p + 0x28, OriginalSize);
+ G64(p + 0x30, CurrentSize);
+ G32(p + 0x38, DiskGeometry);
+ G32(p + 0x3C, Type);
+ memcpy(Id, p + 0x44, 16);
+ SavedState = p[0x54];
+ return CheckBlock(p, 512, 0x40, 0x55);
+}
+
+/*
+struct CParentLocatorEntry
+{
+ UInt32 Code;
+ UInt32 DataSpace;
+ UInt32 DataLen;
+ UInt64 DataOffset;
+
+ bool Parse(const Byte *p);
+};
+bool CParentLocatorEntry::Parse(const Byte *p)
+{
+ G32(p + 0x00, Code);
+ G32(p + 0x04, DataSpace);
+ G32(p + 0x08, DataLen);
+ G32(p + 0x10, DataOffset);
+ return (Get32(p + 0x0C) == 0); // Resrved
+}
+*/
+
+struct CDynHeader
+{
+ // UInt64 DataOffset;
+ UInt64 TableOffset;
+ // UInt32 HeaderVersion;
+ UInt32 NumBlocks;
+ int BlockSizeLog;
+ UInt32 ParentTime;
+ Byte ParentId[16];
+ UString ParentName;
+ // CParentLocatorEntry ParentLocators[8];
+
+ bool Parse(const Byte *p);
+ UInt32 NumBitMapSectors() const
+ {
+ UInt32 numSectorsInBlock = (1 << (BlockSizeLog - 9));
+ return (numSectorsInBlock + 512 * 8 - 1) / (512 * 8);
+ }
+};
+
+static int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+bool CDynHeader::Parse(const Byte *p)
+{
+ if (memcmp(p, "cxsparse", 8) != 0)
+ return false;
+ // G64(p + 0x08, DataOffset);
+ G64(p + 0x10, TableOffset);
+ // G32(p + 0x18, HeaderVersion);
+ G32(p + 0x1C, NumBlocks);
+ BlockSizeLog = GetLog(Get32(p + 0x20));
+ if (BlockSizeLog < 9 || BlockSizeLog > 30)
+ return false;
+ G32(p + 0x38, ParentTime);
+ if (Get32(p + 0x3C) != 0) // reserved
+ return false;
+ memcpy(ParentId, p + 0x28, 16);
+ {
+ const int kNameLength = 256;
+ wchar_t *s = ParentName.GetBuffer(kNameLength);
+ for (unsigned i = 0; i < kNameLength; i++)
+ s[i] = Get16(p + 0x40 + i * 2);
+ s[kNameLength] = 0;
+ ParentName.ReleaseBuffer();
+ }
+ /*
+ for (int i = 0; i < 8; i++)
+ if (!ParentLocators[i].Parse(p + 0x240 + i * 24))
+ return false;
+ */
+ return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24);
+}
+
+class CHandler:
+ public IInStream,
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ UInt64 _phyPos;
+ UInt64 _phyLimit;
+
+ CFooter Footer;
+ CDynHeader Dyn;
+ CRecordVector<UInt32> Bat;
+ CByteBuffer BitMap;
+ UInt32 BitMapTag;
+ UInt32 NumUsedBlocks;
+ CMyComPtr<IInStream> Stream;
+ CMyComPtr<IInStream> ParentStream;
+ CHandler *Parent;
+
+ HRESULT Seek(UInt64 offset);
+ HRESULT InitAndSeek();
+ HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size);
+
+ bool NeedParent() const { return Footer.Type == kDiskType_Diff; }
+ UInt64 GetPackSize() const
+ { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; }
+
+ UString GetParentName() const
+ {
+ const CHandler *p = this;
+ UString res;
+ while (p && p->NeedParent())
+ {
+ if (!res.IsEmpty())
+ res += L" -> ";
+ res += p->Dyn.ParentName;
+ p = p->Parent;
+ }
+ return res;
+ }
+
+ bool IsOK() const
+ {
+ const CHandler *p = this;
+ while (p->NeedParent())
+ {
+ p = p->Parent;
+ if (p == 0)
+ return false;
+ }
+ return true;
+ }
+
+ HRESULT Open3();
+ HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level);
+
+public:
+ MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
+
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(offset, STREAM_SEEK_SET, NULL); }
+
+HRESULT CHandler::InitAndSeek()
+{
+ if (ParentStream)
+ {
+ RINOK(Parent->InitAndSeek());
+ }
+ _virtPos = _phyPos = 0;
+ BitMapTag = kUnusedBlock;
+ BitMap.SetCapacity(Dyn.NumBitMapSectors() << 9);
+ return Seek(0);
+}
+
+HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size)
+{
+ if (offset + size > _phyLimit)
+ return S_FALSE;
+ if (offset != _phyPos)
+ {
+ _phyPos = offset;
+ RINOK(Seek(offset));
+ }
+ HRESULT res = ReadStream_FALSE(Stream, data, size);
+ _phyPos += size;
+ return res;
+}
+
+HRESULT CHandler::Open3()
+{
+ RINOK(Stream->Seek(0, STREAM_SEEK_END, &_phyPos));
+ if (_phyPos < 512)
+ return S_FALSE;
+ const UInt32 kDynSize = 1024;
+ Byte buf[kDynSize];
+
+ _phyLimit = _phyPos;
+ RINOK(ReadPhy(_phyLimit - 512, buf, 512));
+ if (!Footer.Parse(buf))
+ return S_FALSE;
+ _phyLimit -= 512;
+
+ if (!Footer.ThereIsDynamic())
+ return S_OK;
+
+ RINOK(ReadPhy(0, buf + 512, 512));
+ if (memcmp(buf, buf + 512, 512) != 0)
+ return S_FALSE;
+
+ RINOK(ReadPhy(Footer.DataOffset, buf, kDynSize));
+ if (!Dyn.Parse(buf))
+ return S_FALSE;
+
+ if (Dyn.NumBlocks >= (UInt32)1 << 31)
+ return S_FALSE;
+ if (Footer.CurrentSize == 0)
+ {
+ if (Dyn.NumBlocks != 0)
+ return S_FALSE;
+ }
+ else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks)
+ return S_FALSE;
+
+ Bat.Reserve(Dyn.NumBlocks);
+ while ((UInt32)Bat.Size() < Dyn.NumBlocks)
+ {
+ RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, 512));
+ for (UInt32 j = 0; j < 512; j += 4)
+ {
+ UInt32 v = Get32(buf + j);
+ if (v != kUnusedBlock)
+ NumUsedBlocks++;
+ Bat.Add(v);
+ if ((UInt32)Bat.Size() >= Dyn.NumBlocks)
+ break;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= Footer.CurrentSize)
+ return (Footer.CurrentSize == _virtPos) ? S_OK: E_FAIL;
+ UInt64 rem = Footer.CurrentSize - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (size == 0)
+ return S_OK;
+ UInt32 blockIndex = (UInt32)(_virtPos >> Dyn.BlockSizeLog);
+ UInt32 blockSectIndex = Bat[blockIndex];
+ UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog;
+ UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ size = MyMin(blockSize - offsetInBlock, size);
+
+ HRESULT res = S_OK;
+ if (blockSectIndex == kUnusedBlock)
+ {
+ if (ParentStream)
+ {
+ RINOK(ParentStream->Seek(_virtPos, STREAM_SEEK_SET, NULL));
+ res = ParentStream->Read(data, size, &size);
+ }
+ else
+ memset(data, 0, size);
+ }
+ else
+ {
+ UInt64 newPos = (UInt64)blockSectIndex << 9;
+ if (BitMapTag != blockIndex)
+ {
+ RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.GetCapacity()));
+ BitMapTag = blockIndex;
+ }
+ RINOK(ReadPhy(newPos + BitMap.GetCapacity() + offsetInBlock, data, size));
+ for (UInt32 cur = 0; cur < size;)
+ {
+ UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur);
+ UInt32 bmi = offsetInBlock >> 9;
+ if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0)
+ {
+ if (ParentStream)
+ {
+ RINOK(ParentStream->Seek(_virtPos + cur, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(ParentStream, (Byte *)data + cur, rem));
+ }
+ else
+ {
+ const Byte *p = (const Byte *)data + cur;
+ for (UInt32 i = 0; i < rem; i++)
+ if (p[i] != 0)
+ return S_FALSE;
+ }
+ }
+ offsetInBlock += rem;
+ cur += rem;
+ }
+ }
+ if (processedSize != NULL)
+ *processedSize = size;
+ _virtPos += size;
+ return res;
+}
+
+STDMETHODIMP CHandler::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = Footer.CurrentSize + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+enum
+{
+ kpidParent = kpidUserDefined,
+ kpidSavedState
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidClusterSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR},
+ { L"Parent", kpidParent, VT_BSTR},
+ { NULL, kpidCreatorApp, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR},
+ { L"Saved State", kpidSavedState, VT_BOOL},
+ { NULL, kpidId, VT_BSTR}
+ };
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME}
+
+ /*
+ { NULL, kpidNumCyls, VT_UI4},
+ { NULL, kpidNumHeads, VT_UI4},
+ { NULL, kpidSectorsPerTrack, VT_UI4}
+ */
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+// VHD start time: 2000-01-01
+static const UInt64 kVhdTimeStartValue = (UInt64)3600 * 24 * (399 * 365 + 24 * 4);
+
+static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop)
+{
+ FILETIME ft, utc;
+ UInt64 v = (kVhdTimeStartValue + vhdTime) * 10000000;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+ // specification says that it's UTC time, but Virtual PC 6 writes local time. Why?
+ LocalFileTimeToFileTime(&ft, &utc);
+ prop = utc;
+}
+
+static void StringToAString(char *dest, UInt32 s)
+{
+ for (int i = 24; i >= 0; i -= 8)
+ {
+ Byte b = (Byte)((s >> i) & 0xFF);
+ if (b < 0x20 || b > 0x7F)
+ break;
+ *dest++ = b;
+ }
+ *dest = 0;
+}
+
+static void ConvertByteToHex(unsigned value, char *s)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ unsigned t = value & 0xF;
+ value >>= 4;
+ s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break;
+ case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break;
+ case kpidMethod:
+ {
+ AString s = Footer.GetTypeString();
+ if (NeedParent())
+ {
+ s += " -> ";
+ const CHandler *p = this;
+ while (p != 0 && p->NeedParent())
+ p = p->Parent;
+ if (p == 0)
+ s += '?';
+ else
+ s += p->Footer.GetTypeString();
+ }
+ prop = s;
+ break;
+ }
+ case kpidCreatorApp:
+ {
+ char s[16];
+ StringToAString(s, Footer.CreatorApp);
+ AString res = s;
+ res.Trim();
+ ConvertUInt32ToString(Footer.CreatorVersion >> 16, s);
+ res += ' ';
+ res += s;
+ res += '.';
+ ConvertUInt32ToString(Footer.CreatorVersion & 0xFFFF, s);
+ res += s;
+ prop = res;
+ break;
+ }
+ case kpidHostOS:
+ {
+ if (Footer.CreatorHostOS == 0x5769326b)
+ prop = "Windows";
+ else
+ {
+ char s[16];
+ StringToAString(s, Footer.CreatorHostOS);
+ prop = s;
+ }
+ break;
+ }
+ case kpidId:
+ {
+ char s[32 + 4];
+ for (int i = 0; i < 16; i++)
+ ConvertByteToHex(Footer.Id[i], s + i * 2);
+ s[32] = 0;
+ prop = s;
+ break;
+ }
+ case kpidSavedState: prop = Footer.SavedState ? true : false; break;
+ case kpidParent: if (NeedParent()) prop = GetParentName(); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level)
+{
+ Close();
+ Stream = stream;
+ if (level > 32)
+ return S_FALSE;
+ RINOK(Open3());
+ if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0)
+ return S_FALSE;
+ if (Footer.Type != kDiskType_Diff)
+ return S_OK;
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ if (openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback) != S_OK)
+ return S_FALSE;
+ CMyComPtr<IInStream> nextStream;
+ HRESULT res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream);
+ if (res == S_FALSE)
+ return S_OK;
+ RINOK(res);
+
+ Parent = new CHandler;
+ ParentStream = Parent;
+ return Parent->Open2(nextStream, this, openArchiveCallback, level + 1);
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ {
+ HRESULT res;
+ try
+ {
+ res = Open2(stream, NULL, openArchiveCallback, 0);
+ if (res == S_OK)
+ return S_OK;
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ Close();
+ return res;
+ }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ Bat.Clear();
+ NumUsedBlocks = 0;
+ Parent = 0;
+ Stream.Release();
+ ParentStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ switch(propID)
+ {
+ case kpidSize: prop = Footer.CurrentSize; break;
+ case kpidPackSize: prop = GetPackSize(); break;
+ case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break;
+ /*
+ case kpidNumCyls: prop = Footer.NumCyls(); break;
+ case kpidNumHeads: prop = Footer.NumHeads(); break;
+ case kpidSectorsPerTrack: prop = Footer.NumSectorsPerTrack(); break;
+ */
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ RINOK(extractCallback->SetTotal(Footer.CurrentSize));
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &outStream, askMode));
+ if (!testMode && !outStream)
+ return S_OK;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ int res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(0, &inStream);
+ if (hres == S_FALSE)
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ RINOK(hres);
+ HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres == S_OK)
+ {
+ if (copyCoderSpec->TotalSize == Footer.CurrentSize)
+ res = NExtract::NOperationResult::kOK;
+ }
+ else
+ {
+ if (hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ }
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(res);
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ if (Footer.IsFixed())
+ {
+ CLimitedInStream *streamSpec = new CLimitedInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->SetStream(Stream);
+ streamSpec->InitAndSeek(0, Footer.CurrentSize);
+ RINOK(streamSpec->SeekToStart());
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+ if (!Footer.ThereIsDynamic() || !IsOK())
+ return S_FALSE;
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ RINOK(InitAndSeek());
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"VHD", L"vhd", L".mbr", 0xDC, { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }, 10, false, CreateArc, 0 };
+
+REGISTER_ARC(Vhd)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandler.cpp
new file mode 100644
index 000000000..eaad1e7ca
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -0,0 +1,660 @@
+// WimHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringToInt.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "WimHandler.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NWim {
+
+#define WIM_DETAILS
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidShortName, VT_BSTR}
+
+ #ifdef WIM_DETAILS
+ , { NULL, kpidVolume, VT_UI4}
+ , { NULL, kpidOffset, VT_UI8}
+ , { NULL, kpidLinks, VT_UI4}
+ #endif
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidUnpackVer, VT_BSTR},
+ { NULL, kpidIsVolume, VT_BOOL},
+ { NULL, kpidVolume, VT_UI4},
+ { NULL, kpidNumVolumes, VT_UI4}
+};
+
+static bool ParseNumber64(const AString &s, UInt64 &res)
+{
+ const char *end;
+ if (s.Left(2) == "0x")
+ {
+ if (s.Length() == 2)
+ return false;
+ res = ConvertHexStringToUInt64((const char *)s + 2, &end);
+ }
+ else
+ {
+ if (s.IsEmpty())
+ return false;
+ res = ConvertStringToUInt64(s, &end);
+ }
+ return *end == 0;
+}
+
+static bool ParseNumber32(const AString &s, UInt32 &res)
+{
+ UInt64 res64;
+ if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32))
+ return false;
+ res = (UInt32)res64;
+ return true;
+}
+
+bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag)
+{
+ int index = item.FindSubTag(tag);
+ if (index >= 0)
+ {
+ const CXmlItem &timeItem = item.SubItems[index];
+ UInt32 low = 0, high = 0;
+ if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) &&
+ ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high))
+ {
+ ft.dwLowDateTime = low;
+ ft.dwHighDateTime = high;
+ return true;
+ }
+ }
+ return false;
+}
+
+void CImageInfo::Parse(const CXmlItem &item)
+{
+ CTimeDefined = ParseTime(item, CTime, "CREATIONTIME");
+ MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME");
+ NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name);
+ // IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index);
+}
+
+void CXml::ToUnicode(UString &s)
+{
+ size_t size = Data.GetCapacity();
+ if (size < 2 || (size & 1) != 0 || size > (1 << 24))
+ return;
+ const Byte *p = Data;
+ if (Get16(p) != 0xFEFF)
+ return;
+ wchar_t *chars = s.GetBuffer((int)size / 2);
+ for (size_t i = 2; i < size; i += 2)
+ *chars++ = (wchar_t)Get16(p + i);
+ *chars = 0;
+ s.ReleaseBuffer();
+}
+
+void CXml::Parse()
+{
+ UString s;
+ ToUnicode(s);
+ AString utf;
+ if (!ConvertUnicodeToUTF8(s, utf))
+ return;
+ ::CXml xml;
+ if (!xml.Parse(utf))
+ return;
+ if (xml.Root.Name != "WIM")
+ return;
+
+ for (int i = 0; i < xml.Root.SubItems.Size(); i++)
+ {
+ const CXmlItem &item = xml.Root.SubItems[i];
+ if (item.IsTagged("IMAGE"))
+ {
+ CImageInfo imageInfo;
+ imageInfo.Parse(item);
+ Images.Add(imageInfo);
+ }
+ }
+}
+
+static const char *kMethodLZX = "LZX";
+static const char *kMethodXpress = "XPress";
+static const char *kMethodCopy = "Copy";
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CImageInfo *image = NULL;
+ if (_xmls.Size() == 1)
+ {
+ const CXml &xml = _xmls[0];
+ if (xml.Images.Size() == 1)
+ image = &xml.Images[0];
+ }
+
+ switch(propID)
+ {
+ case kpidSize: prop = _db.GetUnpackSize(); break;
+ case kpidPackSize: prop = _db.GetPackSize(); break;
+
+ case kpidCTime:
+ if (_xmls.Size() == 1)
+ {
+ const CXml &xml = _xmls[0];
+ int index = -1;
+ for (int i = 0; i < xml.Images.Size(); i++)
+ {
+ const CImageInfo &image = xml.Images[i];
+ if (image.CTimeDefined)
+ if (index < 0 || ::CompareFileTime(&image.CTime, &xml.Images[index].CTime) < 0)
+ index = i;
+ }
+ if (index >= 0)
+ prop = xml.Images[index].CTime;
+ }
+ break;
+
+ case kpidMTime:
+ if (_xmls.Size() == 1)
+ {
+ const CXml &xml = _xmls[0];
+ int index = -1;
+ for (int i = 0; i < xml.Images.Size(); i++)
+ {
+ const CImageInfo &image = xml.Images[i];
+ if (image.MTimeDefined)
+ if (index < 0 || ::CompareFileTime(&image.MTime, &xml.Images[index].MTime) > 0)
+ index = i;
+ }
+ if (index >= 0)
+ prop = xml.Images[index].MTime;
+ }
+ break;
+
+ case kpidComment:
+ if (image != NULL)
+ {
+ if (_xmlInComments)
+ {
+ UString s;
+ _xmls[0].ToUnicode(s);
+ prop = s;
+ }
+ else if (image->NameDefined)
+ prop = image->Name;
+ }
+ break;
+
+ case kpidUnpackVer:
+ {
+ UInt32 ver1 = _version >> 16;
+ UInt32 ver2 = (_version >> 8) & 0xFF;
+ UInt32 ver3 = (_version) & 0xFF;
+
+ char s[16];
+ ConvertUInt32ToString(ver1, s);
+ AString res = s;
+ res += '.';
+ ConvertUInt32ToString(ver2, s);
+ res += s;
+ if (ver3 != 0)
+ {
+ res += '.';
+ ConvertUInt32ToString(ver3, s);
+ res += s;
+ }
+ prop = res;
+ break;
+ }
+
+ case kpidIsVolume:
+ if (_xmls.Size() > 0)
+ {
+ UInt16 volIndex = _xmls[0].VolIndex;
+ if (volIndex < _volumes.Size())
+ prop = (_volumes[volIndex].Header.NumParts > 1);
+ }
+ break;
+ case kpidVolume:
+ if (_xmls.Size() > 0)
+ {
+ UInt16 volIndex = _xmls[0].VolIndex;
+ if (volIndex < _volumes.Size())
+ prop = (UInt32)_volumes[volIndex].Header.PartNumber;
+ }
+ break;
+ case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break;
+ case kpidMethod:
+ {
+ bool lzx = false, xpress = false, copy = false;
+ for (int i = 0; i < _xmls.Size(); i++)
+ {
+ const CHeader &header = _volumes[_xmls[i].VolIndex].Header;
+ if (header.IsCompressed())
+ if (header.IsLzxMode())
+ lzx = true;
+ else
+ xpress = true;
+ else
+ copy = true;
+ }
+ AString res;
+ if (lzx)
+ res = kMethodLZX;
+ if (xpress)
+ {
+ if (!res.IsEmpty())
+ res += ' ';
+ res += kMethodXpress;
+ }
+ if (copy)
+ {
+ if (!res.IsEmpty())
+ res += ' ';
+ res += kMethodCopy;
+ }
+ prop = res;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ if (index < (UInt32)_db.SortedItems.Size())
+ {
+ int realIndex = _db.SortedItems[index];
+ const CItem &item = _db.Items[realIndex];
+ const CStreamInfo *si = NULL;
+ const CVolume *vol = NULL;
+ if (item.StreamIndex >= 0)
+ {
+ si = &_db.Streams[item.StreamIndex];
+ vol = &_volumes[si->PartNumber];
+ }
+
+ switch(propID)
+ {
+ case kpidPath:
+ if (item.HasMetadata)
+ prop = _db.GetItemPath(realIndex);
+ else
+ {
+ char sz[16];
+ ConvertUInt32ToString(item.StreamIndex, sz);
+ AString s = sz;
+ while (s.Length() < _nameLenForStreams)
+ s = '0' + s;
+ /*
+ if (si->Resource.IsFree())
+ prefix = "[Free]";
+ */
+ s = "[Files]" STRING_PATH_SEPARATOR + s;
+ prop = s;
+ }
+ break;
+ case kpidShortName: if (item.HasMetadata) prop = item.ShortName; break;
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidAttrib: if (item.HasMetadata) prop = item.Attrib; break;
+ case kpidCTime: if (item.HasMetadata) prop = item.CTime; break;
+ case kpidATime: if (item.HasMetadata) prop = item.ATime; break;
+ case kpidMTime: if (item.HasMetadata) prop = item.MTime; break;
+ case kpidPackSize: prop = si ? si->Resource.PackSize : (UInt64)0; break;
+ case kpidSize: prop = si ? si->Resource.UnpackSize : (UInt64)0; break;
+ case kpidMethod: if (si) prop = si->Resource.IsCompressed() ?
+ (vol->Header.IsLzxMode() ? kMethodLZX : kMethodXpress) : kMethodCopy; break;
+ #ifdef WIM_DETAILS
+ case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break;
+ case kpidOffset: if (si) prop = (UInt64)si->Resource.Offset; break;
+ case kpidLinks: prop = si ? (UInt32)si->RefCount : (UInt32)0; break;
+ #endif
+ }
+ }
+ else
+ {
+ index -= _db.SortedItems.Size();
+ {
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ char sz[16];
+ ConvertUInt32ToString(_xmls[index].VolIndex, sz);
+ prop = (AString)"[" + (AString)sz + "].xml";
+ break;
+ }
+ case kpidIsDir: prop = false; break;
+ case kpidPackSize:
+ case kpidSize: prop = (UInt64)_xmls[index].Data.GetCapacity(); break;
+ case kpidMethod: prop = kMethodCopy; break;
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CVolumeName
+{
+ // UInt32 _volIndex;
+ UString _before;
+ UString _after;
+public:
+ CVolumeName() {};
+
+ void InitName(const UString &name)
+ {
+ // _volIndex = 1;
+ int dotPos = name.ReverseFind('.');
+ if (dotPos < 0)
+ dotPos = name.Length();
+ _before = name.Left(dotPos);
+ _after = name.Mid(dotPos);
+ }
+
+ UString GetNextName(UInt32 index)
+ {
+ wchar_t s[16];
+ ConvertUInt32ToString(index, s);
+ return _before + (UString)s + _after;
+ }
+};
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ Close();
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+
+ CVolumeName seqName;
+ if (openArchiveCallback != NULL)
+ openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+
+ UInt32 numVolumes = 1;
+ int firstVolumeIndex = -1;
+ for (UInt32 i = 1; i <= numVolumes; i++)
+ {
+ CMyComPtr<IInStream> curStream;
+ if (i != 1)
+ {
+ UString fullName = seqName.GetNextName(i);
+ HRESULT result = openVolumeCallback->GetStream(fullName, &curStream);
+ if (result == S_FALSE)
+ continue;
+ if (result != S_OK)
+ return result;
+ if (!curStream)
+ break;
+ }
+ else
+ curStream = inStream;
+ CHeader header;
+ HRESULT res = NWim::ReadHeader(curStream, header);
+ if (res != S_OK)
+ {
+ if (i == 1)
+ return res;
+ if (res == S_FALSE)
+ continue;
+ return res;
+ }
+ _version = header.Version;
+ _isOldVersion = header.IsOldVersion();
+ if (firstVolumeIndex >= 0)
+ if (!header.AreFromOnArchive(_volumes[firstVolumeIndex].Header))
+ break;
+ if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream)
+ break;
+ CXml xml;
+ xml.VolIndex = header.PartNumber;
+ res = _db.Open(curStream, header, xml.Data, openArchiveCallback);
+ if (res != S_OK)
+ {
+ if (i == 1)
+ return res;
+ if (res == S_FALSE)
+ continue;
+ return res;
+ }
+
+ while (_volumes.Size() <= header.PartNumber)
+ _volumes.Add(CVolume());
+ CVolume &volume = _volumes[header.PartNumber];
+ volume.Header = header;
+ volume.Stream = curStream;
+
+ firstVolumeIndex = header.PartNumber;
+
+ bool needAddXml = true;
+ if (_xmls.Size() != 0)
+ if (xml.Data == _xmls[0].Data)
+ needAddXml = false;
+ if (needAddXml)
+ {
+ xml.Parse();
+ _xmls.Add(xml);
+ }
+
+ if (i == 1)
+ {
+ if (header.PartNumber != 1)
+ break;
+ if (!openVolumeCallback)
+ break;
+ numVolumes = header.NumParts;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
+ if (prop.vt != VT_BSTR)
+ break;
+ seqName.InitName(prop.bstrVal);
+ }
+ }
+ }
+
+ _db.DetectPathMode();
+ RINOK(_db.Sort(_db.SkipRoot));
+
+ wchar_t sz[16];
+ ConvertUInt32ToString(_db.Streams.Size(), sz);
+ _nameLenForStreams = MyStringLen(sz);
+
+ _xmlInComments = (_xmls.Size() == 1 && !_db.ShowImageNumber);
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _db.Clear();
+ _volumes.Clear();
+ _xmls.Clear();
+ _nameLenForStreams = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+
+ if (allFilesMode)
+ numItems = _db.SortedItems.Size() + _xmls.Size();
+ if (numItems == 0)
+ return S_OK;
+
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = allFilesMode ? i : indices[i];
+ if (index < (UInt32)_db.SortedItems.Size())
+ {
+ int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex;
+ if (streamIndex >= 0)
+ {
+ const CStreamInfo &si = _db.Streams[streamIndex];
+ totalSize += si.Resource.UnpackSize;
+ }
+ }
+ else
+ totalSize += _xmls[index - (UInt32)_db.SortedItems.Size()].Data.GetCapacity();
+ }
+
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 currentTotalPacked = 0;
+ UInt64 currentTotalUnPacked = 0;
+ UInt64 currentItemUnPacked, currentItemPacked;
+
+ int prevSuccessStreamIndex = -1;
+
+ CUnpacker unpacker;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; currentTotalUnPacked += currentItemUnPacked,
+ currentTotalPacked += currentItemPacked)
+ {
+ currentItemUnPacked = 0;
+ currentItemPacked = 0;
+
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = currentTotalUnPacked;
+
+ RINOK(lps->SetCur());
+ UInt32 index = allFilesMode ? i : indices[i];
+ i++;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ if (index >= (UInt32)_db.SortedItems.Size())
+ {
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ const CByteBuffer &data = _xmls[index - (UInt32)_db.SortedItems.Size()].Data;
+ currentItemUnPacked = data.GetCapacity();
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetCapacity()));
+ realOutStream.Release();
+ }
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ const CItem &item = _db.Items[_db.SortedItems[index]];
+ int streamIndex = item.StreamIndex;
+ if (streamIndex < 0)
+ {
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(item.HasStream() ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ const CStreamInfo &si = _db.Streams[streamIndex];
+ currentItemUnPacked = si.Resource.UnpackSize;
+ currentItemPacked = si.Resource.PackSize;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ if (streamIndex != prevSuccessStreamIndex || realOutStream)
+ {
+ Byte digest[20];
+ const CVolume &vol = _volumes[si.PartNumber];
+ HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(),
+ realOutStream, progress, digest);
+ if (res == S_OK)
+ {
+ if (memcmp(digest, si.Hash, kHashSize) == 0)
+ prevSuccessStreamIndex = streamIndex;
+ else
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ else if (res == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ return res;
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.SortedItems.Size();
+ if (!_xmlInComments)
+ *numItems += _xmls.Size();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandler.h
new file mode 100644
index 000000000..aa92069a5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandler.h
@@ -0,0 +1,77 @@
+// WimHandler.h
+
+#ifndef __ARCHIVE_WIM_HANDLER_H
+#define __ARCHIVE_WIM_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "Common/MyXml.h"
+
+#include "WimIn.h"
+
+namespace NArchive {
+namespace NWim {
+
+struct CVolume
+{
+ CHeader Header;
+ CMyComPtr<IInStream> Stream;
+};
+
+struct CImageInfo
+{
+ bool CTimeDefined;
+ bool MTimeDefined;
+ bool NameDefined;
+ // bool IndexDefined;
+
+ FILETIME CTime;
+ FILETIME MTime;
+ UString Name;
+ // UInt32 Index;
+
+ CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false)
+ // , IndexDefined(false)
+ {}
+ void Parse(const CXmlItem &item);
+};
+
+struct CXml
+{
+ CByteBuffer Data;
+ UInt16 VolIndex;
+ CObjectVector<CImageInfo> Images;
+
+ void ToUnicode(UString &s);
+ void Parse();
+};
+
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CDatabase _db;
+ UInt32 _version;
+ bool _isOldVersion;
+ CObjectVector<CVolume> _volumes;
+ CObjectVector<CXml> _xmls;
+ int _nameLenForStreams;
+ bool _xmlInComments;
+
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+class COutHandler:
+ public IOutArchive,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IOutArchive)
+ INTERFACE_IOutArchive(;)
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
new file mode 100644
index 000000000..50b879e79
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
@@ -0,0 +1,639 @@
+// WimHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Crypto/RandGen.h"
+#include "../../Crypto/Sha1.h"
+
+#include "WimHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NWim {
+
+struct CSha1Hash
+{
+ Byte Hash[kHashSize];
+};
+
+struct CHashList
+{
+ CRecordVector<CSha1Hash> Digests;
+ CIntVector Sorted;
+
+ int AddUnique(const CSha1Hash &h);
+};
+
+int CHashList::AddUnique(const CSha1Hash &h)
+{
+ int left = 0, right = Sorted.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ int index = Sorted[mid];
+ UInt32 i;
+ const Byte *hash2 = Digests[index].Hash;
+ for (i = 0; i < kHashSize; i++)
+ if (h.Hash[i] != hash2[i])
+ break;
+ if (i == kHashSize)
+ return index;
+ if (h.Hash[i] < hash2[i])
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Sorted.Insert(left, Digests.Add(h));
+ return -1;
+}
+
+struct CUpdateItem
+{
+ UString Name;
+ UInt64 Size;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ UInt32 Attrib;
+ bool IsDir;
+ int HashIndex;
+
+ CUpdateItem(): HashIndex(-1) {}
+};
+
+struct CDir
+{
+ int Index;
+ UString Name;
+ CObjectVector<CDir> Dirs;
+ CIntVector Files;
+
+ CDir(): Index(-1) {}
+ bool IsLeaf() const { return Index >= 0; }
+ UInt64 GetNumDirs() const;
+ UInt64 GetNumFiles() const;
+ CDir* AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index);
+};
+
+UInt64 CDir::GetNumDirs() const
+{
+ UInt64 num = Dirs.Size();
+ for (int i = 0; i < Dirs.Size(); i++)
+ num += Dirs[i].GetNumDirs();
+ return num;
+}
+
+UInt64 CDir::GetNumFiles() const
+{
+ UInt64 num = Files.Size();
+ for (int i = 0; i < Dirs.Size(); i++)
+ num += Dirs[i].GetNumFiles();
+ return num;
+}
+
+CDir* CDir::AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index)
+{
+ int left = 0, right = Dirs.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ CDir &d = Dirs[mid];
+ int compare = name.CompareNoCase(d.IsLeaf() ? items[Dirs[mid].Index].Name : d.Name);
+ if (compare == 0)
+ {
+ if (index >= 0)
+ d.Index = index;
+ return &d;
+ }
+ if (compare < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Dirs.Insert(left, CDir());
+ CDir &d = Dirs[left];
+ d.Index = index;
+ if (index < 0)
+ d.Name = name;
+ return &d;
+}
+
+
+STDMETHODIMP COutHandler::GetFileTimeType(UInt32 *type)
+{
+ *type = NFileTimeType::kWindows;
+ return S_OK;
+}
+
+static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &ft)
+{
+ ft.dwLowDateTime = ft.dwHighDateTime = 0;
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ ft = prop.filetime;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+#define Set16(p, d) SetUi16(p, d)
+#define Set32(p, d) SetUi32(p, d)
+#define Set64(p, d) SetUi64(p, d)
+
+void CResource::WriteTo(Byte *p) const
+{
+ Set64(p, PackSize);
+ p[7] = Flags;
+ Set64(p + 8, Offset);
+ Set64(p + 16, UnpackSize);
+}
+
+void CHeader::WriteTo(Byte *p) const
+{
+ memcpy(p, kSignature, kSignatureSize);
+ Set32(p + 8, kHeaderSizeMax);
+ Set32(p + 0xC, Version);
+ Set32(p + 0x10, Flags);
+ Set32(p + 0x14, ChunkSize);
+ memcpy(p + 0x18, Guid, 16);
+ Set16(p + 0x28, PartNumber);
+ Set16(p + 0x2A, NumParts);
+ Set32(p + 0x2C, NumImages);
+ OffsetResource.WriteTo(p + 0x30);
+ XmlResource.WriteTo(p + 0x48);
+ MetadataResource.WriteTo(p + 0x60);
+ IntegrityResource.WriteTo(p + 0x7C);
+ Set32(p + 0x78, BootIndex);
+ memset(p + 0x94, 0, 60);
+}
+
+void CStreamInfo::WriteTo(Byte *p) const
+{
+ Resource.WriteTo(p);
+ Set16(p + 0x18, PartNumber);
+ Set32(p + 0x1A, RefCount);
+ memcpy(p + 0x1E, Hash, kHashSize);
+}
+
+class CInStreamWithSha1:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ NCrypto::NSha1::CContext _sha;
+public:
+ MY_UNKNOWN_IMP1(IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ _sha.Init();
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt64 GetSize() const { return _size; }
+ void Final(Byte *digest) { _sha.Final(digest); }
+};
+
+STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ _sha.Update((const Byte *)data, realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+static void SetFileTimeToMem(Byte *p, const FILETIME &ft)
+{
+ Set32(p, ft.dwLowDateTime);
+ Set32(p + 4, ft.dwHighDateTime);
+}
+
+static size_t WriteItem(const CUpdateItem &item, Byte *p, const Byte *hash)
+{
+ int fileNameLen = item.Name.Length() * 2;
+ int fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+
+ size_t totalLen = ((kDirRecordSize + fileNameLen2 + 6) & ~7);
+ if (p)
+ {
+ memset(p, 0, totalLen);
+ Set64(p, totalLen);
+ Set64(p + 8, item.Attrib);
+ Set32(p + 0xC, (UInt32)(Int32)-1); // item.SecurityId
+ // Set64(p + 0x10, 0); // subdirOffset
+ SetFileTimeToMem(p + 0x28, item.CTime);
+ SetFileTimeToMem(p + 0x30, item.ATime);
+ SetFileTimeToMem(p + 0x38, item.MTime);
+ if (hash)
+ memcpy(p + 0x40, hash, kHashSize);
+ /*
+ else
+ memset(p + 0x40, 0, kHashSize);
+ */
+ // Set16(p + 98, 0); // shortNameLen
+ Set16(p + 100, (UInt16)fileNameLen);
+ for (int i = 0; i * 2 < fileNameLen; i++)
+ Set16(p + kDirRecordSize + i * 2, item.Name[i]);
+ }
+ return totalLen;
+}
+
+static void WriteTree(const CDir &tree, CRecordVector<CSha1Hash> &digests,
+ CUpdateItem &defaultDirItem,
+ CObjectVector<CUpdateItem> &updateItems, Byte *dest, size_t &pos)
+{
+ int i;
+ for (i = 0; i < tree.Files.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[tree.Files[i]];
+ pos += WriteItem(ui, dest ? dest + pos : NULL,
+ ui.HashIndex >= 0 ? digests[ui.HashIndex].Hash : NULL);
+ }
+
+ size_t posStart = pos;
+ for (i = 0; i < tree.Dirs.Size(); i++)
+ {
+ const CDir &subfolder = tree.Dirs[i];
+ CUpdateItem *item = &defaultDirItem;
+ if (subfolder.IsLeaf())
+ item = &updateItems[subfolder.Index];
+ else
+ defaultDirItem.Name = subfolder.Name;
+ pos += WriteItem(*item, NULL, NULL);
+ }
+
+ if (dest)
+ Set64(dest + pos, 0);
+
+ pos += 8;
+
+ for (i = 0; i < tree.Dirs.Size(); i++)
+ {
+ const CDir &subfolder = tree.Dirs[i];
+ if (dest)
+ {
+ CUpdateItem *item = &defaultDirItem;
+ if (subfolder.IsLeaf())
+ item = &updateItems[subfolder.Index];
+ else
+ defaultDirItem.Name = subfolder.Name;
+ size_t len = WriteItem(*item, dest + posStart, NULL);
+ Set64(dest + posStart + 0x10, pos);
+ posStart += len;
+ }
+ WriteTree(subfolder, digests, defaultDirItem, updateItems, dest, pos);
+ }
+}
+
+static void AddTag(AString &s, const char *name, const AString &value)
+{
+ s += "<";
+ s += name;
+ s += ">";
+ s += value;
+ s += "</";
+ s += name;
+ s += ">";
+}
+
+static void AddTagUInt64(AString &s, const char *name, UInt64 value)
+{
+ char temp[32];
+ ConvertUInt64ToString(value, temp);
+ AddTag(s, name, temp);
+}
+
+static AString TimeToXml(FILETIME &ft)
+{
+ AString res;
+ char temp[16] = { '0', 'x' };
+ ConvertUInt32ToHexWithZeros(ft.dwHighDateTime, temp + 2);
+ AddTag(res, "HIGHPART", temp);
+ ConvertUInt32ToHexWithZeros(ft.dwLowDateTime, temp + 2);
+ AddTag(res, "LOWPART", temp);
+ return res;
+}
+
+void CHeader::SetDefaultFields(bool useLZX)
+{
+ Version = kWimVersion;
+ Flags = NHeaderFlags::kRpFix;
+ ChunkSize = 0;
+ if (useLZX)
+ {
+ Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX;
+ ChunkSize = kChunkSize;
+ }
+ g_RandomGenerator.Generate(Guid, 16);
+ PartNumber = 1;
+ NumParts = 1;
+ NumImages = 1;
+ BootIndex = 0;
+ OffsetResource.Clear();
+ XmlResource.Clear();
+ MetadataResource.Clear();
+ IntegrityResource.Clear();
+}
+
+static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream,
+ CDir &rootFolder,
+ CObjectVector<CUpdateItem> &updateItems,
+ IArchiveUpdateCallback *callback)
+{
+ CMyComPtr<IOutStream> outStream;
+ RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
+ if (!outStream)
+ return E_NOTIMPL;
+
+ UInt64 complexity = 0;
+
+ int i;
+ for (i = 0; i < updateItems.Size(); i++)
+ complexity += updateItems[i].Size;
+
+ RINOK(callback->SetTotal(complexity));
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(callback, true);
+
+ complexity = 0;
+
+ bool useCompression = false;
+
+ CHeader header;
+ header.SetDefaultFields(useCompression);
+ Byte buf[kHeaderSizeMax];
+ header.WriteTo(buf);
+ RINOK(WriteStream(outStream, buf, kHeaderSizeMax));
+
+ CHashList hashes;
+ CObjectVector<CStreamInfo> streams;
+
+ UInt64 curPos = kHeaderSizeMax;
+ UInt64 unpackTotalSize = 0;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur());
+
+ CUpdateItem &ui = updateItems[i];
+ if (ui.IsDir || ui.Size == 0)
+ continue;
+
+ CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1;
+ CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec;
+
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = callback->GetStream(i, &fileInStream);
+ if (res != S_FALSE)
+ {
+ RINOK(res);
+ inShaStreamSpec->SetStream(fileInStream);
+ fileInStream.Release();
+ inShaStreamSpec->Init();
+ UInt64 offsetBlockSize = 0;
+ if (useCompression)
+ {
+ for (UInt64 t = kChunkSize; t < ui.Size; t += kChunkSize)
+ {
+ Byte buf[8];
+ SetUi32(buf, (UInt32)t);
+ RINOK(WriteStream(outStream, buf, 4));
+ offsetBlockSize += 4;
+ }
+ }
+
+ RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress));
+ ui.Size = copyCoderSpec->TotalSize;
+
+ CSha1Hash hash;
+ unpackTotalSize += ui.Size;
+ UInt64 packSize = offsetBlockSize + ui.Size;
+ inShaStreamSpec->Final(hash.Hash);
+ int index = hashes.AddUnique(hash);
+ if (index >= 0)
+ {
+ ui.HashIndex = index;
+ streams[index].RefCount++;
+ outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos);
+ outStream->SetSize(curPos);
+ }
+ else
+ {
+ ui.HashIndex = hashes.Digests.Size() - 1;
+ CStreamInfo s;
+ s.Resource.PackSize = packSize;
+ s.Resource.Offset = curPos;
+ s.Resource.UnpackSize = ui.Size;
+ s.Resource.Flags = 0;
+ if (useCompression)
+ s.Resource.Flags = NResourceFlags::Compressed;
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, hash.Hash, kHashSize);
+ streams.Add(s);
+ curPos += packSize;
+ }
+ }
+ fileInStream.Release();
+ complexity += ui.Size;
+ RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+ }
+
+
+ CUpdateItem ri;
+ FILETIME ft;
+ NTime::GetCurUtcFileTime(ft);
+ ri.MTime = ri.ATime = ri.CTime = ft;
+ ri.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+
+ const UInt32 kSecuritySize = 8;
+ size_t pos = kSecuritySize;
+ WriteTree(rootFolder, hashes.Digests, ri, updateItems, NULL, pos);
+
+ CByteBuffer meta;
+ meta.SetCapacity(pos);
+
+ // we can write 0 here only if there is no security data, imageX does it,
+ // but some programs expect size = 8
+ Set32((Byte *)meta, 8); // size of security data
+ Set32((Byte *)meta + 4, 0); // num security entries
+
+ pos = kSecuritySize;
+ WriteTree(rootFolder, hashes.Digests, ri, updateItems, (Byte *)meta, pos);
+
+ {
+ NCrypto::NSha1::CContext sha;
+ sha.Init();
+ sha.Update((const Byte *)meta, pos);
+ CSha1Hash digest;
+ sha.Final(digest.Hash);
+
+ CStreamInfo s;
+ s.Resource.PackSize = pos;
+ s.Resource.Offset = curPos;
+ s.Resource.UnpackSize = pos;
+ s.Resource.Flags = NResourceFlags::kMetadata;
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, digest.Hash, kHashSize);
+ streams.Add(s);
+ RINOK(WriteStream(outStream, (const Byte *)meta, pos));
+ meta.Free();
+ curPos += pos;
+ }
+
+
+ header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize;
+ header.OffsetResource.Offset = curPos;
+ header.OffsetResource.Flags = NResourceFlags::kMetadata;
+
+ for (i = 0; i < streams.Size(); i++)
+ {
+ Byte buf[kStreamInfoSize];
+ streams[i].WriteTo(buf);
+ RINOK(WriteStream(outStream, buf, kStreamInfoSize));
+ curPos += kStreamInfoSize;
+ }
+
+ AString xml = "<WIM>";
+ AddTagUInt64(xml, "TOTALBYTES", curPos);
+ xml += "<IMAGE INDEX=\"1\"><NAME>1</NAME>";
+ AddTagUInt64(xml, "DIRCOUNT", rootFolder.GetNumDirs());
+ AddTagUInt64(xml, "FILECOUNT", rootFolder.GetNumFiles());
+ AddTagUInt64(xml, "TOTALBYTES", unpackTotalSize);
+ NTime::GetCurUtcFileTime(ft);
+ AddTag(xml, "CREATIONTIME", TimeToXml(ft));
+ AddTag(xml, "LASTMODIFICATIONTIME", TimeToXml(ft));
+ xml += "</IMAGE></WIM>";
+
+ size_t xmlSize = (xml.Length() + 1) * 2;
+ meta.SetCapacity(xmlSize);
+ Set16((Byte *)meta, 0xFEFF);
+ for (i = 0; i < xml.Length(); i++)
+ Set16((Byte *)meta + 2 + i * 2, xml[i]);
+ RINOK(WriteStream(outStream, (const Byte *)meta, xmlSize));
+ meta.Free();
+
+ header.XmlResource.UnpackSize = header.XmlResource.PackSize = xmlSize;
+ header.XmlResource.Offset = curPos;
+ header.XmlResource.Flags = NResourceFlags::kMetadata;
+
+ outStream->Seek(0, STREAM_SEEK_SET, NULL);
+ header.WriteTo(buf);
+ return WriteStream(outStream, buf, kHeaderSizeMax);
+}
+
+STDMETHODIMP COutHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback)
+{
+ COM_TRY_BEGIN
+ CObjectVector<CUpdateItem> updateItems;
+ CDir tree;
+ tree.Dirs.Add(CDir());
+ CDir &rootFolder = tree.Dirs.Back();
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!callback)
+ return E_FAIL;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Attrib = (ui.IsDir ? FILE_ATTRIBUTE_DIRECTORY : 0);
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Attrib = prop.ulVal;
+ }
+
+ RINOK(GetTime(callback, i, kpidCTime, ui.CTime));
+ RINOK(GetTime(callback, i, kpidATime, ui.ATime));
+ RINOK(GetTime(callback, i, kpidMTime, ui.MTime));
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ ui.Size = prop.uhVal.QuadPart;
+ }
+
+ UString path;
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop));
+ if (prop.vt == VT_BSTR)
+ path = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+
+ CDir *curItem = &rootFolder;
+ int len = path.Length();
+ UString fileName;
+ for (int j = 0; j < len; j++)
+ {
+ wchar_t c = path[j];
+ if (c == WCHAR_PATH_SEPARATOR || c == L'/')
+ {
+ curItem = curItem->AddDir(updateItems, fileName, -1);
+ fileName.Empty();
+ }
+ else
+ fileName += c;
+ }
+
+ ui.Name = fileName;
+ updateItems.Add(ui);
+ if (ui.IsDir)
+ curItem->AddDir(updateItems, fileName, (int)i);
+ else
+ curItem->Files.Add(i);
+ }
+ return UpdateArchive(outStream, tree, updateItems, callback);
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimIn.cpp
new file mode 100644
index 000000000..c210804df
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -0,0 +1,855 @@
+// Archive/WimIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/IntToString.h"
+
+#include "../../Common/StreamUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/LimitedStreams.h"
+
+#include "../Common/OutStreamWithSha1.h"
+
+#include "WimIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NWim {
+
+namespace NXpress {
+
+class CDecoderFlusher
+{
+ CDecoder *m_Decoder;
+public:
+ bool NeedFlush;
+ CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ m_Decoder->Flush();
+ m_Decoder->ReleaseStreams();
+ }
+};
+
+HRESULT CDecoder::CodeSpec(UInt32 outSize)
+{
+ {
+ Byte levels[kMainTableSize];
+ for (unsigned i = 0; i < kMainTableSize; i += 2)
+ {
+ Byte b = m_InBitStream.DirectReadByte();
+ levels[i] = b & 0xF;
+ levels[i + 1] = b >> 4;
+ }
+ if (!m_MainDecoder.SetCodeLengths(levels))
+ return S_FALSE;
+ }
+
+ while (outSize > 0)
+ {
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < 256)
+ {
+ m_OutWindowStream.PutByte((Byte)number);
+ outSize--;
+ }
+ else
+ {
+ if (number >= kMainTableSize)
+ return S_FALSE;
+ UInt32 posLenSlot = number - 256;
+ UInt32 posSlot = posLenSlot / kNumLenSlots;
+ UInt32 len = posLenSlot % kNumLenSlots;
+ UInt32 distance = (1 << posSlot) - 1 + m_InBitStream.ReadBits(posSlot);
+
+ if (len == kNumLenSlots - 1)
+ {
+ len = m_InBitStream.DirectReadByte();
+ if (len == 0xFF)
+ {
+ len = m_InBitStream.DirectReadByte();
+ len |= (UInt32)m_InBitStream.DirectReadByte() << 8;
+ }
+ else
+ len += kNumLenSlots - 1;
+ }
+
+ len += kMatchMinLen;
+ UInt32 locLen = (len <= outSize ? len : outSize);
+
+ if (!m_OutWindowStream.CopyBlock(distance, locLen))
+ return S_FALSE;
+
+ len -= locLen;
+ outSize -= locLen;
+ if (len != 0)
+ return S_FALSE;
+ }
+ }
+ return S_OK;
+}
+
+const UInt32 kDictSize = (1 << kNumPosSlots);
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize)
+{
+ if (!m_OutWindowStream.Create(kDictSize) || !m_InBitStream.Create(1 << 16))
+ return E_OUTOFMEMORY;
+
+ CDecoderFlusher flusher(this);
+
+ m_InBitStream.SetStream(inStream);
+ m_OutWindowStream.SetStream(outStream);
+ m_InBitStream.Init();
+ m_OutWindowStream.Init(false);
+
+ RINOK(CodeSpec(outSize));
+
+ flusher.NeedFlush = false;
+ return Flush();
+}
+
+HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize)
+{
+ try { return CodeReal(inStream, outStream, outSize); }
+ catch(const CInBufferException &e) { return e.ErrorCode; } \
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}
+
+HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL));
+
+ CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream();
+ CMyComPtr<ISequentialInStream> limitedStream = limitedStreamSpec;
+ limitedStreamSpec->SetStream(inStream);
+
+ if (!copyCoder)
+ {
+ copyCoderSpec = new NCompress::CCopyCoder;
+ copyCoder = copyCoderSpec;
+ }
+ if (!resource.IsCompressed())
+ {
+ if (resource.PackSize != resource.UnpackSize)
+ return S_FALSE;
+ limitedStreamSpec->Init(resource.PackSize);
+ return copyCoder->Code(limitedStreamSpec, outStream, NULL, NULL, progress);
+ }
+ if (resource.UnpackSize == 0)
+ return S_OK;
+ UInt64 numChunks = (resource.UnpackSize + kChunkSize - 1) >> kChunkSizeBits;
+ unsigned entrySize = ((resource.UnpackSize > (UInt64)1 << 32) ? 8 : 4);
+ UInt64 sizesBufSize64 = entrySize * (numChunks - 1);
+ size_t sizesBufSize = (size_t)sizesBufSize64;
+ if (sizesBufSize != sizesBufSize64)
+ return E_OUTOFMEMORY;
+ if (sizesBufSize > sizesBuf.GetCapacity())
+ {
+ sizesBuf.Free();
+ sizesBuf.SetCapacity(sizesBufSize);
+ }
+ RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize));
+ const Byte *p = (const Byte *)sizesBuf;
+
+ if (lzxMode && !lzxDecoder)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder(true);
+ lzxDecoder = lzxDecoderSpec;
+ RINOK(lzxDecoderSpec->SetParams(kChunkSizeBits));
+ }
+
+ UInt64 baseOffset = resource.Offset + sizesBufSize64;
+ UInt64 outProcessed = 0;
+ for (UInt32 i = 0; i < (UInt32)numChunks; i++)
+ {
+ UInt64 offset = 0;
+ if (i > 0)
+ {
+ offset = (entrySize == 4) ? Get32(p): Get64(p);
+ p += entrySize;
+ }
+ UInt64 nextOffset = resource.PackSize - sizesBufSize64;
+ if (i + 1 < (UInt32)numChunks)
+ nextOffset = (entrySize == 4) ? Get32(p): Get64(p);
+ if (nextOffset < offset)
+ return S_FALSE;
+
+ RINOK(inStream->Seek(baseOffset + offset, STREAM_SEEK_SET, NULL));
+ UInt64 inSize = nextOffset - offset;
+ limitedStreamSpec->Init(inSize);
+
+ if (progress)
+ {
+ RINOK(progress->SetRatioInfo(&offset, &outProcessed));
+ }
+
+ UInt32 outSize = kChunkSize;
+ if (outProcessed + outSize > resource.UnpackSize)
+ outSize = (UInt32)(resource.UnpackSize - outProcessed);
+ UInt64 outSize64 = outSize;
+ if (inSize == outSize)
+ {
+ RINOK(copyCoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
+ }
+ else
+ {
+ if (lzxMode)
+ {
+ lzxDecoderSpec->SetKeepHistory(false);
+ RINOK(lzxDecoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
+ }
+ else
+ {
+ RINOK(xpressDecoder.Code(limitedStreamSpec, outStream, outSize));
+ }
+ }
+ outProcessed += outSize;
+ }
+ return S_OK;
+}
+
+HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest)
+{
+ COutStreamWithSha1 *shaStreamSpec = new COutStreamWithSha1();
+ CMyComPtr<ISequentialOutStream> shaStream = shaStreamSpec;
+ shaStreamSpec->SetStream(outStream);
+ shaStreamSpec->Init(digest != NULL);
+ HRESULT result = Unpack(inStream, resource, lzxMode, shaStream, progress);
+ if (digest)
+ shaStreamSpec->Final(digest);
+ return result;
+}
+
+static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool lzxMode, CByteBuffer &buf, Byte *digest)
+{
+ size_t size = (size_t)resource.UnpackSize;
+ if (size != resource.UnpackSize)
+ return E_OUTOFMEMORY;
+ buf.Free();
+ buf.SetCapacity(size);
+
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream();
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->Init((Byte *)buf, size);
+
+ CUnpacker unpacker;
+ return unpacker.Unpack(inStream, resource, lzxMode, outStream, NULL, digest);
+}
+
+void CResource::Parse(const Byte *p)
+{
+ Flags = p[7];
+ PackSize = Get64(p) & (((UInt64)1 << 56) - 1);
+ Offset = Get64(p + 8);
+ UnpackSize = Get64(p + 16);
+}
+
+#define GetResource(p, res) res.Parse(p)
+
+static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s)
+{
+ s.Resource.Parse(p);
+ if (oldVersion)
+ {
+ s.PartNumber = 1;
+ s.Id = Get32(p + 24);
+ s.RefCount = Get32(p + 28);
+ memcpy(s.Hash, p + 32, kHashSize);
+ }
+ else
+ {
+ s.PartNumber = Get16(p + 24);
+ s.RefCount = Get32(p + 26);
+ memcpy(s.Hash, p + 30, kHashSize);
+ }
+}
+
+static const wchar_t *kLongPath = L"[LongPath]";
+
+UString CDatabase::GetItemPath(const int index1) const
+{
+ int size = 0;
+ int index = index1;
+ int newLevel;
+ for (newLevel = 0;; newLevel = 1)
+ {
+ const CItem &item = Items[index];
+ index = item.Parent;
+ if (index >= 0 || !SkipRoot)
+ size += item.Name.Length() + newLevel;
+ if (index < 0)
+ break;
+ if ((UInt32)size >= ((UInt32)1 << 16))
+ return kLongPath;
+ }
+
+ wchar_t temp[16];
+ int imageLen = 0;
+ if (ShowImageNumber)
+ {
+ ConvertUInt32ToString(-1 - index, temp);
+ imageLen = MyStringLen(temp);
+ size += imageLen + 1;
+ }
+ if ((UInt32)size >= ((UInt32)1 << 16))
+ return kLongPath;
+
+ UString path;
+ wchar_t *s = path.GetBuffer(size);
+ s[size] = 0;
+ if (ShowImageNumber)
+ {
+ memcpy(s, temp, imageLen * sizeof(wchar_t));
+ s[imageLen] = WCHAR_PATH_SEPARATOR;
+ }
+
+ index = index1;
+
+ for (newLevel = 0;; newLevel = 1)
+ {
+ const CItem &item = Items[index];
+ index = item.Parent;
+ if (index >= 0 || !SkipRoot)
+ {
+ if (newLevel)
+ s[--size] = WCHAR_PATH_SEPARATOR;
+ size -= item.Name.Length();
+ memcpy(s + size, item.Name, sizeof(wchar_t) * item.Name.Length());
+ }
+ if (index < 0)
+ {
+ path.ReleaseBuffer();
+ return path;
+ }
+ }
+}
+
+static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
+{
+ ft->dwLowDateTime = Get32(p);
+ ft->dwHighDateTime = Get32(p + 4);
+}
+
+static HRESULT ReadName(const Byte *p, int size, UString &dest)
+{
+ if (size == 0)
+ return S_OK;
+ if (Get16(p + size) != 0)
+ return S_FALSE;
+ wchar_t *s = dest.GetBuffer(size / 2);
+ for (int i = 0; i <= size; i += 2)
+ *s++ = Get16(p + i);
+ dest.ReleaseBuffer();
+ return S_OK;
+}
+
+HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
+{
+ if ((pos & 7) != 0)
+ return S_FALSE;
+
+ int prevIndex = -1;
+ for (int numItems = 0;; numItems++)
+ {
+ if (OpenCallback)
+ {
+ UInt64 numFiles = Items.Size();
+ if ((numFiles & 0x3FF) == 0)
+ {
+ RINOK(OpenCallback->SetCompleted(&numFiles, NULL));
+ }
+ }
+ size_t rem = DirSize - pos;
+ if (pos < DirStartOffset || pos > DirSize || rem < 8)
+ return S_FALSE;
+ const Byte *p = DirData + pos;
+ UInt64 len = Get64(p);
+ if (len == 0)
+ {
+ if (parent < 0 && numItems != 1)
+ SkipRoot = false;
+ DirProcessed += 8;
+ return S_OK;
+ }
+ if ((len & 7) != 0 || rem < len)
+ return S_FALSE;
+ if (!IsOldVersion)
+ if (len < 0x28)
+ return S_FALSE;
+ DirProcessed += (size_t)len;
+ if (DirProcessed > DirSize)
+ return S_FALSE;
+ int extraOffset = 0;
+ if (IsOldVersion)
+ {
+ if (len < 0x40 || (/* Get32(p + 12) == 0 && */ Get32(p + 0x14) != 0))
+ {
+ extraOffset = 0x10;
+ }
+ }
+ else if (Get64(p + 8) == 0)
+ extraOffset = 0x24;
+ if (extraOffset)
+ {
+ if (prevIndex == -1)
+ return S_FALSE;
+ UInt32 fileNameLen = Get16(p + extraOffset);
+ if ((fileNameLen & 1) != 0)
+ return S_FALSE;
+ /* Probably different versions of ImageX can use different number of
+ additional ZEROs. So we don't use exact check. */
+ UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+ if (((extraOffset + 2 + fileNameLen2 + 6) & ~7) > len)
+ return S_FALSE;
+
+ UString name;
+ RINOK(ReadName(p + extraOffset + 2, fileNameLen, name));
+
+ CItem &prevItem = Items[prevIndex];
+ if (name.IsEmpty() && !prevItem.HasStream())
+ {
+ if (IsOldVersion)
+ prevItem.Id = Get32(p + 8);
+ else
+ memcpy(prevItem.Hash, p + 0x10, kHashSize);
+ }
+ else
+ {
+ CItem item;
+ item.Name = prevItem.Name + L':' + name;
+ item.CTime = prevItem.CTime;
+ item.ATime = prevItem.ATime;
+ item.MTime = prevItem.MTime;
+ if (IsOldVersion)
+ {
+ item.Id = Get32(p + 8);
+ memset(item.Hash, 0, kHashSize);
+ }
+ else
+ memcpy(item.Hash, p + 0x10, kHashSize);
+ item.Attrib = 0;
+ item.Order = Order++;
+ item.Parent = parent;
+ Items.Add(item);
+ }
+ pos += (size_t)len;
+ continue;
+ }
+
+ UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize;
+ if (len < dirRecordSize)
+ return S_FALSE;
+
+ CItem item;
+ item.Attrib = Get32(p + 8);
+ // item.SecurityId = Get32(p + 0xC);
+ UInt64 subdirOffset = Get64(p + 0x10);
+ UInt32 timeOffset = IsOldVersion ? 0x18: 0x28;
+ GetFileTimeFromMem(p + timeOffset, &item.CTime);
+ GetFileTimeFromMem(p + timeOffset + 8, &item.ATime);
+ GetFileTimeFromMem(p + timeOffset + 16, &item.MTime);
+ if (IsOldVersion)
+ {
+ item.Id = Get32(p + 0x10);
+ memset(item.Hash, 0, kHashSize);
+ }
+ else
+ {
+ memcpy(item.Hash, p + 0x40, kHashSize);
+ }
+ // UInt32 numStreams = Get16(p + dirRecordSize - 6);
+ UInt32 shortNameLen = Get16(p + dirRecordSize - 4);
+ UInt32 fileNameLen = Get16(p + dirRecordSize - 2);
+
+ if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0)
+ return S_FALSE;
+
+ UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2);
+ UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+
+ if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len)
+ return S_FALSE;
+ p += dirRecordSize;
+
+ RINOK(ReadName(p, fileNameLen, item.Name));
+ RINOK(ReadName(p + fileNameLen2, shortNameLen, item.ShortName));
+
+ if (parent < 0 && (shortNameLen || fileNameLen || !item.IsDir()))
+ SkipRoot = false;
+
+ /*
+ // there are some extra data for some files.
+ p -= dirRecordSize;
+ p += ((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7);
+ if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len)
+ p = p;
+ */
+
+ /*
+ if (parent >= 0)
+ {
+ UString s = GetItemPath(parent) + L"\\" + item.Name;
+ printf("\n%s %8x %S", item.IsDir() ? "D" : " ", (int)subdirOffset, (const wchar_t *)s);
+ }
+ */
+
+ if (fileNameLen == 0 && item.IsDir() && !item.HasStream())
+ item.Attrib = 0x10; // some swm archives have system/hidden attributes for root
+
+ item.Parent = parent;
+ prevIndex = Items.Add(item);
+ if (item.IsDir() && subdirOffset != 0)
+ {
+ RINOK(ParseDirItem((size_t)subdirOffset, prevIndex));
+ }
+ Items[prevIndex].Order = Order++;
+ pos += (size_t)len;
+ }
+}
+
+HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent)
+{
+ DirData = buf;
+ DirSize = buf.GetCapacity();
+
+ size_t pos = 0;
+ if (DirSize < 8)
+ return S_FALSE;
+ const Byte *p = DirData;
+ UInt32 totalLength = Get32(p);
+ if (IsOldVersion)
+ {
+ for (pos = 4;; pos += 8)
+ {
+ if (pos + 4 > DirSize)
+ return S_FALSE;
+ UInt32 n = Get32(p + pos);
+ if (n == 0)
+ break;
+ if (pos + 8 > DirSize)
+ return S_FALSE;
+ totalLength += Get32(p + pos + 4);
+ if (totalLength > DirSize)
+ return S_FALSE;
+ }
+ pos += totalLength + 4;
+ pos = (pos + 7) & ~(size_t)7;
+ if (pos > DirSize)
+ return S_FALSE;
+ }
+ else
+ {
+
+ // UInt32 numEntries = Get32(p + 4);
+ pos += 8;
+ {
+ /*
+ CRecordVector<UInt64> entryLens;
+ UInt64 sum = 0;
+ for (UInt32 i = 0; i < numEntries; i++)
+ {
+ if (pos + 8 > DirSize)
+ return S_FALSE;
+ UInt64 len = Get64(p + pos);
+ entryLens.Add(len);
+ sum += len;
+ pos += 8;
+ }
+ pos += (size_t)sum; // skip security descriptors
+ while ((pos & 7) != 0)
+ pos++;
+ if (pos != totalLength)
+ return S_FALSE;
+ */
+ if (totalLength == 0)
+ pos = 8;
+ else if (totalLength < 8)
+ return S_FALSE;
+ else
+ pos = totalLength;
+ }
+ }
+ DirStartOffset = DirProcessed = pos;
+ RINOK(ParseDirItem(pos, parent));
+ if (DirProcessed == DirSize)
+ return S_OK;
+ /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), but
+ reference to that folder is empty */
+ if (DirProcessed == DirSize - 8 && DirProcessed - DirStartOffset == 112 &&
+ Get64(p + DirSize - 8) == 0)
+ return S_OK;
+ return S_FALSE;
+}
+
+HRESULT CHeader::Parse(const Byte *p)
+{
+ UInt32 headerSize = Get32(p + 8);
+ Version = Get32(p + 0x0C);
+ Flags = Get32(p + 0x10);
+ if (!IsSupported())
+ return S_FALSE;
+ ChunkSize = Get32(p + 0x14);
+ if (ChunkSize != kChunkSize && ChunkSize != 0)
+ return S_FALSE;
+ int offset;
+ if (IsOldVersion())
+ {
+ if (headerSize != 0x60)
+ return S_FALSE;
+ memset(Guid, 0, 16);
+ offset = 0x18;
+ PartNumber = 1;
+ NumParts = 1;
+ }
+ else
+ {
+ if (headerSize < 0x74)
+ return S_FALSE;
+ memcpy(Guid, p + 0x18, 16);
+ PartNumber = Get16(p + 0x28);
+ NumParts = Get16(p + 0x2A);
+ offset = 0x2C;
+ if (IsNewVersion())
+ {
+ NumImages = Get32(p + offset);
+ offset += 4;
+ }
+ }
+ GetResource(p + offset, OffsetResource);
+ GetResource(p + offset + 0x18, XmlResource);
+ GetResource(p + offset + 0x30, MetadataResource);
+ if (IsNewVersion())
+ {
+ if (headerSize < 0xD0)
+ return S_FALSE;
+ BootIndex = Get32(p + 0x48);
+ IntegrityResource.Parse(p + offset + 0x4C);
+ }
+ return S_OK;
+}
+
+const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 };
+
+HRESULT ReadHeader(IInStream *inStream, CHeader &h)
+{
+ Byte p[kHeaderSizeMax];
+ RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax));
+ if (memcmp(p, kSignature, kSignatureSize) != 0)
+ return S_FALSE;
+ return h.Parse(p);
+}
+
+static HRESULT ReadStreams(bool oldVersion, IInStream *inStream, const CHeader &h, CDatabase &db)
+{
+ CByteBuffer offsetBuf;
+ RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL));
+ size_t i;
+ size_t streamInfoSize = oldVersion ? kStreamInfoSize + 2 : kStreamInfoSize;
+ for (i = 0; offsetBuf.GetCapacity() - i >= streamInfoSize; i += streamInfoSize)
+ {
+ CStreamInfo s;
+ GetStream(oldVersion, (const Byte *)offsetBuf + i, s);
+ if (s.PartNumber == h.PartNumber)
+ db.Streams.Add(s);
+ }
+ return (i == offsetBuf.GetCapacity()) ? S_OK : S_FALSE;
+}
+
+static bool IsEmptySha(const Byte *data)
+{
+ for (int i = 0; i < kHashSize; i++)
+ if (data[i] != 0)
+ return false;
+ return true;
+}
+
+HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback)
+{
+ OpenCallback = openCallback;
+ IsOldVersion = h.IsOldVersion();
+ RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL));
+ RINOK(ReadStreams(h.IsOldVersion(), inStream, h, *this));
+ bool needBootMetadata = !h.MetadataResource.IsEmpty();
+ Order = 0;
+ if (h.PartNumber == 1)
+ {
+ int imageIndex = 1;
+ for (int i = 0; i < Streams.Size(); i++)
+ {
+ // if (imageIndex > 1) break;
+ const CStreamInfo &si = Streams[i];
+ if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber)
+ continue;
+ Byte hash[kHashSize];
+ CByteBuffer metadata;
+ RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash));
+ if (memcmp(hash, si.Hash, kHashSize) != 0 &&
+ !(h.IsOldVersion() && IsEmptySha(si.Hash)))
+ return S_FALSE;
+ NumImages++;
+ RINOK(ParseImageDirs(metadata, -(int)(++imageIndex)));
+ if (needBootMetadata)
+ if (h.MetadataResource.Offset == si.Resource.Offset)
+ needBootMetadata = false;
+ }
+ }
+
+ if (needBootMetadata)
+ {
+ CByteBuffer metadata;
+ RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL));
+ RINOK(ParseImageDirs(metadata, -1));
+ NumImages++;
+ }
+ return S_OK;
+}
+
+
+static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */)
+{
+ int res = MyCompare(p1->PartNumber, p2->PartNumber);
+ if (res != 0)
+ return res;
+ return MyCompare(p1->Resource.Offset, p2->Resource.Offset);
+}
+
+static int CompareIDs(const int *p1, const int *p2, void *param)
+{
+ const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
+ return MyCompare(streams[*p1].Id, streams[*p2].Id);
+}
+
+static int CompareHashRefs(const int *p1, const int *p2, void *param)
+{
+ const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
+ return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize);
+}
+
+static int FindId(const CRecordVector<CStreamInfo> &streams,
+ const CIntVector &sortedByHash, UInt32 id)
+{
+ int left = 0, right = streams.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ int streamIndex = sortedByHash[mid];
+ UInt32 id2 = streams[streamIndex].Id;
+ if (id == id2)
+ return streamIndex;
+ if (id < id2)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+static int FindHash(const CRecordVector<CStreamInfo> &streams,
+ const CIntVector &sortedByHash, const Byte *hash)
+{
+ int left = 0, right = streams.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ int streamIndex = sortedByHash[mid];
+ UInt32 i;
+ const Byte *hash2 = streams[streamIndex].Hash;
+ for (i = 0; i < kHashSize; i++)
+ if (hash[i] != hash2[i])
+ break;
+ if (i == kHashSize)
+ return streamIndex;
+ if (hash[i] < hash2[i])
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+static int CompareItems(const int *a1, const int *a2, void *param)
+{
+ const CObjectVector<CItem> &items = ((CDatabase *)param)->Items;
+ const CItem &i1 = items[*a1];
+ const CItem &i2 = items[*a2];
+
+ if (i1.IsDir() != i2.IsDir())
+ return i1.IsDir() ? 1 : -1;
+ int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
+ if (res != 0)
+ return res;
+ return MyCompare(i1.Order, i2.Order);
+}
+
+HRESULT CDatabase::Sort(bool skipRootDir)
+{
+ Streams.Sort(CompareStreamsByPos, NULL);
+
+ {
+ CIntVector sortedByHash;
+ {
+ for (int i = 0; i < Streams.Size(); i++)
+ sortedByHash.Add(i);
+ if (IsOldVersion)
+ sortedByHash.Sort(CompareIDs, &Streams);
+ else
+ sortedByHash.Sort(CompareHashRefs, &Streams);
+ }
+
+ for (int i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ item.StreamIndex = -1;
+ if (item.HasStream())
+ if (IsOldVersion)
+ item.StreamIndex = FindId(Streams, sortedByHash, item.Id);
+ else
+ item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash);
+ }
+ }
+
+ {
+ CRecordVector<bool> used;
+ int i;
+ for (i = 0; i < Streams.Size(); i++)
+ {
+ const CStreamInfo &s = Streams[i];
+ used.Add(s.Resource.IsMetadata() && s.PartNumber == 1);
+ // used.Add(false);
+ }
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ if (item.StreamIndex >= 0)
+ used[item.StreamIndex] = true;
+ }
+ for (i = 0; i < Streams.Size(); i++)
+ if (!used[i])
+ {
+ CItem item;
+ item.StreamIndex = i;
+ item.HasMetadata = false;
+ Items.Add(item);
+ }
+ }
+
+ SortedItems.Reserve(Items.Size());
+ for (int i = (skipRootDir ? 1 : 0); i < Items.Size(); i++)
+ SortedItems.Add(i);
+ SortedItems.Sort(CompareItems, this);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimIn.h
new file mode 100644
index 000000000..da3e28a56
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimIn.h
@@ -0,0 +1,297 @@
+// Archive/WimIn.h
+
+#ifndef __ARCHIVE_WIM_IN_H
+#define __ARCHIVE_WIM_IN_H
+
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/LzxDecoder.h"
+
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace NWim {
+
+namespace NXpress {
+
+class CBitStream
+{
+ CInBuffer m_Stream;
+ UInt32 m_Value;
+ unsigned m_BitPos;
+public:
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); }
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+
+ void Init() { m_Stream.Init(); m_BitPos = 0; }
+ // UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - m_BitPos / 8; }
+ Byte DirectReadByte() { return m_Stream.ReadByte(); }
+
+ void Normalize()
+ {
+ if (m_BitPos < 16)
+ {
+ Byte b0 = m_Stream.ReadByte();
+ Byte b1 = m_Stream.ReadByte();
+ m_Value = (m_Value << 8) | b1;
+ m_Value = (m_Value << 8) | b0;
+ m_BitPos += 16;
+ }
+ }
+
+ UInt32 GetValue(unsigned numBits)
+ {
+ Normalize();
+ return (m_Value >> (m_BitPos - numBits)) & ((1 << numBits) - 1);
+ }
+
+ void MovePos(unsigned numBits) { m_BitPos -= numBits; }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ m_BitPos -= numBits;
+ return res;
+ }
+};
+
+const unsigned kNumHuffmanBits = 16;
+const UInt32 kMatchMinLen = 3;
+const UInt32 kNumLenSlots = 16;
+const UInt32 kNumPosSlots = 16;
+const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
+const UInt32 kMainTableSize = 256 + kNumPosLenSlots;
+
+class CDecoder
+{
+ CBitStream m_InBitStream;
+ CLzOutWindow m_OutWindowStream;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+
+ HRESULT CodeSpec(UInt32 size);
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
+public:
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+ HRESULT Flush() { return m_OutWindowStream.Flush(); }
+ HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
+};
+
+}
+
+namespace NResourceFlags
+{
+ const Byte kFree = 1;
+ const Byte kMetadata = 2;
+ const Byte Compressed = 4;
+ const Byte Spanned = 4;
+}
+
+struct CResource
+{
+ UInt64 PackSize;
+ UInt64 Offset;
+ UInt64 UnpackSize;
+ Byte Flags;
+
+ void Clear()
+ {
+ PackSize = 0;
+ Offset = 0;
+ UnpackSize = 0;
+ Flags = 0;
+ }
+ void Parse(const Byte *p);
+ void WriteTo(Byte *p) const;
+ bool IsFree() const { return (Flags & NResourceFlags::kFree) != 0; }
+ bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; }
+ bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; }
+ bool IsEmpty() const { return (UnpackSize == 0); }
+};
+
+namespace NHeaderFlags
+{
+ const UInt32 kCompression = 2;
+ const UInt32 kSpanned = 8;
+ const UInt32 kRpFix = 0x80;
+ const UInt32 kXPRESS = 0x20000;
+ const UInt32 kLZX = 0x40000;
+}
+
+const UInt32 kWimVersion = 0x010D00;
+const UInt32 kHeaderSizeMax = 0xD0;
+const UInt32 kSignatureSize = 8;
+extern const Byte kSignature[kSignatureSize];
+const unsigned kChunkSizeBits = 15;
+const UInt32 kChunkSize = (1 << kChunkSizeBits);
+
+struct CHeader
+{
+ UInt32 Version;
+ UInt32 Flags;
+ UInt32 ChunkSize;
+ Byte Guid[16];
+ UInt16 PartNumber;
+ UInt16 NumParts;
+ UInt32 NumImages;
+
+ CResource OffsetResource;
+ CResource XmlResource;
+ CResource MetadataResource;
+ CResource IntegrityResource;
+ UInt32 BootIndex;
+
+ void SetDefaultFields(bool useLZX);
+
+ void WriteTo(Byte *p) const;
+ HRESULT Parse(const Byte *p);
+ bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; }
+ bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0 || (Flags & NHeaderFlags::kXPRESS) != 0 ) ; }
+ bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; }
+ bool IsSpanned() const { return (!IsCompressed() || (Flags & NHeaderFlags::kSpanned) != 0); }
+ bool IsOldVersion() const { return (Version <= 0x010A00); }
+ bool IsNewVersion() const { return (Version > 0x010C00); }
+
+ bool AreFromOnArchive(const CHeader &h)
+ {
+ return (memcmp(Guid, h.Guid, sizeof(Guid)) == 0) && (h.NumParts == NumParts);
+ }
+};
+
+const UInt32 kHashSize = 20;
+const UInt32 kStreamInfoSize = 24 + 2 + 4 + kHashSize;
+
+struct CStreamInfo
+{
+ CResource Resource;
+ UInt16 PartNumber;
+ UInt32 RefCount;
+ UInt32 Id;
+ BYTE Hash[kHashSize];
+
+ void WriteTo(Byte *p) const;
+};
+
+const UInt32 kDirRecordSizeOld = 62;
+const UInt32 kDirRecordSize = 102;
+
+struct CItem
+{
+ UString Name;
+ UString ShortName;
+ UInt32 Attrib;
+ // UInt32 SecurityId;
+ BYTE Hash[kHashSize];
+ UInt32 Id;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ // UInt32 ReparseTag;
+ // UInt64 HardLink;
+ // UInt16 NumStreams;
+ int StreamIndex;
+ int Parent;
+ unsigned Order;
+ bool HasMetadata;
+ CItem(): HasMetadata(true), StreamIndex(-1), Id(0) {}
+ bool IsDir() const { return HasMetadata && ((Attrib & 0x10) != 0); }
+ bool HasStream() const
+ {
+ for (unsigned i = 0; i < kHashSize; i++)
+ if (Hash[i] != 0)
+ return true;
+ return Id != 0;
+ }
+};
+
+class CDatabase
+{
+ const Byte *DirData;
+ size_t DirSize;
+ size_t DirProcessed;
+ size_t DirStartOffset;
+ int Order;
+ IArchiveOpenCallback *OpenCallback;
+
+ HRESULT ParseDirItem(size_t pos, int parent);
+ HRESULT ParseImageDirs(const CByteBuffer &buf, int parent);
+
+public:
+ CRecordVector<CStreamInfo> Streams;
+ CObjectVector<CItem> Items;
+ CIntVector SortedItems;
+ int NumImages;
+ bool SkipRoot;
+ bool ShowImageNumber;
+
+ bool IsOldVersion;
+
+ UInt64 GetUnpackSize() const
+ {
+ UInt64 res = 0;
+ for (int i = 0; i < Streams.Size(); i++)
+ res += Streams[i].Resource.UnpackSize;
+ return res;
+ }
+
+ UInt64 GetPackSize() const
+ {
+ UInt64 res = 0;
+ for (int i = 0; i < Streams.Size(); i++)
+ res += Streams[i].Resource.PackSize;
+ return res;
+ }
+
+ void Clear()
+ {
+ Streams.Clear();
+ Items.Clear();
+ SortedItems.Clear();
+ NumImages = 0;
+
+ SkipRoot = true;
+ ShowImageNumber = true;
+ IsOldVersion = false;
+ }
+
+ UString GetItemPath(int index) const;
+
+ HRESULT Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback);
+
+ void DetectPathMode()
+ {
+ ShowImageNumber = (NumImages != 1);
+ }
+
+ HRESULT Sort(bool skipRootDir);
+};
+
+HRESULT ReadHeader(IInStream *inStream, CHeader &header);
+
+class CUnpacker
+{
+ NCompress::CCopyCoder *copyCoderSpec;
+ CMyComPtr<ICompressCoder> copyCoder;
+
+ NCompress::NLzx::CDecoder *lzxDecoderSpec;
+ CMyComPtr<ICompressCoder> lzxDecoder;
+
+ NXpress::CDecoder xpressDecoder;
+
+ CByteBuffer sizesBuf;
+ HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+public:
+ HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimRegister.cpp
new file mode 100644
index 000000000..8da914360
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Wim/WimRegister.cpp
@@ -0,0 +1,18 @@
+// WimRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "WimHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NWim::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NWim::COutHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Wim)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/XarHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/XarHandler.cpp
new file mode 100644
index 000000000..e7d88b6c7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/XarHandler.cpp
@@ -0,0 +1,588 @@
+// XarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/MyXml.h"
+#include "Common/StringToInt.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BZip2Decoder.h"
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+#include "Common/OutStreamWithSha1.h"
+
+#define XAR_SHOW_RAW
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+namespace NArchive {
+namespace NXar {
+
+struct CFile
+{
+ AString Name;
+ AString Method;
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt64 Offset;
+
+ // UInt32 mode;
+ UInt64 CTime;
+ UInt64 MTime;
+ UInt64 ATime;
+
+ bool IsDir;
+ bool HasData;
+
+ bool Sha1IsDefined;
+ Byte Sha1[20];
+ // bool packSha1IsDefined;
+ // Byte packSha1[20];
+
+ int Parent;
+
+ CFile(): IsDir(false), HasData(false), Sha1IsDefined(false),
+ /* packSha1IsDefined(false), */
+ Parent(-1), Size(0), PackSize(0), CTime(0), MTime(0), ATime(0) {}
+};
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ UInt64 _dataStartPos;
+ CMyComPtr<IInStream> _inStream;
+ AString _xml;
+ CObjectVector<CFile> _files;
+
+ HRESULT Open2(IInStream *stream);
+ HRESULT Extract(IInStream *stream);
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14);
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+static bool ParseNumber(const char *s, int size, UInt32 &res)
+{
+ const char *end;
+ res = (UInt32)ConvertStringToUInt64(s, &end);
+ return (end - s == size);
+}
+
+static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res)
+{
+ AString s = item.GetSubStringForTag(name);
+ const char *end;
+ res = ConvertStringToUInt64(s, &end);
+ return (end - (const char *)s == s.Length());
+}
+
+static UInt64 ParseTime(const CXmlItem &item, const char *name)
+{
+ AString s = item.GetSubStringForTag(name);
+ if (s.Length() < 20)
+ return 0;
+ const char *p = s;
+ if (p[ 4] != '-' || p[ 7] != '-' || p[10] != 'T' ||
+ p[13] != ':' || p[16] != ':' || p[19] != 'Z')
+ return 0;
+ UInt32 year, month, day, hour, min, sec;
+ if (!ParseNumber(p, 4, year )) return 0;
+ if (!ParseNumber(p + 5, 2, month)) return 0;
+ if (!ParseNumber(p + 8, 2, day )) return 0;
+ if (!ParseNumber(p + 11, 2, hour )) return 0;
+ if (!ParseNumber(p + 14, 2, min )) return 0;
+ if (!ParseNumber(p + 17, 2, sec )) return 0;
+
+ UInt64 numSecs;
+ if (!NWindows::NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
+ return 0;
+ return numSecs * 10000000;
+}
+
+static bool HexToByte(char c, Byte &res)
+{
+ if (c >= '0' && c <= '9') res = c - '0';
+ else if (c >= 'A' && c <= 'F') res = c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f') res = c - 'a' + 10;
+ else return false;
+ return true;
+}
+
+#define METHOD_NAME_ZLIB "zlib"
+
+static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest)
+{
+ int index = item.FindSubTag(name);
+ if (index < 0)
+ return false;
+ const CXmlItem &checkItem = item.SubItems[index];
+ AString style = checkItem.GetPropertyValue("style");
+ if (style == "SHA1")
+ {
+ AString s = checkItem.GetSubString();
+ if (s.Length() != 40)
+ return false;
+ for (int i = 0; i < s.Length(); i += 2)
+ {
+ Byte b0, b1;
+ if (!HexToByte(s[i], b0) || !HexToByte(s[i + 1], b1))
+ return false;
+ digest[i / 2] = (b0 << 4) | b1;
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int parent)
+{
+ if (!item.IsTag)
+ return true;
+ if (item.Name == "file")
+ {
+ CFile file;
+ file.Parent = parent;
+ parent = files.Size();
+ file.Name = item.GetSubStringForTag("name");
+ AString type = item.GetSubStringForTag("type");
+ if (type == "directory")
+ file.IsDir = true;
+ else if (type == "file")
+ file.IsDir = false;
+ else
+ return false;
+
+ int dataIndex = item.FindSubTag("data");
+ if (dataIndex >= 0 && !file.IsDir)
+ {
+ file.HasData = true;
+ const CXmlItem &dataItem = item.SubItems[dataIndex];
+ if (!ParseUInt64(dataItem, "size", file.Size))
+ return false;
+ if (!ParseUInt64(dataItem, "length", file.PackSize))
+ return false;
+ if (!ParseUInt64(dataItem, "offset", file.Offset))
+ return false;
+ file.Sha1IsDefined = ParseSha1(dataItem, "extracted-checksum", file.Sha1);
+ // file.packSha1IsDefined = ParseSha1(dataItem, "archived-checksum", file.packSha1);
+ int encodingIndex = dataItem.FindSubTag("encoding");
+ if (encodingIndex >= 0)
+ {
+ const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex];
+ if (encodingItem.IsTag)
+ {
+ AString s = encodingItem.GetPropertyValue("style");
+ if (s.Length() >= 0)
+ {
+ AString appl = "application/";
+ if (s.Left(appl.Length()) == appl)
+ {
+ s = s.Mid(appl.Length());
+ AString xx = "x-";
+ if (s.Left(xx.Length()) == xx)
+ {
+ s = s.Mid(xx.Length());
+ if (s == "gzip")
+ s = METHOD_NAME_ZLIB;
+ }
+ }
+ file.Method = s;
+ }
+ }
+ }
+ }
+
+ file.CTime = ParseTime(item, "ctime");
+ file.MTime = ParseTime(item, "mtime");
+ file.ATime = ParseTime(item, "atime");
+ files.Add(file);
+ }
+ for (int i = 0; i < item.SubItems.Size(); i++)
+ if (!AddItem(item.SubItems[i], files, parent))
+ return false;
+ return true;
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ UInt64 archiveStartPos;
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, &archiveStartPos));
+
+ const UInt32 kHeaderSize = 0x1C;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
+
+ UInt32 size = Get16(buf + 4);
+ // UInt32 ver = Get16(buf + 6); // == 0
+ if (Get32(buf) != 0x78617221 || size != kHeaderSize)
+ return S_FALSE;
+
+ UInt64 packSize = Get64(buf + 8);
+ UInt64 unpackSize = Get64(buf + 0x10);
+ // UInt32 checkSumAlogo = Get32(buf + 0x18);
+
+ if (unpackSize >= kXmlSizeMax)
+ return S_FALSE;
+
+ _dataStartPos = archiveStartPos + kHeaderSize + packSize;
+
+ char *ss = _xml.GetBuffer((int)unpackSize + 1);
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStreamLim(inStreamLimSpec);
+ inStreamLimSpec->SetStream(stream);
+ inStreamLimSpec->Init(packSize);
+
+ CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec);
+ outStreamLimSpec->Init((Byte *)ss, (size_t)unpackSize);
+
+ RINOK(zlibCoder->Code(inStreamLim, outStreamLim, NULL, NULL, NULL));
+
+ if (outStreamLimSpec->GetPos() != (size_t)unpackSize)
+ return S_FALSE;
+
+ ss[(size_t)unpackSize] = 0;
+ _xml.ReleaseBuffer();
+
+ CXml xml;
+ if (!xml.Parse(_xml))
+ return S_FALSE;
+
+ if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1)
+ return S_FALSE;
+ const CXmlItem &toc = xml.Root.SubItems[0];
+ if (!toc.IsTagged("toc"))
+ return S_FALSE;
+ if (!AddItem(toc, _files, -1))
+ return S_FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ if (Open2(stream) != S_OK)
+ return S_FALSE;
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _files.Clear();
+ _xml.Empty();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _files.Size()
+ #ifdef XAR_SHOW_RAW
+ + 1
+ #endif
+ ;
+ return S_OK;
+}
+
+static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
+{
+ if (t != 0)
+ {
+ FILETIME ft;
+ ft.dwLowDateTime = (UInt32)(t);
+ ft.dwHighDateTime = (UInt32)(t >> 32);
+ prop = ft;
+ }
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ #ifdef XAR_SHOW_RAW
+ if ((int)index == _files.Size())
+ {
+ switch(propID)
+ {
+ case kpidPath: prop = L"[TOC].xml"; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)_xml.Length(); break;
+ }
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ UString name;
+ if (!item.Method.IsEmpty() && ConvertUTF8ToUnicode(item.Method, name))
+ prop = name;
+ break;
+ }
+ case kpidPath:
+ {
+ AString path;
+ int cur = index;
+ do
+ {
+ const CFile &item = _files[cur];
+ AString s = item.Name;
+ if (s.IsEmpty())
+ s = "unknown";
+ if (path.IsEmpty())
+ path = s;
+ else
+ path = s + CHAR_PATH_SEPARATOR + path;
+ cur = item.Parent;
+ }
+ while (cur >= 0);
+
+ UString name;
+ if (ConvertUTF8ToUnicode(path, name))
+ prop = name;
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidSize: if (!item.IsDir) prop = item.Size; break;
+ case kpidPackSize: if (!item.IsDir) prop = item.PackSize; break;
+
+ case kpidMTime: TimeToProp(item.MTime, prop); break;
+ case kpidCTime: TimeToProp(item.CTime, prop); break;
+ case kpidATime: TimeToProp(item.ATime, prop); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _files.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ int index = (int)(allFilesMode ? i : indices[i]);
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ totalSize += _xml.Length();
+ else
+ #endif
+ totalSize += _files[index].Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentPackTotal = 0;
+ UInt64 currentUnpTotal = 0;
+ UInt64 currentPackSize = 0;
+ UInt64 currentUnpSize = 0;
+
+ const UInt32 kZeroBufSize = (1 << 14);
+ CByteBuffer zeroBuf;
+ zeroBuf.SetCapacity(kZeroBufSize);
+ memset(zeroBuf, 0, kZeroBufSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+ CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
+
+ NCompress::NDeflate::NDecoder::CCOMCoder *deflateCoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
+ CMyComPtr<ICompressCoder> deflateCoder = deflateCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
+ inStreamSpec->SetStream(_inStream);
+
+
+ CLimitedSequentialOutStream *outStreamLimSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamLimSpec);
+
+ COutStreamWithSha1 *outStreamSha1Spec = new COutStreamWithSha1;
+ {
+ CMyComPtr<ISequentialOutStream> outStreamSha1(outStreamSha1Spec);
+ outStreamLimSpec->SetStream(outStreamSha1);
+ }
+
+ for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
+ {
+ lps->InSize = currentPackTotal;
+ lps->OutSize = currentUnpTotal;
+ currentPackSize = 0;
+ currentUnpSize = 0;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (index < _files.Size())
+ {
+ const CFile &item = _files[index];
+ if (item.IsDir)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ outStreamSha1Spec->SetStream(realOutStream);
+ realOutStream.Release();
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ {
+ outStreamSha1Spec->Init(false);
+ outStreamLimSpec->Init(_xml.Length());
+ RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
+ currentPackSize = currentUnpSize = _xml.Length();
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ if (item.HasData)
+ {
+ currentPackSize = item.PackSize;
+ currentUnpSize = item.Size;
+
+ RINOK(_inStream->Seek(_dataStartPos + item.Offset, STREAM_SEEK_SET, NULL));
+ inStreamSpec->Init(item.PackSize);
+ outStreamSha1Spec->Init(item.Sha1IsDefined);
+ outStreamLimSpec->Init(item.Size);
+ HRESULT res = S_OK;
+
+ ICompressCoder *coder = NULL;
+ if (item.Method.IsEmpty() || item.Method == "octet-stream")
+ if (item.PackSize == item.Size)
+ coder = copyCoder;
+ else
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ else if (item.Method == METHOD_NAME_ZLIB)
+ coder = zlibCoder;
+ else if (item.Method == "bzip2")
+ coder = bzip2Coder;
+ else
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+
+ if (coder)
+ res = coder->Code(inStream, outStream, NULL, NULL, progress);
+
+ if (res != S_OK)
+ {
+ if (!outStreamLimSpec->IsFinishedOK())
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (res != S_FALSE)
+ return res;
+ if (opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ if (outStreamLimSpec->IsFinishedOK() &&
+ outStreamSha1Spec->GetSize() == item.Size)
+ {
+ if (!outStreamLimSpec->IsFinishedOK())
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ else if (item.Sha1IsDefined)
+ {
+ Byte digest[NCrypto::NSha1::kDigestSize];
+ outStreamSha1Spec->Final(digest);
+ if (memcmp(digest, item.Sha1, NCrypto::NSha1::kDigestSize) != 0)
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ }
+ else
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ }
+ }
+ outStreamSha1Spec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NXar::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Xar", L"xar", 0, 0xE1, { 'x', 'a', 'r', '!', 0, 0x1C }, 6, false, CreateArc, 0 };
+
+REGISTER_ARC(Xar)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/XzHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/XzHandler.cpp
new file mode 100644
index 000000000..64b7a5863
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/XzHandler.cpp
@@ -0,0 +1,707 @@
+// XzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/XzCrc64.h"
+#include "../../../C/XzEnc.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+
+#include "../ICoder.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "IArchive.h"
+
+#include "Common/HandlerOut.h"
+
+using namespace NWindows;
+
+namespace NCompress {
+namespace NLzma2 {
+
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);
+
+}}
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+namespace NArchive {
+namespace NXz {
+
+struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit;
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ #ifndef EXTRACT_ONLY
+ public IOutArchive,
+ public ISetProperties,
+ public COutHandler,
+ #endif
+ public CMyUnknownImp
+{
+ Int64 _startPosition;
+ UInt64 _packSize;
+ UInt64 _unpackSize;
+ UInt64 _numBlocks;
+ AString _methodsString;
+ bool _useSeq;
+ UInt64 _unpackSizeDefined;
+ UInt64 _packSizeDefined;
+
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ UInt32 _crcSize;
+
+ void Init()
+ {
+ _crcSize = 4;
+ COutHandler::Init();
+ }
+
+ HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
+ #ifndef EXTRACT_ONLY
+ MY_QUERYINTERFACE_ENTRY(IOutArchive)
+ MY_QUERYINTERFACE_ENTRY(ISetProperties)
+ #endif
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+
+ #ifndef EXTRACT_ONLY
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+ #endif
+
+ CHandler();
+};
+
+CHandler::CHandler()
+{
+ Init();
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidNumBlocks, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+static inline void AddHexToString(AString &res, Byte value)
+{
+ res += GetHex((Byte)(value >> 4));
+ res += GetHex((Byte)(value & 0xF));
+}
+
+static AString ConvertUInt32ToString(UInt32 value)
+{
+ char temp[32];
+ ::ConvertUInt32ToString(value, temp);
+ return temp;
+}
+
+static AString Lzma2PropToString(int prop)
+{
+ if ((prop & 1) == 0)
+ return ConvertUInt32ToString(prop / 2 + 12);
+ AString res;
+ char c;
+
+ UInt32 size = (2 | ((prop) & 1)) << ((prop) / 2 + 1);
+
+ if (prop > 17)
+ {
+ res = ConvertUInt32ToString(size >> 10);
+ c = 'm';
+ }
+ else
+ {
+ res = ConvertUInt32ToString(size);
+ c = 'k';
+ }
+ return res + c;
+}
+
+struct CMethodNamePair
+{
+ UInt32 Id;
+ const char *Name;
+};
+
+static CMethodNamePair g_NamePairs[] =
+{
+ { XZ_ID_Subblock, "SB" },
+ { XZ_ID_Delta, "Delta" },
+ { XZ_ID_X86, "x86" },
+ { XZ_ID_PPC, "PPC" },
+ { XZ_ID_IA64, "IA64" },
+ { XZ_ID_ARM, "ARM" },
+ { XZ_ID_ARMT, "ARMT" },
+ { XZ_ID_SPARC, "SPARC" },
+ { XZ_ID_LZMA2, "LZMA2" }
+};
+
+static AString GetMethodString(const CXzFilter &f)
+{
+ AString s;
+
+ for (int i = 0; i < sizeof(g_NamePairs) / sizeof(g_NamePairs[i]); i++)
+ if (g_NamePairs[i].Id == f.id)
+ s = g_NamePairs[i].Name;
+ if (s.IsEmpty())
+ {
+ char temp[32];
+ ::ConvertUInt64ToString(f.id, temp);
+ s = temp;
+ }
+
+ if (f.propsSize > 0)
+ {
+ s += ':';
+ if (f.id == XZ_ID_LZMA2 && f.propsSize == 1)
+ s += Lzma2PropToString(f.props[0]);
+ else if (f.id == XZ_ID_Delta && f.propsSize == 1)
+ s += ConvertUInt32ToString((UInt32)f.props[0] + 1);
+ else
+ {
+ s += '[';
+ for (UInt32 bi = 0; bi < f.propsSize; bi++)
+ AddHexToString(s, f.props[bi]);
+ s += ']';
+ }
+ }
+ return s;
+}
+
+static void AddString(AString &dest, const AString &src)
+{
+ if (!dest.IsEmpty())
+ dest += ' ';
+ dest += src;
+}
+
+static const char *kChecks[] =
+{
+ "NoCheck",
+ "CRC32",
+ NULL,
+ NULL,
+ "CRC64",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SHA256",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static AString GetCheckString(const CXzs &xzs)
+{
+ size_t i;
+ UInt32 mask = 0;
+ for (i = 0; i < xzs.num; i++)
+ mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags));
+ AString s;
+ for (i = 0; i <= XZ_CHECK_MASK; i++)
+ if (((mask >> i) & 1) != 0)
+ {
+ AString s2;
+ if (kChecks[i])
+ s2 = kChecks[i];
+ else
+ s2 = "Check-" + ConvertUInt32ToString((UInt32)i);
+ AddString(s, s2);
+ }
+ return s;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidNumBlocks: if (!_useSeq) prop = _numBlocks; break;
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSize: if (_unpackSizeDefined) prop = _unpackSize; break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+struct COpenCallbackWrap
+{
+ ICompressProgress p;
+ IArchiveOpenCallback *OpenCallback;
+ HRESULT Res;
+ COpenCallbackWrap(IArchiveOpenCallback *progress);
+};
+
+static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */)
+{
+ COpenCallbackWrap *p = (COpenCallbackWrap *)pp;
+ p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
+ return (SRes)p->Res;
+}
+
+COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback)
+{
+ p.Progress = OpenCallbackProgress;
+ OpenCallback = callback;
+ Res = SZ_OK;
+}
+
+struct CXzsCPP
+{
+ CXzs p;
+ CXzsCPP() { Xzs_Construct(&p); }
+ ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
+};
+
+HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback)
+{
+ CSeekInStreamWrap inStreamImp(inStream);
+
+ CLookToRead lookStream;
+ LookToRead_CreateVTable(&lookStream, True);
+ lookStream.realStream = &inStreamImp.p;
+ LookToRead_Init(&lookStream);
+
+ COpenCallbackWrap openWrap(callback);
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize));
+ RINOK(callback->SetTotal(NULL, &_packSize));
+
+ CXzsCPP xzs;
+ SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &_startPosition, &openWrap.p, &g_Alloc);
+ if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0)
+ res = SZ_OK;
+ if (res == SZ_OK)
+ {
+ _packSize -= _startPosition;
+ _unpackSize = Xzs_GetUnpackSize(&xzs.p);
+ _unpackSizeDefined = _packSizeDefined = true;
+ _numBlocks = (UInt64)Xzs_GetNumBlocks(&xzs.p);
+
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ CXzStreamFlags st;
+ CSeqInStreamWrap inStreamWrap(inStream);
+ SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p);
+
+ if (res2 == SZ_OK)
+ {
+ CXzBlock block;
+ Bool isIndex;
+ UInt32 headerSizeRes;
+ res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes);
+ if (res2 == SZ_OK && !isIndex)
+ {
+ int numFilters = XzBlock_GetNumFilters(&block);
+ for (int i = 0; i < numFilters; i++)
+ AddString(_methodsString, GetMethodString(block.filters[i]));
+ }
+ }
+ AddString(_methodsString, GetCheckString(xzs.p));
+ }
+
+ if (res != SZ_OK || _startPosition != 0)
+ {
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ CXzStreamFlags st;
+ CSeqInStreamWrap inStreamWrap(inStream);
+ SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p);
+ if (res2 == SZ_OK)
+ {
+ res = res2;
+ _startPosition = 0;
+ _useSeq = True;
+ _unpackSizeDefined = _packSizeDefined = false;
+ }
+ }
+ if (res == SZ_ERROR_NO_ARCHIVE)
+ return S_FALSE;
+ RINOK(SResToHRESULT(res));
+ _stream = inStream;
+ _seqStream = inStream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ return Open2(inStream, callback);
+ }
+ catch(...) { return S_FALSE; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _numBlocks = 0;
+ _useSeq = true;
+ _unpackSizeDefined = _packSizeDefined = false;
+ _methodsString.Empty();
+ _stream.Release();
+ _seqStream.Release();
+ return S_OK;
+}
+
+class CSeekToSeqStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+public:
+ CMyComPtr<ISequentialInStream> Stream;
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ return Stream->Read(data, size, processedSize);
+}
+
+STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; }
+
+struct CXzUnpackerCPP
+{
+ Byte *InBuf;
+ Byte *OutBuf;
+ CXzUnpacker p;
+ CXzUnpackerCPP(): InBuf(0), OutBuf(0) {}
+ ~CXzUnpackerCPP()
+ {
+ XzUnpacker_Free(&p);
+ MyFree(InBuf);
+ MyFree(OutBuf);
+ }
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ }
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ CCompressProgressWrap progressWrap(progress);
+
+ SRes res;
+
+ const UInt32 kInBufSize = 1 << 15;
+ const UInt32 kOutBufSize = 1 << 21;
+
+ UInt32 inPos = 0;
+ UInt32 inSize = 0;
+ UInt32 outPos = 0;
+ CXzUnpackerCPP xzu;
+ res = XzUnpacker_Create(&xzu.p, &g_Alloc);
+ if (res == SZ_OK)
+ {
+ xzu.InBuf = (Byte *)MyAlloc(kInBufSize);
+ xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize);
+ if (xzu.InBuf == 0 || xzu.OutBuf == 0)
+ res = SZ_ERROR_MEM;
+ }
+ if (res == SZ_OK)
+ for (;;)
+ {
+ if (inPos == inSize)
+ {
+ inPos = inSize = 0;
+ RINOK(_seqStream->Read(xzu.InBuf, kInBufSize, &inSize));
+ }
+
+ SizeT inLen = inSize - inPos;
+ SizeT outLen = kOutBufSize - outPos;
+ ECoderStatus status;
+ res = XzUnpacker_Code(&xzu.p,
+ xzu.OutBuf + outPos, &outLen,
+ xzu.InBuf + inPos, &inLen,
+ (inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status);
+
+ // printf("\n_inPos = %6d inLen = %5d, outLen = %5d", inPos, inLen, outLen);
+
+ inPos += (UInt32)inLen;
+ outPos += (UInt32)outLen;
+ lps->InSize += inLen;
+ lps->OutSize += outLen;
+
+ bool finished = (((inLen == 0) && (outLen == 0)) || res != SZ_OK);
+
+ if (outPos == kOutBufSize || finished)
+ {
+ if (realOutStream && outPos > 0)
+ {
+ RINOK(WriteStream(realOutStream, xzu.OutBuf, outPos));
+ }
+ outPos = 0;
+ }
+ if (finished)
+ {
+ _packSize = lps->InSize;
+ _unpackSize = lps->OutSize;
+ _packSizeDefined = _unpackSizeDefined = true;
+ if (res == SZ_OK)
+ {
+ if (status == CODER_STATUS_NEEDS_MORE_INPUT)
+ {
+ if (XzUnpacker_IsStreamWasFinished(&xzu.p))
+ _packSize -= xzu.p.padSize;
+ else
+ res = SZ_ERROR_DATA;
+ }
+ else
+ res = SZ_ERROR_DATA;
+ }
+ break;
+ }
+ RINOK(lps->SetCur());
+ }
+
+ Int32 opRes;
+ switch(res)
+ {
+ case SZ_OK:
+ opRes = NExtract::NOperationResult::kOK; break;
+ case SZ_ERROR_UNSUPPORTED:
+ opRes = NExtract::NOperationResult::kUnSupportedMethod; break;
+ case SZ_ERROR_CRC:
+ opRes = NExtract::NOperationResult::kCRCError; break;
+ case SZ_ERROR_DATA:
+ case SZ_ERROR_ARCHIVE:
+ case SZ_ERROR_NO_ARCHIVE:
+ opRes = NExtract::NOperationResult::kDataError; break;
+ default:
+ return SResToHRESULT(res);
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifndef EXTRACT_ONLY
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CSeqOutStreamWrap seqOutStream(outStream);
+
+ if (numItems == 0)
+ {
+ SRes res = Xz_EncodeEmpty(&seqOutStream.p);
+ return SResToHRESULT(res);
+ }
+
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
+ if (prop.vt != VT_EMPTY)
+ if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ {
+ UInt64 size;
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ RINOK(updateCallback->SetTotal(size));
+ }
+
+ CLzma2EncProps lzma2Props;
+ Lzma2EncProps_Init(&lzma2Props);
+
+ lzma2Props.lzmaProps.level = _level;
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+
+ CSeqInStreamWrap seqInStream(fileInStream);
+
+ for (int i = 0; i < _methods.Size(); i++)
+ {
+ COneMethodInfo &m = _methods[i];
+ SetCompressionMethod2(m
+ #ifndef _7ZIP_ST
+ , _numThreads
+ #endif
+ );
+ if (m.IsLzma())
+ {
+ for (int j = 0; j < m.Props.Size(); j++)
+ {
+ const CProp &prop = m.Props[j];
+ RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props));
+ }
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ lzma2Props.numTotalThreads = _numThreads;
+ #endif
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CCompressProgressWrap progressWrap(progress);
+ SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &lzma2Props, False, &progressWrap.p);
+ if (res == SZ_OK)
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+ return SResToHRESULT(res);
+ }
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+ if (_stream)
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ return NCompress::CopyStream(_stream, outStream, 0);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ COM_TRY_BEGIN
+ BeforeSetProperty();
+ for (int i = 0; i < numProps; i++)
+ {
+ RINOK(SetProperty(names[i], values[i]));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+#endif
+
+static IInArchive *CreateArc() { return new NArchive::NXz::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NXz::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"xz", L"xz txz", L"* .tar", 0xC, {0xFD, '7' , 'z', 'X', 'Z', '\0'}, 6, true, CreateArc, CreateArcOut };
+
+REGISTER_ARC(xz)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/ZHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/ZHandler.cpp
new file mode 100644
index 000000000..49b76a116
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/ZHandler.cpp
@@ -0,0 +1,161 @@
+// ZHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/ZDecoder.h"
+
+#include "Common/DummyOutStream.h"
+
+namespace NArchive {
+namespace NZ {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ UInt64 _streamStartPosition;
+ UInt64 _packSize;
+ Byte _properties;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPackSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPackSize: prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+static const int kSignatureSize = 3;
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_streamStartPosition));
+ Byte buffer[kSignatureSize];
+ RINOK(ReadStream_FALSE(stream, buffer, kSignatureSize));
+ if (buffer[0] != 0x1F || buffer[1] != 0x9D)
+ return S_FALSE;
+ _properties = buffer[2];
+
+ UInt64 endPosition;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition));
+ _packSize = endPosition - _streamStartPosition - kSignatureSize;
+
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_packSize);
+
+ UInt64 currentTotalPacked = 0;
+
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ RINOK(_stream->Seek(_streamStartPosition + kSignatureSize, STREAM_SEEK_SET, NULL));
+
+ CMyComPtr<ICompressCoder> decoder;
+ NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder;
+ decoder = decoderSpec;
+
+ HRESULT result = decoderSpec->SetDecoderProperties2(&_properties, 1);
+
+ int opResult;
+ if (result != S_OK)
+ opResult = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ result = decoder->Code(_stream, outStream, NULL, NULL, progress);
+ if (result == S_FALSE)
+ opResult = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(result);
+ opResult = NExtract::NOperationResult::kOK;
+ }
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(opResult);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Z", L"z taz", L"* .tar", 5, { 0x1F, 0x9D }, 2, false, CreateArc, 0 };
+
+REGISTER_ARC(Z)
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
new file mode 100644
index 000000000..4c5fd38d1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
@@ -0,0 +1,379 @@
+// ZipAddCommon.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../ICoder.h"
+#include "../../IPassword.h"
+#include "../../MyVersion.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/LzmaEncoder.h"
+#include "../../Compress/PpmdZip.h"
+
+#include "../Common/InStreamWithCRC.h"
+
+#include "ZipAddCommon.h"
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+static const CMethodId kMethodId_ZipBase = 0x040100;
+static const CMethodId kMethodId_BZip2 = 0x040202;
+
+static const UInt32 kLzmaPropsSize = 5;
+static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize;
+
+class CLzmaEncoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ NCompress::NLzma::CEncoder *EncoderSpec;
+ CMyComPtr<ICompressCoder> Encoder;
+ Byte Header[kLzmaHeaderSize];
+public:
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+
+ MY_UNKNOWN_IMP
+};
+
+HRESULT CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ if (!Encoder)
+ {
+ EncoderSpec = new NCompress::NLzma::CEncoder;
+ Encoder = EncoderSpec;
+ }
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init(Header + 4, kLzmaPropsSize);
+ RINOK(EncoderSpec->SetCoderProperties(propIDs, props, numProps));
+ RINOK(EncoderSpec->WriteCoderProperties(outStream));
+ if (outStreamSpec->GetPos() != kLzmaPropsSize)
+ return E_FAIL;
+ Header[0] = MY_VER_MAJOR;
+ Header[1] = MY_VER_MINOR;
+ Header[2] = kLzmaPropsSize;
+ Header[3] = 0;
+ return S_OK;
+}
+
+HRESULT CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ RINOK(WriteStream(outStream, Header, kLzmaHeaderSize));
+ return Encoder->Code(inStream, outStream, inSize, outSize, progress);
+}
+
+
+CAddCommon::CAddCommon(const CCompressionMethodMode &options):
+ _options(options),
+ _copyCoderSpec(NULL),
+ _cryptoStreamSpec(0)
+ {}
+
+static HRESULT GetStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC)
+{
+ UInt32 crc = CRC_INIT_VAL;
+ const UInt32 kBufferSize = (1 << 14);
+ Byte buffer[kBufferSize];
+ for (;;)
+ {
+ UInt32 realProcessedSize;
+ RINOK(inStream->Read(buffer, kBufferSize, &realProcessedSize));
+ if (realProcessedSize == 0)
+ {
+ resultCRC = CRC_GET_DIGEST(crc);
+ return S_OK;
+ }
+ crc = CrcUpdate(crc, buffer, (size_t)realProcessedSize);
+ }
+}
+
+HRESULT CAddCommon::Compress(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream, IOutStream *outStream,
+ ICompressProgressInfo *progress, CCompressingResult &opRes)
+{
+ CSequentialInStreamWithCRC *inSecCrcStreamSpec = 0;
+ CInStreamWithCRC *inCrcStreamSpec = 0;
+ CMyComPtr<ISequentialInStream> inCrcStream;
+ {
+ CMyComPtr<IInStream> inStream2;
+ // we don't support stdin, since stream from stdin can require 64-bit size header
+ RINOK(inStream->QueryInterface(IID_IInStream, (void **)&inStream2));
+ if (inStream2)
+ {
+ inCrcStreamSpec = new CInStreamWithCRC;
+ inCrcStream = inCrcStreamSpec;
+ inCrcStreamSpec->SetStream(inStream2);
+ inCrcStreamSpec->Init();
+ }
+ else
+ {
+ inSecCrcStreamSpec = new CSequentialInStreamWithCRC;
+ inCrcStream = inSecCrcStreamSpec;
+ inSecCrcStreamSpec->SetStream(inStream);
+ inSecCrcStreamSpec->Init();
+ }
+ }
+
+ int numTestMethods = _options.MethodSequence.Size();
+ if (numTestMethods > 1 || _options.PasswordIsDefined)
+ {
+ if (inCrcStreamSpec == 0)
+ {
+ if (_options.PasswordIsDefined)
+ return E_NOTIMPL;
+ numTestMethods = 1;
+ }
+ }
+ Byte method = 0;
+ COutStreamReleaser outStreamReleaser;
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
+ for (int i = 0; i < numTestMethods; i++)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
+ if (inCrcStreamSpec != 0)
+ RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(outStream->SetSize(0));
+ RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
+ if (_options.PasswordIsDefined)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_ZipCrypto;
+
+ if (!_cryptoStream)
+ {
+ _cryptoStreamSpec = new CFilterCoder;
+ _cryptoStream = _cryptoStreamSpec;
+ }
+ if (_options.IsAesMode)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Aes;
+ if (!_cryptoStreamSpec->Filter)
+ {
+ _cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder;
+ _filterAesSpec->SetKeyMode(_options.AesKeyMode);
+ RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length()));
+ }
+ RINOK(_filterAesSpec->WriteHeader(outStream));
+ }
+ else
+ {
+ if (!_cryptoStreamSpec->Filter)
+ {
+ _cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder;
+ _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length());
+ }
+ UInt32 crc = 0;
+ RINOK(GetStreamCRC(inStream, crc));
+ RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(_filterSpec->WriteHeader(outStream, crc));
+ }
+ RINOK(_cryptoStreamSpec->SetOutStream(outStream));
+ outStreamReleaser.FilterCoder = _cryptoStreamSpec;
+ }
+
+ method = _options.MethodSequence[i];
+ switch(method)
+ {
+ case NFileHeader::NCompressionMethod::kStored:
+ {
+ if (_copyCoderSpec == NULL)
+ {
+ _copyCoderSpec = new NCompress::CCopyCoder;
+ _copyCoder = _copyCoderSpec;
+ }
+ CMyComPtr<ISequentialOutStream> outStreamNew;
+ if (_options.PasswordIsDefined)
+ outStreamNew = _cryptoStream;
+ else
+ outStreamNew = outStream;
+ RINOK(_copyCoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
+ break;
+ }
+ default:
+ {
+ if (!_compressEncoder)
+ {
+ if (method == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_LZMA;
+ CLzmaEncoder *_lzmaEncoder = new CLzmaEncoder();
+ _compressEncoder = _lzmaEncoder;
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ #ifndef _7ZIP_ST
+ _options.NumThreads,
+ #endif
+ _options.Algo,
+ _options.DicSize,
+ _options.NumFastBytes,
+ const_cast<BSTR>((const wchar_t *)_options.MatchFinder),
+ _options.NumMatchFinderCycles
+ };
+ PROPID propIDs[] =
+ {
+ #ifndef _7ZIP_ST
+ NCoderPropID::kNumThreads,
+ #endif
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinder,
+ NCoderPropID::kMatchFinderCycles
+ };
+ int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ if (!_options.NumMatchFinderCyclesDefined)
+ numProps--;
+ RINOK(_lzmaEncoder->SetCoderProperties(propIDs, props, numProps));
+ }
+ else if (method == NFileHeader::NCompressionMethod::kPPMd)
+ {
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_PPMd;
+ NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder();
+ _compressEncoder = encoder;
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.Algo,
+ _options.MemSize,
+ _options.Order
+
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kUsedMemorySize,
+ NCoderPropID::kOrder
+ };
+ RINOK(encoder->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0])));
+ }
+ else
+ {
+ CMethodId methodId;
+ switch(method)
+ {
+ case NFileHeader::NCompressionMethod::kBZip2:
+ methodId = kMethodId_BZip2;
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_BZip2;
+ break;
+ default:
+ _compressExtractVersion = ((method == NFileHeader::NCompressionMethod::kDeflated64) ?
+ NFileHeader::NCompressionMethod::kExtractVersion_Deflate64 :
+ NFileHeader::NCompressionMethod::kExtractVersion_Deflate);
+ methodId = kMethodId_ZipBase + method;
+ break;
+ }
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId, _compressEncoder, true));
+ if (!_compressEncoder)
+ return E_NOTIMPL;
+
+ if (method == NFileHeader::NCompressionMethod::kDeflated ||
+ method == NFileHeader::NCompressionMethod::kDeflated64)
+ {
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.Algo,
+ _options.NumPasses,
+ _options.NumFastBytes,
+ _options.NumMatchFinderCycles
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumPasses,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinderCycles
+ };
+ int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ if (!_options.NumMatchFinderCyclesDefined)
+ numProps--;
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties);
+ if (setCoderProperties)
+ {
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, numProps));
+ }
+ }
+ else if (method == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.DicSize,
+ _options.NumPasses
+ #ifndef _7ZIP_ST
+ , _options.NumThreads
+ #endif
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumPasses
+ #ifndef _7ZIP_ST
+ , NCoderPropID::kNumThreads
+ #endif
+ };
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties);
+ if (setCoderProperties)
+ {
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0])));
+ }
+ }
+ }
+ }
+ CMyComPtr<ISequentialOutStream> outStreamNew;
+ if (_options.PasswordIsDefined)
+ outStreamNew = _cryptoStream;
+ else
+ outStreamNew = outStream;
+ if (_compressExtractVersion > opRes.ExtractVersion)
+ opRes.ExtractVersion = _compressExtractVersion;
+ RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
+ break;
+ }
+ }
+
+ RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
+
+ if (inCrcStreamSpec != 0)
+ {
+ opRes.CRC = inCrcStreamSpec->GetCRC();
+ opRes.UnpackSize = inCrcStreamSpec->GetSize();
+ }
+ else
+ {
+ opRes.CRC = inSecCrcStreamSpec->GetCRC();
+ opRes.UnpackSize = inSecCrcStreamSpec->GetSize();
+ }
+
+ if (_options.PasswordIsDefined)
+ {
+ if (opRes.PackSize < opRes.UnpackSize +
+ (_options.IsAesMode ? _filterAesSpec->GetHeaderSize() : NCrypto::NZip::kHeaderSize))
+ break;
+ }
+ else if (opRes.PackSize < opRes.UnpackSize)
+ break;
+ }
+ if (_options.IsAesMode)
+ {
+ RINOK(_filterAesSpec->WriteFooter(outStream));
+ RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
+ }
+ opRes.Method = method;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipAddCommon.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipAddCommon.h
new file mode 100644
index 000000000..e4c02db3f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipAddCommon.h
@@ -0,0 +1,56 @@
+// ZipAddCommon.h
+
+#ifndef __ZIP_ADD_COMMON_H
+#define __ZIP_ADD_COMMON_H
+
+#include "../../ICoder.h"
+#include "../../IProgress.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../../Crypto/ZipCrypto.h"
+#include "../../Crypto/WzAes.h"
+
+#include "ZipCompressionMode.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CCompressingResult
+{
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt32 CRC;
+ UInt16 Method;
+ Byte ExtractVersion;
+};
+
+class CAddCommon
+{
+ CCompressionMethodMode _options;
+ NCompress::CCopyCoder *_copyCoderSpec;
+ CMyComPtr<ICompressCoder> _copyCoder;
+
+ CMyComPtr<ICompressCoder> _compressEncoder;
+ Byte _compressExtractVersion;
+
+ CFilterCoder *_cryptoStreamSpec;
+ CMyComPtr<ISequentialOutStream> _cryptoStream;
+
+ NCrypto::NZip::CEncoder *_filterSpec;
+ NCrypto::NWzAes::CEncoder *_filterAesSpec;
+
+public:
+ CAddCommon(const CCompressionMethodMode &options);
+ HRESULT Compress(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream, IOutStream *outStream,
+ ICompressProgressInfo *progress, CCompressingResult &operationResult);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipCompressionMode.h
new file mode 100644
index 000000000..7ef7cfb28
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipCompressionMode.h
@@ -0,0 +1,42 @@
+// CompressionMode.h
+
+#ifndef __ZIP_COMPRESSION_MODE_H
+#define __ZIP_COMPRESSION_MODE_H
+
+#include "Common/MyString.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CCompressionMethodMode
+{
+ CRecordVector<Byte> MethodSequence;
+ UString MatchFinder;
+ UInt32 Algo;
+ UInt32 NumPasses;
+ UInt32 NumFastBytes;
+ bool NumMatchFinderCyclesDefined;
+ UInt32 NumMatchFinderCycles;
+ UInt32 DicSize;
+ UInt32 MemSize;
+ UInt32 Order;
+
+ #ifndef _7ZIP_ST
+ UInt32 NumThreads;
+ #endif
+ bool PasswordIsDefined;
+ AString Password;
+ bool IsAesMode;
+ Byte AesKeyMode;
+
+ CCompressionMethodMode():
+ NumMatchFinderCyclesDefined(false),
+ PasswordIsDefined(false),
+ IsAesMode(false),
+ AesKeyMode(3)
+ {}
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandler.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandler.cpp
new file mode 100644
index 000000000..bd1563226
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -0,0 +1,822 @@
+// ZipHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/FilterCoder.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/LzmaDecoder.h"
+#include "../../Compress/ImplodeDecoder.h"
+#include "../../Compress/PpmdZip.h"
+#include "../../Compress/ShrinkDecoder.h"
+
+#include "../../Crypto/WzAes.h"
+#include "../../Crypto/ZipCrypto.h"
+#include "../../Crypto/ZipStrong.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "ZipHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NZip {
+
+static const CMethodId kMethodId_ZipBase = 0x040100;
+static const CMethodId kMethodId_BZip2 = 0x040202;
+
+static const char *kHostOS[] =
+{
+ "FAT",
+ "AMIGA",
+ "VMS",
+ "Unix",
+ "VM/CMS",
+ "Atari",
+ "HPFS",
+ "Macintosh",
+ "Z-System",
+ "CP/M",
+ "TOPS-20",
+ "NTFS",
+ "SMS/QDOS",
+ "Acorn",
+ "VFAT",
+ "MVS",
+ "BeOS",
+ "Tandem",
+ "OS/400",
+ "OS/X"
+};
+
+static const char *kUnknownOS = "Unknown";
+
+static const char *kMethods[] =
+{
+ "Store",
+ "Shrink",
+ "Reduced1",
+ "Reduced2",
+ "Reduced3",
+ "Reduced4",
+ "Implode",
+ "Tokenizing",
+ "Deflate",
+ "Deflate64",
+ "PKImploding"
+};
+
+static const char *kBZip2Method = "BZip2";
+static const char *kLZMAMethod = "LZMA";
+static const char *kJpegMethod = "Jpeg";
+static const char *kWavPackMethod = "WavPack";
+static const char *kPPMdMethod = "PPMd";
+static const char *kAESMethod = "AES";
+static const char *kZipCryptoMethod = "ZipCrypto";
+static const char *kStrongCryptoMethod = "StrongCrypto";
+
+static struct CStrongCryptoPair
+{
+ UInt16 Id;
+ const char *Name;
+} g_StrongCryptoPairs[] =
+{
+ { NStrongCryptoFlags::kDES, "DES" },
+ { NStrongCryptoFlags::kRC2old, "RC2a" },
+ { NStrongCryptoFlags::k3DES168, "3DES-168" },
+ { NStrongCryptoFlags::k3DES112, "3DES-112" },
+ { NStrongCryptoFlags::kAES128, "pkAES-128" },
+ { NStrongCryptoFlags::kAES192, "pkAES-192" },
+ { NStrongCryptoFlags::kAES256, "pkAES-256" },
+ { NStrongCryptoFlags::kRC2, "RC2" },
+ { NStrongCryptoFlags::kBlowfish, "Blowfish" },
+ { NStrongCryptoFlags::kTwofish, "Twofish" },
+ { NStrongCryptoFlags::kRC4, "RC4" }
+};
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidUnpackVer, VT_UI4}
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8}
+};
+
+CHandler::CHandler()
+{
+ InitMethodProperties();
+}
+
+static AString BytesToString(const CByteBuffer &data)
+{
+ AString s;
+ int size = (int)data.GetCapacity();
+ if (size > 0)
+ {
+ char *p = s.GetBuffer(size + 1);
+ memcpy(p, (const Byte *)data, size);
+ p[size] = '\0';
+ s.ReleaseBuffer();
+ }
+ return s;
+}
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break;
+ case kpidComment: prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break;
+ case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break;
+ case kpidOffset: if (m_Archive.ArcInfo.StartPosition != 0) prop = m_Archive.ArcInfo.StartPosition; break;
+ }
+ prop.Detach(value);
+ COM_TRY_END
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = m_Items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItemEx &item = m_Items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.UnPackSize; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidTimeType:
+ {
+ FILETIME ft;
+ UInt32 unixTime;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
+ prop = (UInt32)NFileTimeType::kWindows;
+ else if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime))
+ prop = (UInt32)NFileTimeType::kUnix;
+ else
+ prop = (UInt32)NFileTimeType::kDOS;
+ break;
+ }
+ case kpidCTime:
+ {
+ FILETIME ft;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft))
+ prop = ft;
+ break;
+ }
+ case kpidATime:
+ {
+ FILETIME ft;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft))
+ prop = ft;
+ break;
+ }
+ case kpidMTime:
+ {
+ FILETIME utc;
+ if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc))
+ {
+ UInt32 unixTime;
+ if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime))
+ NTime::UnixTimeToFileTime(unixTime, utc);
+ else
+ {
+ FILETIME localFileTime;
+ if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
+ !LocalFileTimeToFileTime(&localFileTime, &utc))
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ }
+ prop = utc;
+ break;
+ }
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break;
+ case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break;
+ case kpidMethod:
+ {
+ UInt16 methodId = item.CompressionMethod;
+ AString method;
+ if (item.IsEncrypted())
+ {
+ if (methodId == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ method = kAESMethod;
+ CWzAesExtraField aesField;
+ if (item.CentralExtra.GetWzAesField(aesField))
+ {
+ method += '-';
+ char s[32];
+ ConvertUInt64ToString((aesField.Strength + 1) * 64 , s);
+ method += s;
+ method += ' ';
+ methodId = aesField.Method;
+ }
+ }
+ else
+ {
+ if (item.IsStrongEncrypted())
+ {
+ CStrongCryptoField f;
+ bool finded = false;
+ if (item.CentralExtra.GetStrongCryptoField(f))
+ {
+ for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++)
+ {
+ const CStrongCryptoPair &pair = g_StrongCryptoPairs[i];
+ if (f.AlgId == pair.Id)
+ {
+ method += pair.Name;
+ finded = true;
+ break;
+ }
+ }
+ }
+ if (!finded)
+ method += kStrongCryptoMethod;
+ }
+ else
+ method += kZipCryptoMethod;
+ method += ' ';
+ }
+ }
+ if (methodId < sizeof(kMethods) / sizeof(kMethods[0]))
+ method += kMethods[methodId];
+ else switch (methodId)
+ {
+ case NFileHeader::NCompressionMethod::kLZMA:
+ method += kLZMAMethod;
+ if (item.IsLzmaEOS())
+ method += ":EOS";
+ break;
+ case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break;
+ case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break;
+ case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break;
+ case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break;
+ default:
+ {
+ char s[32];
+ ConvertUInt64ToString(methodId, s);
+ method += s;
+ }
+ }
+ prop = method;
+ break;
+ }
+ case kpidHostOS:
+ prop = (item.MadeByVersion.HostOS < sizeof(kHostOS) / sizeof(kHostOS[0])) ?
+ (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS;
+ break;
+ case kpidUnpackVer:
+ prop = (UInt32)item.ExtractVersion.Version;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+public:
+ STDMETHOD(SetTotal)(UInt64 numFiles);
+ STDMETHOD(SetCompleted)(UInt64 numFiles);
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
+};
+
+STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetTotal(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(m_Archive.Open(inStream, maxCheckStartPosition));
+ CProgressImp progressImp(callback);
+ return m_Archive.ReadHeaders(m_Items, &progressImp);
+ }
+ catch(const CInArchiveException &) { Close(); return S_FALSE; }
+ catch(...) { Close(); throw; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ m_Items.Clear();
+ m_Archive.Close();
+ return S_OK;
+}
+
+//////////////////////////////////////
+// CHandler::DecompressItems
+
+class CLzmaDecoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ NCompress::NLzma::CDecoder *DecoderSpec;
+ CMyComPtr<ICompressCoder> Decoder;
+public:
+ CLzmaDecoder();
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ MY_UNKNOWN_IMP
+};
+
+CLzmaDecoder::CLzmaDecoder()
+{
+ DecoderSpec = new NCompress::NLzma::CDecoder;
+ Decoder = DecoderSpec;
+}
+
+HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ Byte buf[9];
+ RINOK(ReadStream_FALSE(inStream, buf, 9));
+ if (buf[2] != 5 || buf[3] != 0)
+ return E_NOTIMPL;
+ RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5));
+ return Decoder->Code(inStream, outStream, NULL, outSize, progress);
+}
+
+struct CMethodItem
+{
+ UInt16 ZipMethod;
+ CMyComPtr<ICompressCoder> Coder;
+};
+
+class CZipDecoder
+{
+ NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec;
+ NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec;
+ NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec;
+
+ CMyComPtr<ICompressFilter> _zipCryptoDecoder;
+ CMyComPtr<ICompressFilter> _pkAesDecoder;
+ CMyComPtr<ICompressFilter> _wzAesDecoder;
+
+ CFilterCoder *filterStreamSpec;
+ CMyComPtr<ISequentialInStream> filterStream;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ CObjectVector<CMethodItem> methodItems;
+
+public:
+ CZipDecoder():
+ _zipCryptoDecoderSpec(0),
+ _pkAesDecoderSpec(0),
+ _wzAesDecoderSpec(0),
+ filterStreamSpec(0) {}
+
+ HRESULT Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CInArchive &archive, const CItemEx &item,
+ ISequentialOutStream *realOutStream,
+ IArchiveExtractCallback *extractCallback,
+ ICompressProgressInfo *compressProgress,
+ UInt32 numThreads, Int32 &res);
+};
+
+HRESULT CZipDecoder::Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CInArchive &archive, const CItemEx &item,
+ ISequentialOutStream *realOutStream,
+ IArchiveExtractCallback *extractCallback,
+ ICompressProgressInfo *compressProgress,
+ UInt32 numThreads, Int32 &res)
+{
+ res = NExtract::NOperationResult::kDataError;
+ CInStreamReleaser inStreamReleaser;
+
+ bool needCRC = true;
+ bool wzAesMode = false;
+ bool pkAesMode = false;
+ UInt16 methodId = item.CompressionMethod;
+ if (item.IsEncrypted())
+ {
+ if (item.IsStrongEncrypted())
+ {
+ CStrongCryptoField f;
+ if (item.CentralExtra.GetStrongCryptoField(f))
+ {
+ pkAesMode = true;
+ }
+ if (!pkAesMode)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ }
+ if (methodId == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ CWzAesExtraField aesField;
+ if (item.CentralExtra.GetWzAesField(aesField))
+ {
+ wzAesMode = true;
+ needCRC = aesField.NeedCrc();
+ }
+ }
+ }
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init(needCRC);
+
+ UInt64 authenticationPos;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ {
+ UInt64 packSize = item.PackSize;
+ if (wzAesMode)
+ {
+ if (packSize < NCrypto::NWzAes::kMacSize)
+ return S_OK;
+ packSize -= NCrypto::NWzAes::kMacSize;
+ }
+ UInt64 dataPos = item.GetDataPosition();
+ inStream.Attach(archive.CreateLimitedStream(dataPos, packSize));
+ authenticationPos = dataPos + packSize;
+ }
+
+ CMyComPtr<ICompressFilter> cryptoFilter;
+ if (item.IsEncrypted())
+ {
+ if (wzAesMode)
+ {
+ CWzAesExtraField aesField;
+ if (!item.CentralExtra.GetWzAesField(aesField))
+ return S_OK;
+ methodId = aesField.Method;
+ if (!_wzAesDecoder)
+ {
+ _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder;
+ _wzAesDecoder = _wzAesDecoderSpec;
+ }
+ cryptoFilter = _wzAesDecoder;
+ Byte properties = aesField.Strength;
+ RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1));
+ }
+ else if (pkAesMode)
+ {
+ if (!_pkAesDecoder)
+ {
+ _pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder;
+ _pkAesDecoder = _pkAesDecoderSpec;
+ }
+ cryptoFilter = _pkAesDecoder;
+ }
+ else
+ {
+ if (!_zipCryptoDecoder)
+ {
+ _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder;
+ _zipCryptoDecoder = _zipCryptoDecoderSpec;
+ }
+ cryptoFilter = _zipCryptoDecoder;
+ }
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
+
+ if (!getTextPassword)
+ extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password));
+ AString charPassword;
+ if (wzAesMode || pkAesMode)
+ {
+ charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
+ /*
+ for (int i = 0;; i++)
+ {
+ wchar_t c = password[i];
+ if (c == 0)
+ break;
+ if (c >= 0x80)
+ {
+ res = NExtract::NOperationResult::kDataError;
+ return S_OK;
+ }
+ charPassword += (char)c;
+ }
+ */
+ }
+ else
+ {
+ // we use OEM. WinZip/Windows probably use ANSI for some files
+ charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
+ }
+ HRESULT result = cryptoSetPassword->CryptoSetPassword(
+ (const Byte *)(const char *)charPassword, charPassword.Length());
+ if (result != S_OK)
+ return S_OK;
+ }
+ else
+ {
+ RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
+ }
+ }
+
+ int m;
+ for (m = 0; m < methodItems.Size(); m++)
+ if (methodItems[m].ZipMethod == methodId)
+ break;
+
+ if (m == methodItems.Size())
+ {
+ CMethodItem mi;
+ mi.ZipMethod = methodId;
+ if (methodId == NFileHeader::NCompressionMethod::kStored)
+ mi.Coder = new NCompress::CCopyCoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kShrunk)
+ mi.Coder = new NCompress::NShrink::CDecoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kImploded)
+ mi.Coder = new NCompress::NImplode::NDecoder::CCoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kLZMA)
+ mi.Coder = new CLzmaDecoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kPPMd)
+ mi.Coder = new NCompress::NPpmdZip::CDecoder(true);
+ else
+ {
+ CMethodId szMethodID;
+ if (methodId == NFileHeader::NCompressionMethod::kBZip2)
+ szMethodID = kMethodId_BZip2;
+ else
+ {
+ if (methodId > 0xFF)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ szMethodID = kMethodId_ZipBase + (Byte)methodId;
+ }
+
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false));
+
+ if (mi.Coder == 0)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ }
+ m = methodItems.Add(mi);
+ }
+ ICompressCoder *coder = methodItems[m].Coder;
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ Byte properties = (Byte)item.Flags;
+ RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1));
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(numThreads));
+ }
+ }
+ #endif
+
+ {
+ HRESULT result = S_OK;
+ CMyComPtr<ISequentialInStream> inStreamNew;
+ if (item.IsEncrypted())
+ {
+ if (!filterStream)
+ {
+ filterStreamSpec = new CFilterCoder;
+ filterStream = filterStreamSpec;
+ }
+ filterStreamSpec->Filter = cryptoFilter;
+ if (wzAesMode)
+ {
+ result = _wzAesDecoderSpec->ReadHeader(inStream);
+ }
+ else if (pkAesMode)
+ {
+ result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize);
+ if (result == S_OK)
+ {
+ bool passwOK;
+ result = _pkAesDecoderSpec->CheckPassword(passwOK);
+ if (result == S_OK && !passwOK)
+ result = S_FALSE;
+ }
+ }
+ else
+ {
+ result = _zipCryptoDecoderSpec->ReadHeader(inStream);
+ }
+
+ if (result == S_OK)
+ {
+ RINOK(filterStreamSpec->SetInStream(inStream));
+ inStreamReleaser.FilterCoder = filterStreamSpec;
+ inStreamNew = filterStream;
+ if (wzAesMode)
+ {
+ if (!_wzAesDecoderSpec->CheckPasswordVerifyCode())
+ result = S_FALSE;
+ }
+ }
+ }
+ else
+ inStreamNew = inStream;
+ if (result == S_OK)
+ result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress);
+ if (result == S_FALSE)
+ return S_OK;
+ if (result == E_NOTIMPL)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+
+ RINOK(result);
+ }
+ bool crcOK = true;
+ bool authOk = true;
+ if (needCRC)
+ crcOK = (outStreamSpec->GetCRC() == item.FileCRC);
+ if (wzAesMode)
+ {
+ inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize));
+ if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
+ authOk = false;
+ }
+
+ res = ((crcOK && authOk) ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kCRCError);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ CZipDecoder myDecoder;
+ UInt64 totalUnPacked = 0, totalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = m_Items.Size();
+ if(numItems == 0)
+ return S_OK;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItemEx &item = m_Items[allFilesMode ? i : indices[i]];
+ totalUnPacked += item.UnPackSize;
+ totalPacked += item.PackSize;
+ }
+ RINOK(extractCallback->SetTotal(totalUnPacked));
+
+ UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
+ UInt64 currentItemUnPacked, currentItemPacked;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
+ currentTotalPacked += currentItemPacked)
+ {
+ currentItemUnPacked = 0;
+ currentItemPacked = 0;
+
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = currentTotalUnPacked;
+ RINOK(lps->SetCur());
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ CItemEx item = m_Items[index];
+ if (!item.FromLocal)
+ {
+ HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item);
+ if (res == S_FALSE)
+ {
+ if (item.IsDir() || realOutStream || testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ }
+ continue;
+ }
+ RINOK(res);
+ }
+
+ if (item.IsDir() || item.IgnoreItem())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ continue;
+ }
+
+ currentItemUnPacked = item.UnPackSize;
+ currentItemPacked = item.PackSize;
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ Int32 res;
+ RINOK(myDecoder.Decode(
+ EXTERNAL_CODECS_VARS
+ m_Archive, item, realOutStream, extractCallback,
+ progress, _numThreads, res));
+ realOutStream.Release();
+
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandler.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandler.h
new file mode 100644
index 000000000..04cede84e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandler.h
@@ -0,0 +1,101 @@
+// Zip/Handler.h
+
+#ifndef __ZIP_HANDLER_H
+#define __ZIP_HANDLER_H
+
+#include "Common/DynamicBuffer.h"
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "ZipIn.h"
+#include "ZipCompressionMode.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/System.h"
+#endif
+
+namespace NArchive {
+namespace NZip {
+
+class CHandler:
+ public IInArchive,
+ public IOutArchive,
+ public ISetProperties,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IOutArchive)
+ MY_QUERYINTERFACE_ENTRY(ISetProperties)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+
+ DECL_ISetCompressCodecsInfo
+
+ CHandler();
+private:
+ CObjectVector<CItemEx> m_Items;
+ CInArchive m_Archive;
+
+ int m_Level;
+ int m_MainMethod;
+ UInt32 m_DicSize;
+ UInt32 m_Algo;
+ UInt32 m_NumPasses;
+ UInt32 m_NumFastBytes;
+ UInt32 m_NumMatchFinderCycles;
+ UInt32 m_MemSize;
+ UInt32 m_Order;
+
+ bool m_NumMatchFinderCyclesDefined;
+
+ bool m_ForceAesMode;
+ bool m_IsAesMode;
+ Byte m_AesKeyMode;
+
+ bool m_WriteNtfsTimeExtra;
+ bool m_ForceLocal;
+ bool m_ForceUtf8;
+
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ #endif
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ void InitMethodProperties()
+ {
+ m_Level = -1;
+ m_MainMethod = -1;
+ m_Algo =
+ m_DicSize =
+ m_NumPasses =
+ m_NumFastBytes =
+ m_Order =
+ m_MemSize =
+ m_NumMatchFinderCycles = 0xFFFFFFFF;
+ m_NumMatchFinderCyclesDefined = false;
+ m_ForceAesMode = false;
+ m_IsAesMode = false;
+ m_AesKeyMode = 3; // aes-256
+ m_WriteNtfsTimeExtra = false;
+ m_ForceLocal = false;
+ m_ForceUtf8 = false;
+ #ifndef _7ZIP_ST
+ _numThreads = NWindows::NSystem::GetNumberOfProcessors();;
+ #endif
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
new file mode 100644
index 000000000..ee1c07fae
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
@@ -0,0 +1,537 @@
+// ZipHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/OutBuffer.h"
+
+#include "../../Crypto/WzAes.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/ParseProperties.h"
+
+#include "ZipHandler.h"
+#include "ZipUpdate.h"
+
+using namespace NWindows;
+using namespace NCOM;
+using namespace NTime;
+
+namespace NArchive {
+namespace NZip {
+
+static const UInt32 kLzAlgoX1 = 0;
+static const UInt32 kLzAlgoX5 = 1;
+
+static const UInt32 kDeflateNumPassesX1 = 1;
+static const UInt32 kDeflateNumPassesX7 = 3;
+static const UInt32 kDeflateNumPassesX9 = 10;
+
+static const UInt32 kDeflateNumFastBytesX1 = 32;
+static const UInt32 kDeflateNumFastBytesX7 = 64;
+static const UInt32 kDeflateNumFastBytesX9 = 128;
+
+static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
+static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
+
+static const UInt32 kLzmaNumFastBytesX1 = 32;
+static const UInt32 kLzmaNumFastBytesX7 = 64;
+
+static const UInt32 kLzmaDicSizeX1 = 1 << 16;
+static const UInt32 kLzmaDicSizeX3 = 1 << 20;
+static const UInt32 kLzmaDicSizeX5 = 1 << 24;
+static const UInt32 kLzmaDicSizeX7 = 1 << 25;
+static const UInt32 kLzmaDicSizeX9 = 1 << 26;
+
+static const UInt32 kBZip2NumPassesX1 = 1;
+static const UInt32 kBZip2NumPassesX7 = 2;
+static const UInt32 kBZip2NumPassesX9 = 7;
+
+static const UInt32 kBZip2DicSizeX1 = 100000;
+static const UInt32 kBZip2DicSizeX3 = 500000;
+static const UInt32 kBZip2DicSizeX5 = 900000;
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kDOS;
+ return S_OK;
+}
+
+static bool IsAsciiString(const UString &s)
+{
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ if (c < 0x20 || c > 0x7F)
+ return false;
+ }
+ return true;
+}
+
+#define COM_TRY_BEGIN2 try {
+#define COM_TRY_END2 } \
+catch(const CSystemException &e) { return e.ErrorCode; } \
+catch(...) { return E_OUTOFMEMORY; }
+
+static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &filetime)
+{
+ filetime.dwHighDateTime = filetime.dwLowDateTime = 0;
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ filetime = prop.filetime;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback)
+{
+ COM_TRY_BEGIN2
+ CObjectVector<CUpdateItem> updateItems;
+ bool thereAreAesUpdates = false;
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData;
+ Int32 newProperties;
+ UInt32 indexInArchive;
+ if (!callback)
+ return E_FAIL;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProperties, &indexInArchive));
+ ui.NewProperties = IntToBool(newProperties);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArchive = indexInArchive;
+ ui.IndexInClient = i;
+ bool existInArchive = (indexInArchive != (UInt32)-1);
+ if (existInArchive && newData)
+ if (m_Items[indexInArchive].IsAesEncrypted())
+ thereAreAesUpdates = true;
+
+ if (IntToBool(newProperties))
+ {
+ UString name;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Attributes = 0;
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Attributes = prop.ulVal;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop));
+ if (prop.vt == VT_EMPTY)
+ name.Empty();
+ else if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ else
+ name = prop.bstrVal;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ {
+ CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidTimeType, &prop));
+ if (prop.vt == VT_UI4)
+ ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows);
+ else
+ ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra;
+ }
+ RINOK(GetTime(callback, i, kpidMTime, ui.NtfsMTime));
+ RINOK(GetTime(callback, i, kpidATime, ui.NtfsATime));
+ RINOK(GetTime(callback, i, kpidCTime, ui.NtfsCTime));
+
+ {
+ FILETIME localFileTime = { 0, 0 };
+ if (ui.NtfsMTime.dwHighDateTime != 0 ||
+ ui.NtfsMTime.dwLowDateTime != 0)
+ if (!FileTimeToLocalFileTime(&ui.NtfsMTime, &localFileTime))
+ return E_INVALIDARG;
+ FileTimeToDosTime(localFileTime, ui.Time);
+ }
+
+ name = NItemName::MakeLegalName(name);
+ bool needSlash = ui.IsDir;
+ const wchar_t kSlash = L'/';
+ if (!name.IsEmpty())
+ {
+ if (name[name.Length() - 1] == kSlash)
+ {
+ if (!ui.IsDir)
+ return E_INVALIDARG;
+ needSlash = false;
+ }
+ }
+ if (needSlash)
+ name += kSlash;
+
+ bool tryUtf8 = true;
+ if (m_ForceLocal || !m_ForceUtf8)
+ {
+#ifdef _WIN32
+ bool defaultCharWasUsed;
+ ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP, '_', defaultCharWasUsed);
+ tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed ||
+ MultiByteToUnicodeString(ui.Name, CP_OEMCP) != name));
+#else
+ // FIXME
+ ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP);
+ tryUtf8 = (!m_ForceLocal);
+#endif
+ }
+
+ if (tryUtf8)
+ {
+ int i;
+ for (i = 0; i < name.Length() && (unsigned)name[i] < 0x80; i++);
+ ui.IsUtf8 = (i != name.Length());
+ if (!ConvertUnicodeToUTF8(name, ui.Name))
+ return E_INVALIDARG;
+ }
+
+ if (ui.Name.Length() >= (1 << 16))
+ return E_INVALIDARG;
+
+ ui.IndexInClient = i;
+ /*
+ if (existInArchive)
+ {
+ const CItemEx &itemInfo = m_Items[indexInArchive];
+ // ui.Commented = itemInfo.IsCommented();
+ ui.Commented = false;
+ if (ui.Commented)
+ {
+ ui.CommentRange.Position = itemInfo.GetCommentPosition();
+ ui.CommentRange.Size = itemInfo.CommentSize;
+ }
+ }
+ else
+ ui.Commented = false;
+ */
+ }
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ ui.Size = size;
+ }
+ updateItems.Add(ui);
+ }
+
+ CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
+ {
+ CMyComPtr<IArchiveUpdateCallback> udateCallBack2(callback);
+ udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
+ }
+ CCompressionMethodMode options;
+
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ Int32 passwordIsDefined;
+ RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password));
+ options.PasswordIsDefined = IntToBool(passwordIsDefined);
+ if (options.PasswordIsDefined)
+ {
+ options.IsAesMode = (m_ForceAesMode ? m_IsAesMode : thereAreAesUpdates);
+ options.AesKeyMode = m_AesKeyMode;
+
+ if (!IsAsciiString((const wchar_t *)password))
+ return E_INVALIDARG;
+ if (options.IsAesMode)
+ {
+ if (options.Password.Length() > NCrypto::NWzAes::kPasswordSizeMax)
+ return E_INVALIDARG;
+ }
+ options.Password = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
+ }
+ }
+ else
+ options.PasswordIsDefined = false;
+
+ int level = m_Level;
+ if (level < 0)
+ level = 5;
+
+ Byte mainMethod;
+ if (m_MainMethod < 0)
+ mainMethod = (Byte)(((level == 0) ?
+ NFileHeader::NCompressionMethod::kStored :
+ NFileHeader::NCompressionMethod::kDeflated));
+ else
+ mainMethod = (Byte)m_MainMethod;
+ options.MethodSequence.Add(mainMethod);
+ if (mainMethod != NFileHeader::NCompressionMethod::kStored)
+ options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStored);
+ bool isDeflate = (mainMethod == NFileHeader::NCompressionMethod::kDeflated) ||
+ (mainMethod == NFileHeader::NCompressionMethod::kDeflated64);
+ bool isLZMA = (mainMethod == NFileHeader::NCompressionMethod::kLZMA);
+ bool isLz = (isLZMA || isDeflate);
+ options.NumPasses = m_NumPasses;
+ options.DicSize = m_DicSize;
+ options.NumFastBytes = m_NumFastBytes;
+ options.NumMatchFinderCycles = m_NumMatchFinderCycles;
+ options.NumMatchFinderCyclesDefined = m_NumMatchFinderCyclesDefined;
+ options.Algo = m_Algo;
+ options.MemSize = m_MemSize;
+ options.Order = m_Order;
+ #ifndef _7ZIP_ST
+ options.NumThreads = _numThreads;
+ #endif
+ if (isLz)
+ {
+ if (isDeflate)
+ {
+ if (options.NumPasses == 0xFFFFFFFF)
+ options.NumPasses = (level >= 9 ? kDeflateNumPassesX9 :
+ (level >= 7 ? kDeflateNumPassesX7 :
+ kDeflateNumPassesX1));
+ if (options.NumFastBytes == 0xFFFFFFFF)
+ options.NumFastBytes = (level >= 9 ? kDeflateNumFastBytesX9 :
+ (level >= 7 ? kDeflateNumFastBytesX7 :
+ kDeflateNumFastBytesX1));
+ }
+ else if (isLZMA)
+ {
+ if (options.DicSize == 0xFFFFFFFF)
+ options.DicSize =
+ (level >= 9 ? kLzmaDicSizeX9 :
+ (level >= 7 ? kLzmaDicSizeX7 :
+ (level >= 5 ? kLzmaDicSizeX5 :
+ (level >= 3 ? kLzmaDicSizeX3 :
+ kLzmaDicSizeX1))));
+
+ if (options.NumFastBytes == 0xFFFFFFFF)
+ options.NumFastBytes = (level >= 7 ? kLzmaNumFastBytesX7 :
+ kLzmaNumFastBytesX1);
+
+ options.MatchFinder =
+ (level >= 5 ? kLzmaMatchFinderX5 :
+ kLzmaMatchFinderX1);
+ }
+
+ if (options.Algo == 0xFFFFFFFF)
+ options.Algo = (level >= 5 ? kLzAlgoX5 :
+ kLzAlgoX1);
+ }
+ if (mainMethod == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ if (options.NumPasses == 0xFFFFFFFF)
+ options.NumPasses = (level >= 9 ? kBZip2NumPassesX9 :
+ (level >= 7 ? kBZip2NumPassesX7 :
+ kBZip2NumPassesX1));
+ if (options.DicSize == 0xFFFFFFFF)
+ options.DicSize = (level >= 5 ? kBZip2DicSizeX5 :
+ (level >= 3 ? kBZip2DicSizeX3 :
+ kBZip2DicSizeX1));
+ }
+ if (mainMethod == NFileHeader::NCompressionMethod::kPPMd)
+ {
+ int level2 = level;
+ if (level2 < 1) level2 = 1;
+ if (level2 > 9) level2 = 9;
+
+ if (options.MemSize == 0xFFFFFFFF)
+ options.MemSize = (1 << (19 + (level2 > 8 ? 8 : level2)));
+
+ if (options.Order == 0xFFFFFFFF)
+ options.Order = 3 + level2;
+
+ if (options.Algo == 0xFFFFFFFF)
+ options.Algo = (level2 >= 7 ? 1 : 0);
+ }
+
+ return Update(
+ EXTERNAL_CODECS_VARS
+ m_Items, updateItems, outStream,
+ m_Archive.IsOpen() ? &m_Archive : NULL, &options, callback);
+ COM_TRY_END2
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+ #ifndef _7ZIP_ST
+ const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+ _numThreads = numProcessors;
+ #endif
+ InitMethodProperties();
+ for (int i = 0; i < numProperties; i++)
+ {
+ UString name = UString(names[i]);
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &prop = values[i];
+
+ if (name[0] == L'X')
+ {
+ UInt32 level = 9;
+ RINOK(ParsePropValue(name.Mid(1), prop, level));
+ m_Level = level;
+ continue;
+ }
+ else if (name == L"M")
+ {
+ if (prop.vt == VT_BSTR)
+ {
+ UString m = prop.bstrVal;
+ m.MakeUpper();
+ if (m == L"COPY") m_MainMethod = NFileHeader::NCompressionMethod::kStored;
+ else if (m == L"DEFLATE") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated;
+ else if (m == L"DEFLATE64") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated64;
+ else if (m == L"BZIP2") m_MainMethod = NFileHeader::NCompressionMethod::kBZip2;
+ else if (m == L"LZMA") m_MainMethod = NFileHeader::NCompressionMethod::kLZMA;
+ else if (m == L"PPMD") m_MainMethod = NFileHeader::NCompressionMethod::kPPMd;
+ else return E_INVALIDARG;
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ switch(prop.ulVal)
+ {
+ case NFileHeader::NCompressionMethod::kStored:
+ case NFileHeader::NCompressionMethod::kDeflated:
+ case NFileHeader::NCompressionMethod::kDeflated64:
+ case NFileHeader::NCompressionMethod::kBZip2:
+ case NFileHeader::NCompressionMethod::kLZMA:
+ m_MainMethod = (Byte)prop.ulVal;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else if (name.Left(2) == L"EM")
+ {
+ if (prop.vt == VT_BSTR)
+ {
+ UString valueString = prop.bstrVal;
+ valueString.MakeUpper();
+ if (valueString.Left(3) == L"AES")
+ {
+ valueString = valueString.Mid(3);
+ if (valueString == L"128")
+ m_AesKeyMode = 1;
+ else if (valueString == L"192")
+ m_AesKeyMode = 2;
+ else if (valueString == L"256" || valueString.IsEmpty())
+ m_AesKeyMode = 3;
+ else
+ return E_INVALIDARG;
+ m_IsAesMode = true;
+ m_ForceAesMode = true;
+ }
+ else if (valueString == L"ZIPCRYPTO")
+ {
+ m_IsAesMode = false;
+ m_ForceAesMode = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else if (name[0] == L'D')
+ {
+ UInt32 dicSize = kBZip2DicSizeX5;
+ RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
+ m_DicSize = dicSize;
+ }
+ else if (name.Left(3) == L"MEM")
+ {
+ UInt32 memSize = 1 << 24;
+ RINOK(ParsePropDictionaryValue(name.Mid(3), prop, memSize));
+ m_MemSize = memSize;
+ }
+ else if (name[0] == L'O')
+ {
+ UInt32 order = 8;
+ RINOK(ParsePropValue(name.Mid(1), prop, order));
+ m_Order = order;
+ }
+ else if (name.Left(4) == L"PASS")
+ {
+ UInt32 num = kDeflateNumPassesX9;
+ RINOK(ParsePropValue(name.Mid(4), prop, num));
+ m_NumPasses = num;
+ }
+ else if (name.Left(2) == L"FB")
+ {
+ UInt32 num = kDeflateNumFastBytesX9;
+ RINOK(ParsePropValue(name.Mid(2), prop, num));
+ m_NumFastBytes = num;
+ }
+ else if (name.Left(2) == L"MC")
+ {
+ UInt32 num = 0xFFFFFFFF;
+ RINOK(ParsePropValue(name.Mid(2), prop, num));
+ m_NumMatchFinderCycles = num;
+ m_NumMatchFinderCyclesDefined = true;
+ }
+ else if (name.Left(2) == L"MT")
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
+ #endif
+ }
+ else if (name.Left(1) == L"A")
+ {
+ UInt32 num = kLzAlgoX5;
+ RINOK(ParsePropValue(name.Mid(1), prop, num));
+ m_Algo = num;
+ }
+ else if (name.CompareNoCase(L"TC") == 0)
+ {
+ RINOK(SetBoolProperty(m_WriteNtfsTimeExtra, prop));
+ }
+ else if (name.CompareNoCase(L"CL") == 0)
+ {
+ RINOK(SetBoolProperty(m_ForceLocal, prop));
+ if (m_ForceLocal)
+ m_ForceUtf8 = false;
+ }
+ else if (name.CompareNoCase(L"CU") == 0)
+ {
+ RINOK(SetBoolProperty(m_ForceUtf8, prop));
+ if (m_ForceUtf8)
+ m_ForceLocal = false;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHeader.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHeader.cpp
new file mode 100644
index 000000000..582187b51
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHeader.cpp
@@ -0,0 +1,36 @@
+// Archive/Zip/Header.h
+
+#include "StdAfx.h"
+
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+namespace NSignature
+{
+ UInt32 kLocalFileHeader = 0x04034B50 + 1;
+ UInt32 kDataDescriptor = 0x08074B50 + 1;
+ UInt32 kCentralFileHeader = 0x02014B50 + 1;
+ UInt32 kEndOfCentralDir = 0x06054B50 + 1;
+ UInt32 kZip64EndOfCentralDir = 0x06064B50 + 1;
+ UInt32 kZip64EndOfCentralDirLocator = 0x07064B50 + 1;
+
+ class CMarkersInitializer
+ {
+ public:
+ CMarkersInitializer()
+ {
+ kLocalFileHeader--;
+ kDataDescriptor--;
+ kCentralFileHeader--;
+ kEndOfCentralDir--;
+ kZip64EndOfCentralDir--;
+ kZip64EndOfCentralDirLocator--;
+ }
+ };
+ static CMarkersInitializer g_MarkerInitializer;
+}
+
+}}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHeader.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHeader.h
new file mode 100644
index 000000000..ce8c1e4f7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -0,0 +1,284 @@
+// Archive/Zip/Header.h
+
+#ifndef __ARCHIVE_ZIP_HEADER_H
+#define __ARCHIVE_ZIP_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NZip {
+
+namespace NSignature
+{
+ extern UInt32 kLocalFileHeader;
+ extern UInt32 kDataDescriptor;
+ extern UInt32 kCentralFileHeader;
+ extern UInt32 kEndOfCentralDir;
+ extern UInt32 kZip64EndOfCentralDir;
+ extern UInt32 kZip64EndOfCentralDirLocator;
+
+ static const UInt32 kMarkerSize = 4;
+}
+
+const UInt32 kEcdSize = 22;
+const UInt32 kZip64EcdSize = 44;
+const UInt32 kZip64EcdLocatorSize = 20;
+/*
+struct CEndOfCentralDirectoryRecord
+{
+ UInt16 ThisDiskNumber;
+ UInt16 StartCentralDirectoryDiskNumber;
+ UInt16 NumEntriesInCentaralDirectoryOnThisDisk;
+ UInt16 NumEntriesInCentaralDirectory;
+ UInt32 CentralDirectorySize;
+ UInt32 CentralDirectoryStartOffset;
+ UInt16 CommentSize;
+};
+
+struct CEndOfCentralDirectoryRecordFull
+{
+ UInt32 Signature;
+ CEndOfCentralDirectoryRecord Header;
+};
+*/
+
+namespace NFileHeader
+{
+ /*
+ struct CVersion
+ {
+ Byte Version;
+ Byte HostOS;
+ };
+ */
+
+ namespace NCompressionMethod
+ {
+ enum EType
+ {
+ kStored = 0,
+ kShrunk = 1,
+ kReduced1 = 2,
+ kReduced2 = 3,
+ kReduced3 = 4,
+ kReduced4 = 5,
+ kImploded = 6,
+ kReservedTokenizing = 7, // reserved for tokenizing
+ kDeflated = 8,
+ kDeflated64 = 9,
+ kPKImploding = 10,
+
+ kBZip2 = 12,
+ kLZMA = 14,
+ kTerse = 18,
+ kLz77 = 19,
+ kJpeg = 0x60,
+ kWavPack = 0x61,
+ kPPMd = 0x62,
+ kWzAES = 0x63
+ };
+ const int kNumCompressionMethods = 11;
+ const Byte kMadeByProgramVersion = 63;
+
+ const Byte kExtractVersion_Default = 10;
+ const Byte kExtractVersion_Dir = 20;
+ const Byte kExtractVersion_ZipCrypto = 20;
+ const Byte kExtractVersion_Deflate = 20;
+ const Byte kExtractVersion_Deflate64 = 21;
+ const Byte kExtractVersion_Zip64 = 45;
+ const Byte kExtractVersion_BZip2 = 46;
+ const Byte kExtractVersion_Aes = 51;
+ const Byte kExtractVersion_LZMA = 63;
+ const Byte kExtractVersion_PPMd = 63;
+
+ // const Byte kSupportedVersion = 20;
+ }
+
+ namespace NExtraID
+ {
+ enum
+ {
+ kZip64 = 0x01,
+ kNTFS = 0x0A,
+ kStrongEncrypt = 0x17,
+ kUnixTime = 0x5455,
+ kWzAES = 0x9901
+ };
+ }
+
+ namespace NNtfsExtra
+ {
+ const UInt16 kTagTime = 1;
+ enum
+ {
+ kMTime = 0,
+ kATime,
+ kCTime
+ };
+ }
+
+ namespace NUnixTime
+ {
+ enum
+ {
+ kMTime = 0,
+ kATime,
+ kCTime
+ };
+ }
+
+ const UInt32 kLocalBlockSize = 26;
+ /*
+ struct CLocalBlock
+ {
+ CVersion ExtractVersion;
+
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ UInt16 NameSize;
+ UInt16 ExtraSize;
+ };
+ */
+
+ const UInt32 kDataDescriptorSize = 16;
+ // const UInt32 kDataDescriptor64Size = 16 + 8;
+ /*
+ struct CDataDescriptor
+ {
+ UInt32 Signature;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ };
+
+ struct CLocalBlockFull
+ {
+ UInt32 Signature;
+ CLocalBlock Header;
+ };
+ */
+
+ const UInt32 kCentralBlockSize = 42;
+ /*
+ struct CBlock
+ {
+ CVersion MadeByVersion;
+ CVersion ExtractVersion;
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ UInt16 NameSize;
+ UInt16 ExtraSize;
+ UInt16 CommentSize;
+ UInt16 DiskNumberStart;
+ UInt16 InternalAttributes;
+ UInt32 ExternalAttributes;
+ UInt32 LocalHeaderOffset;
+ };
+
+ struct CBlockFull
+ {
+ UInt32 Signature;
+ CBlock Header;
+ };
+ */
+
+ namespace NFlags
+ {
+ const int kEncrypted = 1 << 0;
+ const int kLzmaEOS = 1 << 1;
+ const int kDescriptorUsedMask = 1 << 3;
+ const int kStrongEncrypted = 1 << 6;
+ const int kUtf8 = 1 << 11;
+
+ const int kImplodeDictionarySizeMask = 1 << 1;
+ const int kImplodeLiteralsOnMask = 1 << 2;
+
+ const int kDeflateTypeBitStart = 1;
+ const int kNumDeflateTypeBits = 2;
+ const int kNumDeflateTypes = (1 << kNumDeflateTypeBits);
+ const int kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1;
+ }
+
+ namespace NHostOS
+ {
+ enum EEnum
+ {
+ kFAT = 0,
+ kAMIGA = 1,
+ kVMS = 2, // VAX/VMS
+ kUnix = 3,
+ kVM_CMS = 4,
+ kAtari = 5, // what if it's a minix filesystem? [cjh]
+ kHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
+ kMac = 7,
+ kZ_System = 8,
+ kCPM = 9,
+ kTOPS20 = 10, // pkzip 2.50 NTFS
+ kNTFS = 11, // filesystem used by Windows NT
+ kQDOS = 12, // SMS/QDOS
+ kAcorn = 13, // Archimedes Acorn RISC OS
+ kVFAT = 14, // filesystem used by Windows 95, NT
+ kMVS = 15,
+ kBeOS = 16, // hybrid POSIX/database filesystem
+ kTandem = 17,
+ kOS400 = 18,
+ kOSX = 19
+ };
+ }
+ namespace NUnixAttribute
+ {
+ const UInt32 kIFMT = 0170000; /* Unix file type mask */
+
+ const UInt32 kIFDIR = 0040000; /* Unix directory */
+ const UInt32 kIFREG = 0100000; /* Unix regular file */
+ const UInt32 kIFSOCK = 0140000; /* Unix socket (BSD, not SysV or Amiga) */
+ const UInt32 kIFLNK = 0120000; /* Unix symbolic link (not SysV, Amiga) */
+ const UInt32 kIFBLK = 0060000; /* Unix block special (not Amiga) */
+ const UInt32 kIFCHR = 0020000; /* Unix character special (not Amiga) */
+ const UInt32 kIFIFO = 0010000; /* Unix fifo (BCC, not MSC or Amiga) */
+
+ const UInt32 kISUID = 04000; /* Unix set user id on execution */
+ const UInt32 kISGID = 02000; /* Unix set group id on execution */
+ const UInt32 kISVTX = 01000; /* Unix directory permissions control */
+ const UInt32 kENFMT = kISGID; /* Unix record locking enforcement flag */
+ const UInt32 kIRWXU = 00700; /* Unix read, write, execute: owner */
+ const UInt32 kIRUSR = 00400; /* Unix read permission: owner */
+ const UInt32 kIWUSR = 00200; /* Unix write permission: owner */
+ const UInt32 kIXUSR = 00100; /* Unix execute permission: owner */
+ const UInt32 kIRWXG = 00070; /* Unix read, write, execute: group */
+ const UInt32 kIRGRP = 00040; /* Unix read permission: group */
+ const UInt32 kIWGRP = 00020; /* Unix write permission: group */
+ const UInt32 kIXGRP = 00010; /* Unix execute permission: group */
+ const UInt32 kIRWXO = 00007; /* Unix read, write, execute: other */
+ const UInt32 kIROTH = 00004; /* Unix read permission: other */
+ const UInt32 kIWOTH = 00002; /* Unix write permission: other */
+ const UInt32 kIXOTH = 00001; /* Unix execute permission: other */
+ }
+
+ namespace NAmigaAttribute
+ {
+ const UInt32 kIFMT = 06000; /* Amiga file type mask */
+ const UInt32 kIFDIR = 04000; /* Amiga directory */
+ const UInt32 kIFREG = 02000; /* Amiga regular file */
+ const UInt32 kIHIDDEN = 00200; /* to be supported in AmigaDOS 3.x */
+ const UInt32 kISCRIPT = 00100; /* executable script (text command file) */
+ const UInt32 kIPURE = 00040; /* allow loading into resident memory */
+ const UInt32 kIARCHIVE = 00020; /* not modified since bit was last set */
+ const UInt32 kIREAD = 00010; /* can be opened for reading */
+ const UInt32 kIWRITE = 00004; /* can be opened for writing */
+ const UInt32 kIEXECUTE = 00002; /* executable image, a loadable runfile */
+ const UInt32 kIDELETE = 00001; /* can be deleted */
+ }
+}
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipIn.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipIn.cpp
new file mode 100644
index 000000000..b36b61be7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -0,0 +1,893 @@
+// Archive/ZipIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/DynamicBuffer.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "ZipIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NZip {
+
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ _inBufMode = false;
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition));
+ m_Position = m_StreamStartPosition;
+ RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit));
+ RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
+ m_Stream = stream;
+ return S_OK;
+}
+
+void CInArchive::Close()
+{
+ _inBuffer.ReleaseStream();
+ m_Stream.Release();
+}
+
+HRESULT CInArchive::Seek(UInt64 offset)
+{
+ return m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+}
+
+//////////////////////////////////////
+// Markers
+
+static inline bool TestMarkerCandidate(const Byte *p, UInt32 &value)
+{
+ value = Get32(p);
+ return
+ (value == NSignature::kLocalFileHeader) ||
+ (value == NSignature::kEndOfCentralDir);
+}
+
+static const UInt32 kNumMarkerAddtionalBytes = 2;
+static inline bool TestMarkerCandidate2(const Byte *p, UInt32 &value)
+{
+ value = Get32(p);
+ if (value == NSignature::kEndOfCentralDir)
+ return (Get16(p + 4) == 0);
+ return (value == NSignature::kLocalFileHeader && p[4] < 128);
+}
+
+HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ ArcInfo.Clear();
+ m_Position = m_StreamStartPosition;
+
+ Byte marker[NSignature::kMarkerSize];
+ RINOK(ReadStream_FALSE(stream, marker, NSignature::kMarkerSize));
+ m_Position += NSignature::kMarkerSize;
+ if (TestMarkerCandidate(marker, m_Signature))
+ return S_OK;
+
+ CByteDynamicBuffer dynamicBuffer;
+ const UInt32 kSearchMarkerBufferSize = 0x10000;
+ dynamicBuffer.EnsureCapacity(kSearchMarkerBufferSize);
+ Byte *buffer = dynamicBuffer;
+ UInt32 numBytesPrev = NSignature::kMarkerSize - 1;
+ memcpy(buffer, marker + 1, numBytesPrev);
+ UInt64 curTestPos = m_StreamStartPosition + 1;
+ for (;;)
+ {
+ if (searchHeaderSizeLimit != NULL)
+ if (curTestPos - m_StreamStartPosition > *searchHeaderSizeLimit)
+ break;
+ size_t numReadBytes = kSearchMarkerBufferSize - numBytesPrev;
+ RINOK(ReadStream(stream, buffer + numBytesPrev, &numReadBytes));
+ m_Position += numReadBytes;
+ UInt32 numBytesInBuffer = numBytesPrev + (UInt32)numReadBytes;
+ const UInt32 kMarker2Size = NSignature::kMarkerSize + kNumMarkerAddtionalBytes;
+ if (numBytesInBuffer < kMarker2Size)
+ break;
+ UInt32 numTests = numBytesInBuffer - kMarker2Size + 1;
+ for (UInt32 pos = 0; pos < numTests; pos++)
+ {
+ if (buffer[pos] != 0x50)
+ continue;
+ if (TestMarkerCandidate2(buffer + pos, m_Signature))
+ {
+ curTestPos += pos;
+ ArcInfo.StartPosition = curTestPos;
+ m_Position = curTestPos + NSignature::kMarkerSize;
+ return S_OK;
+ }
+ }
+ curTestPos += numTests;
+ numBytesPrev = numBytesInBuffer - numTests;
+ memmove(buffer, buffer + numTests, numBytesPrev);
+ }
+ return S_FALSE;
+}
+
+HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t realProcessedSize = size;
+ HRESULT result = S_OK;
+ if (_inBufMode)
+ {
+ try { realProcessedSize = _inBuffer.ReadBytes((Byte *)data, size); }
+ catch (const CInBufferException &e) { return e.ErrorCode; }
+ }
+ else
+ result = ReadStream(m_Stream, data, &realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize = (UInt32)realProcessedSize;
+ m_Position += realProcessedSize;
+ return result;
+}
+
+void CInArchive::Skip(UInt64 num)
+{
+ for (UInt64 i = 0; i < num; i++)
+ ReadByte();
+}
+
+void CInArchive::IncreaseRealPosition(UInt64 addValue)
+{
+ if (m_Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position) != S_OK)
+ throw CInArchiveException(CInArchiveException::kSeekStreamError);
+}
+
+bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
+{
+ UInt32 realProcessedSize;
+ if (ReadBytes(data, size, &realProcessedSize) != S_OK)
+ throw CInArchiveException(CInArchiveException::kReadStreamError);
+ return (realProcessedSize == size);
+}
+
+void CInArchive::SafeReadBytes(void *data, UInt32 size)
+{
+ if (!ReadBytesAndTestSize(data, size))
+ throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+}
+
+void CInArchive::ReadBuffer(CByteBuffer &buffer, UInt32 size)
+{
+ buffer.SetCapacity(size);
+ if (size > 0)
+ SafeReadBytes(buffer, size);
+}
+
+Byte CInArchive::ReadByte()
+{
+ Byte b;
+ SafeReadBytes(&b, 1);
+ return b;
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ Byte buf[2];
+ SafeReadBytes(buf, 2);
+ return Get16(buf);
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ Byte buf[4];
+ SafeReadBytes(buf, 4);
+ return Get32(buf);
+}
+
+UInt64 CInArchive::ReadUInt64()
+{
+ Byte buf[8];
+ SafeReadBytes(buf, 8);
+ return Get64(buf);
+}
+
+bool CInArchive::ReadUInt32(UInt32 &value)
+{
+ Byte buf[4];
+ if (!ReadBytesAndTestSize(buf, 4))
+ return false;
+ value = Get32(buf);
+ return true;
+}
+
+void CInArchive::ReadFileName(UInt32 nameSize, AString &dest)
+{
+ if (nameSize == 0)
+ dest.Empty();
+ char *p = dest.GetBuffer((int)nameSize);
+ SafeReadBytes(p, nameSize);
+ p[nameSize] = 0;
+ dest.ReleaseBuffer();
+}
+
+void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
+ UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber)
+{
+ extraBlock.Clear();
+ UInt32 remain = extraSize;
+ while(remain >= 4)
+ {
+ CExtraSubBlock subBlock;
+ subBlock.ID = ReadUInt16();
+ UInt32 dataSize = ReadUInt16();
+ remain -= 4;
+ if (dataSize > remain) // it's bug
+ dataSize = remain;
+ if (subBlock.ID == NFileHeader::NExtraID::kZip64)
+ {
+ if (unpackSize == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ unpackSize = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (packSize == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ packSize = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (localHeaderOffset == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ localHeaderOffset = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (diskStartNumber == 0xFFFF)
+ {
+ if (dataSize < 4)
+ break;
+ diskStartNumber = ReadUInt32();
+ remain -= 4;
+ dataSize -= 4;
+ }
+ for (UInt32 i = 0; i < dataSize; i++)
+ ReadByte();
+ }
+ else
+ {
+ ReadBuffer(subBlock.Data, dataSize);
+ extraBlock.SubBlocks.Add(subBlock);
+ }
+ remain -= dataSize;
+ }
+ Skip(remain);
+}
+
+HRESULT CInArchive::ReadLocalItem(CItemEx &item)
+{
+ const int kBufSize = 26;
+ Byte p[kBufSize];
+ SafeReadBytes(p, kBufSize);
+
+ item.ExtractVersion.Version = p[0];
+ item.ExtractVersion.HostOS = p[1];
+ item.Flags = Get16(p + 2);
+ item.CompressionMethod = Get16(p + 4);
+ item.Time = Get32(p + 6);
+ item.FileCRC = Get32(p + 10);
+ item.PackSize = Get32(p + 14);
+ item.UnPackSize = Get32(p + 18);
+ UInt32 fileNameSize = Get16(p + 22);
+ item.LocalExtraSize = Get16(p + 24);
+ ReadFileName(fileNameSize, item.Name);
+ item.FileHeaderWithNameSize = 4 + NFileHeader::kLocalBlockSize + fileNameSize;
+ if (item.LocalExtraSize > 0)
+ {
+ UInt64 localHeaderOffset = 0;
+ UInt32 diskStartNumber = 0;
+ ReadExtra(item.LocalExtraSize, item.LocalExtra, item.UnPackSize, item.PackSize,
+ localHeaderOffset, diskStartNumber);
+ }
+ /*
+ if (item.IsDir())
+ item.UnPackSize = 0; // check It
+ */
+ return S_OK;
+}
+
+static bool FlagsAreSame(CItem &i1, CItem &i2)
+{
+ if (i1.CompressionMethod != i2.CompressionMethod)
+ return false;
+ // i1.Time
+
+ if (i1.Flags == i2.Flags)
+ return true;
+ UInt32 mask = 0xFFFF;
+ switch(i1.CompressionMethod)
+ {
+ case NFileHeader::NCompressionMethod::kDeflated:
+ mask = 0x7FF9;
+ break;
+ default:
+ if (i1.CompressionMethod <= NFileHeader::NCompressionMethod::kImploded)
+ mask = 0x7FFF;
+ }
+ return ((i1.Flags & mask) == (i2.Flags & mask));
+}
+
+HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item)
+{
+ if (item.FromLocal)
+ return S_OK;
+ try
+ {
+ RINOK(Seek(ArcInfo.Base + item.LocalHeaderPosition));
+ CItemEx localItem;
+ if (ReadUInt32() != NSignature::kLocalFileHeader)
+ return S_FALSE;
+ RINOK(ReadLocalItem(localItem));
+ if (!FlagsAreSame(item, localItem))
+ return S_FALSE;
+
+ if ((!localItem.HasDescriptor() &&
+ (
+ item.FileCRC != localItem.FileCRC ||
+ item.PackSize != localItem.PackSize ||
+ item.UnPackSize != localItem.UnPackSize
+ )
+ ) ||
+ item.Name.Length() != localItem.Name.Length()
+ )
+ return S_FALSE;
+ item.FileHeaderWithNameSize = localItem.FileHeaderWithNameSize;
+ item.LocalExtraSize = localItem.LocalExtraSize;
+ item.LocalExtra = localItem.LocalExtra;
+ item.FromLocal = true;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item)
+{
+ if (item.HasDescriptor())
+ {
+ const int kBufferSize = (1 << 12);
+ Byte buffer[kBufferSize];
+
+ UInt32 numBytesInBuffer = 0;
+ UInt32 packedSize = 0;
+
+ bool descriptorWasFound = false;
+ for (;;)
+ {
+ UInt32 processedSize;
+ RINOK(ReadBytes(buffer + numBytesInBuffer, kBufferSize - numBytesInBuffer, &processedSize));
+ numBytesInBuffer += processedSize;
+ if (numBytesInBuffer < NFileHeader::kDataDescriptorSize)
+ return S_FALSE;
+ UInt32 i;
+ for (i = 0; i <= numBytesInBuffer - NFileHeader::kDataDescriptorSize; i++)
+ {
+ // descriptorSignature field is Info-ZIP's extension
+ // to Zip specification.
+ UInt32 descriptorSignature = Get32(buffer + i);
+
+ // !!!! It must be fixed for Zip64 archives
+ UInt32 descriptorPackSize = Get32(buffer + i + 8);
+ if (descriptorSignature== NSignature::kDataDescriptor && descriptorPackSize == packedSize + i)
+ {
+ descriptorWasFound = true;
+ item.FileCRC = Get32(buffer + i + 4);
+ item.PackSize = descriptorPackSize;
+ item.UnPackSize = Get32(buffer + i + 12);
+ IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - NFileHeader::kDataDescriptorSize))));
+ break;
+ }
+ }
+ if (descriptorWasFound)
+ break;
+ packedSize += i;
+ int j;
+ for (j = 0; i < numBytesInBuffer; i++, j++)
+ buffer[j] = buffer[i];
+ numBytesInBuffer = j;
+ }
+ }
+ else
+ IncreaseRealPosition(item.PackSize);
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item)
+{
+ if (item.FromLocal)
+ return S_OK;
+ try
+ {
+ RINOK(ReadLocalItemAfterCdItem(item));
+ if (item.HasDescriptor())
+ {
+ RINOK(Seek(ArcInfo.Base + item.GetDataPosition() + item.PackSize));
+ if (ReadUInt32() != NSignature::kDataDescriptor)
+ return S_FALSE;
+ UInt32 crc = ReadUInt32();
+ UInt64 packSize, unpackSize;
+
+ /*
+ if (IsZip64)
+ {
+ packSize = ReadUInt64();
+ unpackSize = ReadUInt64();
+ }
+ else
+ */
+ {
+ packSize = ReadUInt32();
+ unpackSize = ReadUInt32();
+ }
+
+ if (crc != item.FileCRC || item.PackSize != packSize || item.UnPackSize != unpackSize)
+ return S_FALSE;
+ }
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadCdItem(CItemEx &item)
+{
+ item.FromCentral = true;
+ const int kBufSize = 42;
+ Byte p[kBufSize];
+ SafeReadBytes(p, kBufSize);
+ item.MadeByVersion.Version = p[0];
+ item.MadeByVersion.HostOS = p[1];
+ item.ExtractVersion.Version = p[2];
+ item.ExtractVersion.HostOS = p[3];
+ item.Flags = Get16(p + 4);
+ item.CompressionMethod = Get16(p + 6);
+ item.Time = Get32(p + 8);
+ item.FileCRC = Get32(p + 12);
+ item.PackSize = Get32(p + 16);
+ item.UnPackSize = Get32(p + 20);
+ UInt16 headerNameSize = Get16(p + 24);
+ UInt16 headerExtraSize = Get16(p + 26);
+ UInt16 headerCommentSize = Get16(p + 28);
+ UInt32 headerDiskNumberStart = Get16(p + 30);
+ item.InternalAttributes = Get16(p + 32);
+ item.ExternalAttributes = Get32(p + 34);
+ item.LocalHeaderPosition = Get32(p + 38);
+ ReadFileName(headerNameSize, item.Name);
+
+ if (headerExtraSize > 0)
+ {
+ ReadExtra(headerExtraSize, item.CentralExtra, item.UnPackSize, item.PackSize,
+ item.LocalHeaderPosition, headerDiskNumberStart);
+ }
+
+ if (headerDiskNumberStart != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+
+ // May be these strings must be deleted
+ /*
+ if (item.IsDir())
+ item.UnPackSize = 0;
+ */
+
+ ReadBuffer(item.Comment, headerCommentSize);
+ return S_OK;
+}
+
+HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
+{
+ RINOK(Seek(offset));
+ const UInt32 kEcd64Size = 56;
+ Byte buf[kEcd64Size];
+ if (!ReadBytesAndTestSize(buf, kEcd64Size))
+ return S_FALSE;
+ if (Get32(buf) != NSignature::kZip64EndOfCentralDir)
+ return S_FALSE;
+ // cdInfo.NumEntries = Get64(buf + 24);
+ cdInfo.Size = Get64(buf + 40);
+ cdInfo.Offset = Get64(buf + 48);
+ return S_OK;
+}
+
+HRESULT CInArchive::FindCd(CCdInfo &cdInfo)
+{
+ UInt64 endPosition;
+ RINOK(m_Stream->Seek(0, STREAM_SEEK_END, &endPosition));
+ const UInt32 kBufSizeMax = (1 << 16) + kEcdSize + kZip64EcdLocatorSize;
+ CByteBuffer byteBuffer;
+ byteBuffer.SetCapacity(kBufSizeMax);
+ Byte *buf = byteBuffer;
+ UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeMax;
+ if (bufSize < kEcdSize)
+ return S_FALSE;
+ UInt64 startPosition = endPosition - bufSize;
+ RINOK(m_Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != startPosition)
+ return S_FALSE;
+ if (!ReadBytesAndTestSize(buf, bufSize))
+ return S_FALSE;
+ for (int i = (int)(bufSize - kEcdSize); i >= 0; i--)
+ {
+ if (Get32(buf + i) == NSignature::kEndOfCentralDir)
+ {
+ if (i >= kZip64EcdLocatorSize)
+ {
+ const Byte *locator = buf + i - kZip64EcdLocatorSize;
+ if (Get32(locator) == NSignature::kZip64EndOfCentralDirLocator)
+ {
+ UInt64 ecd64Offset = Get64(locator + 8);
+ if (TryEcd64(ecd64Offset, cdInfo) == S_OK)
+ return S_OK;
+ if (TryEcd64(ArcInfo.StartPosition + ecd64Offset, cdInfo) == S_OK)
+ {
+ ArcInfo.Base = ArcInfo.StartPosition;
+ return S_OK;
+ }
+ }
+ }
+ if (Get32(buf + i + 4) == 0)
+ {
+ // cdInfo.NumEntries = GetUInt16(buf + i + 10);
+ cdInfo.Size = Get32(buf + i + 12);
+ cdInfo.Offset = Get32(buf + i + 16);
+ UInt64 curPos = endPosition - bufSize + i;
+ UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
+ if (curPos != cdEnd)
+ {
+ /*
+ if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
+ {
+ // here we support some rare ZIP files with Central directory at the start
+ ArcInfo.Base = 0;
+ }
+ else
+ */
+ ArcInfo.Base = curPos - cdEnd;
+ }
+ return S_OK;
+ }
+ }
+ }
+ return S_FALSE;
+}
+
+HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress)
+{
+ items.Clear();
+ RINOK(m_Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != cdOffset)
+ return S_FALSE;
+
+ if (!_inBuffer.Create(1 << 15))
+ return E_OUTOFMEMORY;
+ _inBuffer.SetStream(m_Stream);
+ _inBuffer.Init();
+ _inBufMode = true;
+
+ while(m_Position - cdOffset < cdSize)
+ {
+ if (ReadUInt32() != NSignature::kCentralFileHeader)
+ return S_FALSE;
+ CItemEx cdItem;
+ RINOK(ReadCdItem(cdItem));
+ items.Add(cdItem);
+ if (progress && items.Size() % 1000 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ }
+ return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress)
+{
+ ArcInfo.Base = 0;
+ CCdInfo cdInfo;
+ RINOK(FindCd(cdInfo));
+ HRESULT res = S_FALSE;
+ cdSize = cdInfo.Size;
+ cdOffset = cdInfo.Offset;
+ res = TryReadCd(items, ArcInfo.Base + cdOffset, cdSize, progress);
+ if (res == S_FALSE && ArcInfo.Base == 0)
+ {
+ res = TryReadCd(items, cdInfo.Offset + ArcInfo.StartPosition, cdSize, progress);
+ if (res == S_OK)
+ ArcInfo.Base = ArcInfo.StartPosition;
+ }
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ return res;
+}
+
+HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems)
+{
+ items.Clear();
+ numCdItems = 0;
+ while (m_Signature == NSignature::kLocalFileHeader)
+ {
+ // FSeek points to next byte after signature
+ // NFileHeader::CLocalBlock localHeader;
+ CItemEx item;
+ item.LocalHeaderPosition = m_Position - m_StreamStartPosition - 4; // points to signature;
+ RINOK(ReadLocalItem(item));
+ item.FromLocal = true;
+ ReadLocalItemDescriptor(item);
+ items.Add(item);
+ if (progress && items.Size() % 100 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ if (!ReadUInt32(m_Signature))
+ break;
+ }
+ cdOffset = m_Position - 4;
+ int i;
+ for (i = 0; i < items.Size(); i++, numCdItems++)
+ {
+ if (progress && i % 1000 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ if (m_Signature == NSignature::kEndOfCentralDir)
+ break;
+
+ if (m_Signature != NSignature::kCentralFileHeader)
+ return S_FALSE;
+
+ CItemEx cdItem;
+ RINOK(ReadCdItem(cdItem));
+
+ if (i == 0)
+ {
+ int j;
+ for (j = 0; j < items.Size(); j++)
+ {
+ CItemEx &item = items[j];
+ if (item.Name == cdItem.Name)
+ {
+ ArcInfo.Base = item.LocalHeaderPosition - cdItem.LocalHeaderPosition;
+ break;
+ }
+ }
+ if (j == items.Size())
+ return S_FALSE;
+ }
+
+ int index;
+ int left = 0, right = items.Size();
+ for (;;)
+ {
+ if (left >= right)
+ return S_FALSE;
+ index = (left + right) / 2;
+ UInt64 position = items[index].LocalHeaderPosition - ArcInfo.Base;
+ if (cdItem.LocalHeaderPosition == position)
+ break;
+ if (cdItem.LocalHeaderPosition < position)
+ right = index;
+ else
+ left = index + 1;
+ }
+ CItemEx &item = items[index];
+ // item.LocalHeaderPosition = cdItem.LocalHeaderPosition;
+ item.MadeByVersion = cdItem.MadeByVersion;
+ item.CentralExtra = cdItem.CentralExtra;
+
+ if (
+ // item.ExtractVersion != cdItem.ExtractVersion ||
+ !FlagsAreSame(item, cdItem) ||
+ item.FileCRC != cdItem.FileCRC)
+ return S_FALSE;
+
+ if (item.Name.Length() != cdItem.Name.Length() ||
+ item.PackSize != cdItem.PackSize ||
+ item.UnPackSize != cdItem.UnPackSize
+ )
+ return S_FALSE;
+ item.Name = cdItem.Name;
+ item.InternalAttributes = cdItem.InternalAttributes;
+ item.ExternalAttributes = cdItem.ExternalAttributes;
+ item.Comment = cdItem.Comment;
+ item.FromCentral = cdItem.FromCentral;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ }
+ for (i = 0; i < items.Size(); i++)
+ items[i].LocalHeaderPosition -= ArcInfo.Base;
+ return S_OK;
+}
+
+struct CEcd
+{
+ UInt16 thisDiskNumber;
+ UInt16 startCDDiskNumber;
+ UInt16 numEntriesInCDOnThisDisk;
+ UInt16 numEntriesInCD;
+ UInt32 cdSize;
+ UInt32 cdStartOffset;
+ UInt16 commentSize;
+ void Parse(const Byte *p);
+};
+
+void CEcd::Parse(const Byte *p)
+{
+ thisDiskNumber = Get16(p);
+ startCDDiskNumber = Get16(p + 2);
+ numEntriesInCDOnThisDisk = Get16(p + 4);
+ numEntriesInCD = Get16(p + 6);
+ cdSize = Get32(p + 8);
+ cdStartOffset = Get32(p + 12);
+ commentSize = Get16(p + 16);
+}
+
+struct CEcd64
+{
+ UInt16 versionMade;
+ UInt16 versionNeedExtract;
+ UInt32 thisDiskNumber;
+ UInt32 startCDDiskNumber;
+ UInt64 numEntriesInCDOnThisDisk;
+ UInt64 numEntriesInCD;
+ UInt64 cdSize;
+ UInt64 cdStartOffset;
+ void Parse(const Byte *p);
+ CEcd64() { memset(this, 0, sizeof(*this)); }
+};
+
+void CEcd64::Parse(const Byte *p)
+{
+ versionMade = Get16(p);
+ versionNeedExtract = Get16(p + 2);
+ thisDiskNumber = Get32(p + 4);
+ startCDDiskNumber = Get32(p + 8);
+ numEntriesInCDOnThisDisk = Get64(p + 12);
+ numEntriesInCD = Get64(p + 20);
+ cdSize = Get64(p + 28);
+ cdStartOffset = Get64(p + 36);
+}
+
+#define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd. n;
+#define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd. n;
+
+HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress)
+{
+ // m_Signature must be kLocalFileHeaderSignature or
+ // kEndOfCentralDirSignature
+ // m_Position points to next byte after signature
+
+ IsZip64 = false;
+ items.Clear();
+
+ UInt64 cdSize, cdStartOffset;
+ HRESULT res;
+ try
+ {
+ res = ReadCd(items, cdStartOffset, cdSize, progress);
+ }
+ catch(CInArchiveException &)
+ {
+ res = S_FALSE;
+ }
+ if (res != S_FALSE && res != S_OK)
+ return res;
+
+ /*
+ if (res != S_OK)
+ return res;
+ res = S_FALSE;
+ */
+
+ int numCdItems = items.Size();
+ if (res == S_FALSE)
+ {
+ _inBufMode = false;
+ ArcInfo.Base = 0;
+ RINOK(m_Stream->Seek(ArcInfo.StartPosition, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != ArcInfo.StartPosition)
+ return S_FALSE;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ RINOK(ReadLocalsAndCd(items, progress, cdStartOffset, numCdItems));
+ cdSize = (m_Position - 4) - cdStartOffset;
+ cdStartOffset -= ArcInfo.Base;
+ }
+
+ CEcd64 ecd64;
+ bool isZip64 = false;
+ UInt64 zip64EcdStartOffset = m_Position - 4 - ArcInfo.Base;
+ if (m_Signature == NSignature::kZip64EndOfCentralDir)
+ {
+ IsZip64 = isZip64 = true;
+ UInt64 recordSize = ReadUInt64();
+
+ const int kBufSize = kZip64EcdSize;
+ Byte buf[kBufSize];
+ SafeReadBytes(buf, kBufSize);
+ ecd64.Parse(buf);
+
+ Skip(recordSize - kZip64EcdSize);
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+ if (ecd64.numEntriesInCDOnThisDisk != numCdItems ||
+ ecd64.numEntriesInCD != numCdItems ||
+ ecd64.cdSize != cdSize ||
+ (ecd64.cdStartOffset != cdStartOffset &&
+ (!items.IsEmpty())))
+ return S_FALSE;
+ }
+ if (m_Signature == NSignature::kZip64EndOfCentralDirLocator)
+ {
+ /* UInt32 startEndCDDiskNumber = */ ReadUInt32();
+ UInt64 endCDStartOffset = ReadUInt64();
+ /* UInt32 numberOfDisks = */ ReadUInt32();
+ if (zip64EcdStartOffset != endCDStartOffset)
+ return S_FALSE;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ }
+ if (m_Signature != NSignature::kEndOfCentralDir)
+ return S_FALSE;
+
+ const int kBufSize = kEcdSize - 4;
+ Byte buf[kBufSize];
+ SafeReadBytes(buf, kBufSize);
+ CEcd ecd;
+ ecd.Parse(buf);
+
+ COPY_ECD_ITEM_16(thisDiskNumber);
+ COPY_ECD_ITEM_16(startCDDiskNumber);
+ COPY_ECD_ITEM_16(numEntriesInCDOnThisDisk);
+ COPY_ECD_ITEM_16(numEntriesInCD);
+ COPY_ECD_ITEM_32(cdSize);
+ COPY_ECD_ITEM_32(cdStartOffset);
+
+ ReadBuffer(ArcInfo.Comment, ecd.commentSize);
+
+ if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+ if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)numCdItems) ||
+ (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) ||
+ (UInt32)ecd64.cdSize != (UInt32)cdSize ||
+ ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdStartOffset &&
+ (!items.IsEmpty())))
+ return S_FALSE;
+
+ _inBufMode = false;
+ _inBuffer.Free();
+ IsOkHeaders = (numCdItems == items.Size());
+ ArcInfo.FinishPosition = m_Position;
+ return S_OK;
+}
+
+ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
+{
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> stream(streamSpec);
+ SeekInArchive(ArcInfo.Base + position);
+ streamSpec->SetStream(m_Stream);
+ streamSpec->Init(size);
+ return stream.Detach();
+}
+
+IInStream* CInArchive::CreateStream()
+{
+ CMyComPtr<IInStream> stream = m_Stream;
+ return stream.Detach();
+}
+
+bool CInArchive::SeekInArchive(UInt64 position)
+{
+ UInt64 newPosition;
+ if (m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition) != S_OK)
+ return false;
+ return (newPosition == position);
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipIn.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipIn.h
new file mode 100644
index 000000000..0565339a0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipIn.h
@@ -0,0 +1,125 @@
+// Archive/ZipIn.h
+
+#ifndef __ZIP_IN_H
+#define __ZIP_IN_H
+
+#include "Common/MyCom.h"
+
+#include "../../IStream.h"
+
+#include "../../Common/InBuffer.h"
+
+#include "ZipHeader.h"
+#include "ZipItemEx.h"
+
+namespace NArchive {
+namespace NZip {
+
+class CInArchiveException
+{
+public:
+ enum ECauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kArchiceHeaderCRCError,
+ kFileHeaderCRCError,
+ kIncorrectArchive,
+ kDataDescroptorsAreNotSupported,
+ kMultiVolumeArchiveAreNotSupported,
+ kReadStreamError,
+ kSeekStreamError
+ }
+ Cause;
+ CInArchiveException(ECauseType cause): Cause(cause) {}
+};
+
+class CInArchiveInfo
+{
+public:
+ UInt64 Base;
+ UInt64 StartPosition;
+ UInt64 FinishPosition;
+ CByteBuffer Comment;
+
+ CInArchiveInfo(): Base(0), StartPosition(0) {}
+ UInt64 GetPhySize() const { return FinishPosition - StartPosition; }
+ void Clear()
+ {
+ Base = 0;
+ StartPosition = 0;
+ Comment.SetCapacity(0);
+ }
+};
+
+class CProgressVirt
+{
+public:
+ STDMETHOD(SetTotal)(UInt64 numFiles) PURE;
+ STDMETHOD(SetCompleted)(UInt64 numFiles) PURE;
+};
+
+struct CCdInfo
+{
+ // UInt64 NumEntries;
+ UInt64 Size;
+ UInt64 Offset;
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+ UInt32 m_Signature;
+ UInt64 m_StreamStartPosition;
+ UInt64 m_Position;
+
+ bool _inBufMode;
+ CInBuffer _inBuffer;
+
+ HRESULT Seek(UInt64 offset);
+
+ HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+ void ReadFileName(UInt32 nameSize, AString &dest);
+
+ HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize);
+ bool ReadBytesAndTestSize(void *data, UInt32 size);
+ void SafeReadBytes(void *data, UInt32 size);
+ void ReadBuffer(CByteBuffer &buffer, UInt32 size);
+ Byte ReadByte();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ bool ReadUInt32(UInt32 &signature);
+
+ void Skip(UInt64 num);
+ void IncreaseRealPosition(UInt64 addValue);
+
+ void ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
+ UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber);
+ HRESULT ReadLocalItem(CItemEx &item);
+ HRESULT ReadLocalItemDescriptor(CItemEx &item);
+ HRESULT ReadCdItem(CItemEx &item);
+ HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo);
+ HRESULT FindCd(CCdInfo &cdInfo);
+ HRESULT TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress);
+ HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress);
+ HRESULT ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems);
+public:
+ CInArchiveInfo ArcInfo;
+ bool IsZip64;
+ bool IsOkHeaders;
+
+ HRESULT ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress);
+ HRESULT ReadLocalItemAfterCdItem(CItemEx &item);
+ HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item);
+ HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+ void Close();
+ bool SeekInArchive(UInt64 position);
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
+
+ bool IsOpen() const { return m_Stream != NULL; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItem.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItem.cpp
new file mode 100644
index 000000000..4dd58f7d6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -0,0 +1,181 @@
+// Archive/ZipItem.cpp
+
+#include "StdAfx.h"
+
+#include "ZipHeader.h"
+#include "ZipItem.h"
+#include "../Common/ItemNameUtils.h"
+#include "../../../../C/CpuArch.h"
+
+namespace NArchive {
+namespace NZip {
+
+bool operator==(const CVersion &v1, const CVersion &v2)
+{
+ return (v1.Version == v2.Version) && (v1.HostOS == v2.HostOS);
+}
+
+bool operator!=(const CVersion &v1, const CVersion &v2)
+{
+ return !(v1 == v2);
+}
+
+bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const
+{
+ ft.dwHighDateTime = ft.dwLowDateTime = 0;
+ UInt32 size = (UInt32)Data.GetCapacity();
+ if (ID != NFileHeader::NExtraID::kNTFS || size < 32)
+ return false;
+ const Byte *p = (const Byte *)Data;
+ p += 4; // for reserved
+ size -= 4;
+ while (size > 4)
+ {
+ UInt16 tag = GetUi16(p);
+ UInt32 attrSize = GetUi16(p + 2);
+ p += 4;
+ size -= 4;
+ if (attrSize > size)
+ attrSize = size;
+
+ if (tag == NFileHeader::NNtfsExtra::kTagTime && attrSize >= 24)
+ {
+ p += 8 * index;
+ ft.dwLowDateTime = GetUi32(p);
+ ft.dwHighDateTime = GetUi32(p + 4);
+ return true;
+ }
+ p += attrSize;
+ size -= attrSize;
+ }
+ return false;
+}
+
+bool CExtraSubBlock::ExtractUnixTime(int index, UInt32 &res) const
+{
+ res = 0;
+ UInt32 size = (UInt32)Data.GetCapacity();
+ if (ID != NFileHeader::NExtraID::kUnixTime || size < 5)
+ return false;
+ const Byte *p = (const Byte *)Data;
+ Byte flags = *p++;
+ size--;
+ for (int i = 0; i < 3; i++)
+ if ((flags & (1 << i)) != 0)
+ {
+ if (size < 4)
+ return false;
+ if (index == i)
+ {
+ res = GetUi32(p);
+ return true;
+ }
+ p += 4;
+ size -= 4;
+ }
+ return false;
+}
+
+bool CLocalItem::IsDir() const
+{
+ return NItemName::HasTailSlash(Name, GetCodePage());
+}
+
+bool CItem::IsDir() const
+{
+ if (NItemName::HasTailSlash(Name, GetCodePage()))
+ return true;
+ if (!FromCentral)
+ return false;
+ WORD highAttributes = WORD((ExternalAttributes >> 16 ) & 0xFFFF);
+ switch(MadeByVersion.HostOS)
+ {
+ case NFileHeader::NHostOS::kAMIGA:
+ switch (highAttributes & NFileHeader::NAmigaAttribute::kIFMT)
+ {
+ case NFileHeader::NAmigaAttribute::kIFDIR: return true;
+ case NFileHeader::NAmigaAttribute::kIFREG: return false;
+ default: return false; // change it throw kUnknownAttributes;
+ }
+ case NFileHeader::NHostOS::kFAT:
+ case NFileHeader::NHostOS::kNTFS:
+ case NFileHeader::NHostOS::kHPFS:
+ case NFileHeader::NHostOS::kVFAT:
+ return ((ExternalAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ case NFileHeader::NHostOS::kAtari:
+ case NFileHeader::NHostOS::kMac:
+ case NFileHeader::NHostOS::kVMS:
+ case NFileHeader::NHostOS::kVM_CMS:
+ case NFileHeader::NHostOS::kAcorn:
+ case NFileHeader::NHostOS::kMVS:
+ return false; // change it throw kUnknownAttributes;
+ default:
+ /*
+ switch (highAttributes & NFileHeader::NUnixAttribute::kIFMT)
+ {
+ case NFileHeader::NUnixAttribute::kIFDIR:
+ return true;
+ default:
+ return false;
+ }
+ */
+ return false;
+ }
+}
+
+#ifndef FILE_ATTRIBUTE_UNIX_EXTENSION
+UInt32 CLocalItem::GetWinAttributes() const
+{
+ DWORD winAttributes = 0;
+ if (IsDir())
+ winAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAttributes;
+}
+#endif
+
+UInt32 CItem::GetWinAttributes() const
+{
+ DWORD winAttributes = 0;
+ switch(MadeByVersion.HostOS)
+ {
+ case NFileHeader::NHostOS::kFAT:
+ case NFileHeader::NHostOS::kNTFS:
+ if (FromCentral)
+ winAttributes = ExternalAttributes;
+ break;
+#ifdef FILE_ATTRIBUTE_UNIX_EXTENSION
+ case NFileHeader::NHostOS::kUnix:
+ winAttributes = (ExternalAttributes & 0xFFFF0000) | FILE_ATTRIBUTE_UNIX_EXTENSION;
+ if (winAttributes & (NFileHeader::NUnixAttribute::kIFDIR << 16))
+ winAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAttributes;
+#endif
+ default:
+ winAttributes = 0; // must be converted from unix value;
+ }
+ if (IsDir()) // test it;
+ winAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAttributes;
+}
+
+void CLocalItem::SetFlagBits(int startBitNumber, int numBits, int value)
+{
+ UInt16 mask = (UInt16)(((1 << numBits) - 1) << startBitNumber);
+ Flags &= ~mask;
+ Flags |= value << startBitNumber;
+}
+
+void CLocalItem::SetBitMask(int bitMask, bool enable)
+{
+ if(enable)
+ Flags |= bitMask;
+ else
+ Flags &= ~bitMask;
+}
+
+void CLocalItem::SetEncrypted(bool encrypted)
+ { SetBitMask(NFileHeader::NFlags::kEncrypted, encrypted); }
+void CLocalItem::SetUtf8(bool isUtf8)
+ { SetBitMask(NFileHeader::NFlags::kUtf8, isUtf8); }
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItem.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItem.h
new file mode 100644
index 000000000..31f2de732
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItem.h
@@ -0,0 +1,281 @@
+// Archive/ZipItem.h
+
+#ifndef __ARCHIVE_ZIP_ITEM_H
+#define __ARCHIVE_ZIP_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+#include "Common/UTFConvert.h"
+#include "Common/StringConvert.h"
+
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CVersion
+{
+ Byte Version;
+ Byte HostOS;
+};
+
+bool operator==(const CVersion &v1, const CVersion &v2);
+bool operator!=(const CVersion &v1, const CVersion &v2);
+
+struct CExtraSubBlock
+{
+ UInt16 ID;
+ CByteBuffer Data;
+ bool ExtractNtfsTime(int index, FILETIME &ft) const;
+ bool ExtractUnixTime(int index, UInt32 &res) const;
+};
+
+struct CWzAesExtraField
+{
+ UInt16 VendorVersion; // 0x0001 - AE-1, 0x0002 - AE-2,
+ // UInt16 VendorId; // "AE"
+ Byte Strength; // 1 - 128-bit , 2 - 192-bit , 3 - 256-bit
+ UInt16 Method;
+
+ CWzAesExtraField(): VendorVersion(2), Strength(3), Method(0) {}
+
+ bool NeedCrc() const { return (VendorVersion == 1); }
+
+ bool ParseFromSubBlock(const CExtraSubBlock &sb)
+ {
+ if (sb.ID != NFileHeader::NExtraID::kWzAES)
+ return false;
+ if (sb.Data.GetCapacity() < 7)
+ return false;
+ const Byte *p = (const Byte *)sb.Data;
+ VendorVersion = (((UInt16)p[1]) << 8) | p[0];
+ if (p[2] != 'A' || p[3] != 'E')
+ return false;
+ Strength = p[4];
+ Method = (((UInt16)p[6]) << 16) | p[5];
+ return true;
+ }
+ void SetSubBlock(CExtraSubBlock &sb) const
+ {
+ sb.Data.SetCapacity(7);
+ sb.ID = NFileHeader::NExtraID::kWzAES;
+ Byte *p = (Byte *)sb.Data;
+ p[0] = (Byte)VendorVersion;
+ p[1] = (Byte)(VendorVersion >> 8);
+ p[2] = 'A';
+ p[3] = 'E';
+ p[4] = Strength;
+ p[5] = (Byte)Method;
+ p[6] = (Byte)(Method >> 8);
+ }
+};
+
+namespace NStrongCryptoFlags
+{
+ const UInt16 kDES = 0x6601;
+ const UInt16 kRC2old = 0x6602;
+ const UInt16 k3DES168 = 0x6603;
+ const UInt16 k3DES112 = 0x6609;
+ const UInt16 kAES128 = 0x660E;
+ const UInt16 kAES192 = 0x660F;
+ const UInt16 kAES256 = 0x6610;
+ const UInt16 kRC2 = 0x6702;
+ const UInt16 kBlowfish = 0x6720;
+ const UInt16 kTwofish = 0x6721;
+ const UInt16 kRC4 = 0x6801;
+}
+
+struct CStrongCryptoField
+{
+ UInt16 Format;
+ UInt16 AlgId;
+ UInt16 BitLen;
+ UInt16 Flags;
+
+ bool ParseFromSubBlock(const CExtraSubBlock &sb)
+ {
+ if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt)
+ return false;
+ const Byte *p = (const Byte *)sb.Data;
+ if (sb.Data.GetCapacity() < 8)
+ return false;
+ Format = (((UInt16)p[1]) << 8) | p[0];
+ AlgId = (((UInt16)p[3]) << 8) | p[2];
+ BitLen = (((UInt16)p[5]) << 8) | p[4];
+ Flags = (((UInt16)p[7]) << 8) | p[6];
+ return (Format == 2);
+ }
+};
+
+struct CExtraBlock
+{
+ CObjectVector<CExtraSubBlock> SubBlocks;
+ void Clear() { SubBlocks.Clear(); }
+ size_t GetSize() const
+ {
+ size_t res = 0;
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ res += SubBlocks[i].Data.GetCapacity() + 2 + 2;
+ return res;
+ }
+ bool GetWzAesField(CWzAesExtraField &aesField) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ if (aesField.ParseFromSubBlock(SubBlocks[i]))
+ return true;
+ return false;
+ }
+
+ bool GetStrongCryptoField(CStrongCryptoField &f) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ if (f.ParseFromSubBlock(SubBlocks[i]))
+ return true;
+ return false;
+ }
+
+ bool HasWzAesField() const
+ {
+ CWzAesExtraField aesField;
+ return GetWzAesField(aesField);
+ }
+
+ bool GetNtfsTime(int index, FILETIME &ft) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kNTFS)
+ return sb.ExtractNtfsTime(index, ft);
+ }
+ return false;
+ }
+
+ bool GetUnixTime(int index, UInt32 &res) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kUnixTime)
+ return sb.ExtractUnixTime(index, res);
+ }
+ return false;
+ }
+
+ /*
+ bool HasStrongCryptoField() const
+ {
+ CStrongCryptoField f;
+ return GetStrongCryptoField(f);
+ }
+ */
+
+ void RemoveUnknownSubBlocks()
+ {
+ for (int i = SubBlocks.Size() - 1; i >= 0; i--)
+ if (SubBlocks[i].ID != NFileHeader::NExtraID::kWzAES)
+ SubBlocks.Delete(i);
+ }
+};
+
+
+class CLocalItem
+{
+public:
+ CVersion ExtractVersion;
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt64 PackSize;
+ UInt64 UnPackSize;
+
+ AString Name;
+
+ CExtraBlock LocalExtra;
+
+ bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; }
+
+ bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; }
+ bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; };
+ bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || CompressionMethod == NFileHeader::NCompressionMethod::kWzAES); };
+
+ bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; }
+
+ bool IsDir() const;
+ bool IgnoreItem() const { return false; }
+ UInt32 GetWinAttributes() const;
+
+ bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; }
+
+ UString GetUnicodeString(const AString &s) const
+ {
+ UString res;
+ if (IsUtf8())
+ if (!ConvertUTF8ToUnicode(s, res))
+ res.Empty();
+ if (res.IsEmpty())
+ res = MultiByteToUnicodeString(s, GetCodePage());
+ return res;
+ }
+
+private:
+ void SetFlagBits(int startBitNumber, int numBits, int value);
+ void SetBitMask(int bitMask, bool enable);
+public:
+ void ClearFlags() { Flags = 0; }
+ void SetEncrypted(bool encrypted);
+ void SetUtf8(bool isUtf8);
+
+ WORD GetCodePage() const { return CP_OEMCP; }
+};
+
+class CItem: public CLocalItem
+{
+public:
+ CVersion MadeByVersion;
+ UInt16 InternalAttributes;
+ UInt32 ExternalAttributes;
+
+ UInt64 LocalHeaderPosition;
+
+ FILETIME NtfsMTime;
+ FILETIME NtfsATime;
+ FILETIME NtfsCTime;
+
+ CExtraBlock CentralExtra;
+ CByteBuffer Comment;
+
+ bool FromLocal;
+ bool FromCentral;
+ bool NtfsTimeIsDefined;
+
+ bool IsDir() const;
+ UInt32 GetWinAttributes() const;
+
+ bool IsThereCrc() const
+ {
+ if (CompressionMethod == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ CWzAesExtraField aesField;
+ if (CentralExtra.GetWzAesField(aesField))
+ return aesField.NeedCrc();
+ }
+ return (FileCRC != 0 || !IsDir());
+ }
+
+ WORD GetCodePage() const
+ {
+ return (WORD)((MadeByVersion.HostOS == NFileHeader::NHostOS::kFAT
+ || MadeByVersion.HostOS == NFileHeader::NHostOS::kNTFS
+ ) ? CP_OEMCP : CP_ACP);
+ }
+ CItem() : FromLocal(false), FromCentral(false), NtfsTimeIsDefined(false) {}
+};
+
+}}
+
+#endif
+
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItemEx.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItemEx.h
new file mode 100644
index 000000000..ab62cdbb4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipItemEx.h
@@ -0,0 +1,34 @@
+// Archive/ZipItemEx.h
+
+#ifndef __ARCHIVE_ZIP_ITEMEX_H
+#define __ARCHIVE_ZIP_ITEMEX_H
+
+#include "ZipHeader.h"
+#include "ZipItem.h"
+
+namespace NArchive {
+namespace NZip {
+
+class CItemEx: public CItem
+{
+public:
+ UInt32 FileHeaderWithNameSize;
+ UInt16 LocalExtraSize;
+
+ UInt64 GetLocalFullSize() const
+ { return FileHeaderWithNameSize + LocalExtraSize + PackSize +
+ (HasDescriptor() ? NFileHeader::kDataDescriptorSize : 0); };
+ /*
+ UInt64 GetLocalFullSize(bool isZip64) const
+ { return FileHeaderWithNameSize + LocalExtraSize + PackSize +
+ (HasDescriptor() ? (isZip64 ? NFileHeader::kDataDescriptor64Size : NFileHeader::kDataDescriptorSize) : 0); };
+ */
+ UInt64 GetLocalExtraPosition() const
+ { return LocalHeaderPosition + FileHeaderWithNameSize; };
+ UInt64 GetDataPosition() const
+ { return GetLocalExtraPosition() + LocalExtraSize; };
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipOut.cpp
new file mode 100644
index 000000000..aa82143e3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -0,0 +1,289 @@
+// ZipOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/OffsetStream.h"
+
+#include "ZipOut.h"
+
+namespace NArchive {
+namespace NZip {
+
+void COutArchive::Create(IOutStream *outStream)
+{
+ if (!m_OutBuffer.Create(1 << 16))
+ throw CSystemException(E_OUTOFMEMORY);
+ m_Stream = outStream;
+ m_OutBuffer.SetStream(outStream);
+ m_OutBuffer.Init();
+ m_BasePosition = 0;
+}
+
+void COutArchive::MoveBasePosition(UInt64 distanceToMove)
+{
+ m_BasePosition += distanceToMove; // test overflow
+}
+
+void COutArchive::PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption)
+{
+ m_IsZip64 = isZip64;
+ m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0;
+ if (aesEncryption)
+ m_ExtraSize += 4 + 7;
+ m_LocalFileHeaderSize = 4 + NFileHeader::kLocalBlockSize + fileNameLength + m_ExtraSize;
+}
+
+void COutArchive::PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption)
+{
+ // We test it to 0xF8000000 to support case when compressed size
+ // can be larger than uncompressed size.
+ PrepareWriteCompressedDataZip64(fileNameLength, unPackSize >= 0xF8000000, aesEncryption);
+}
+
+void COutArchive::PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
+{
+ bool isUnPack64 = unPackSize >= 0xFFFFFFFF;
+ bool isPack64 = packSize >= 0xFFFFFFFF;
+ bool isZip64 = isPack64 || isUnPack64;
+ PrepareWriteCompressedDataZip64(fileNameLength, isZip64, aesEncryption);
+}
+
+void COutArchive::WriteBytes(const void *buffer, UInt32 size)
+{
+ m_OutBuffer.WriteBytes(buffer, size);
+ m_BasePosition += size;
+}
+
+void COutArchive::WriteByte(Byte b)
+{
+ WriteBytes(&b, 1);
+}
+
+void COutArchive::WriteUInt16(UInt16 value)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteUInt32(UInt32 value)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteUInt64(UInt64 value)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteExtra(const CExtraBlock &extra)
+{
+ if (extra.SubBlocks.Size() != 0)
+ {
+ for (int i = 0; i < extra.SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &subBlock = extra.SubBlocks[i];
+ WriteUInt16(subBlock.ID);
+ WriteUInt16((UInt16)subBlock.Data.GetCapacity());
+ WriteBytes(subBlock.Data, (UInt32)subBlock.Data.GetCapacity());
+ }
+ }
+}
+
+void COutArchive::SeekTo(UInt64 offset)
+{
+ HRESULT res = m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+ if (res != S_OK)
+ throw CSystemException(res);
+}
+
+void COutArchive::WriteLocalHeader(const CLocalItem &item)
+{
+ SeekTo(m_BasePosition);
+
+ bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+
+ WriteUInt32(NSignature::kLocalFileHeader);
+ {
+ Byte ver = item.ExtractVersion.Version;
+ if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
+ ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
+ WriteByte(ver);
+ }
+ WriteByte(item.ExtractVersion.HostOS);
+ WriteUInt16(item.Flags);
+ WriteUInt16(item.CompressionMethod);
+ WriteUInt32(item.Time);
+ WriteUInt32(item.FileCRC);
+ WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
+ WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
+ WriteUInt16((UInt16)item.Name.Length());
+ {
+ UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 16): 0) + item.LocalExtra.GetSize());
+ if (localExtraSize > m_ExtraSize)
+ throw CSystemException(E_FAIL);
+ }
+ WriteUInt16((UInt16)m_ExtraSize); // test it;
+ WriteBytes((const char *)item.Name, item.Name.Length());
+
+ UInt32 extraPos = 0;
+ if (isZip64)
+ {
+ extraPos += 4 + 16;
+ WriteUInt16(NFileHeader::NExtraID::kZip64);
+ WriteUInt16(16);
+ WriteUInt64(item.UnPackSize);
+ WriteUInt64(item.PackSize);
+ }
+
+ WriteExtra(item.LocalExtra);
+ extraPos += (UInt32)item.LocalExtra.GetSize();
+ for (; extraPos < m_ExtraSize; extraPos++)
+ WriteByte(0);
+
+ m_OutBuffer.FlushWithCheck();
+ MoveBasePosition(item.PackSize);
+ SeekTo(m_BasePosition);
+}
+
+void COutArchive::WriteCentralHeader(const CItem &item)
+{
+ bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
+ bool isPack64 = item.PackSize >= 0xFFFFFFFF;
+ bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
+ bool isZip64 = isPack64 || isUnPack64 || isPosition64;
+
+ WriteUInt32(NSignature::kCentralFileHeader);
+ WriteByte(item.MadeByVersion.Version);
+ WriteByte(item.MadeByVersion.HostOS);
+ {
+ Byte ver = item.ExtractVersion.Version;
+ if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
+ ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
+ WriteByte(ver);
+ }
+ WriteByte(item.ExtractVersion.HostOS);
+ WriteUInt16(item.Flags);
+ WriteUInt16(item.CompressionMethod);
+ WriteUInt32(item.Time);
+ WriteUInt32(item.FileCRC);
+ WriteUInt32(isPack64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
+ WriteUInt32(isUnPack64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
+ WriteUInt16((UInt16)item.Name.Length());
+ UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
+ const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8);
+ UInt16 centralExtraSize = (UInt16)(isZip64 ? (4 + zip64ExtraSize) : 0) + (item.NtfsTimeIsDefined ? (4 + kNtfsExtraSize) : 0);
+ centralExtraSize = (UInt16)(centralExtraSize + item.CentralExtra.GetSize());
+ WriteUInt16(centralExtraSize); // test it;
+ WriteUInt16((UInt16)item.Comment.GetCapacity());
+ WriteUInt16(0); // DiskNumberStart;
+ WriteUInt16(item.InternalAttributes);
+ WriteUInt32(item.ExternalAttributes);
+ WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
+ WriteBytes((const char *)item.Name, item.Name.Length());
+ if (isZip64)
+ {
+ WriteUInt16(NFileHeader::NExtraID::kZip64);
+ WriteUInt16(zip64ExtraSize);
+ if(isUnPack64)
+ WriteUInt64(item.UnPackSize);
+ if(isPack64)
+ WriteUInt64(item.PackSize);
+ if(isPosition64)
+ WriteUInt64(item.LocalHeaderPosition);
+ }
+ if (item.NtfsTimeIsDefined)
+ {
+ WriteUInt16(NFileHeader::NExtraID::kNTFS);
+ WriteUInt16(kNtfsExtraSize);
+ WriteUInt32(0); // reserved
+ WriteUInt16(NFileHeader::NNtfsExtra::kTagTime);
+ WriteUInt16(8 * 3);
+ WriteUInt32(item.NtfsMTime.dwLowDateTime);
+ WriteUInt32(item.NtfsMTime.dwHighDateTime);
+ WriteUInt32(item.NtfsATime.dwLowDateTime);
+ WriteUInt32(item.NtfsATime.dwHighDateTime);
+ WriteUInt32(item.NtfsCTime.dwLowDateTime);
+ WriteUInt32(item.NtfsCTime.dwHighDateTime);
+ }
+ WriteExtra(item.CentralExtra);
+ if (item.Comment.GetCapacity() > 0)
+ WriteBytes(item.Comment, (UInt32)item.Comment.GetCapacity());
+}
+
+void COutArchive::WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment)
+{
+ SeekTo(m_BasePosition);
+
+ UInt64 cdOffset = GetCurrentPosition();
+ for(int i = 0; i < items.Size(); i++)
+ WriteCentralHeader(items[i]);
+ UInt64 cd64EndOffset = GetCurrentPosition();
+ UInt64 cdSize = cd64EndOffset - cdOffset;
+ bool cdOffset64 = cdOffset >= 0xFFFFFFFF;
+ bool cdSize64 = cdSize >= 0xFFFFFFFF;
+ bool items64 = items.Size() >= 0xFFFF;
+ bool isZip64 = (cdOffset64 || cdSize64 || items64);
+
+ if (isZip64)
+ {
+ WriteUInt32(NSignature::kZip64EndOfCentralDir);
+ WriteUInt64(kZip64EcdSize); // ThisDiskNumber = 0;
+ WriteUInt16(45); // version
+ WriteUInt16(45); // version
+ WriteUInt32(0); // ThisDiskNumber = 0;
+ WriteUInt32(0); // StartCentralDirectoryDiskNumber;;
+ WriteUInt64((UInt64)items.Size());
+ WriteUInt64((UInt64)items.Size());
+ WriteUInt64((UInt64)cdSize);
+ WriteUInt64((UInt64)cdOffset);
+
+ WriteUInt32(NSignature::kZip64EndOfCentralDirLocator);
+ WriteUInt32(0); // number of the disk with the start of the zip64 end of central directory
+ WriteUInt64(cd64EndOffset);
+ WriteUInt32(1); // total number of disks
+ }
+ WriteUInt32(NSignature::kEndOfCentralDir);
+ WriteUInt16(0); // ThisDiskNumber = 0;
+ WriteUInt16(0); // StartCentralDirectoryDiskNumber;
+ WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
+ WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
+ WriteUInt32(cdSize64 ? 0xFFFFFFFF: (UInt32)cdSize);
+ WriteUInt32(cdOffset64 ? 0xFFFFFFFF: (UInt32)cdOffset);
+ UInt32 commentSize = (UInt32)(comment ? comment->GetCapacity() : 0);
+ WriteUInt16((UInt16)commentSize);
+ if (commentSize > 0)
+ WriteBytes((const Byte *)*comment, commentSize);
+ m_OutBuffer.FlushWithCheck();
+}
+
+void COutArchive::CreateStreamForCompressing(IOutStream **outStream)
+{
+ COffsetOutStream *streamSpec = new COffsetOutStream;
+ CMyComPtr<IOutStream> tempStream(streamSpec);
+ streamSpec->Init(m_Stream, m_BasePosition + m_LocalFileHeaderSize);
+ *outStream = tempStream.Detach();
+}
+
+void COutArchive::SeekToPackedDataPosition()
+{
+ SeekTo(m_BasePosition + m_LocalFileHeaderSize);
+}
+
+void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream)
+{
+ CMyComPtr<ISequentialOutStream> tempStream(m_Stream);
+ *outStream = tempStream.Detach();
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipOut.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipOut.h
new file mode 100644
index 000000000..2f6349e5c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipOut.h
@@ -0,0 +1,56 @@
+// ZipOut.h
+
+#ifndef __ZIP_OUT_H
+#define __ZIP_OUT_H
+
+#include "Common/MyCom.h"
+
+#include "../../IStream.h"
+#include "../../Common/OutBuffer.h"
+
+#include "ZipItem.h"
+
+namespace NArchive {
+namespace NZip {
+
+// can throw CSystemException and COutBufferException
+
+class COutArchive
+{
+ CMyComPtr<IOutStream> m_Stream;
+ COutBuffer m_OutBuffer;
+
+ UInt64 m_BasePosition;
+ UInt32 m_LocalFileHeaderSize;
+ UInt32 m_ExtraSize;
+ bool m_IsZip64;
+
+ void WriteBytes(const void *buffer, UInt32 size);
+ void WriteByte(Byte b);
+ void WriteUInt16(UInt16 value);
+ void WriteUInt32(UInt32 value);
+ void WriteUInt64(UInt64 value);
+
+ void WriteExtraHeader(const CItem &item);
+ void WriteCentralHeader(const CItem &item);
+ void WriteExtra(const CExtraBlock &extra);
+ void SeekTo(UInt64 offset);
+public:
+ void Create(IOutStream *outStream);
+ void MoveBasePosition(UInt64 distanceToMove);
+ UInt64 GetCurrentPosition() const { return m_BasePosition; };
+ void PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption);
+ void PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption);
+ void PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption);
+ void WriteLocalHeader(const CLocalItem &item);
+
+ void WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment);
+
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipRegister.cpp
new file mode 100644
index 000000000..3e7aade85
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipRegister.cpp
@@ -0,0 +1,18 @@
+// ZipRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "ZipHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NZip::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NZip::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"zip", L"zip jar xpi odt ods docx xlsx", 0, 1, { 0x50, 0x4B, 0x03, 0x04 }, 4, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Zip)
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipUpdate.cpp
new file mode 100644
index 000000000..bd0c8221d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -0,0 +1,1076 @@
+// ZipUpdate.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+
+#include "Common/AutoPtr.h"
+#include "Common/Defs.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Defs.h"
+#include "Windows/Thread.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/OutMemStream.h"
+#include "../../Common/ProgressUtils.h"
+#ifndef _7ZIP_ST
+#include "../../Common/ProgressMt.h"
+#endif
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "ZipAddCommon.h"
+#include "ZipOut.h"
+#include "ZipUpdate.h"
+
+using namespace NWindows;
+using namespace NSynchronization;
+
+namespace NArchive {
+namespace NZip {
+
+static const Byte kHostOS =
+ #ifdef _WIN32
+ NFileHeader::NHostOS::kFAT;
+ #else
+ NFileHeader::NHostOS::kUnix;
+ #endif
+
+static const Byte kMadeByHostOS = kHostOS;
+static const Byte kExtractHostOS = kHostOS;
+
+static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored;
+
+static HRESULT CopyBlockToArchive(ISequentialInStream *inStream,
+ COutArchive &outArchive, ICompressProgressInfo *progress)
+{
+ CMyComPtr<ISequentialOutStream> outStream;
+ outArchive.CreateStreamForCopying(&outStream);
+ return NCompress::CopyStream(inStream, outStream, progress);
+}
+
+static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive,
+ const CUpdateRange &range, ICompressProgressInfo *progress)
+{
+ UInt64 position;
+ RINOK(inStream->Seek(range.Position, STREAM_SEEK_SET, &position));
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(range.Size);
+
+ RINOK(CopyBlockToArchive(inStreamLimited, outArchive, progress));
+ return progress->SetRatioInfo(&range.Size, &range.Size);
+}
+
+static void SetFileHeader(
+ COutArchive &archive,
+ const CCompressionMethodMode &options,
+ const CUpdateItem &ui,
+ CItem &item)
+{
+ item.UnPackSize = ui.Size;
+ bool isDir;
+
+ item.ClearFlags();
+
+ if (ui.NewProperties)
+ {
+ isDir = ui.IsDir;
+ item.Name = ui.Name;
+ item.SetUtf8(ui.IsUtf8);
+ item.ExternalAttributes = ui.Attributes;
+ item.Time = ui.Time;
+ item.NtfsMTime = ui.NtfsMTime;
+ item.NtfsATime = ui.NtfsATime;
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+ }
+ else
+ isDir = item.IsDir();
+
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ item.MadeByVersion.HostOS = kMadeByHostOS;
+ item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
+
+ item.ExtractVersion.HostOS = kExtractHostOS;
+
+ item.InternalAttributes = 0; // test it
+ item.SetEncrypted(!isDir && options.PasswordIsDefined);
+ if (isDir)
+ {
+ item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
+ item.CompressionMethod = kMethodForDirectory;
+ item.PackSize = 0;
+ item.FileCRC = 0; // test it
+ }
+}
+
+static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
+ bool isAesMode, Byte aesKeyMode, CItem &item)
+{
+ item.ExtractVersion.Version = compressingResult.ExtractVersion;
+ item.CompressionMethod = compressingResult.Method;
+ item.FileCRC = compressingResult.CRC;
+ item.UnPackSize = compressingResult.UnpackSize;
+ item.PackSize = compressingResult.PackSize;
+
+ item.LocalExtra.Clear();
+ item.CentralExtra.Clear();
+
+ if (isAesMode)
+ {
+ CWzAesExtraField wzAesField;
+ wzAesField.Strength = aesKeyMode;
+ wzAesField.Method = compressingResult.Method;
+ item.CompressionMethod = NFileHeader::NCompressionMethod::kWzAES;
+ item.FileCRC = 0;
+ CExtraSubBlock sb;
+ wzAesField.SetSubBlock(sb);
+ item.LocalExtra.SubBlocks.Add(sb);
+ item.CentralExtra.SubBlocks.Add(sb);
+ }
+}
+
+#ifndef _7ZIP_ST
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
+
+struct CThreadInfo
+{
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ICompressCodecsInfo> _codecsInfo;
+ const CObjectVector<CCodecInfoEx> *_externalCodecs;
+ #endif
+
+ NWindows::CThread Thread;
+ NWindows::NSynchronization::CAutoResetEvent CompressEvent;
+ NWindows::NSynchronization::CAutoResetEventWFMO CompressionCompletedEvent;
+ bool ExitThread;
+
+ CMtCompressProgress *ProgressSpec;
+ CMyComPtr<ICompressProgressInfo> Progress;
+
+ COutMemStream *OutStreamSpec;
+ CMyComPtr<IOutStream> OutStream;
+ CMyComPtr<ISequentialInStream> InStream;
+
+ CAddCommon Coder;
+ HRESULT Result;
+ CCompressingResult CompressingResult;
+
+ bool IsFree;
+ UInt32 UpdateIndex;
+
+ CThreadInfo(const CCompressionMethodMode &options):
+ ExitThread(false),
+ ProgressSpec(0),
+ OutStreamSpec(0),
+ Coder(options)
+ {}
+
+ HRESULT CreateEvents(CSynchro *sync)
+ {
+ RINOK(CompressEvent.CreateIfNotCreated());
+ return CompressionCompletedEvent.CreateIfNotCreated(sync);
+ }
+ HRes CreateThread() { return Thread.Create(CoderThread, this); }
+
+ void WaitAndCode();
+ void StopWaitClose()
+ {
+ ExitThread = true;
+ if (OutStreamSpec != 0)
+ OutStreamSpec->StopWriting(E_ABORT);
+ if (CompressEvent.IsCreated())
+ CompressEvent.Set();
+ Thread.Wait();
+ Thread.Close();
+ }
+
+};
+
+void CThreadInfo::WaitAndCode()
+{
+ for (;;)
+ {
+ CompressEvent.Lock();
+ if (ExitThread)
+ return;
+ Result = Coder.Compress(
+ #ifdef EXTERNAL_CODECS
+ _codecsInfo, _externalCodecs,
+ #endif
+ InStream, OutStream, Progress, CompressingResult);
+ if (Result == S_OK && Progress)
+ Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
+ CompressionCompletedEvent.Set();
+ }
+}
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo)
+{
+ ((CThreadInfo *)threadCoderInfo)->WaitAndCode();
+ return 0;
+}
+
+class CThreads
+{
+public:
+ CObjectVector<CThreadInfo> Threads;
+ ~CThreads()
+ {
+ for (int i = 0; i < Threads.Size(); i++)
+ Threads[i].StopWaitClose();
+ }
+};
+
+struct CMemBlocks2: public CMemLockBlocks
+{
+ CCompressingResult CompressingResult;
+ bool Defined;
+ bool Skip;
+ CMemBlocks2(): Defined(false), Skip(false) {}
+};
+
+class CMemRefs
+{
+public:
+ CMemBlockManagerMt *Manager;
+ CObjectVector<CMemBlocks2> Refs;
+ CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ;
+ ~CMemRefs()
+ {
+ for (int i = 0; i < Refs.Size(); i++)
+ Refs[i].FreeOpt(Manager);
+ }
+};
+
+class CMtProgressMixer2:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ UInt64 ProgressOffset;
+ UInt64 InSizes[2];
+ UInt64 OutSizes[2];
+ CMyComPtr<IProgress> Progress;
+ CMyComPtr<ICompressProgressInfo> RatioProgress;
+ bool _inSizeIsMain;
+public:
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ MY_UNKNOWN_IMP
+ void Create(IProgress *progress, bool inSizeIsMain);
+ void SetProgressOffset(UInt64 progressOffset);
+ HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize);
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain)
+{
+ Progress = progress;
+ Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress);
+ _inSizeIsMain = inSizeIsMain;
+ ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0;
+}
+
+void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset)
+{
+ CriticalSection.Enter();
+ InSizes[1] = OutSizes[1] = 0;
+ ProgressOffset = progressOffset;
+ CriticalSection.Leave();
+}
+
+HRESULT CMtProgressMixer2::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ if (index == 0 && RatioProgress)
+ {
+ RINOK(RatioProgress->SetRatioInfo(inSize, outSize));
+ }
+ if (inSize != 0)
+ InSizes[index] = *inSize;
+ if (outSize != 0)
+ OutSizes[index] = *outSize;
+ UInt64 v = ProgressOffset + (_inSizeIsMain ?
+ (InSizes[0] + InSizes[1]) :
+ (OutSizes[0] + OutSizes[1]));
+ return Progress->SetCompleted(&v);
+}
+
+STDMETHODIMP CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ return SetRatioInfo(0, inSize, outSize);
+}
+
+class CMtProgressMixer:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ CMtProgressMixer2 *Mixer2;
+ CMyComPtr<ICompressProgressInfo> RatioProgress;
+ void Create(IProgress *progress, bool inSizeIsMain);
+ MY_UNKNOWN_IMP
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain)
+{
+ Mixer2 = new CMtProgressMixer2;
+ RatioProgress = Mixer2;
+ Mixer2->Create(progress, inSizeIsMain);
+}
+
+STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ return Mixer2->SetRatioInfo(1, inSize, outSize);
+}
+
+
+#endif
+
+
+static HRESULT UpdateItemOldData(COutArchive &archive,
+ IInStream *inStream,
+ const CUpdateItem &ui, CItemEx &item,
+ /* bool izZip64, */
+ ICompressProgressInfo *progress,
+ UInt64 &complexity)
+{
+ if (ui.NewProperties)
+ {
+ if (item.HasDescriptor())
+ return E_NOTIMPL;
+
+ // use old name size.
+ // CUpdateRange range(item.GetLocalExtraPosition(), item.LocalExtraSize + item.PackSize);
+ CUpdateRange range(item.GetDataPosition(), item.PackSize);
+
+ // item.ExternalAttributes = ui.Attributes;
+ // Test it
+ item.Name = ui.Name;
+ item.SetUtf8(ui.IsUtf8);
+ item.Time = ui.Time;
+ item.NtfsMTime = ui.NtfsMTime;
+ item.NtfsATime = ui.NtfsATime;
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+
+ item.CentralExtra.RemoveUnknownSubBlocks();
+ item.LocalExtra.RemoveUnknownSubBlocks();
+
+ archive.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField());
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ archive.SeekToPackedDataPosition();
+ RINOK(WriteRange(inStream, archive, range, progress));
+ complexity += range.Size;
+ archive.WriteLocalHeader(item);
+ }
+ else
+ {
+ CUpdateRange range(item.LocalHeaderPosition, item.GetLocalFullSize());
+
+ // set new header position
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+
+ RINOK(WriteRange(inStream, archive, range, progress));
+ complexity += range.Size;
+ archive.MoveBasePosition(range.Size);
+ }
+ return S_OK;
+}
+
+static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
+ const CUpdateItem &ui, CItemEx &item)
+{
+ SetFileHeader(archive, *options, ui, item);
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ archive.WriteLocalHeader(item);
+}
+
+static HRESULT Update2St(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ COutArchive &archive,
+ CInArchive *inArchive,
+ IInStream *inStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ const CCompressionMethodMode *options,
+ const CByteBuffer *comment,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CAddCommon compressor(*options);
+
+ CObjectVector<CItem> items;
+ UInt64 unpackSizeTotal = 0, packSizeTotal = 0;
+
+ for (int itemIndex = 0; itemIndex < updateItems.Size(); itemIndex++)
+ {
+ lps->InSize = unpackSizeTotal;
+ lps->OutSize = packSizeTotal;
+ RINOK(lps->SetCur());
+ const CUpdateItem &ui = updateItems[itemIndex];
+ CItemEx item;
+ if (!ui.NewProperties || !ui.NewData)
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ }
+
+ if (ui.NewData)
+ {
+ bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir());
+ if (isDir)
+ {
+ WriteDirHeader(archive, options, ui, item);
+ }
+ else
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ lps->ProgressOffset += ui.Size;
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(res);
+
+ // file Size can be 64-bit !!!
+ SetFileHeader(archive, *options, ui, item);
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ CCompressingResult compressingResult;
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ RINOK(compressor.Compress(
+ EXTERNAL_CODECS_LOC_VARS
+ fileInStream, outStream, progress, compressingResult));
+ SetItemInfoFromCompressingResult(compressingResult, options->IsAesMode, options->AesKeyMode, item);
+ archive.WriteLocalHeader(item);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ unpackSizeTotal += item.UnPackSize;
+ packSizeTotal += item.PackSize;
+ }
+ }
+ else
+ {
+ UInt64 complexity = 0;
+ lps->SendRatio = false;
+ RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity));
+ lps->SendRatio = true;
+ lps->ProgressOffset += complexity;
+ }
+ items.Add(item);
+ lps->ProgressOffset += NFileHeader::kLocalBlockSize;
+ }
+ archive.WriteCentralDir(items, comment);
+ return S_OK;
+}
+
+static HRESULT Update2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ COutArchive &archive,
+ CInArchive *inArchive,
+ IInStream *inStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ const CCompressionMethodMode *options,
+ const CByteBuffer *comment,
+ IArchiveUpdateCallback *updateCallback)
+{
+ UInt64 complexity = 0;
+ UInt64 numFilesToCompress = 0;
+ UInt64 numBytesToCompress = 0;
+
+ int i;
+ for(i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ complexity += ui.Size;
+ numBytesToCompress += ui.Size;
+ numFilesToCompress++;
+ /*
+ if (ui.Commented)
+ complexity += ui.CommentRange.Size;
+ */
+ }
+ else
+ {
+ CItemEx inputItem = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(inputItem) != S_OK)
+ return E_NOTIMPL;
+ complexity += inputItem.GetLocalFullSize();
+ // complexity += inputItem.GetCentralExtraPlusCommentSize();
+ }
+ complexity += NFileHeader::kLocalBlockSize;
+ complexity += NFileHeader::kCentralBlockSize;
+ }
+
+ if (comment)
+ complexity += comment->GetCapacity();
+ complexity++; // end of central
+ updateCallback->SetTotal(complexity);
+
+ CAddCommon compressor(*options);
+
+ complexity = 0;
+
+ #ifndef _7ZIP_ST
+
+ const size_t kNumMaxThreads = (1 << 10);
+ UInt32 numThreads = options->NumThreads;
+ if (numThreads > kNumMaxThreads)
+ numThreads = kNumMaxThreads;
+
+ const size_t kMemPerThread = (1 << 25);
+ const size_t kBlockSize = 1 << 16;
+
+ CCompressionMethodMode options2;
+ if (options != 0)
+ options2 = *options;
+
+ bool mtMode = ((options != 0) && (numThreads > 1));
+
+ if (numFilesToCompress <= 1)
+ mtMode = false;
+
+ if (mtMode)
+ {
+ Byte method = options->MethodSequence.Front();
+ if (method == NFileHeader::NCompressionMethod::kStored && !options->PasswordIsDefined)
+ mtMode = false;
+ if (method == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ UInt64 averageSize = numBytesToCompress / numFilesToCompress;
+ UInt32 blockSize = options->DicSize;
+ if (blockSize == 0)
+ blockSize = 1;
+ UInt64 averageNumberOfBlocks = averageSize / blockSize;
+ UInt32 numBZip2Threads = 32;
+ if (averageNumberOfBlocks < numBZip2Threads)
+ numBZip2Threads = (UInt32)averageNumberOfBlocks;
+ if (numBZip2Threads < 1)
+ numBZip2Threads = 1;
+ numThreads = numThreads / numBZip2Threads;
+ options2.NumThreads = numBZip2Threads;
+ if (numThreads <= 1)
+ mtMode = false;
+ }
+ if (method == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ UInt32 numLZMAThreads = (options->Algo > 0 ? 2 : 1);
+ numThreads /= numLZMAThreads;
+ options2.NumThreads = numLZMAThreads;
+ if (numThreads <= 1)
+ mtMode = false;
+ }
+ }
+
+ if (!mtMode)
+ #endif
+ return Update2St(
+ EXTERNAL_CODECS_LOC_VARS
+ archive, inArchive,inStream,
+ inputItems, updateItems, options, comment, updateCallback);
+
+
+ #ifndef _7ZIP_ST
+
+ // Warning : before memManager, threads and compressingCompletedEvents
+ // in order to have a "good" order for the destructor
+ NWindows::NSynchronization::CSynchro synchroForCompressingCompletedEvents;
+ synchroForCompressingCompletedEvents.Create();
+ NWindows::NSynchronization::CSynchro synchroForOutStreamSpec;
+ synchroForOutStreamSpec.Create();
+
+
+ CObjectVector<CItem> items;
+
+ CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
+ CMyComPtr<ICompressProgressInfo> progress = mtProgressMixerSpec;
+ mtProgressMixerSpec->Create(updateCallback, true);
+
+ CMtCompressProgressMixer mtCompressProgressMixer;
+ mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress);
+
+ CMemBlockManagerMt memManager(kBlockSize);
+ CMemRefs refs(&memManager);
+
+ CThreads threads;
+ CRecordVector<HANDLE> compressingCompletedEvents;
+ CRecordVector<int> threadIndices; // list threads in order of updateItems
+
+ {
+ RINOK(memManager.AllocateSpaceAlways(&synchroForOutStreamSpec,(size_t)numThreads * (kMemPerThread / kBlockSize)));
+ for(i = 0; i < updateItems.Size(); i++)
+ refs.Refs.Add(CMemBlocks2());
+
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ threads.Threads.Add(CThreadInfo(options2));
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ #ifdef EXTERNAL_CODECS
+ threadInfo._codecsInfo = codecsInfo;
+ threadInfo._externalCodecs = externalCodecs;
+ #endif
+ RINOK(threadInfo.CreateEvents(&synchroForCompressingCompletedEvents));
+ threadInfo.OutStreamSpec = new COutMemStream(&memManager);
+ RINOK(threadInfo.OutStreamSpec->CreateEvents(&synchroForOutStreamSpec));
+ threadInfo.OutStream = threadInfo.OutStreamSpec;
+ threadInfo.IsFree = true;
+ threadInfo.ProgressSpec = new CMtCompressProgress();
+ threadInfo.Progress = threadInfo.ProgressSpec;
+ threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i);
+ RINOK(threadInfo.CreateThread());
+ }
+ }
+ int mtItemIndex = 0;
+
+ int itemIndex = 0;
+ int lastRealStreamItemIndex = -1;
+
+ while (itemIndex < updateItems.Size())
+ {
+ if ((UInt32)threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
+ {
+ const CUpdateItem &ui = updateItems[mtItemIndex++];
+ if (!ui.NewData)
+ continue;
+ CItemEx item;
+ if (ui.NewProperties)
+ {
+ if (ui.IsDir)
+ continue;
+ }
+ else
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ if (item.IsDir())
+ continue;
+ }
+ CMyComPtr<ISequentialInStream> fileInStream;
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ complexity += ui.Size;
+ complexity += NFileHeader::kLocalBlockSize;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ refs.Refs[mtItemIndex - 1].Skip = true;
+ continue;
+ }
+ RINOK(res);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+
+ for (UInt32 i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ if (threadInfo.IsFree)
+ {
+ threadInfo.IsFree = false;
+ threadInfo.InStream = fileInStream;
+
+ // !!!!! we must release ref before sending event
+ // BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time
+ fileInStream.Release();
+
+ threadInfo.OutStreamSpec->Init();
+ threadInfo.ProgressSpec->Reinit();
+ threadInfo.CompressEvent.Set();
+ threadInfo.UpdateIndex = mtItemIndex - 1;
+
+ compressingCompletedEvents.Add(threadInfo.CompressionCompletedEvent);
+ threadIndices.Add(i);
+ break;
+ }
+ }
+ continue;
+ }
+
+ if (refs.Refs[itemIndex].Skip)
+ {
+ itemIndex++;
+ continue;
+ }
+
+ const CUpdateItem &ui = updateItems[itemIndex];
+
+ CItemEx item;
+ if (!ui.NewProperties || !ui.NewData)
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ }
+
+ if (ui.NewData)
+ {
+ bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir());
+ if (isDir)
+ {
+ WriteDirHeader(archive, options, ui, item);
+ }
+ else
+ {
+ if (lastRealStreamItemIndex < itemIndex)
+ {
+ lastRealStreamItemIndex = itemIndex;
+ SetFileHeader(archive, *options, ui, item);
+ // file Size can be 64-bit !!!
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ }
+
+ CMemBlocks2 &memRef = refs.Refs[itemIndex];
+ if (memRef.Defined)
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ memRef.WriteToStream(memManager.GetBlockSize(), outStream);
+ SetItemInfoFromCompressingResult(memRef.CompressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ SetFileHeader(archive, *options, ui, item);
+ archive.WriteLocalHeader(item);
+ // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ memRef.FreeOpt(&memManager);
+ }
+ else
+ {
+ {
+ CThreadInfo &thread = threads.Threads[threadIndices.Front()];
+ if (!thread.OutStreamSpec->WasUnlockEventSent())
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ thread.OutStreamSpec->SetOutStream(outStream);
+ thread.OutStreamSpec->SetRealStreamMode();
+ }
+ }
+
+ DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(),
+ &compressingCompletedEvents.Front(), FALSE, INFINITE);
+ int t = (int)(result - WAIT_OBJECT_0);
+ CThreadInfo &threadInfo = threads.Threads[threadIndices[t]];
+ threadInfo.InStream.Release();
+ threadInfo.IsFree = true;
+ RINOK(threadInfo.Result);
+ threadIndices.Delete(t);
+ compressingCompletedEvents.Delete(t);
+ if (t == 0)
+ {
+ RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
+ threadInfo.OutStreamSpec->ReleaseOutStream();
+ SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ SetFileHeader(archive, *options, ui, item);
+ archive.WriteLocalHeader(item);
+ }
+ else
+ {
+ CMemBlocks2 &memRef = refs.Refs[threadInfo.UpdateIndex];
+ threadInfo.OutStreamSpec->DetachData(memRef);
+ memRef.CompressingResult = threadInfo.CompressingResult;
+ memRef.Defined = true;
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity));
+ }
+ items.Add(item);
+ complexity += NFileHeader::kLocalBlockSize;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
+ itemIndex++;
+ }
+ archive.WriteCentralDir(items, comment);
+ return S_OK;
+ #endif
+}
+
+static const size_t kCacheBlockSize = (1 << 20);
+static const size_t kCacheSize = (kCacheBlockSize << 2);
+static const size_t kCacheMask = (kCacheSize - 1);
+
+class CCacheOutStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IOutStream> _stream;
+ Byte *_cache;
+ UInt64 _virtPos;
+ UInt64 _virtSize;
+ UInt64 _phyPos;
+ UInt64 _phySize; // <= _virtSize
+ UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize
+ size_t _cachedSize;
+
+ HRESULT MyWrite(size_t size);
+ HRESULT MyWriteBlock()
+ {
+ return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)));
+ }
+ HRESULT FlushCache();
+public:
+ CCacheOutStream(): _cache(0) {}
+ ~CCacheOutStream();
+ bool Allocate();
+ HRESULT Init(IOutStream *stream);
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+bool CCacheOutStream::Allocate()
+{
+ if (!_cache)
+ _cache = (Byte *)::MidAlloc(kCacheSize);
+ return (_cache != NULL);
+}
+
+HRESULT CCacheOutStream::Init(IOutStream *stream)
+{
+ _virtPos = _phyPos = 0;
+ _stream = stream;
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos));
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize));
+ RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos));
+ _phyPos = _virtPos;
+ _phySize = _virtSize;
+ _cachedPos = 0;
+ _cachedSize = 0;
+ return S_OK;
+}
+
+HRESULT CCacheOutStream::MyWrite(size_t size)
+{
+ while (size != 0 && _cachedSize != 0)
+ {
+ if (_phyPos != _cachedPos)
+ {
+ RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos));
+ }
+ size_t pos = (size_t)_cachedPos & kCacheMask;
+ size_t curSize = MyMin(kCacheSize - pos, _cachedSize);
+ curSize = MyMin(curSize, size);
+ RINOK(WriteStream(_stream, _cache + pos, curSize));
+ _phyPos += curSize;
+ if (_phySize < _phyPos)
+ _phySize = _phyPos;
+ _cachedPos += curSize;
+ _cachedSize -= curSize;
+ size -= curSize;
+ }
+ return S_OK;
+}
+
+HRESULT CCacheOutStream::FlushCache()
+{
+ return MyWrite(_cachedSize);
+}
+
+CCacheOutStream::~CCacheOutStream()
+{
+ FlushCache();
+ if (_virtSize != _phySize)
+ _stream->SetSize(_virtSize);
+ if (_virtPos != _phyPos)
+ _stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
+ ::MidFree(_cache);
+}
+
+STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+
+ UInt64 zerosStart = _virtPos;
+ if (_cachedSize != 0)
+ {
+ if (_virtPos < _cachedPos)
+ {
+ RINOK(FlushCache());
+ }
+ else
+ {
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ if (cachedEnd < _virtPos)
+ {
+ if (cachedEnd < _phySize)
+ {
+ RINOK(FlushCache());
+ }
+ else
+ zerosStart = cachedEnd;
+ }
+ }
+ }
+
+ if (_cachedSize == 0 && _phySize < _virtPos)
+ _cachedPos = zerosStart = _phySize;
+
+ if (zerosStart != _virtPos)
+ {
+ // write zeros to [cachedEnd ... _virtPos)
+
+ for (;;)
+ {
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ size_t endPos = (size_t)cachedEnd & kCacheMask;
+ size_t curSize = kCacheSize - endPos;
+ if (curSize > _virtPos - cachedEnd)
+ curSize = (size_t)(_virtPos - cachedEnd);
+ if (curSize == 0)
+ break;
+ while (curSize > (kCacheSize - _cachedSize))
+ {
+ RINOK(MyWriteBlock());
+ }
+ memset(_cache + endPos, 0, curSize);
+ _cachedSize += curSize;
+ }
+ }
+
+ if (_cachedSize == 0)
+ _cachedPos = _virtPos;
+
+ size_t pos = (size_t)_virtPos & kCacheMask;
+ size = (UInt32)MyMin((size_t)size, kCacheSize - pos);
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ if (_virtPos != cachedEnd) // _virtPos < cachedEnd
+ size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos));
+ else
+ {
+ // _virtPos == cachedEnd
+ if (_cachedSize == kCacheSize)
+ {
+ RINOK(MyWriteBlock());
+ }
+ size_t startPos = (size_t)_cachedPos & kCacheMask;
+ if (startPos > pos)
+ size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos));
+ _cachedSize += size;
+ }
+ memcpy(_cache + pos, data, size);
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ if (_virtSize < _virtPos)
+ _virtSize = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = _virtSize + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize)
+{
+ _virtSize = newSize;
+ if (newSize < _phySize)
+ {
+ RINOK(_stream->SetSize(newSize));
+ _phySize = newSize;
+ }
+ if (newSize <= _cachedPos)
+ {
+ _cachedSize = 0;
+ _cachedPos = newSize;
+ }
+ if (newSize < _cachedPos + _cachedSize)
+ _cachedSize = (size_t)(newSize - _cachedPos);
+ return S_OK;
+}
+
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ ISequentialOutStream *seqOutStream,
+ CInArchive *inArchive,
+ CCompressionMethodMode *compressionMethodMode,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CMyComPtr<IOutStream> outStream;
+ {
+ CMyComPtr<IOutStream> outStreamReal;
+ seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
+ if (!outStreamReal)
+ return E_NOTIMPL;
+ CCacheOutStream *cacheStream = new CCacheOutStream();
+ outStream = cacheStream;
+ if (!cacheStream->Allocate())
+ return E_OUTOFMEMORY;
+ RINOK(cacheStream->Init(outStreamReal));
+ }
+
+ if (inArchive)
+ {
+ if (inArchive->ArcInfo.Base != 0 ||
+ inArchive->ArcInfo.StartPosition != 0 ||
+ !inArchive->IsOkHeaders)
+ return E_NOTIMPL;
+ }
+
+ COutArchive outArchive;
+ outArchive.Create(outStream);
+ /*
+ if (inArchive && inArchive->ArcInfo.StartPosition > 0)
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+ inStream.Attach(inArchive->CreateLimitedStream(0, inArchive->ArcInfo.StartPosition));
+ RINOK(CopyBlockToArchive(inStream, outArchive, NULL));
+ outArchive.MoveBasePosition(inArchive->ArcInfo.StartPosition);
+ }
+ */
+ CMyComPtr<IInStream> inStream;
+ if (inArchive)
+ inStream.Attach(inArchive->CreateStream());
+
+ return Update2(
+ EXTERNAL_CODECS_LOC_VARS
+ outArchive, inArchive, inStream,
+ inputItems, updateItems,
+ compressionMethodMode,
+ inArchive ? &inArchive->ArcInfo.Comment : NULL,
+ updateCallback);
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipUpdate.h b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipUpdate.h
new file mode 100644
index 000000000..eee16738c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Archive/Zip/ZipUpdate.h
@@ -0,0 +1,58 @@
+// Zip/Update.h
+
+#ifndef __ZIP_UPDATE_H
+#define __ZIP_UPDATE_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "ZipCompressionMode.h"
+#include "ZipIn.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CUpdateRange
+{
+ UInt64 Position;
+ UInt64 Size;
+ CUpdateRange() {};
+ CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {};
+};
+
+struct CUpdateItem
+{
+ bool NewData;
+ bool NewProperties;
+ bool IsDir;
+ bool NtfsTimeIsDefined;
+ bool IsUtf8;
+ int IndexInArchive;
+ int IndexInClient;
+ UInt32 Attributes;
+ UInt32 Time;
+ UInt64 Size;
+ AString Name;
+ // bool Commented;
+ // CUpdateRange CommentRange;
+ FILETIME NtfsMTime;
+ FILETIME NtfsATime;
+ FILETIME NtfsCTime;
+
+ CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {}
+};
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ ISequentialOutStream *seqOutStream,
+ CInArchive *inArchive,
+ CCompressionMethodMode *compressionMethodMode,
+ IArchiveUpdateCallback *updateCallback);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/CWrappers.cpp b/src/libs/7zip/unix/CPP/7zip/Common/CWrappers.cpp
new file mode 100644
index 000000000..358f0b503
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/CWrappers.cpp
@@ -0,0 +1,226 @@
+// CWrappers.h
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "CWrappers.h"
+
+#include "StreamUtils.h"
+
+#define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1)
+
+#define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x)
+
+static SRes CompressProgress(void *pp, UInt64 inSize, UInt64 outSize)
+{
+ CCompressProgressWrap *p = (CCompressProgressWrap *)pp;
+ p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize));
+ return (SRes)p->Res;
+}
+
+CCompressProgressWrap::CCompressProgressWrap(ICompressProgressInfo *progress)
+{
+ p.Progress = CompressProgress;
+ Progress = progress;
+ Res = SZ_OK;
+}
+
+static const UInt32 kStreamStepSize = (UInt32)1 << 31;
+
+SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes)
+{
+ switch(res)
+ {
+ case S_OK: return SZ_OK;
+ case E_OUTOFMEMORY: return SZ_ERROR_MEM;
+ case E_INVALIDARG: return SZ_ERROR_PARAM;
+ case E_ABORT: return SZ_ERROR_PROGRESS;
+ case S_FALSE: return SZ_ERROR_DATA;
+ }
+ return defaultRes;
+}
+
+static SRes MyRead(void *object, void *data, size_t *size)
+{
+ CSeqInStreamWrap *p = (CSeqInStreamWrap *)object;
+ UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
+ p->Res = (p->Stream->Read(data, curSize, &curSize));
+ *size = curSize;
+ if (p->Res == S_OK)
+ return SZ_OK;
+ return HRESULT_To_SRes(p->Res, SZ_ERROR_READ);
+}
+
+static size_t MyWrite(void *object, const void *data, size_t size)
+{
+ CSeqOutStreamWrap *p = (CSeqOutStreamWrap *)object;
+ if (p->Stream)
+ {
+ p->Res = WriteStream(p->Stream, data, size);
+ if (p->Res != 0)
+ return 0;
+ }
+ else
+ p->Res = S_OK;
+ p->Processed += size;
+ return size;
+}
+
+CSeqInStreamWrap::CSeqInStreamWrap(ISequentialInStream *stream)
+{
+ p.Read = MyRead;
+ Stream = stream;
+}
+
+CSeqOutStreamWrap::CSeqOutStreamWrap(ISequentialOutStream *stream)
+{
+ p.Write = MyWrite;
+ Stream = stream;
+ Res = SZ_OK;
+ Processed = 0;
+}
+
+HRESULT SResToHRESULT(SRes res)
+{
+ switch(res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PARAM: return E_INVALIDARG;
+ case SZ_ERROR_PROGRESS: return E_ABORT;
+ case SZ_ERROR_DATA: return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+static SRes InStreamWrap_Read(void *pp, void *data, size_t *size)
+{
+ CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp;
+ UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
+ p->Res = p->Stream->Read(data, curSize, &curSize);
+ *size = curSize;
+ return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes InStreamWrap_Seek(void *pp, Int64 *offset, ESzSeek origin)
+{
+ CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp;
+ UInt32 moveMethod;
+ switch(origin)
+ {
+ case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break;
+ case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break;
+ case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break;
+ default: return SZ_ERROR_PARAM;
+ }
+ UInt64 newPosition;
+ p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition);
+ *offset = (Int64)newPosition;
+ return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
+}
+
+CSeekInStreamWrap::CSeekInStreamWrap(IInStream *stream)
+{
+ Stream = stream;
+ p.Read = InStreamWrap_Read;
+ p.Seek = InStreamWrap_Seek;
+ Res = S_OK;
+}
+
+
+/* ---------- CByteInBufWrap ---------- */
+
+void CByteInBufWrap::Free()
+{
+ ::MidFree(Buf);
+ Buf = 0;
+}
+
+bool CByteInBufWrap::Alloc(UInt32 size)
+{
+ if (Buf == 0 || size != Size)
+ {
+ Free();
+ Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size);
+ Size = size;
+ }
+ return (Buf != 0);
+}
+
+Byte CByteInBufWrap::ReadByteFromNewBlock()
+{
+ if (Res == S_OK)
+ {
+ UInt32 avail;
+ Processed += (Cur - Buf);
+ Res = Stream->Read(Buf, Size, &avail);
+ Cur = Buf;
+ Lim = Buf + avail;
+ if (avail != 0)
+ return *Cur++;
+ }
+ Extra = true;
+ return 0;
+}
+
+static Byte Wrap_ReadByte(void *pp)
+{
+ CByteInBufWrap *p = (CByteInBufWrap *)pp;
+ if (p->Cur != p->Lim)
+ return *p->Cur++;
+ return p->ReadByteFromNewBlock();
+}
+
+CByteInBufWrap::CByteInBufWrap(): Buf(0)
+{
+ p.Read = Wrap_ReadByte;
+}
+
+
+/* ---------- CByteOutBufWrap ---------- */
+
+void CByteOutBufWrap::Free()
+{
+ ::MidFree(Buf);
+ Buf = 0;
+}
+
+bool CByteOutBufWrap::Alloc(size_t size)
+{
+ if (Buf == 0 || size != Size)
+ {
+ Free();
+ Buf = (Byte *)::MidAlloc(size);
+ Size = size;
+ }
+ return (Buf != 0);
+}
+
+HRESULT CByteOutBufWrap::Flush()
+{
+ if (Res == S_OK)
+ {
+ size_t size = (Cur - Buf);
+ Res = WriteStream(Stream, Buf, size);
+ if (Res == S_OK)
+ Processed += size;
+ Cur = Buf;
+ }
+ return Res;
+}
+
+static void Wrap_WriteByte(void *pp, Byte b)
+{
+ CByteOutBufWrap *p = (CByteOutBufWrap *)pp;
+ Byte *dest = p->Cur;
+ *dest = b;
+ p->Cur = ++dest;
+ if (dest == p->Lim)
+ p->Flush();
+}
+
+CByteOutBufWrap::CByteOutBufWrap(): Buf(0)
+{
+ p.Write = Wrap_WriteByte;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/CWrappers.h b/src/libs/7zip/unix/CPP/7zip/Common/CWrappers.h
new file mode 100644
index 000000000..80a8a1b61
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/CWrappers.h
@@ -0,0 +1,109 @@
+// CWrappers.h
+
+#ifndef __C_WRAPPERS_H
+#define __C_WRAPPERS_H
+
+#include "../ICoder.h"
+#include "../../Common/MyCom.h"
+
+struct CCompressProgressWrap
+{
+ ICompressProgress p;
+ ICompressProgressInfo *Progress;
+ HRESULT Res;
+ CCompressProgressWrap(ICompressProgressInfo *progress);
+};
+
+struct CSeqInStreamWrap
+{
+ ISeqInStream p;
+ ISequentialInStream *Stream;
+ HRESULT Res;
+ CSeqInStreamWrap(ISequentialInStream *stream);
+};
+
+struct CSeekInStreamWrap
+{
+ ISeekInStream p;
+ IInStream *Stream;
+ HRESULT Res;
+ CSeekInStreamWrap(IInStream *stream);
+};
+
+struct CSeqOutStreamWrap
+{
+ ISeqOutStream p;
+ ISequentialOutStream *Stream;
+ HRESULT Res;
+ UInt64 Processed;
+ CSeqOutStreamWrap(ISequentialOutStream *stream);
+};
+
+HRESULT SResToHRESULT(SRes res);
+
+struct CByteInBufWrap
+{
+ IByteIn p;
+ const Byte *Cur;
+ const Byte *Lim;
+ Byte *Buf;
+ UInt32 Size;
+ ISequentialInStream *Stream;
+ UInt64 Processed;
+ bool Extra;
+ HRESULT Res;
+
+ CByteInBufWrap();
+ ~CByteInBufWrap() { Free(); }
+ void Free();
+ bool Alloc(UInt32 size);
+ void Init()
+ {
+ Lim = Cur = Buf;
+ Processed = 0;
+ Extra = false;
+ Res = S_OK;
+ }
+ UInt64 GetProcessed() const { return Processed + (Cur - Buf); }
+ Byte ReadByteFromNewBlock();
+ Byte ReadByte()
+ {
+ if (Cur != Lim)
+ return *Cur++;
+ return ReadByteFromNewBlock();
+ }
+};
+
+struct CByteOutBufWrap
+{
+ IByteOut p;
+ Byte *Cur;
+ const Byte *Lim;
+ Byte *Buf;
+ size_t Size;
+ ISequentialOutStream *Stream;
+ UInt64 Processed;
+ HRESULT Res;
+
+ CByteOutBufWrap();
+ ~CByteOutBufWrap() { Free(); }
+ void Free();
+ bool Alloc(size_t size);
+ void Init()
+ {
+ Cur = Buf;
+ Lim = Buf + Size;
+ Processed = 0;
+ Res = S_OK;
+ }
+ UInt64 GetProcessed() const { return Processed + (Cur - Buf); }
+ HRESULT Flush();
+ void WriteByte(Byte b)
+ {
+ *Cur++ = b;
+ if (Cur == Lim)
+ Flush();
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.cpp b/src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.cpp
new file mode 100644
index 000000000..cc82a0db5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.cpp
@@ -0,0 +1,293 @@
+// CreateCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Windows/Defs.h"
+#include "../../Windows/PropVariant.h"
+
+#include "CreateCoder.h"
+
+#include "FilterCoder.h"
+#include "RegisterCodec.h"
+
+static const unsigned int kNumCodecsMax = 64;
+unsigned int g_NumCodecs = 0;
+const CCodecInfo *g_Codecs[kNumCodecsMax];
+void RegisterCodec(const CCodecInfo *codecInfo)
+{
+ if (g_NumCodecs < kNumCodecsMax)
+ g_Codecs[g_NumCodecs++] = codecInfo;
+}
+
+#ifdef EXTERNAL_CODECS
+static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(codecsInfo->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_EMPTY)
+ res = 1;
+ else if (prop.vt == VT_UI4)
+ res = prop.ulVal;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(codecsInfo->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_EMPTY)
+ res = true;
+ else if (prop.vt == VT_BOOL)
+ res = VARIANT_BOOLToBool(prop.boolVal);
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+HRESULT LoadExternalCodecs(ICompressCodecsInfo *codecsInfo, CObjectVector<CCodecInfoEx> &externalCodecs)
+{
+ UInt32 num;
+ RINOK(codecsInfo->GetNumberOfMethods(&num));
+ for (UInt32 i = 0; i < num; i++)
+ {
+ CCodecInfoEx info;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(codecsInfo->GetProperty(i, NMethodPropID::kID, &prop));
+ // if (prop.vt != VT_BSTR)
+ // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal);
+ // memmove(info.Id.ID, prop.bstrVal, info.Id.IDSize);
+ if (prop.vt != VT_UI8)
+ {
+ continue; // old Interface
+ // return E_INVALIDARG;
+ }
+ info.Id = prop.uhVal.QuadPart;
+ prop.Clear();
+
+ RINOK(codecsInfo->GetProperty(i, NMethodPropID::kName, &prop));
+ if (prop.vt == VT_BSTR)
+ info.Name = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;;
+
+ RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kInStreams, info.NumInStreams));
+ RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kOutStreams, info.NumOutStreams));
+ RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned));
+ RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned));
+
+ externalCodecs.Add(info);
+ }
+ return S_OK;
+}
+
+#endif
+
+bool FindMethod(
+ #ifdef EXTERNAL_CODECS
+ ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
+ #endif
+ const UString &name,
+ CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams)
+{
+ UInt32 i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (name.CompareNoCase(codec.Name) == 0)
+ {
+ methodId = codec.Id;
+ numInStreams = codec.NumInStreams;
+ numOutStreams = 1;
+ return true;
+ }
+ }
+ #ifdef EXTERNAL_CODECS
+ if (externalCodecs)
+ for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+ {
+ const CCodecInfoEx &codec = (*externalCodecs)[i];
+ if (codec.Name.CompareNoCase(name) == 0)
+ {
+ methodId = codec.Id;
+ numInStreams = codec.NumInStreams;
+ numOutStreams = codec.NumOutStreams;
+ return true;
+ }
+ }
+ #endif
+ return false;
+}
+
+bool FindMethod(
+ #ifdef EXTERNAL_CODECS
+ ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
+ #endif
+ CMethodId methodId, UString &name)
+{
+ UInt32 i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (methodId == codec.Id)
+ {
+ name = codec.Name;
+ return true;
+ }
+ }
+ #ifdef EXTERNAL_CODECS
+ if (externalCodecs)
+ for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+ {
+ const CCodecInfoEx &codec = (*externalCodecs)[i];
+ if (methodId == codec.Id)
+ {
+ name = codec.Name;
+ return true;
+ }
+ }
+ #endif
+ return false;
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode, bool onlyCoder)
+{
+ bool created = false;
+ UInt32 i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (codec.Id == methodId)
+ {
+ if (encode)
+ {
+ if (codec.CreateEncoder)
+ {
+ void *p = codec.CreateEncoder();
+ if (codec.IsFilter) filter = (ICompressFilter *)p;
+ else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
+ else coder2 = (ICompressCoder2 *)p;
+ created = (p != 0);
+ break;
+ }
+ }
+ else
+ if (codec.CreateDecoder)
+ {
+ void *p = codec.CreateDecoder();
+ if (codec.IsFilter) filter = (ICompressFilter *)p;
+ else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
+ else coder2 = (ICompressCoder2 *)p;
+ created = (p != 0);
+ break;
+ }
+ }
+ }
+
+ #ifdef EXTERNAL_CODECS
+ if (!created && externalCodecs)
+ for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+ {
+ const CCodecInfoEx &codec = (*externalCodecs)[i];
+ if (codec.Id == methodId)
+ {
+ if (encode)
+ {
+ if (codec.EncoderIsAssigned)
+ {
+ if (codec.IsSimpleCodec())
+ {
+ HRESULT result = codecsInfo->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder);
+ if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
+ return result;
+ if (!coder)
+ {
+ RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter));
+ }
+ }
+ else
+ {
+ RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2));
+ }
+ break;
+ }
+ }
+ else
+ if (codec.DecoderIsAssigned)
+ {
+ if (codec.IsSimpleCodec())
+ {
+ HRESULT result = codecsInfo->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder);
+ if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
+ return result;
+ if (!coder)
+ {
+ RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter));
+ }
+ }
+ else
+ {
+ RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2));
+ }
+ break;
+ }
+ }
+ }
+ #endif
+
+ if (onlyCoder && filter)
+ {
+ CFilterCoder *coderSpec = new CFilterCoder;
+ coder = coderSpec;
+ coderSpec->Filter = filter;
+ }
+ return S_OK;
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode)
+{
+ CMyComPtr<ICompressFilter> filter;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ filter, coder, coder2, encode, true);
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder, bool encode)
+{
+ CMyComPtr<ICompressFilter> filter;
+ CMyComPtr<ICompressCoder2> coder2;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ coder, coder2, encode);
+}
+
+HRESULT CreateFilter(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ bool encode)
+{
+ CMyComPtr<ICompressCoder> coder;
+ CMyComPtr<ICompressCoder2> coder2;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ filter, coder, coder2, encode, false);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.h b/src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.h
new file mode 100644
index 000000000..bf0e96a38
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/CreateCoder.h
@@ -0,0 +1,98 @@
+// CreateCoder.h
+
+#ifndef __CREATE_CODER_H
+#define __CREATE_CODER_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyString.h"
+#include "../ICoder.h"
+
+#include "MethodId.h"
+
+#ifdef EXTERNAL_CODECS
+
+struct CCodecInfoEx
+{
+ UString Name;
+ CMethodId Id;
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+ bool IsSimpleCodec() const { return NumOutStreams == 1 && NumInStreams == 1; }
+ CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {}
+};
+
+HRESULT LoadExternalCodecs(ICompressCodecsInfo *codecsInfo, CObjectVector<CCodecInfoEx> &externalCodecs);
+
+#define PUBLIC_ISetCompressCodecsInfo public ISetCompressCodecsInfo,
+#define QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_ENTRY(ISetCompressCodecsInfo)
+#define DECL_ISetCompressCodecsInfo STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo);
+#define IMPL_ISetCompressCodecsInfo2(x) \
+STDMETHODIMP x::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo) { \
+ COM_TRY_BEGIN _codecsInfo = compressCodecsInfo; return LoadExternalCodecs(_codecsInfo, _externalCodecs); COM_TRY_END }
+#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler)
+
+#define EXTERNAL_CODECS_VARS2 _codecsInfo, &_externalCodecs
+
+#define DECL_EXTERNAL_CODECS_VARS CMyComPtr<ICompressCodecsInfo> _codecsInfo; CObjectVector<CCodecInfoEx> _externalCodecs;
+#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2,
+
+#define DECL_EXTERNAL_CODECS_LOC_VARS2 ICompressCodecsInfo *codecsInfo, const CObjectVector<CCodecInfoEx> *externalCodecs
+#define EXTERNAL_CODECS_LOC_VARS2 codecsInfo, externalCodecs
+
+#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2,
+#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2,
+
+#else
+
+#define PUBLIC_ISetCompressCodecsInfo
+#define QUERY_ENTRY_ISetCompressCodecsInfo
+#define DECL_ISetCompressCodecsInfo
+#define IMPL_ISetCompressCodecsInfo
+#define EXTERNAL_CODECS_VARS2
+#define DECL_EXTERNAL_CODECS_VARS
+#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS2
+#define EXTERNAL_CODECS_LOC_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS
+#define EXTERNAL_CODECS_LOC_VARS
+
+#endif
+
+bool FindMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams);
+
+bool FindMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, UString &name);
+
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode, bool onlyCoder);
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode);
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder, bool encode);
+
+HRESULT CreateFilter(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ bool encode);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.cpp b/src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.cpp
new file mode 100644
index 000000000..7d6e36f14
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.cpp
@@ -0,0 +1,55 @@
+// FilePathAutoRename.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Defs.h"
+#include "Common/IntToString.h"
+
+#include "Windows/FileFind.h"
+
+#include "FilePathAutoRename.h"
+
+using namespace NWindows;
+
+static bool MakeAutoName(const UString &name,
+ const UString &extension, unsigned value, UString &path)
+{
+ wchar_t number[16];
+ ConvertUInt32ToString(value, number);
+ path = name;
+ path += number;
+ path += extension;
+ return NFile::NFind::DoesFileOrDirExist(path);
+}
+
+bool AutoRenamePath(UString &fullProcessedPath)
+{
+ UString path;
+ int dotPos = fullProcessedPath.ReverseFind(L'.');
+
+ int slashPos = fullProcessedPath.ReverseFind(L'/');
+ #ifdef _WIN32
+ int slash1Pos = fullProcessedPath.ReverseFind(L'\\');
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+
+ UString name, extension;
+ if (dotPos > slashPos && dotPos > 0)
+ {
+ name = fullProcessedPath.Left(dotPos);
+ extension = fullProcessedPath.Mid(dotPos);
+ }
+ else
+ name = fullProcessedPath;
+ name += L'_';
+ unsigned left = 1, right = (1 << 30);
+ while (left != right)
+ {
+ unsigned mid = (left + right) / 2;
+ if (MakeAutoName(name, extension, mid, path))
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ return !MakeAutoName(name, extension, right, fullProcessedPath);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.h b/src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.h
new file mode 100644
index 000000000..3ef87f482
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/FilePathAutoRename.h
@@ -0,0 +1,10 @@
+// Util/FilePathAutoRename.h
+
+#ifndef __FILEPATHAUTORENAME_H
+#define __FILEPATHAUTORENAME_H
+
+#include "Common/MyString.h"
+
+bool AutoRenamePath(UString &fullProcessedPath);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/FileStreams.cpp b/src/libs/7zip/unix/CPP/7zip/Common/FileStreams.cpp
new file mode 100644
index 000000000..76ab5ee29
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/FileStreams.cpp
@@ -0,0 +1,273 @@
+// FileStreams.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include "FileStreams.h"
+
+static inline HRESULT ConvertBoolToHRESULT(bool result)
+{
+ #ifdef _WIN32
+ if (result)
+ return S_OK;
+ DWORD lastError = ::GetLastError();
+ if (lastError == 0)
+ return E_FAIL;
+ return HRESULT_FROM_WIN32(lastError);
+ #else
+ return result ? S_OK: E_FAIL;
+ #endif
+}
+
+bool CInFileStream::Open(LPCTSTR fileName)
+{
+#ifdef ENV_UNIX
+ return File.Open(fileName,_ignoreSymbolicLink);
+#else
+ return File.Open(fileName);
+#endif
+}
+
+#ifdef USE_WIN_FILE
+#ifndef _UNICODE
+bool CInFileStream::Open(LPCWSTR fileName)
+{
+#ifdef ENV_UNIX
+ return File.Open(fileName,_ignoreSymbolicLink);
+#else
+ return File.Open(fileName);
+#endif
+}
+#endif
+#endif
+
+bool CInFileStream::OpenShared(LPCTSTR fileName, bool shareForWrite)
+{
+#ifdef ENV_UNIX
+ return File.Open(fileName,_ignoreSymbolicLink);
+#else
+ return File.OpenShared(fileName, shareForWrite);
+#endif
+}
+
+#ifdef USE_WIN_FILE
+#ifndef _UNICODE
+bool CInFileStream::OpenShared(LPCWSTR fileName, bool shareForWrite)
+{
+ return File.OpenShared(fileName, shareForWrite);
+}
+#endif
+#endif
+
+STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef USE_WIN_FILE
+
+ UInt32 realProcessedSize;
+ bool result = File.ReadPart(data, size, realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ if(processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res = File.Read(data, (size_t)size);
+ if (res == -1)
+ return E_FAIL;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+#ifndef _WIN32_WCE
+STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef _WIN32
+ UInt32 realProcessedSize;
+ BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE),
+ data, size, (DWORD *)&realProcessedSize, NULL);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
+ return S_OK;
+ return ConvertBoolToHRESULT(res != FALSE);
+
+ #else
+
+ if(processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res;
+ do
+ {
+ res = read(0, data, (size_t)size);
+ }
+ while (res < 0 && (errno == EINTR));
+ if (res == -1)
+ return E_FAIL;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+#endif
+
+STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin,
+ UInt64 *newPosition)
+{
+ if(seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+
+ #ifdef USE_WIN_FILE
+
+ UInt64 realNewPosition;
+ bool result = File.Seek(offset, seekOrigin, realNewPosition);
+ if(newPosition != NULL)
+ *newPosition = realNewPosition;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ off_t res = File.Seek(offset, seekOrigin);
+ if (res == -1)
+ return E_FAIL;
+ if(newPosition != NULL)
+ *newPosition = (UInt64)res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
+{
+ return ConvertBoolToHRESULT(File.GetLength(*size));
+}
+
+
+//////////////////////////
+// COutFileStream
+
+HRESULT COutFileStream::Close()
+{
+ return ConvertBoolToHRESULT(File.Close());
+}
+
+STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef USE_WIN_FILE
+
+ UInt32 realProcessedSize;
+ bool result = File.WritePart(data, size, realProcessedSize);
+ ProcessedSize += realProcessedSize;
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ if(processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res = File.Write(data, (size_t)size);
+ if (res == -1)
+ return E_FAIL;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)res;
+ ProcessedSize += res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if(seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+ #ifdef USE_WIN_FILE
+
+ UInt64 realNewPosition;
+ bool result = File.Seek(offset, seekOrigin, realNewPosition);
+ if(newPosition != NULL)
+ *newPosition = realNewPosition;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ off_t res = File.Seek(offset, seekOrigin);
+ if (res == -1)
+ return E_FAIL;
+ if(newPosition != NULL)
+ *newPosition = (UInt64)res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP COutFileStream::SetSize(UInt64 newSize)
+{
+ #ifdef USE_WIN_FILE
+ UInt64 currentPos;
+ if(!File.Seek(0, FILE_CURRENT, currentPos))
+ return E_FAIL;
+ bool result = File.SetLength(newSize);
+ UInt64 currentPos2;
+ result = result && File.Seek(currentPos, currentPos2);
+ return result ? S_OK : E_FAIL;
+ #else
+ return E_FAIL;
+ #endif
+}
+
+#ifndef _WIN32_WCE
+STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if(processedSize != NULL)
+ *processedSize = 0;
+
+ #ifdef _WIN32
+ UInt32 realProcessedSize;
+ BOOL res = TRUE;
+ if (size > 0)
+ {
+ // Seems that Windows doesn't like big amounts writing to stdout.
+ // So we limit portions by 32KB.
+ UInt32 sizeTemp = (1 << 15);
+ if (sizeTemp > size)
+ sizeTemp = size;
+ res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
+ data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
+ size -= realProcessedSize;
+ data = (const void *)((const Byte *)data + realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize += realProcessedSize;
+ }
+ return ConvertBoolToHRESULT(res != FALSE);
+
+ #else
+
+ ssize_t res;
+ do
+ {
+ res = write(1, data, (size_t)size);
+ }
+ while (res < 0 && (errno == EINTR));
+ if (res == -1)
+ return E_FAIL;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ return S_OK;
+ #endif
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/FileStreams.h b/src/libs/7zip/unix/CPP/7zip/Common/FileStreams.h
new file mode 100644
index 000000000..f70905b56
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/FileStreams.h
@@ -0,0 +1,134 @@
+// FileStreams.h
+
+#ifndef __FILESTREAMS_H
+#define __FILESTREAMS_H
+
+#if defined(_WIN32) || defined(ENV_UNIX)
+#define USE_WIN_FILE
+#endif
+
+#ifdef USE_WIN_FILE
+#include "../../Windows/FileIO.h"
+#else
+#include "../../Common/C_FileIO.h"
+#endif
+
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+class CInFileStream:
+ public IInStream,
+ public IStreamGetSize,
+ public CMyUnknownImp
+{
+ bool _ignoreSymbolicLink;
+public:
+ #ifdef USE_WIN_FILE
+ NWindows::NFile::NIO::CInFile File;
+ #else
+ NC::NFile::NIO::CInFile File;
+ #endif
+ CInFileStream(bool b=false) { _ignoreSymbolicLink = b; }
+ virtual ~CInFileStream() {}
+
+ bool Open(LPCTSTR fileName);
+ #ifdef USE_WIN_FILE
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName);
+ #endif
+ #endif
+
+ bool OpenShared(LPCTSTR fileName, bool shareForWrite);
+ #ifdef USE_WIN_FILE
+ #ifndef _UNICODE
+ bool OpenShared(LPCWSTR fileName, bool shareForWrite);
+ #endif
+ #endif
+
+ MY_UNKNOWN_IMP2(IInStream, IStreamGetSize)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+
+ STDMETHOD(GetSize)(UInt64 *size);
+};
+
+class CStdInFileStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ virtual ~CStdInFileStream() {}
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class COutFileStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ #ifdef USE_WIN_FILE
+ NWindows::NFile::NIO::COutFile File;
+ #else
+ NC::NFile::NIO::COutFile File;
+ #endif
+public:
+ virtual ~COutFileStream() {}
+ bool Create(LPCTSTR fileName, bool createAlways)
+ {
+ ProcessedSize = 0;
+ return File.Create(fileName, createAlways);
+ }
+ bool Open(LPCTSTR fileName, DWORD creationDisposition)
+ {
+ ProcessedSize = 0;
+ return File.Open(fileName, creationDisposition);
+ }
+ #ifdef USE_WIN_FILE
+ #ifndef _UNICODE
+ bool Create(LPCWSTR fileName, bool createAlways)
+ {
+ ProcessedSize = 0;
+ return File.Create(fileName, createAlways);
+ }
+ bool Open(LPCWSTR fileName, DWORD creationDisposition)
+ {
+ ProcessedSize = 0;
+ return File.Open(fileName, creationDisposition);
+ }
+ #endif
+ #endif
+
+ HRESULT Close();
+
+ UInt64 ProcessedSize;
+
+ #ifdef USE_WIN_FILE
+ bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
+ {
+ return File.SetTime(cTime, aTime, mTime);
+ }
+ bool SetMTime(const FILETIME *mTime) { return File.SetMTime(mTime); }
+ #endif
+
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+class CStdOutFileStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ virtual ~CStdOutFileStream() {}
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.cpp b/src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.cpp
new file mode 100644
index 000000000..696735278
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.cpp
@@ -0,0 +1,247 @@
+// FilterCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../../Common/Defs.h"
+
+#include "FilterCoder.h"
+#include "StreamUtils.h"
+
+static const UInt32 kBufferSize = 1 << 17;
+
+CFilterCoder::CFilterCoder()
+{
+ _buffer = (Byte *)::MidAlloc(kBufferSize);
+ if (_buffer == 0)
+ throw 1;
+}
+
+CFilterCoder::~CFilterCoder()
+{
+ ::MidFree(_buffer);
+}
+
+HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size)
+{
+ if (_outSizeIsDefined)
+ {
+ UInt64 remSize = _outSize - _nowPos64;
+ if (size > remSize)
+ size = (UInt32)remSize;
+ }
+ RINOK(WriteStream(outStream, _buffer, size));
+ _nowPos64 += size;
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ RINOK(Init());
+ UInt32 bufferPos = 0;
+ _outSizeIsDefined = (outSize != 0);
+ if (_outSizeIsDefined)
+ _outSize = *outSize;
+
+ while (!_outSizeIsDefined || _nowPos64 < _outSize)
+ {
+ size_t processedSize = kBufferSize - bufferPos;
+
+ // Change it: It can be optimized using ReadPart
+ RINOK(ReadStream(inStream, _buffer + bufferPos, &processedSize));
+
+ UInt32 endPos = bufferPos + (UInt32)processedSize;
+
+ bufferPos = Filter->Filter(_buffer, endPos);
+ if (bufferPos > endPos)
+ {
+ for (; endPos < bufferPos; endPos++)
+ _buffer[endPos] = 0;
+ bufferPos = Filter->Filter(_buffer, endPos);
+ }
+
+ if (bufferPos == 0)
+ {
+ if (endPos == 0)
+ return S_OK;
+ return WriteWithLimit(outStream, endPos);
+ }
+ RINOK(WriteWithLimit(outStream, bufferPos));
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64));
+ }
+ UInt32 i = 0;
+ while (bufferPos < endPos)
+ _buffer[i++] = _buffer[bufferPos++];
+ bufferPos = i;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
+{
+ _bufferPos = 0;
+ _outStream = outStream;
+ return Init();
+}
+
+STDMETHODIMP CFilterCoder::ReleaseOutStream()
+{
+ _outStream.Release();
+ return S_OK;
+}
+
+
+STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ UInt32 sizeTemp = MyMin(size, kBufferSize - _bufferPos);
+ memcpy(_buffer + _bufferPos, data, sizeTemp);
+ size -= sizeTemp;
+ if (processedSize != NULL)
+ *processedSize += sizeTemp;
+ data = (const Byte *)data + sizeTemp;
+ UInt32 endPos = _bufferPos + sizeTemp;
+ _bufferPos = Filter->Filter(_buffer, endPos);
+ if (_bufferPos == 0)
+ {
+ _bufferPos = endPos;
+ break;
+ }
+ if (_bufferPos > endPos)
+ {
+ if (size != 0)
+ return E_FAIL;
+ break;
+ }
+ RINOK(WriteWithLimit(_outStream, _bufferPos));
+ UInt32 i = 0;
+ while (_bufferPos < endPos)
+ _buffer[i++] = _buffer[_bufferPos++];
+ _bufferPos = i;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Flush()
+{
+ if (_bufferPos != 0)
+ {
+ // _buffer contains only data refused by previous Filter->Filter call.
+ UInt32 endPos = Filter->Filter(_buffer, _bufferPos);
+ if (endPos > _bufferPos)
+ {
+ for (; _bufferPos < endPos; _bufferPos++)
+ _buffer[_bufferPos] = 0;
+ if (Filter->Filter(_buffer, endPos) != endPos)
+ return E_FAIL;
+ }
+ RINOK(WriteWithLimit(_outStream, _bufferPos));
+ _bufferPos = 0;
+ }
+ CMyComPtr<IOutStreamFlush> flush;
+ _outStream.QueryInterface(IID_IOutStreamFlush, &flush);
+ if (flush)
+ return flush->Flush();
+ return S_OK;
+}
+
+
+STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
+{
+ _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
+ _inStream = inStream;
+ return Init();
+}
+
+STDMETHODIMP CFilterCoder::ReleaseInStream()
+{
+ _inStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_convertedPosBegin != _convertedPosEnd)
+ {
+ UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin);
+ memcpy(data, _buffer + _convertedPosBegin, sizeTemp);
+ _convertedPosBegin += sizeTemp;
+ data = (void *)((Byte *)data + sizeTemp);
+ size -= sizeTemp;
+ if (processedSize != NULL)
+ *processedSize += sizeTemp;
+ break;
+ }
+ UInt32 i;
+ for (i = 0; _convertedPosEnd + i < _bufferPos; i++)
+ _buffer[i] = _buffer[_convertedPosEnd + i];
+ _bufferPos = i;
+ _convertedPosBegin = _convertedPosEnd = 0;
+ size_t processedSizeTemp = kBufferSize - _bufferPos;
+ RINOK(ReadStream(_inStream, _buffer + _bufferPos, &processedSizeTemp));
+ _bufferPos += (UInt32)processedSizeTemp;
+ _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
+ if (_convertedPosEnd == 0)
+ {
+ if (_bufferPos == 0)
+ break;
+ _convertedPosEnd = _bufferPos; // check it
+ continue;
+ }
+ if (_convertedPosEnd > _bufferPos)
+ {
+ for (; _bufferPos < _convertedPosEnd; _bufferPos++)
+ _buffer[_bufferPos] = 0;
+ _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
+ }
+ }
+ return S_OK;
+}
+
+#ifndef _NO_CRYPTO
+STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ return _setPassword->CryptoSetPassword(data, size);
+}
+#endif
+
+#ifndef EXTRACT_ONLY
+STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties)
+{
+ return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties);
+}
+
+STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ return _writeCoderProperties->WriteCoderProperties(outStream);
+}
+
+/*
+STDMETHODIMP CFilterCoder::ResetSalt()
+{
+ return _CryptoResetSalt->ResetSalt();
+}
+*/
+
+STDMETHODIMP CFilterCoder::ResetInitVector()
+{
+ return _CryptoResetInitVector->ResetInitVector();
+}
+#endif
+
+STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ return _setDecoderProperties->SetDecoderProperties2(data, size);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.h b/src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.h
new file mode 100644
index 000000000..8132a6dd7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/FilterCoder.h
@@ -0,0 +1,128 @@
+// FilterCoder.h
+
+#ifndef __FILTER_CODER_H
+#define __FILTER_CODER_H
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#define MY_QUERYINTERFACE_ENTRY_AG(i, sub0, sub) if (iid == IID_ ## i) \
+{ if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \
+*outObject = (void *)(i *)this; AddRef(); return S_OK; }
+
+class CFilterCoder:
+ public ICompressCoder,
+ public ICompressSetInStream,
+ public ISequentialInStream,
+ public ICompressSetOutStream,
+ public ISequentialOutStream,
+ public IOutStreamFlush,
+
+ #ifndef _NO_CRYPTO
+ public ICryptoSetPassword,
+ #endif
+ #ifndef EXTRACT_ONLY
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector,
+ #endif
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+protected:
+ Byte *_buffer;
+ CMyComPtr<ISequentialInStream> _inStream;
+ CMyComPtr<ISequentialOutStream> _outStream;
+ UInt32 _bufferPos;
+ UInt32 _convertedPosBegin;
+ UInt32 _convertedPosEnd;
+ bool _outSizeIsDefined;
+ UInt64 _outSize;
+ UInt64 _nowPos64;
+
+ HRESULT Init()
+ {
+ _nowPos64 = 0;
+ _outSizeIsDefined = false;
+ return Filter->Init();
+ }
+
+ CMyComPtr<ICryptoSetPassword> _setPassword;
+ #ifndef EXTRACT_ONLY
+ CMyComPtr<ICompressSetCoderProperties> _SetCoderProperties;
+ CMyComPtr<ICompressWriteCoderProperties> _writeCoderProperties;
+ // CMyComPtr<ICryptoResetSalt> _CryptoResetSalt;
+ CMyComPtr<ICryptoResetInitVector> _CryptoResetInitVector;
+ #endif
+ CMyComPtr<ICompressSetDecoderProperties2> _setDecoderProperties;
+public:
+ CMyComPtr<ICompressFilter> Filter;
+
+ CFilterCoder();
+ ~CFilterCoder();
+ HRESULT WriteWithLimit(ISequentialOutStream *outStream, UInt32 size);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
+ MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream)
+ MY_QUERYINTERFACE_ENTRY(ISequentialOutStream)
+ MY_QUERYINTERFACE_ENTRY(IOutStreamFlush)
+
+ #ifndef _NO_CRYPTO
+ MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword)
+ #endif
+
+ #ifndef EXTRACT_ONLY
+ MY_QUERYINTERFACE_ENTRY_AG(ICompressSetCoderProperties, Filter, _SetCoderProperties)
+ MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties)
+ // MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetSalt, Filter, _CryptoResetSalt)
+ MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetInitVector, Filter, _CryptoResetInitVector)
+ #endif
+
+ MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties)
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); \
+ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
+ STDMETHOD(ReleaseOutStream)();
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Flush)();
+
+ #ifndef _NO_CRYPTO
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+ #endif
+ #ifndef EXTRACT_ONLY
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+ // STDMETHOD(ResetSalt)();
+ STDMETHOD(ResetInitVector)();
+ #endif
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+class CInStreamReleaser
+{
+public:
+ CFilterCoder *FilterCoder;
+ CInStreamReleaser(): FilterCoder(0) {}
+ ~CInStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }
+};
+
+class COutStreamReleaser
+{
+public:
+ CFilterCoder *FilterCoder;
+ COutStreamReleaser(): FilterCoder(0) {}
+ ~COutStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/InBuffer.cpp b/src/libs/7zip/unix/CPP/7zip/Common/InBuffer.cpp
new file mode 100644
index 000000000..ad4f8825e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/InBuffer.cpp
@@ -0,0 +1,83 @@
+// InBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "InBuffer.h"
+
+CInBuffer::CInBuffer():
+ _buffer(0),
+ _bufferLimit(0),
+ _bufferBase(0),
+ _stream(0),
+ _bufferSize(0)
+{}
+
+bool CInBuffer::Create(UInt32 bufferSize)
+{
+ const UInt32 kMinBlockSize = 1;
+ if (bufferSize < kMinBlockSize)
+ bufferSize = kMinBlockSize;
+ if (_bufferBase != 0 && _bufferSize == bufferSize)
+ return true;
+ Free();
+ _bufferSize = bufferSize;
+ _bufferBase = (Byte *)::MidAlloc(bufferSize);
+ return (_bufferBase != 0);
+}
+
+void CInBuffer::Free()
+{
+ ::MidFree(_bufferBase);
+ _bufferBase = 0;
+}
+
+void CInBuffer::SetStream(ISequentialInStream *stream)
+{
+ _stream = stream;
+}
+
+void CInBuffer::Init()
+{
+ _processedSize = 0;
+ _buffer = _bufferBase;
+ _bufferLimit = _buffer;
+ _wasFinished = false;
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
+
+bool CInBuffer::ReadBlock()
+{
+ #ifdef _NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ return false;
+ #endif
+ if (_wasFinished)
+ return false;
+ _processedSize += (_buffer - _bufferBase);
+ UInt32 numProcessedBytes;
+ HRESULT result = _stream->Read(_bufferBase, _bufferSize, &numProcessedBytes);
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = result;
+ #else
+ if (result != S_OK)
+ throw CInBufferException(result);
+ #endif
+ _buffer = _bufferBase;
+ _bufferLimit = _buffer + numProcessedBytes;
+ _wasFinished = (numProcessedBytes == 0);
+ return (!_wasFinished);
+}
+
+Byte CInBuffer::ReadBlock2()
+{
+ if (!ReadBlock())
+ {
+ _processedSize++;
+ return 0xFF;
+ }
+ return *_buffer++;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/InBuffer.h b/src/libs/7zip/unix/CPP/7zip/Common/InBuffer.h
new file mode 100644
index 000000000..75625bfd9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/InBuffer.h
@@ -0,0 +1,81 @@
+// InBuffer.h
+
+#ifndef __INBUFFER_H
+#define __INBUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+
+#ifndef _NO_EXCEPTIONS
+struct CInBufferException: public CSystemException
+{
+ CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+#endif
+
+class CInBuffer
+{
+ Byte *_buffer;
+ Byte *_bufferLimit;
+ Byte *_bufferBase;
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _processedSize;
+ UInt32 _bufferSize;
+ bool _wasFinished;
+
+ bool ReadBlock();
+ Byte ReadBlock2();
+
+public:
+ #ifdef _NO_EXCEPTIONS
+ HRESULT ErrorCode;
+ #endif
+
+ CInBuffer();
+ ~CInBuffer() { Free(); }
+
+ bool Create(UInt32 bufferSize);
+ void Free();
+
+ void SetStream(ISequentialInStream *stream);
+ void Init();
+ void ReleaseStream() { _stream.Release(); }
+
+ bool ReadByte(Byte &b)
+ {
+ if (_buffer >= _bufferLimit)
+ if (!ReadBlock())
+ return false;
+ b = *_buffer++;
+ return true;
+ }
+ Byte ReadByte()
+ {
+ if (_buffer >= _bufferLimit)
+ return ReadBlock2();
+ return *_buffer++;
+ }
+ UInt32 ReadBytes(Byte *buf, UInt32 size)
+ {
+ if ((UInt32)(_bufferLimit - _buffer) >= size)
+ {
+ for (UInt32 i = 0; i < size; i++)
+ buf[i] = _buffer[i];
+ _buffer += size;
+ return size;
+ }
+ for (UInt32 i = 0; i < size; i++)
+ {
+ if (_buffer >= _bufferLimit)
+ if (!ReadBlock())
+ return i;
+ buf[i] = *_buffer++;
+ }
+ return size;
+ }
+ UInt64 GetProcessedSize() const { return _processedSize + (_buffer - _bufferBase); }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.cpp b/src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.cpp
new file mode 100644
index 000000000..dfe8b3d32
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.cpp
@@ -0,0 +1,122 @@
+// InOutTempBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+
+#include "InOutTempBuffer.h"
+#include "StreamUtils.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDirectory;
+
+static const UInt32 kTempBufSize = (1 << 20);
+
+static LPCTSTR kTempFilePrefixString = TEXT("7zt");
+
+CInOutTempBuffer::CInOutTempBuffer(): _buf(NULL) { }
+
+void CInOutTempBuffer::Create()
+{
+ if (!_buf)
+ _buf = new Byte[kTempBufSize];
+}
+
+CInOutTempBuffer::~CInOutTempBuffer()
+{
+ delete []_buf;
+}
+
+void CInOutTempBuffer::InitWriting()
+{
+ _bufPos = 0;
+ _tempFileCreated = false;
+ _size = 0;
+ _crc = CRC_INIT_VAL;
+}
+
+bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size)
+{
+ if (size == 0)
+ return true;
+ if (!_tempFileCreated)
+ {
+ CSysString tempDirPath;
+ if (!MyGetTempPath(tempDirPath))
+ return false;
+ if (_tempFile.Create(tempDirPath, kTempFilePrefixString, _tempFileName) == 0)
+ return false;
+ if (!_outFile.Create(_tempFileName, true))
+ return false;
+ _tempFileCreated = true;
+ }
+ UInt32 processed;
+ if (!_outFile.Write(data, size, processed))
+ return false;
+ _crc = CrcUpdate(_crc, data, processed);
+ _size += processed;
+ return (processed == size);
+}
+
+bool CInOutTempBuffer::Write(const void *data, UInt32 size)
+{
+ if (_bufPos < kTempBufSize)
+ {
+ UInt32 cur = MyMin(kTempBufSize - _bufPos, size);
+ memcpy(_buf + _bufPos, data, cur);
+ _crc = CrcUpdate(_crc, data, cur);
+ _bufPos += cur;
+ size -= cur;
+ data = ((const Byte *)data) + cur;
+ _size += cur;
+ }
+ return WriteToFile(data, size);
+}
+
+HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
+{
+ if (!_outFile.Close())
+ return E_FAIL;
+
+ UInt64 size = 0;
+ UInt32 crc = CRC_INIT_VAL;
+
+ if (_bufPos > 0)
+ {
+ RINOK(WriteStream(stream, _buf, _bufPos));
+ crc = CrcUpdate(crc, _buf, _bufPos);
+ size += _bufPos;
+ }
+ if (_tempFileCreated)
+ {
+ NIO::CInFile inFile;
+ if (!inFile.Open(_tempFileName))
+ return E_FAIL;
+ while (size < _size)
+ {
+ UInt32 processed;
+ if (!inFile.ReadPart(_buf, kTempBufSize, processed))
+ return E_FAIL;
+ if (processed == 0)
+ break;
+ RINOK(WriteStream(stream, _buf, processed));
+ crc = CrcUpdate(crc, _buf, processed);
+ size += processed;
+ }
+ }
+ return (_crc == crc && size == _size) ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processed)
+{
+ if (!_buf->Write(data, size))
+ {
+ if (processed != NULL)
+ *processed = 0;
+ return E_FAIL;
+ }
+ if (processed != NULL)
+ *processed = size;
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.h b/src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.h
new file mode 100644
index 000000000..073f95acf
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/InOutTempBuffer.h
@@ -0,0 +1,48 @@
+// InOutTempBuffer.h
+
+#ifndef __IN_OUT_TEMP_BUFFER_H
+#define __IN_OUT_TEMP_BUFFER_H
+
+#include "../../Common/MyCom.h"
+#include "../../Windows/FileDir.h"
+#include "../../Windows/FileIO.h"
+
+#include "../IStream.h"
+
+class CInOutTempBuffer
+{
+ NWindows::NFile::NDirectory::CTempFile _tempFile;
+ NWindows::NFile::NIO::COutFile _outFile;
+ Byte *_buf;
+ UInt32 _bufPos;
+ CSysString _tempFileName;
+ bool _tempFileCreated;
+ UInt64 _size;
+ UInt32 _crc;
+
+ bool WriteToFile(const void *data, UInt32 size);
+public:
+ CInOutTempBuffer();
+ ~CInOutTempBuffer();
+ void Create();
+
+ void InitWriting();
+ bool Write(const void *data, UInt32 size);
+
+ HRESULT WriteToStream(ISequentialOutStream *stream);
+ UInt64 GetDataSize() const { return _size; }
+};
+
+class CSequentialOutTempBufferImp:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CInOutTempBuffer *_buf;
+public:
+ void Init(CInOutTempBuffer *buffer) { _buf = buffer; }
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.cpp b/src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.cpp
new file mode 100644
index 000000000..1837e3201
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.cpp
@@ -0,0 +1,154 @@
+// LimitedStreams.cpp
+
+#include "StdAfx.h"
+
+#include "LimitedStreams.h"
+#include "../../Common/Defs.h"
+
+STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ UInt32 sizeToRead = (UInt32)MyMin((_size - _pos), (UInt64)size);
+ HRESULT result = S_OK;
+ if (sizeToRead > 0)
+ {
+ result = _stream->Read(data, sizeToRead, &realProcessedSize);
+ _pos += realProcessedSize;
+ if (realProcessedSize == 0)
+ _wasFinished = true;
+ }
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= _size)
+ return (_virtPos == _size) ? S_OK: E_FAIL;
+ UInt64 rem = _size - _virtPos;
+ if (rem < size)
+ size = (UInt32)rem;
+ UInt64 newPos = _startOffset + _virtPos;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+ HRESULT res = _stream->Read(data, size, &size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ _physPos += size;
+ _virtPos += size;
+ return res;
+}
+
+STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = _size + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return (_virtPos == Size) ? S_OK: E_FAIL;
+
+ if (_curRem == 0)
+ {
+ UInt32 blockSize = (UInt32)1 << BlockSizeLog;
+ UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
+ UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ UInt32 phyBlock = Vector[virtBlock];
+ UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+ _curRem = blockSize - offsetInBlock;
+ for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
+ _curRem += (UInt32)1 << BlockSizeLog;
+ UInt64 rem = Size - _virtPos;
+ if (_curRem > rem)
+ _curRem = (UInt32)rem;
+ }
+ if (size > _curRem)
+ size = _curRem;
+ HRESULT res = Stream->Read(data, size, &size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ _physPos += size;
+ _virtPos += size;
+ _curRem -= size;
+ return res;
+}
+
+STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ UInt64 newVirtPos = offset;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: newVirtPos += _virtPos; break;
+ case STREAM_SEEK_END: newVirtPos += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (_virtPos != newVirtPos)
+ _curRem = 0;
+ _virtPos = newVirtPos;
+ if (newPosition)
+ *newPosition = newVirtPos;
+ return S_OK;
+}
+
+
+HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
+{
+ *resStream = 0;
+ CLimitedInStream *streamSpec = new CLimitedInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->SetStream(inStream);
+ RINOK(streamSpec->InitAndSeek(pos, size));
+ streamSpec->SeekToStart();
+ *resStream = streamTemp.Detach();
+ return S_OK;
+}
+
+STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = S_OK;
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (size > _size)
+ {
+ if (_size == 0)
+ {
+ _overflow = true;
+ if (!_overflowIsAllowed)
+ return E_FAIL;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+ }
+ size = (UInt32)_size;
+ }
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ _size -= size;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.h b/src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.h
new file mode 100644
index 000000000..2cbe18e48
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/LimitedStreams.h
@@ -0,0 +1,125 @@
+// LimitedStreams.h
+
+#ifndef __LIMITED_STREAMS_H
+#define __LIMITED_STREAMS_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyVector.h"
+#include "../IStream.h"
+
+class CLimitedSequentialInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ UInt64 _pos;
+ bool _wasFinished;
+public:
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(UInt64 streamSize)
+ {
+ _size = streamSize;
+ _pos = 0;
+ _wasFinished = false;
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ UInt64 GetSize() const { return _pos; }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+class CLimitedInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt64 _size;
+ UInt64 _startOffset;
+
+ HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
+public:
+ void SetStream(IInStream *stream) { _stream = stream; }
+ HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)
+ {
+ _startOffset = startOffset;
+ _physPos = startOffset;
+ _virtPos = 0;
+ _size = size;
+ return SeekToPhys();
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+
+ HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }
+};
+
+class CClusterInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt32 _curRem;
+public:
+ CMyComPtr<IInStream> Stream;
+ UInt64 StartOffset;
+ UInt64 Size;
+ int BlockSizeLog;
+ CRecordVector<UInt32> Vector;
+
+ HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
+
+ HRESULT InitAndSeek()
+ {
+ _curRem = 0;
+ _virtPos = 0;
+ _physPos = StartOffset;
+ if (Vector.Size() > 0)
+ {
+ _physPos = StartOffset + (Vector[0] << BlockSizeLog);
+ return SeekToPhys();
+ }
+ return S_OK;
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream);
+
+class CLimitedSequentialOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ bool _overflow;
+ bool _overflowIsAllowed;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(UInt64 size, bool overflowIsAllowed = false)
+ {
+ _size = size;
+ _overflow = false;
+ _overflowIsAllowed = overflowIsAllowed;
+ }
+ bool IsFinishedOK() const { return (_size == 0 && !_overflow); }
+ UInt64 GetRem() const { return _size; }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/LockedStream.cpp b/src/libs/7zip/unix/CPP/7zip/Common/LockedStream.cpp
new file mode 100644
index 000000000..f05601cb6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/LockedStream.cpp
@@ -0,0 +1,23 @@
+// LockedStream.cpp
+
+#include "StdAfx.h"
+
+#include "LockedStream.h"
+
+HRESULT CLockedInStream::Read(UInt64 startPos, void *data, UInt32 size,
+ UInt32 *processedSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ RINOK(_stream->Seek(startPos, STREAM_SEEK_SET, NULL));
+ return _stream->Read(data, size, processedSize);
+}
+
+STDMETHODIMP CLockedSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ HRESULT result = _lockedInStream->Read(_pos, data, size, &realProcessedSize);
+ _pos += realProcessedSize;
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/LockedStream.h b/src/libs/7zip/unix/CPP/7zip/Common/LockedStream.h
new file mode 100644
index 000000000..486e4220b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/LockedStream.h
@@ -0,0 +1,38 @@
+// LockedStream.h
+
+#ifndef __LOCKEDSTREAM_H
+#define __LOCKEDSTREAM_H
+
+#include "../../Windows/Synchronization.h"
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+class CLockedInStream
+{
+ CMyComPtr<IInStream> _stream;
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ void Init(IInStream *stream)
+ { _stream = stream; }
+ HRESULT Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CLockedSequentialInStreamImp:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CLockedInStream *_lockedInStream;
+ UInt64 _pos;
+public:
+ void Init(CLockedInStream *lockedInStream, UInt64 startPos)
+ {
+ _lockedInStream = lockedInStream;
+ _pos = startPos;
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/MemBlocks.cpp b/src/libs/7zip/unix/CPP/7zip/Common/MemBlocks.cpp
new file mode 100644
index 000000000..67192b402
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/MemBlocks.cpp
@@ -0,0 +1,183 @@
+// MemBlocks.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "MemBlocks.h"
+#include "StreamUtils.h"
+
+bool CMemBlockManager::AllocateSpace(size_t numBlocks)
+{
+ FreeSpace();
+ if (_blockSize < sizeof(void *) || numBlocks < 1)
+ return false;
+ size_t totalSize = numBlocks * _blockSize;
+ if (totalSize / _blockSize != numBlocks)
+ return false;
+ _data = ::MidAlloc(totalSize);
+ if (_data == 0)
+ return false;
+ Byte *p = (Byte *)_data;
+ for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize)
+ *(Byte **)p = (p + _blockSize);
+ *(Byte **)p = 0;
+ _headFree = _data;
+ return true;
+}
+
+void CMemBlockManager::FreeSpace()
+{
+ ::MidFree(_data);
+ _data = 0;
+ _headFree= 0;
+}
+
+void *CMemBlockManager::AllocateBlock()
+{
+ if (_headFree == 0)
+ return 0;
+ void *p = _headFree;
+ _headFree = *(void **)_headFree;
+ return p;
+}
+
+void CMemBlockManager::FreeBlock(void *p)
+{
+ if (p == 0)
+ return;
+ *(void **)p = _headFree;
+ _headFree = p;
+}
+
+
+HRes CMemBlockManagerMt::AllocateSpace(NWindows::NSynchronization::CSynchro *sync,size_t numBlocks, size_t numNoLockBlocks)
+{
+ if (numNoLockBlocks > numBlocks)
+ return E_INVALIDARG;
+ if (!CMemBlockManager::AllocateSpace(numBlocks))
+ return E_OUTOFMEMORY;
+ size_t numLockBlocks = numBlocks - numNoLockBlocks;
+ Semaphore.Close();
+ return Semaphore.Create(sync,(LONG)numLockBlocks, (LONG)numLockBlocks);
+}
+
+HRes CMemBlockManagerMt::AllocateSpaceAlways(NWindows::NSynchronization::CSynchro *sync,size_t desiredNumberOfBlocks, size_t numNoLockBlocks)
+{
+ if (numNoLockBlocks > desiredNumberOfBlocks)
+ return E_INVALIDARG;
+ for (;;)
+ {
+ if (AllocateSpace(sync,desiredNumberOfBlocks, numNoLockBlocks) == 0)
+ return 0;
+ if (desiredNumberOfBlocks == numNoLockBlocks)
+ return E_OUTOFMEMORY;
+ desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1);
+ }
+}
+
+void CMemBlockManagerMt::FreeSpace()
+{
+ Semaphore.Close();
+ CMemBlockManager::FreeSpace();
+}
+
+void *CMemBlockManagerMt::AllocateBlock()
+{
+ // Semaphore.Lock();
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ return CMemBlockManager::AllocateBlock();
+}
+
+void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode)
+{
+ if (p == 0)
+ return;
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ CMemBlockManager::FreeBlock(p);
+ }
+ if (lockMode)
+ Semaphore.Release();
+}
+
+void CMemBlocks::Free(CMemBlockManagerMt *manager)
+{
+ while(Blocks.Size() > 0)
+ {
+ manager->FreeBlock(Blocks.Back());
+ Blocks.DeleteBack();
+ }
+ TotalSize = 0;
+}
+
+void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager)
+{
+ Free(manager);
+ Blocks.ClearAndFree();
+}
+
+HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const
+{
+ UInt64 totalSize = TotalSize;
+ for (int blockIndex = 0; totalSize > 0; blockIndex++)
+ {
+ UInt32 curSize = (UInt32)blockSize;
+ if (totalSize < curSize)
+ curSize = (UInt32)totalSize;
+ if (blockIndex >= Blocks.Size())
+ return E_FAIL;
+ RINOK(WriteStream(outStream, Blocks[blockIndex], curSize));
+ totalSize -= curSize;
+ }
+ return S_OK;
+}
+
+
+void CMemLockBlocks::FreeBlock(int index, CMemBlockManagerMt *memManager)
+{
+ memManager->FreeBlock(Blocks[index], LockMode);
+ Blocks[index] = 0;
+}
+
+void CMemLockBlocks::Free(CMemBlockManagerMt *memManager)
+{
+ while (Blocks.Size() > 0)
+ {
+ FreeBlock(Blocks.Size() - 1, memManager);
+ Blocks.DeleteBack();
+ }
+ TotalSize = 0;
+}
+
+HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager)
+{
+ if (LockMode)
+ {
+ if (Blocks.Size() > 0)
+ {
+ RINOK(memManager->ReleaseLockedBlocks(Blocks.Size()));
+ }
+ LockMode = false;
+ }
+ return 0;
+}
+
+void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager)
+{
+ blocks.Free(memManager);
+ blocks.LockMode = LockMode;
+ UInt64 totalSize = 0;
+ size_t blockSize = memManager->GetBlockSize();
+ for (int i = 0; i < Blocks.Size(); i++)
+ {
+ if (totalSize < TotalSize)
+ blocks.Blocks.Add(Blocks[i]);
+ else
+ FreeBlock(i, memManager);
+ Blocks[i] = 0;
+ totalSize += blockSize;
+ }
+ blocks.TotalSize = TotalSize;
+ Free(memManager);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/MemBlocks.h b/src/libs/7zip/unix/CPP/7zip/Common/MemBlocks.h
new file mode 100644
index 000000000..f23852fbd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/MemBlocks.h
@@ -0,0 +1,71 @@
+// MemBlocks.h
+
+#ifndef __MEM_BLOCKS_H
+#define __MEM_BLOCKS_H
+
+#include "Common/MyVector.h"
+
+#include "Windows/Synchronization.h"
+
+#include "../IStream.h"
+
+class CMemBlockManager
+{
+ void *_data;
+ size_t _blockSize;
+ void *_headFree;
+public:
+ CMemBlockManager(size_t blockSize = (1 << 20)): _data(0), _blockSize(blockSize), _headFree(0) {}
+ ~CMemBlockManager() { FreeSpace(); }
+
+ bool AllocateSpace(size_t numBlocks);
+ void FreeSpace();
+ size_t GetBlockSize() const { return _blockSize; }
+ void *AllocateBlock();
+ void FreeBlock(void *p);
+};
+
+
+class CMemBlockManagerMt: public CMemBlockManager
+{
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ NWindows::NSynchronization::CSemaphoreWFMO Semaphore;
+
+ CMemBlockManagerMt(size_t blockSize = (1 << 20)): CMemBlockManager(blockSize) {}
+ ~CMemBlockManagerMt() { FreeSpace(); }
+
+ HRes AllocateSpace(NWindows::NSynchronization::CSynchro *sync, size_t numBlocks, size_t numNoLockBlocks = 0);
+ HRes AllocateSpaceAlways(NWindows::NSynchronization::CSynchro *sync, size_t desiredNumberOfBlocks, size_t numNoLockBlocks = 0);
+ void FreeSpace();
+ void *AllocateBlock();
+ void FreeBlock(void *p, bool lockMode = true);
+ HRes ReleaseLockedBlocks(int number) { return Semaphore.Release(number); }
+};
+
+
+class CMemBlocks
+{
+ void Free(CMemBlockManagerMt *manager);
+public:
+ CRecordVector<void *> Blocks;
+ UInt64 TotalSize;
+
+ CMemBlocks(): TotalSize(0) {}
+
+ void FreeOpt(CMemBlockManagerMt *manager);
+ HRESULT WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const;
+};
+
+struct CMemLockBlocks: public CMemBlocks
+{
+ bool LockMode;
+
+ CMemLockBlocks(): LockMode(true) {};
+ void Free(CMemBlockManagerMt *memManager);
+ void FreeBlock(int index, CMemBlockManagerMt *memManager);
+ HRes SwitchToNoLockMode(CMemBlockManagerMt *memManager);
+ void Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/MethodId.cpp b/src/libs/7zip/unix/CPP/7zip/Common/MethodId.cpp
new file mode 100644
index 000000000..b797b6857
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/MethodId.cpp
@@ -0,0 +1,27 @@
+// MethodId.cpp
+
+#include "StdAfx.h"
+
+#include "MethodId.h"
+#include "../../Common/MyString.h"
+
+static inline wchar_t GetHex(Byte value)
+{
+ return (wchar_t)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+UString ConvertMethodIdToString(UInt64 id)
+{
+ wchar_t s[32];
+ int len = 32;
+ s[--len] = 0;
+ do
+ {
+ s[--len] = GetHex((Byte)id & 0xF);
+ id >>= 4;
+ s[--len] = GetHex((Byte)id & 0xF);
+ id >>= 4;
+ }
+ while (id != 0);
+ return s + len;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/MethodId.h b/src/libs/7zip/unix/CPP/7zip/Common/MethodId.h
new file mode 100644
index 000000000..54ebc9f7d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/MethodId.h
@@ -0,0 +1,10 @@
+// MethodId.h
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "../../Common/Types.h"
+
+typedef UInt64 CMethodId;
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/MethodProps.cpp b/src/libs/7zip/unix/CPP/7zip/Common/MethodProps.cpp
new file mode 100644
index 000000000..5836d0f84
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/MethodProps.cpp
@@ -0,0 +1,99 @@
+// MethodProps.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "MethodProps.h"
+
+static const UInt64 k_LZMA = 0x030101;
+static const UInt64 k_LZMA2 = 0x21;
+
+HRESULT SetMethodProperties(const CMethod &method, const UInt64 *inSizeForReduce, IUnknown *coder)
+{
+ bool tryReduce = false;
+ UInt32 reducedDictionarySize = 1 << 10;
+ if (inSizeForReduce != 0 && (method.Id == k_LZMA || method.Id == k_LZMA2))
+ {
+ for (;;)
+ {
+ const UInt32 step = (reducedDictionarySize >> 1);
+ if (reducedDictionarySize >= *inSizeForReduce)
+ {
+ tryReduce = true;
+ break;
+ }
+ reducedDictionarySize += step;
+ if (reducedDictionarySize >= *inSizeForReduce)
+ {
+ tryReduce = true;
+ break;
+ }
+ if (reducedDictionarySize >= ((UInt32)3 << 30))
+ break;
+ reducedDictionarySize += step;
+ }
+ }
+
+ {
+ int numProps = method.Props.Size();
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
+ if (setCoderProperties == NULL)
+ {
+ if (numProps != 0)
+ return E_INVALIDARG;
+ }
+ else
+ {
+ CRecordVector<PROPID> propIDs;
+ NWindows::NCOM::CPropVariant *values = new NWindows::NCOM::CPropVariant[numProps];
+ HRESULT res = S_OK;
+ try
+ {
+ for (int i = 0; i < numProps; i++)
+ {
+ const CProp &prop = method.Props[i];
+ propIDs.Add(prop.Id);
+ NWindows::NCOM::CPropVariant &value = values[i];
+ value = prop.Value;
+ // if (tryReduce && prop.Id == NCoderPropID::kDictionarySize && value.vt == VT_UI4 && reducedDictionarySize < value.ulVal)
+ if (tryReduce)
+ if (prop.Id == NCoderPropID::kDictionarySize)
+ if (value.vt == VT_UI4)
+ if (reducedDictionarySize < value.ulVal)
+ value.ulVal = reducedDictionarySize;
+ }
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
+ res = setCoderProperties->SetCoderProperties(&propIDs.Front(), values, numProps);
+ }
+ catch(...)
+ {
+ delete []values;
+ throw;
+ }
+ delete []values;
+ RINOK(res);
+ }
+ }
+
+ /*
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+ coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+ if (writeCoderProperties != NULL)
+ {
+ CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init();
+ RINOK(writeCoderProperties->WriteCoderProperties(outStream));
+ size_t size = outStreamSpec->GetSize();
+ filterProps.SetCapacity(size);
+ memmove(filterProps, outStreamSpec->GetBuffer(), size);
+ }
+ */
+ return S_OK;
+}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/MethodProps.h b/src/libs/7zip/unix/CPP/7zip/Common/MethodProps.h
new file mode 100644
index 000000000..8127e21ee
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/MethodProps.h
@@ -0,0 +1,41 @@
+// MethodProps.h
+
+#ifndef __7Z_METHOD_PROPS_H
+#define __7Z_METHOD_PROPS_H
+
+#include "../../Common/MyVector.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "MethodId.h"
+
+struct CProp
+{
+ PROPID Id;
+ NWindows::NCOM::CPropVariant Value;
+};
+
+struct CMethod
+{
+ CMethodId Id;
+ CObjectVector<CProp> Props;
+};
+
+struct CMethodsMode
+{
+ CObjectVector<CMethod> Methods;
+ #ifndef _7ZIP_ST
+ UInt32 NumThreads;
+ #endif
+
+ CMethodsMode()
+ #ifndef _7ZIP_ST
+ : NumThreads(1)
+ #endif
+ {}
+ bool IsEmpty() const { return Methods.IsEmpty() ; }
+};
+
+HRESULT SetMethodProperties(const CMethod &method, const UInt64 *inSizeForReduce, IUnknown *coder);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/OffsetStream.cpp b/src/libs/7zip/unix/CPP/7zip/Common/OffsetStream.cpp
new file mode 100644
index 000000000..c5e4e6da4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/OffsetStream.cpp
@@ -0,0 +1,35 @@
+// OffsetStream.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Defs.h"
+#include "OffsetStream.h"
+
+HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset)
+{
+ _offset = offset;
+ _stream = stream;
+ return _stream->Seek(offset, STREAM_SEEK_SET, NULL);
+}
+
+STDMETHODIMP COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ return _stream->Write(data, size, processedSize);
+}
+
+STDMETHODIMP COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin,
+ UInt64 *newPosition)
+{
+ UInt64 absoluteNewPosition;
+ if (seekOrigin == STREAM_SEEK_SET)
+ offset += _offset;
+ HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition);
+ if (newPosition != NULL)
+ *newPosition = absoluteNewPosition - _offset;
+ return result;
+}
+
+STDMETHODIMP COffsetOutStream::SetSize(UInt64 newSize)
+{
+ return _stream->SetSize(_offset + newSize);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/OffsetStream.h b/src/libs/7zip/unix/CPP/7zip/Common/OffsetStream.h
new file mode 100644
index 000000000..de9d06dd0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/OffsetStream.h
@@ -0,0 +1,25 @@
+// OffsetStream.h
+
+#ifndef __OFFSETSTREAM_H
+#define __OFFSETSTREAM_H
+
+#include "Common/MyCom.h"
+#include "../IStream.h"
+
+class COffsetOutStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ UInt64 _offset;
+ CMyComPtr<IOutStream> _stream;
+public:
+ HRESULT Init(IOutStream *stream, UInt64 offset);
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.cpp b/src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.cpp
new file mode 100644
index 000000000..2e5debd83
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.cpp
@@ -0,0 +1,116 @@
+// OutBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "OutBuffer.h"
+
+bool COutBuffer::Create(UInt32 bufferSize)
+{
+ const UInt32 kMinBlockSize = 1;
+ if (bufferSize < kMinBlockSize)
+ bufferSize = kMinBlockSize;
+ if (_buffer != 0 && _bufferSize == bufferSize)
+ return true;
+ Free();
+ _bufferSize = bufferSize;
+ _buffer = (Byte *)::MidAlloc(bufferSize);
+ return (_buffer != 0);
+}
+
+void COutBuffer::Free()
+{
+ ::MidFree(_buffer);
+ _buffer = 0;
+}
+
+void COutBuffer::SetStream(ISequentialOutStream *stream)
+{
+ _stream = stream;
+}
+
+void COutBuffer::Init()
+{
+ _streamPos = 0;
+ _limitPos = _bufferSize;
+ _pos = 0;
+ _processedSize = 0;
+ _overDict = false;
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
+
+UInt64 COutBuffer::GetProcessedSize() const
+{
+ UInt64 res = _processedSize + _pos - _streamPos;
+ if (_streamPos > _pos)
+ res += _bufferSize;
+ return res;
+}
+
+
+HRESULT COutBuffer::FlushPart()
+{
+ // _streamPos < _bufferSize
+ UInt32 size = (_streamPos >= _pos) ? (_bufferSize - _streamPos) : (_pos - _streamPos);
+ HRESULT result = S_OK;
+ #ifdef _NO_EXCEPTIONS
+ result = ErrorCode;
+ #endif
+ if (_buffer2 != 0)
+ {
+ memmove(_buffer2, _buffer + _streamPos, size);
+ _buffer2 += size;
+ }
+
+ if (_stream != 0
+ #ifdef _NO_EXCEPTIONS
+ && (ErrorCode == S_OK)
+ #endif
+ )
+ {
+ UInt32 processedSize = 0;
+ result = _stream->Write(_buffer + _streamPos, size, &processedSize);
+ size = processedSize;
+ }
+ _streamPos += size;
+ if (_streamPos == _bufferSize)
+ _streamPos = 0;
+ if (_pos == _bufferSize)
+ {
+ _overDict = true;
+ _pos = 0;
+ }
+ _limitPos = (_streamPos > _pos) ? _streamPos : _bufferSize;
+ _processedSize += size;
+ return result;
+}
+
+HRESULT COutBuffer::Flush()
+{
+ #ifdef _NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ return ErrorCode;
+ #endif
+
+ while(_streamPos != _pos)
+ {
+ HRESULT result = FlushPart();
+ if (result != S_OK)
+ return result;
+ }
+ return S_OK;
+}
+
+void COutBuffer::FlushWithCheck()
+{
+ HRESULT result = Flush();
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = result;
+ #else
+ if (result != S_OK)
+ throw COutBufferException(result);
+ #endif
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.h b/src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.h
new file mode 100644
index 000000000..62e77caae
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/OutBuffer.h
@@ -0,0 +1,64 @@
+// OutBuffer.h
+
+#ifndef __OUTBUFFER_H
+#define __OUTBUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+
+#ifndef _NO_EXCEPTIONS
+struct COutBufferException: public CSystemException
+{
+ COutBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+#endif
+
+class COutBuffer
+{
+protected:
+ Byte *_buffer;
+ UInt32 _pos;
+ UInt32 _limitPos;
+ UInt32 _streamPos;
+ UInt32 _bufferSize;
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _processedSize;
+ Byte *_buffer2;
+ bool _overDict;
+
+ HRESULT FlushPart();
+public:
+ #ifdef _NO_EXCEPTIONS
+ HRESULT ErrorCode;
+ #endif
+
+ COutBuffer(): _buffer(0), _pos(0), _stream(0), _buffer2(0) {}
+ ~COutBuffer() { Free(); }
+
+ bool Create(UInt32 bufferSize);
+ void Free();
+
+ void SetMemStream(Byte *buffer) { _buffer2 = buffer; }
+ void SetStream(ISequentialOutStream *stream);
+ void Init();
+ HRESULT Flush();
+ void FlushWithCheck();
+ void ReleaseStream() { _stream.Release(); }
+
+ void WriteByte(Byte b)
+ {
+ _buffer[_pos++] = b;
+ if(_pos == _limitPos)
+ FlushWithCheck();
+ }
+ void WriteBytes(const void *data, size_t size)
+ {
+ for (size_t i = 0; i < size; i++)
+ WriteByte(((const Byte *)data)[i]);
+ }
+
+ UInt64 GetProcessedSize() const;
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/OutMemStream.cpp b/src/libs/7zip/unix/CPP/7zip/Common/OutMemStream.cpp
new file mode 100644
index 000000000..2e92886b8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/OutMemStream.cpp
@@ -0,0 +1,142 @@
+// OutMemStream.cpp
+
+#include "StdAfx.h"
+
+#include "OutMemStream.h"
+
+void COutMemStream::Free()
+{
+ Blocks.Free(_memManager);
+ Blocks.LockMode = true;
+}
+
+void COutMemStream::Init()
+{
+ WriteToRealStreamEvent.Reset();
+ _unlockEventWasSent = false;
+ _realStreamMode = false;
+ Free();
+ _curBlockPos = 0;
+ _curBlockIndex = 0;
+}
+
+void COutMemStream::DetachData(CMemLockBlocks &blocks)
+{
+ Blocks.Detach(blocks, _memManager);
+ Free();
+}
+
+
+HRESULT COutMemStream::WriteToRealStream()
+{
+ RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream));
+ Blocks.Free(_memManager);
+ return S_OK;
+}
+
+STDMETHODIMP COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (_realStreamMode)
+ return OutSeqStream->Write(data, size, processedSize);
+ if (processedSize != 0)
+ *processedSize = 0;
+ while(size != 0)
+ {
+ if ((int)_curBlockIndex < Blocks.Blocks.Size())
+ {
+ Byte *p = (Byte *)Blocks.Blocks[(int)_curBlockIndex] + _curBlockPos;
+ size_t curSize = _memManager->GetBlockSize() - _curBlockPos;
+ if (size < curSize)
+ curSize = size;
+ memmove(p, data, curSize);
+ if (processedSize != 0)
+ *processedSize += (UInt32)curSize;
+ data = (const void *)((const Byte *)data + curSize);
+ size -= (UInt32)curSize;
+ _curBlockPos += curSize;
+
+ UInt64 pos64 = GetPos();
+ if (pos64 > Blocks.TotalSize)
+ Blocks.TotalSize = pos64;
+ if (_curBlockPos == _memManager->GetBlockSize())
+ {
+ _curBlockIndex++;
+ _curBlockPos = 0;
+ }
+ continue;
+ }
+ HANDLE events[3] = { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore };
+ DWORD waitResult = ::WaitForMultipleObjects((Blocks.LockMode ? 3 : 2), events, FALSE, INFINITE);
+ switch (waitResult)
+ {
+ case (WAIT_OBJECT_0 + 0):
+ return StopWriteResult;
+ case (WAIT_OBJECT_0 + 1):
+ {
+ _realStreamMode = true;
+ RINOK(WriteToRealStream());
+ UInt32 processedSize2;
+ HRESULT res = OutSeqStream->Write(data, size, &processedSize2);
+ if (processedSize != 0)
+ *processedSize += processedSize2;
+ return res;
+ }
+ /*
+ case (WAIT_OBJECT_0 + 2):
+ {
+ // it has bug: no write.
+ if (!Blocks.SwitchToNoLockMode(_memManager))
+ return E_FAIL;
+ break;
+ }
+ */
+ case (WAIT_OBJECT_0 + 2):
+ break;
+ default:
+ return E_FAIL;
+ }
+ Blocks.Blocks.Add(_memManager->AllocateBlock());
+ if (Blocks.Blocks.Back() == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if (_realStreamMode)
+ {
+ if (!OutStream)
+ return E_FAIL;
+ return OutStream->Seek(offset, seekOrigin, newPosition);
+ }
+ if (seekOrigin == STREAM_SEEK_CUR)
+ {
+ if (offset != 0)
+ return E_NOTIMPL;
+ }
+ else if (seekOrigin == STREAM_SEEK_SET)
+ {
+ if (offset != 0)
+ return E_NOTIMPL;
+ _curBlockIndex = 0;
+ _curBlockPos = 0;
+ }
+ else
+ return E_NOTIMPL;
+ if (newPosition != 0)
+ *newPosition = GetPos();
+ return S_OK;
+}
+
+STDMETHODIMP COutMemStream::SetSize(UInt64 newSize)
+{
+ if (_realStreamMode)
+ {
+ if (!OutStream)
+ return E_FAIL;
+ return OutStream->SetSize(newSize);
+ }
+ Blocks.TotalSize = newSize;
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/OutMemStream.h b/src/libs/7zip/unix/CPP/7zip/Common/OutMemStream.h
new file mode 100644
index 000000000..b512f7dc9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/OutMemStream.h
@@ -0,0 +1,96 @@
+// OutMemStream.h
+
+#ifndef __OUTMEMSTREAM_H
+#define __OUTMEMSTREAM_H
+
+#include "Common/MyCom.h"
+#include "MemBlocks.h"
+
+class COutMemStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ CMemBlockManagerMt *_memManager;
+ size_t _curBlockIndex;
+ size_t _curBlockPos;
+ bool _realStreamMode;
+
+ bool _unlockEventWasSent;
+ NWindows::NSynchronization::CAutoResetEventWFMO StopWritingEvent;
+ NWindows::NSynchronization::CAutoResetEventWFMO WriteToRealStreamEvent;
+ // NWindows::NSynchronization::CAutoResetEvent NoLockEvent;
+
+ HRESULT StopWriteResult;
+ CMemLockBlocks Blocks;
+
+ UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; }
+
+ CMyComPtr<ISequentialOutStream> OutSeqStream;
+ CMyComPtr<IOutStream> OutStream;
+
+public:
+
+ HRes CreateEvents(NWindows::NSynchronization::CSynchro *sync)
+ {
+ RINOK(StopWritingEvent.CreateIfNotCreated(sync));
+ return WriteToRealStreamEvent.CreateIfNotCreated(sync);
+ }
+
+ void SetOutStream(IOutStream *outStream)
+ {
+ OutStream = outStream;
+ OutSeqStream = outStream;
+ }
+
+ void SetSeqOutStream(ISequentialOutStream *outStream)
+ {
+ OutStream = NULL;
+ OutSeqStream = outStream;
+ }
+
+ void ReleaseOutStream()
+ {
+ OutStream.Release();
+ OutSeqStream.Release();
+ }
+
+ COutMemStream(CMemBlockManagerMt *memManager): _memManager(memManager) { }
+
+ ~COutMemStream() { Free(); }
+ void Free();
+
+ void Init();
+ HRESULT WriteToRealStream();
+
+ void DetachData(CMemLockBlocks &blocks);
+
+ bool WasUnlockEventSent() const { return _unlockEventWasSent; }
+
+ void SetRealStreamMode()
+ {
+ _unlockEventWasSent = true;
+ WriteToRealStreamEvent.Set();
+ }
+
+ /*
+ void SetNoLockMode()
+ {
+ _unlockEventWasSent = true;
+ NoLockEvent.Set();
+ }
+ */
+
+ void StopWriting(HRESULT res)
+ {
+ StopWriteResult = res;
+ StopWritingEvent.Set();
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/ProgressMt.cpp b/src/libs/7zip/unix/CPP/7zip/Common/ProgressMt.cpp
new file mode 100644
index 000000000..319bd241b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/ProgressMt.cpp
@@ -0,0 +1,53 @@
+// ProgressMt.h
+
+#include "StdAfx.h"
+
+#include "ProgressMt.h"
+
+void CMtCompressProgressMixer::Init(int numItems, ICompressProgressInfo *progress)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ InSizes.Clear();
+ OutSizes.Clear();
+ for (int i = 0; i < numItems; i++)
+ {
+ InSizes.Add(0);
+ OutSizes.Add(0);
+ }
+ TotalInSize = 0;
+ TotalOutSize = 0;
+ _progress = progress;
+}
+
+void CMtCompressProgressMixer::Reinit(int index)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ InSizes[index] = 0;
+ OutSizes[index] = 0;
+}
+
+HRESULT CMtCompressProgressMixer::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ if (inSize != 0)
+ {
+ UInt64 diff = *inSize - InSizes[index];
+ InSizes[index] = *inSize;
+ TotalInSize += diff;
+ }
+ if (outSize != 0)
+ {
+ UInt64 diff = *outSize - OutSizes[index];
+ OutSizes[index] = *outSize;
+ TotalOutSize += diff;
+ }
+ if (_progress)
+ return _progress->SetRatioInfo(&TotalInSize, &TotalOutSize);
+ return S_OK;
+}
+
+
+STDMETHODIMP CMtCompressProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ return _progress->SetRatioInfo(_index, inSize, outSize);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/ProgressMt.h b/src/libs/7zip/unix/CPP/7zip/Common/ProgressMt.h
new file mode 100644
index 000000000..26079d4e9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/ProgressMt.h
@@ -0,0 +1,46 @@
+// ProgressMt.h
+
+#ifndef __PROGRESSMT_H
+#define __PROGRESSMT_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyVector.h"
+#include "../../Windows/Synchronization.h"
+
+#include "../ICoder.h"
+#include "../IProgress.h"
+
+class CMtCompressProgressMixer
+{
+ CMyComPtr<ICompressProgressInfo> _progress;
+ CRecordVector<UInt64> InSizes;
+ CRecordVector<UInt64> OutSizes;
+ UInt64 TotalInSize;
+ UInt64 TotalOutSize;
+public:
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ void Init(int numItems, ICompressProgressInfo *progress);
+ void Reinit(int index);
+ HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize);
+};
+
+class CMtCompressProgress:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ CMtCompressProgressMixer *_progress;
+ int _index;
+public:
+ void Init(CMtCompressProgressMixer *progress, int index)
+ {
+ _progress = progress;
+ _index = index;
+ }
+ void Reinit() { _progress->Reinit(_index); }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.cpp b/src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.cpp
new file mode 100644
index 000000000..f24ff6b6f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.cpp
@@ -0,0 +1,42 @@
+// ProgressUtils.h
+
+#include "StdAfx.h"
+
+#include "ProgressUtils.h"
+
+CLocalProgress::CLocalProgress()
+{
+ ProgressOffset = InSize = OutSize = 0;
+ SendRatio = SendProgress = true;
+}
+
+void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain)
+{
+ _ratioProgress.Release();
+ _progress = progress;
+ _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress);
+ _inSizeIsMain = inSizeIsMain;
+}
+
+STDMETHODIMP CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ UInt64 inSizeNew = InSize, outSizeNew = OutSize;
+ if (inSize)
+ inSizeNew += (*inSize);
+ if (outSize)
+ outSizeNew += (*outSize);
+ if (SendRatio && _ratioProgress)
+ {
+ RINOK(_ratioProgress->SetRatioInfo(&inSizeNew, &outSizeNew));
+ }
+ inSizeNew += ProgressOffset;
+ outSizeNew += ProgressOffset;
+ if (SendProgress)
+ return _progress->SetCompleted(_inSizeIsMain ? &inSizeNew : &outSizeNew);
+ return S_OK;
+}
+
+HRESULT CLocalProgress::SetCur()
+{
+ return SetRatioInfo(NULL, NULL);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.h b/src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.h
new file mode 100644
index 000000000..bae5395c1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/ProgressUtils.h
@@ -0,0 +1,34 @@
+// ProgressUtils.h
+
+#ifndef __PROGRESSUTILS_H
+#define __PROGRESSUTILS_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IProgress.h"
+
+class CLocalProgress:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ CMyComPtr<IProgress> _progress;
+ CMyComPtr<ICompressProgressInfo> _ratioProgress;
+ bool _inSizeIsMain;
+public:
+ UInt64 ProgressOffset;
+ UInt64 InSize;
+ UInt64 OutSize;
+ bool SendRatio;
+ bool SendProgress;
+
+ CLocalProgress();
+ void Init(IProgress *progress, bool inSizeIsMain);
+ HRESULT SetCur();
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h b/src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h
new file mode 100644
index 000000000..305aac1fd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/RegisterArc.h
@@ -0,0 +1,32 @@
+// RegisterArc.h
+
+#ifndef __REGISTER_ARC_H
+#define __REGISTER_ARC_H
+
+#include "../Archive/IArchive.h"
+
+typedef IInArchive * (*CreateInArchiveP)();
+typedef IOutArchive * (*CreateOutArchiveP)();
+
+struct CArcInfo
+{
+ const wchar_t *Name;
+ const wchar_t *Ext;
+ const wchar_t *AddExt;
+ Byte ClassId;
+ Byte Signature[28]; // FIXME Byte Signature[16]; adding 22 bytes to insure kSignature[0x1A]!= 0 and kSignature[0x1B] != 0
+ int SignatureSize;
+ bool KeepName;
+ CreateInArchiveP CreateInArchive;
+ CreateOutArchiveP CreateOutArchive;
+};
+
+void RegisterArc(const CArcInfo *arcInfo);
+
+#define REGISTER_ARC_NAME(x) CRegister ## x
+
+#define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \
+ REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \
+ static REGISTER_ARC_NAME(x) g_RegisterArc; \
+ void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; }
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h b/src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h
new file mode 100644
index 000000000..d53c4344a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/RegisterCodec.h
@@ -0,0 +1,34 @@
+// RegisterCodec.h
+
+#ifndef __REGISTERCODEC_H
+#define __REGISTERCODEC_H
+
+#include "../Common/MethodId.h"
+
+typedef void * (*CreateCodecP)();
+struct CCodecInfo
+{
+ CreateCodecP CreateDecoder;
+ CreateCodecP CreateEncoder;
+ CMethodId Id;
+ const wchar_t *Name;
+ UInt32 NumInStreams;
+ bool IsFilter;
+};
+
+void RegisterCodec(const CCodecInfo *codecInfo);
+
+#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x
+
+#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \
+ REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \
+ static REGISTER_CODEC_NAME(x) g_RegisterCodec; \
+ void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; }
+
+#define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x
+#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \
+ REGISTER_CODECS_NAME(x)() { for (int i = 0; i < sizeof(g_CodecsInfo) / sizeof(g_CodecsInfo[0]); i++) \
+ RegisterCodec(&g_CodecsInfo[i]); }}; \
+ static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \
+ void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; }
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.cpp b/src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.cpp
new file mode 100644
index 000000000..9dfa3fb75
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.cpp
@@ -0,0 +1,152 @@
+// StreamBinder.cpp
+
+#include "StdAfx.h"
+
+#include "StreamBinder.h"
+#include "../../Common/Defs.h"
+#include "../../Common/MyCom.h"
+
+using namespace NWindows;
+using namespace NSynchronization;
+
+class CSequentialInStreamForBinder:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+private:
+ CStreamBinder *m_StreamBinder;
+public:
+ ~CSequentialInStreamForBinder() { m_StreamBinder->CloseRead(); }
+ void SetBinder(CStreamBinder *streamBinder) { m_StreamBinder = streamBinder; }
+};
+
+STDMETHODIMP CSequentialInStreamForBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
+ { return m_StreamBinder->Read(data, size, processedSize); }
+
+class CSequentialOutStreamForBinder:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+
+private:
+ CStreamBinder *m_StreamBinder;
+public:
+ ~CSequentialOutStreamForBinder() { m_StreamBinder->CloseWrite(); }
+ void SetBinder(CStreamBinder *streamBinder) { m_StreamBinder = streamBinder; }
+};
+
+STDMETHODIMP CSequentialOutStreamForBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+ { return m_StreamBinder->Write(data, size, processedSize); }
+
+
+//////////////////////////
+// CStreamBinder
+// (_thereAreBytesToReadEvent && _bufferSize == 0) means that stream is finished.
+
+HRes CStreamBinder::CreateEvents()
+{
+ _synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent = new NWindows::NSynchronization::CSynchro();
+ _synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent->Create();
+ RINOK(_allBytesAreWritenEvent.Create(_synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent,true));
+ RINOK(_thereAreBytesToReadEvent.Create());
+ return _readStreamIsClosedEvent.Create(_synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent);
+}
+
+void CStreamBinder::ReInit()
+{
+ _thereAreBytesToReadEvent.Reset();
+ _readStreamIsClosedEvent.Reset();
+ ProcessedSize = 0;
+}
+
+
+
+void CStreamBinder::CreateStreams(ISequentialInStream **inStream,
+ ISequentialOutStream **outStream)
+{
+ CSequentialInStreamForBinder *inStreamSpec = new
+ CSequentialInStreamForBinder;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ inStreamSpec->SetBinder(this);
+ *inStream = inStreamLoc.Detach();
+
+ CSequentialOutStreamForBinder *outStreamSpec = new
+ CSequentialOutStreamForBinder;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(outStreamSpec);
+ outStreamSpec->SetBinder(this);
+ *outStream = outStreamLoc.Detach();
+
+ _buffer = NULL;
+ _bufferSize= 0;
+ ProcessedSize = 0;
+}
+
+HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 sizeToRead = size;
+ if (size > 0)
+ {
+ RINOK(_thereAreBytesToReadEvent.Lock());
+ sizeToRead = MyMin(_bufferSize, size);
+ if (_bufferSize > 0)
+ {
+ memcpy(data, _buffer, sizeToRead);
+ _buffer = ((const Byte *)_buffer) + sizeToRead;
+ _bufferSize -= sizeToRead;
+ if (_bufferSize == 0)
+ {
+ _thereAreBytesToReadEvent.Reset();
+ _allBytesAreWritenEvent.Set();
+ }
+ }
+ }
+ if (processedSize != NULL)
+ *processedSize = sizeToRead;
+ ProcessedSize += sizeToRead;
+ return S_OK;
+}
+
+void CStreamBinder::CloseRead()
+{
+ _readStreamIsClosedEvent.Set();
+}
+
+HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (size > 0)
+ {
+ _buffer = data;
+ _bufferSize = size;
+ _allBytesAreWritenEvent.Reset();
+ _thereAreBytesToReadEvent.Set();
+
+ HANDLE events[2];
+ events[0] = _allBytesAreWritenEvent;
+ events[1] = _readStreamIsClosedEvent;
+ DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
+ if (waitResult != WAIT_OBJECT_0 + 0)
+ {
+ // ReadingWasClosed = true;
+ return S_FALSE;
+ }
+ // if(!_allBytesAreWritenEvent.Lock())
+ // return E_FAIL;
+ }
+ if (processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+void CStreamBinder::CloseWrite()
+{
+ // _bufferSize must be = 0
+ _thereAreBytesToReadEvent.Set();
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.h b/src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.h
new file mode 100644
index 000000000..47743dee2
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/StreamBinder.h
@@ -0,0 +1,38 @@
+// StreamBinder.h
+
+#ifndef __STREAMBINDER_H
+#define __STREAMBINDER_H
+
+#include "../IStream.h"
+#include "../../Windows/Synchronization.h"
+
+class CStreamBinder
+{
+ NWindows::NSynchronization::CManualResetEventWFMO _allBytesAreWritenEvent;
+ NWindows::NSynchronization::CManualResetEvent _thereAreBytesToReadEvent;
+ NWindows::NSynchronization::CManualResetEventWFMO _readStreamIsClosedEvent;
+ NWindows::NSynchronization::CSynchro * _synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent;
+ UInt32 _bufferSize;
+ const void *_buffer;
+public:
+ // bool ReadingWasClosed;
+ UInt64 ProcessedSize;
+ CStreamBinder() { _synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent = 0; }
+ ~CStreamBinder() {
+ if (_synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent)
+ delete _synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent;
+ _synchroFor_allBytesAreWritenEvent_and_readStreamIsClosedEvent = 0;
+ }
+ HRes CreateEvents();
+
+ void CreateStreams(ISequentialInStream **inStream,
+ ISequentialOutStream **outStream);
+ HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
+ void CloseRead();
+
+ HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize);
+ void CloseWrite();
+ void ReInit();
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.cpp b/src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.cpp
new file mode 100644
index 000000000..24253a9ed
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.cpp
@@ -0,0 +1,221 @@
+// StreamObjects.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "StreamObjects.h"
+
+STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos > _size)
+ return E_FAIL;
+ size_t rem = _size - (size_t)_pos;
+ if (rem > size)
+ rem = (size_t)size;
+ memcpy(data, _data + (size_t)_pos, rem);
+ _pos += rem;
+ if (processedSize)
+ *processedSize = (UInt32)rem;
+ return S_OK;
+}
+
+STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _pos = offset; break;
+ case STREAM_SEEK_CUR: _pos += offset; break;
+ case STREAM_SEEK_END: _pos = _size + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _pos;
+ return S_OK;
+}
+
+void CByteDynBuffer::Free()
+{
+ free(_buf);
+ _buf = 0;
+ _capacity = 0;
+}
+
+bool CByteDynBuffer::EnsureCapacity(size_t cap)
+{
+ if (cap <= _capacity)
+ return true;
+ size_t delta;
+ if (_capacity > 64)
+ delta = _capacity / 4;
+ else if (_capacity > 8)
+ delta = 16;
+ else
+ delta = 4;
+ cap = MyMax(_capacity + delta, cap);
+ Byte *buf = (Byte *)realloc(_buf, cap);
+ if (!buf)
+ return false;
+ _buf = buf;
+ _capacity = cap;
+ return true;
+}
+
+Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
+{
+ addSize += _size;
+ if (addSize < _size)
+ return NULL;
+ if (!_buffer.EnsureCapacity(addSize))
+ return NULL;
+ return (Byte *)_buffer + _size;
+}
+
+void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
+{
+ dest.SetCapacity(_size);
+ memcpy((Byte *)dest, (const Byte *)_buffer, _size);
+}
+
+STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ Byte *buf = GetBufPtrForWriting(size);
+ if (!buf)
+ return E_OUTOFMEMORY;
+ memcpy(buf, data, size);
+ UpdateSize(size);
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t rem = _size - _pos;
+ if (rem > size)
+ rem = (size_t)size;
+ memcpy(_buffer + _pos, data, rem);
+ _pos += rem;
+ if (processedSize)
+ *processedSize = (UInt32)rem;
+ return (rem != 0 || size == 0) ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Write(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
+
+void CCachedInStream::Free()
+{
+ MyFree(_tags);
+ _tags = 0;
+ MidFree(_data);
+ _data = 0;
+}
+
+bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog)
+{
+ unsigned sizeLog = blockSizeLog + numBlocksLog;
+ if (sizeLog >= sizeof(size_t) * 8)
+ return false;
+ size_t dataSize = (size_t)1 << sizeLog;
+ if (_data == 0 || dataSize != _dataSize)
+ {
+ MidFree(_data);
+ _data = (Byte *)MidAlloc(dataSize);
+ if (_data == 0)
+ return false;
+ _dataSize = dataSize;
+ }
+ if (_tags == 0 || numBlocksLog != _numBlocksLog)
+ {
+ MyFree(_tags);
+ _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
+ if (_tags == 0)
+ return false;
+ _numBlocksLog = numBlocksLog;
+ }
+ _blockSizeLog = blockSizeLog;
+ return true;
+}
+
+void CCachedInStream::Init(UInt64 size)
+{
+ _size = size;
+ _pos = 0;
+ size_t numBlocks = (size_t)1 << _numBlocksLog;
+ for (size_t i = 0; i < numBlocks; i++)
+ _tags[i] = kEmptyTag;
+}
+
+STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos > _size)
+ return E_FAIL;
+
+ {
+ UInt64 rem = _size - _pos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ while (size != 0)
+ {
+ UInt64 cacheTag = _pos >> _blockSizeLog;
+ size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
+ Byte *p = _data + (cacheIndex << _blockSizeLog);
+ if (_tags[cacheIndex] != cacheTag)
+ {
+ UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
+ size_t blockSize = (size_t)1 << _blockSizeLog;
+ if (blockSize > remInBlock)
+ blockSize = (size_t)remInBlock;
+ RINOK(ReadBlock(cacheTag, p, blockSize));
+ _tags[cacheIndex] = cacheTag;
+ }
+ size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1);
+ UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size);
+ memcpy(data, p + offset, cur);
+ if (processedSize)
+ *processedSize += cur;
+ data = (void *)((const Byte *)data + cur);
+ _pos += cur;
+ size -= cur;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _pos = offset; break;
+ case STREAM_SEEK_CUR: _pos = _pos + offset; break;
+ case STREAM_SEEK_END: _pos = _size + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition != 0)
+ *newPosition = _pos;
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.h b/src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.h
new file mode 100644
index 000000000..8cd95c700
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/StreamObjects.h
@@ -0,0 +1,135 @@
+// StreamObjects.h
+
+#ifndef __STREAM_OBJECTS_H
+#define __STREAM_OBJECTS_H
+
+#include "../../Common/Buffer.h"
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+struct CReferenceBuf:
+ public IUnknown,
+ public CMyUnknownImp
+{
+ CByteBuffer Buf;
+ MY_UNKNOWN_IMP
+};
+
+class CBufInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ const Byte *_data;
+ UInt64 _pos;
+ size_t _size;
+ CMyComPtr<IUnknown> _ref;
+public:
+ void Init(const Byte *data, size_t size, IUnknown *ref = 0)
+ {
+ _data = data;
+ _size = size;
+ _pos = 0;
+ _ref = ref;
+ }
+ void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.GetCapacity(), ref); }
+
+ MY_UNKNOWN_IMP1(IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+class CByteDynBuffer
+{
+ size_t _capacity;
+ Byte *_buf;
+public:
+ CByteDynBuffer(): _capacity(0), _buf(0) {};
+ // there is no copy constructor. So don't copy this object.
+ ~CByteDynBuffer() { Free(); }
+ void Free();
+ size_t GetCapacity() const { return _capacity; }
+ operator Byte*() const { return _buf; };
+ operator const Byte*() const { return _buf; };
+ bool EnsureCapacity(size_t capacity);
+};
+
+class CDynBufSeqOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CByteDynBuffer _buffer;
+ size_t _size;
+public:
+ CDynBufSeqOutStream(): _size(0) {}
+ void Init() { _size = 0; }
+ size_t GetSize() const { return _size; }
+ const Byte *GetBuffer() const { return _buffer; }
+ void CopyToBuffer(CByteBuffer &dest) const;
+ Byte *GetBufPtrForWriting(size_t addSize);
+ void UpdateSize(size_t addSize) { _size += addSize; }
+
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CBufPtrSeqOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ Byte *_buffer;
+ size_t _size;
+ size_t _pos;
+public:
+ void Init(Byte *buffer, size_t size)
+ {
+ _buffer = buffer;
+ _pos = 0;
+ _size = size;
+ }
+ size_t GetPos() const { return _pos; }
+
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CSequentialOutStreamSizeCount:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void Init() { _size = 0; }
+ UInt64 GetSize() const { return _size; }
+
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CCachedInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 *_tags;
+ Byte *_data;
+ size_t _dataSize;
+ unsigned _blockSizeLog;
+ unsigned _numBlocksLog;
+ UInt64 _size;
+ UInt64 _pos;
+protected:
+ virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0;
+public:
+ CCachedInStream(): _tags(0), _data(0) {}
+ virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (release calls it) !!!
+ void Free();
+ bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog);
+ void Init(UInt64 size);
+
+ MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.cpp b/src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.cpp
new file mode 100644
index 000000000..049e4aa17
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.cpp
@@ -0,0 +1,56 @@
+// StreamUtils.cpp
+
+#include "StdAfx.h"
+
+#include "StreamUtils.h"
+
+static const UInt32 kBlockSize = ((UInt32)1 << 31);
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize)
+{
+ size_t size = *processedSize;
+ *processedSize = 0;
+ while (size != 0)
+ {
+ UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
+ UInt32 processedSizeLoc;
+ HRESULT res = stream->Read(data, curSize, &processedSizeLoc);
+ *processedSize += processedSizeLoc;
+ data = (void *)((Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ RINOK(res);
+ if (processedSizeLoc == 0)
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size)
+{
+ size_t processedSize = size;
+ RINOK(ReadStream(stream, data, &processedSize));
+ return (size == processedSize) ? S_OK : S_FALSE;
+}
+
+HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size)
+{
+ size_t processedSize = size;
+ RINOK(ReadStream(stream, data, &processedSize));
+ return (size == processedSize) ? S_OK : E_FAIL;
+}
+
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size)
+{
+ while (size != 0)
+ {
+ UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
+ UInt32 processedSizeLoc;
+ HRESULT res = stream->Write(data, curSize, &processedSizeLoc);
+ data = (const void *)((const Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ RINOK(res);
+ if (processedSizeLoc == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.h b/src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.h
new file mode 100644
index 000000000..f1cfd1848
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/StreamUtils.h
@@ -0,0 +1,13 @@
+// StreamUtils.h
+
+#ifndef __STREAMUTILS_H
+#define __STREAMUTILS_H
+
+#include "../IStream.h"
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size);
+HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size);
+HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size);
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/VirtThread.cpp b/src/libs/7zip/unix/CPP/7zip/Common/VirtThread.cpp
new file mode 100644
index 000000000..cf39bd023
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/VirtThread.cpp
@@ -0,0 +1,46 @@
+// VirtThread.cpp
+
+#include "StdAfx.h"
+
+#include "VirtThread.h"
+
+static THREAD_FUNC_DECL CoderThread(void *p)
+{
+ for (;;)
+ {
+ CVirtThread *t = (CVirtThread *)p;
+ t->StartEvent.Lock();
+ if (t->ExitEvent)
+ return 0;
+ t->Execute();
+ t->FinishedEvent.Set();
+ }
+}
+
+WRes CVirtThread::Create()
+{
+ RINOK(StartEvent.CreateIfNotCreated());
+ RINOK(FinishedEvent.CreateIfNotCreated());
+ StartEvent.Reset();
+ FinishedEvent.Reset();
+ ExitEvent = false;
+ if (Thread.IsCreated())
+ return S_OK;
+ return Thread.Create(CoderThread, this);
+}
+
+void CVirtThread::Start()
+{
+ ExitEvent = false;
+ StartEvent.Set();
+}
+
+CVirtThread::~CVirtThread()
+{
+ ExitEvent = true;
+ if (StartEvent.IsCreated())
+ StartEvent.Set();
+ if (Thread.IsCreated())
+ Thread.Wait();
+}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Common/VirtThread.h b/src/libs/7zip/unix/CPP/7zip/Common/VirtThread.h
new file mode 100644
index 000000000..f14a1f223
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Common/VirtThread.h
@@ -0,0 +1,23 @@
+// VirtThread.h
+
+#ifndef __VIRTTHREAD_H
+#define __VIRTTHREAD_H
+
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+
+struct CVirtThread
+{
+ NWindows::NSynchronization::CAutoResetEvent StartEvent;
+ NWindows::NSynchronization::CAutoResetEvent FinishedEvent;
+ NWindows::CThread Thread;
+ bool ExitEvent;
+
+ ~CVirtThread();
+ WRes Create();
+ void Start();
+ void WaitFinish() { FinishedEvent.Lock(); }
+ virtual void Execute() = 0;
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder1.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder1.cpp
new file mode 100644
index 000000000..2c354e1eb
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder1.cpp
@@ -0,0 +1,309 @@
+// ArjDecoder1.cpp
+
+#include "StdAfx.h"
+
+#include "ArjDecoder1.h"
+
+namespace NCompress{
+namespace NArj {
+namespace NDecoder1 {
+
+static const UInt32 kHistorySize = 26624;
+static const UInt32 kMatchMinLen = 3;
+static const UInt32 kMatchMaxLen = 256;
+
+// static const UInt32 kNC = 255 + kMatchMaxLen + 2 - kMatchMinLen;
+
+void CCoder::MakeTable(int nchar, Byte *bitlen, int tablebits,
+ UInt32 *table, int tablesize)
+{
+ UInt32 count[17], weight[17], start[18], *p;
+ UInt32 i, k, len, ch, jutbits, avail, nextcode, mask;
+
+ for (i = 1; i <= 16; i++)
+ count[i] = 0;
+ for (i = 0; (int)i < nchar; i++)
+ count[bitlen[i]]++;
+
+ start[1] = 0;
+ for (i = 1; i <= 16; i++)
+ start[i + 1] = start[i] + (count[i] << (16 - i));
+ if (start[17] != (UInt32) (1 << 16))
+ throw "Data error";
+
+ jutbits = 16 - tablebits;
+ for (i = 1; (int)i <= tablebits; i++)
+ {
+ start[i] >>= jutbits;
+ weight[i] = 1 << (tablebits - i);
+ }
+ while (i <= 16)
+ {
+ weight[i] = 1 << (16 - i);
+ i++;
+ }
+
+ i = start[tablebits + 1] >> jutbits;
+ if (i != (UInt32) (1 << 16))
+ {
+ k = 1 << tablebits;
+ while (i != k)
+ table[i++] = 0;
+ }
+
+ avail = nchar;
+ mask = 1 << (15 - tablebits);
+ for (ch = 0; (int)ch < nchar; ch++)
+ {
+ if ((len = bitlen[ch]) == 0)
+ continue;
+ k = start[len];
+ nextcode = k + weight[len];
+ if ((int)len <= tablebits)
+ {
+ if (nextcode > (UInt32)tablesize)
+ throw "Data error";
+ for (i = start[len]; i < nextcode; i++)
+ table[i] = ch;
+ }
+ else
+ {
+ p = &table[k >> jutbits];
+ i = len - tablebits;
+ while (i != 0)
+ {
+ if (*p == 0)
+ {
+ right[avail] = left[avail] = 0;
+ *p = avail++;
+ }
+ if (k & mask)
+ p = &right[*p];
+ else
+ p = &left[*p];
+ k <<= 1;
+ i--;
+ }
+ *p = ch;
+ }
+ start[len] = nextcode;
+ }
+}
+
+void CCoder::read_pt_len(int nn, int nbit, int i_special)
+{
+ UInt32 n = m_InBitStream.ReadBits(nbit);
+ if (n == 0)
+ {
+ UInt32 c = m_InBitStream.ReadBits(nbit);
+ int i;
+ for (i = 0; i < nn; i++)
+ pt_len[i] = 0;
+ for (i = 0; i < 256; i++)
+ pt_table[i] = c;
+ }
+ else
+ {
+ UInt32 i = 0;
+ while (i < n)
+ {
+ UInt32 bitBuf = m_InBitStream.GetValue(16);
+ int c = bitBuf >> 13;
+ if (c == 7)
+ {
+ UInt32 mask = 1 << (12);
+ while (mask & bitBuf)
+ {
+ mask >>= 1;
+ c++;
+ }
+ }
+ m_InBitStream.MovePos((c < 7) ? 3 : (int)(c - 3));
+ pt_len[i++] = (Byte)c;
+ if (i == (UInt32)i_special)
+ {
+ c = m_InBitStream.ReadBits(2);
+ while (--c >= 0)
+ pt_len[i++] = 0;
+ }
+ }
+ while (i < (UInt32)nn)
+ pt_len[i++] = 0;
+ MakeTable(nn, pt_len, 8, pt_table, PTABLESIZE);
+ }
+}
+
+void CCoder::read_c_len()
+{
+ int i, c, n;
+ UInt32 mask;
+
+ n = m_InBitStream.ReadBits(CBIT);
+ if (n == 0)
+ {
+ c = m_InBitStream.ReadBits(CBIT);
+ for (i = 0; i < NC; i++)
+ c_len[i] = 0;
+ for (i = 0; i < CTABLESIZE; i++)
+ c_table[i] = c;
+ }
+ else
+ {
+ i = 0;
+ while (i < n)
+ {
+ UInt32 bitBuf = m_InBitStream.GetValue(16);
+ c = pt_table[bitBuf >> (8)];
+ if (c >= NT)
+ {
+ mask = 1 << (7);
+ do
+ {
+ if (bitBuf & mask)
+ c = right[c];
+ else
+ c = left[c];
+ mask >>= 1;
+ } while (c >= NT);
+ }
+ m_InBitStream.MovePos((int)(pt_len[c]));
+ if (c <= 2)
+ {
+ if (c == 0)
+ c = 1;
+ else if (c == 1)
+ c = m_InBitStream.ReadBits(4) + 3;
+ else
+ c = m_InBitStream.ReadBits(CBIT) + 20;
+ while (--c >= 0)
+ c_len[i++] = 0;
+ }
+ else
+ c_len[i++] = (Byte)(c - 2);
+ }
+ while (i < NC)
+ c_len[i++] = 0;
+ MakeTable(NC, c_len, 12, c_table, CTABLESIZE);
+ }
+}
+
+UInt32 CCoder::decode_c()
+{
+ UInt32 j, mask;
+ UInt32 bitbuf = m_InBitStream.GetValue(16);
+ j = c_table[bitbuf >> 4];
+ if (j >= NC)
+ {
+ mask = 1 << (3);
+ do
+ {
+ if (bitbuf & mask)
+ j = right[j];
+ else
+ j = left[j];
+ mask >>= 1;
+ } while (j >= NC);
+ }
+ m_InBitStream.MovePos((int)(c_len[j]));
+ return j;
+}
+
+UInt32 CCoder::decode_p()
+{
+ UInt32 j, mask;
+ UInt32 bitbuf = m_InBitStream.GetValue(16);
+ j = pt_table[bitbuf >> (8)];
+ if (j >= NP)
+ {
+ mask = 1 << (7);
+ do
+ {
+ if (bitbuf & mask)
+ j = right[j];
+ else
+ j = left[j];
+ mask >>= 1;
+ } while (j >= NP);
+ }
+ m_InBitStream.MovePos((int)(pt_len[j]));
+ if (j != 0)
+ {
+ j--;
+ j = (1 << j) + m_InBitStream.ReadBits((int)j);
+ }
+ return j;
+}
+
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ // check it
+ for (int i = 0; i < CTABLESIZE; i++)
+ c_table[i] = 0;
+
+ UInt64 pos = 0;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ UInt32 blockSize = 0;
+
+ while(pos < *outSize)
+ {
+ if (blockSize == 0)
+ {
+ if (progress != NULL)
+ {
+ UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ }
+ blockSize = m_InBitStream.ReadBits(16);
+ read_pt_len(NT, TBIT, 3);
+ read_c_len();
+ read_pt_len(NP, PBIT, -1);
+ }
+ blockSize--;
+
+ UInt32 number = decode_c();
+ if (number < 256)
+ {
+ m_OutWindowStream.PutByte((Byte)number);
+ pos++;
+ continue;
+ }
+ else
+ {
+ UInt32 len = number - 256 + kMatchMinLen;
+ UInt32 distance = decode_p();
+ if (distance >= pos)
+ return S_FALSE;
+ m_OutWindowStream.CopyBlock(distance, len);
+ pos += len;
+ }
+ }
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder1.h b/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder1.h
new file mode 100644
index 000000000..17939dafb
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder1.h
@@ -0,0 +1,98 @@
+// ArjDecoder1.h
+
+#ifndef __COMPRESS_ARJ_DECODER1_H
+#define __COMPRESS_ARJ_DECODER1_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NArj {
+namespace NDecoder1 {
+
+#define CODE_BIT 16
+
+#define THRESHOLD 3
+#define DDICSIZ 26624
+#define MAXDICBIT 16
+#define MATCHBIT 8
+#define MAXMATCH 256
+#define NC (0xFF + MAXMATCH + 2 - THRESHOLD)
+#define NP (MAXDICBIT + 1)
+#define CBIT 9
+#define NT (CODE_BIT + 3)
+#define PBIT 5
+#define TBIT 5
+
+#if NT > NP
+#define NPT NT
+#else
+#define NPT NP
+#endif
+
+#define CTABLESIZE 4096
+#define PTABLESIZE 256
+
+
+class CCoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitm::CDecoder<CInBuffer> m_InBitStream;
+
+ UInt32 left[2 * NC - 1];
+ UInt32 right[2 * NC - 1];
+ Byte c_len[NC];
+ Byte pt_len[NPT];
+
+ UInt32 c_table[CTABLESIZE];
+ UInt32 pt_table[PTABLESIZE];
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CCoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+ void MakeTable(int nchar, Byte *bitlen, int tablebits, UInt32 *table, int tablesize);
+
+ void read_c_len();
+ void read_pt_len(int nn, int nbit, int i_special);
+ UInt32 decode_c();
+ UInt32 decode_p();
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder2.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder2.cpp
new file mode 100644
index 000000000..365993bc5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder2.cpp
@@ -0,0 +1,90 @@
+// ArjDecoder2.cpp
+
+#include "StdAfx.h"
+
+#include "ArjDecoder2.h"
+
+namespace NCompress{
+namespace NArj {
+namespace NDecoder2 {
+
+static const UInt32 kHistorySize = 26624;
+static const UInt32 kMatchMinLen = 3;
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo * /* progress */)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ UInt64 pos = 0;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+ CCoderReleaser coderReleaser(this);
+
+ while(pos < *outSize)
+ {
+ const UInt32 kStartWidth = 0;
+ const UInt32 kStopWidth = 7;
+ UInt32 power = 1 << kStartWidth;
+ UInt32 width;
+ UInt32 len = 0;
+ for (width = kStartWidth; width < kStopWidth; width++)
+ {
+ if (m_InBitStream.ReadBits(1) == 0)
+ break;
+ len += power;
+ power <<= 1;
+ }
+ if (width != 0)
+ len += m_InBitStream.ReadBits(width);
+ if (len == 0)
+ {
+ m_OutWindowStream.PutByte((Byte)m_InBitStream.ReadBits(8));
+ pos++;
+ continue;
+ }
+ else
+ {
+ len = len - 1 + kMatchMinLen;
+ const UInt32 kStartWidth = 9;
+ const UInt32 kStopWidth = 13;
+ UInt32 power = 1 << kStartWidth;
+ UInt32 width;
+ UInt32 distance = 0;
+ for (width = kStartWidth; width < kStopWidth; width++)
+ {
+ if (m_InBitStream.ReadBits(1) == 0)
+ break;
+ distance += power;
+ power <<= 1;
+ }
+ if (width != 0)
+ distance += m_InBitStream.ReadBits(width);
+ if (distance >= pos)
+ return S_FALSE;
+ m_OutWindowStream.CopyBlock(distance, len);
+ pos += len;
+ }
+ }
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder2.h b/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder2.h
new file mode 100644
index 000000000..cf00975da
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ArjDecoder2.h
@@ -0,0 +1,59 @@
+// ArjDecoder2.h
+
+#ifndef __COMPRESS_ARJ_DECODER2_H
+#define __COMPRESS_ARJ_DECODER2_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NArj {
+namespace NDecoder2 {
+
+class CCoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitm::CDecoder<CInBuffer> m_InBitStream;
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CCoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Const.h b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Const.h
new file mode 100644
index 000000000..62427aa68
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Const.h
@@ -0,0 +1,54 @@
+// Compress/BZip2Const.h
+
+#ifndef __COMPRESS_BZIP2_CONST_H
+#define __COMPRESS_BZIP2_CONST_H
+
+namespace NCompress {
+namespace NBZip2 {
+
+const Byte kArSig0 = 'B';
+const Byte kArSig1 = 'Z';
+const Byte kArSig2 = 'h';
+const Byte kArSig3 = '0';
+
+const Byte kFinSig0 = 0x17;
+const Byte kFinSig1 = 0x72;
+const Byte kFinSig2 = 0x45;
+const Byte kFinSig3 = 0x38;
+const Byte kFinSig4 = 0x50;
+const Byte kFinSig5 = 0x90;
+
+const Byte kBlockSig0 = 0x31;
+const Byte kBlockSig1 = 0x41;
+const Byte kBlockSig2 = 0x59;
+const Byte kBlockSig3 = 0x26;
+const Byte kBlockSig4 = 0x53;
+const Byte kBlockSig5 = 0x59;
+
+const int kNumOrigBits = 24;
+
+const int kNumTablesBits = 3;
+const int kNumTablesMin = 2;
+const int kNumTablesMax = 6;
+
+const int kNumLevelsBits = 5;
+
+const int kMaxHuffmanLen = 20; // Check it
+
+const int kMaxAlphaSize = 258;
+
+const int kGroupSize = 50;
+
+const int kBlockSizeMultMin = 1;
+const int kBlockSizeMultMax = 9;
+const UInt32 kBlockSizeStep = 100000;
+const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep;
+
+const int kNumSelectorsBits = 15;
+const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize));
+
+const int kRleModeRepSize = 4;
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Crc.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Crc.cpp
new file mode 100644
index 000000000..4e4741f40
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Crc.cpp
@@ -0,0 +1,26 @@
+// BZip2Crc.cpp
+
+#include "StdAfx.h"
+
+#include "BZip2Crc.h"
+
+UInt32 CBZip2Crc::Table[256];
+
+static const UInt32 kBZip2CrcPoly = 0x04c11db7; /* AUTODIN II, Ethernet, & FDDI */
+
+void CBZip2Crc::InitTable()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ UInt32 r = (i << 24);
+ for (int j = 8; j > 0; j--)
+ r = (r & 0x80000000) ? ((r << 1) ^ kBZip2CrcPoly) : (r << 1);
+ Table[i] = r;
+ }
+}
+
+class CBZip2CrcTableInit
+{
+public:
+ CBZip2CrcTableInit() { CBZip2Crc::InitTable(); }
+} g_BZip2CrcTableInit;
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Crc.h b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Crc.h
new file mode 100644
index 000000000..876945b5f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Crc.h
@@ -0,0 +1,31 @@
+// BZip2Crc.h
+
+#ifndef __BZIP2_CRC_H
+#define __BZIP2_CRC_H
+
+#include "Common/Types.h"
+
+class CBZip2Crc
+{
+ UInt32 _value;
+ static UInt32 Table[256];
+public:
+ static void InitTable();
+ CBZip2Crc(): _value(0xFFFFFFFF) {};
+ void Init() { _value = 0xFFFFFFFF; }
+ void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
+ void UpdateByte(unsigned int b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
+ UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; }
+};
+
+class CBZip2CombinedCrc
+{
+ UInt32 _value;
+public:
+ CBZip2CombinedCrc(): _value(0){};
+ void Init() { _value = 0; }
+ void Update(UInt32 v) { _value = ((_value << 1) | (_value >> 31)) ^ v; }
+ UInt32 GetDigest() const { return _value ; }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Decoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Decoder.cpp
new file mode 100644
index 000000000..cb1f981a7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Decoder.cpp
@@ -0,0 +1,943 @@
+// BZip2Decoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "BZip2Decoder.h"
+#include "Mtf8.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+#undef NO_INLINE
+#define NO_INLINE
+
+static const UInt32 kNumThreadsMax = 4;
+
+static const UInt32 kBufferSize = (1 << 17);
+
+static const UInt16 kRandNums[512] = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+};
+
+bool CState::Alloc()
+{
+ if (!Counters)
+ Counters = (UInt32 *)::BigAlloc((256 + kBlockSizeMax) * sizeof(UInt32));
+ return (Counters != 0);
+}
+
+void CState::Free()
+{
+ ::BigFree(Counters);
+ Counters = 0;
+}
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InStream.ReadBits(numBits); }
+Byte CDecoder::ReadByte() {return (Byte)ReadBits(8); }
+bool CDecoder::ReadBit() { return ReadBits(1) != 0; }
+
+UInt32 CDecoder::ReadCrc()
+{
+ UInt32 crc = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ crc <<= 8;
+ crc |= ReadByte();
+ }
+ return crc;
+}
+
+static UInt32 NO_INLINE ReadBits(NBitm::CDecoder<CInBuffer> *m_InStream, unsigned num)
+{
+ return m_InStream->ReadBits(num);
+}
+
+static UInt32 NO_INLINE ReadBit(NBitm::CDecoder<CInBuffer> *m_InStream)
+{
+ return m_InStream->ReadBits(1);
+}
+
+static HRESULT NO_INLINE ReadBlock(NBitm::CDecoder<CInBuffer> *m_InStream,
+ UInt32 *CharCounters, UInt32 blockSizeMax, Byte *m_Selectors, CHuffmanDecoder *m_HuffmanDecoders,
+ UInt32 *blockSizeRes, UInt32 *origPtrRes, bool *randRes)
+{
+ if (randRes)
+ *randRes = ReadBit(m_InStream) ? true : false;
+ *origPtrRes = ReadBits(m_InStream, kNumOrigBits);
+
+ // in original code it compares OrigPtr to (UInt32)(10 + blockSizeMax)) : why ?
+ if (*origPtrRes >= blockSizeMax)
+ return S_FALSE;
+
+ CMtf8Decoder mtf;
+ mtf.StartInit();
+
+ int numInUse = 0;
+ {
+ Byte inUse16[16];
+ int i;
+ for (i = 0; i < 16; i++)
+ inUse16[i] = (Byte)ReadBit(m_InStream);
+ for (i = 0; i < 256; i++)
+ if (inUse16[i >> 4])
+ {
+ if (ReadBit(m_InStream))
+ mtf.Add(numInUse++, (Byte)i);
+ }
+ if (numInUse == 0)
+ return S_FALSE;
+ // mtf.Init(numInUse);
+ }
+ int alphaSize = numInUse + 2;
+
+ int numTables = ReadBits(m_InStream, kNumTablesBits);
+ if (numTables < kNumTablesMin || numTables > kNumTablesMax)
+ return S_FALSE;
+
+ UInt32 numSelectors = ReadBits(m_InStream, kNumSelectorsBits);
+ if (numSelectors < 1 || numSelectors > kNumSelectorsMax)
+ return S_FALSE;
+
+ {
+ Byte mtfPos[kNumTablesMax];
+ int t = 0;
+ do
+ mtfPos[t] = (Byte)t;
+ while(++t < numTables);
+ UInt32 i = 0;
+ do
+ {
+ int j = 0;
+ while (ReadBit(m_InStream))
+ if (++j >= numTables)
+ return S_FALSE;
+ Byte tmp = mtfPos[j];
+ for (;j > 0; j--)
+ mtfPos[j] = mtfPos[j - 1];
+ m_Selectors[i] = mtfPos[0] = tmp;
+ }
+ while(++i < numSelectors);
+ }
+
+ int t = 0;
+ do
+ {
+ Byte lens[kMaxAlphaSize];
+ int len = (int)ReadBits(m_InStream, kNumLevelsBits);
+ int i;
+ for (i = 0; i < alphaSize; i++)
+ {
+ for (;;)
+ {
+ if (len < 1 || len > kMaxHuffmanLen)
+ return S_FALSE;
+ if (!ReadBit(m_InStream))
+ break;
+ len += 1 - (int)(ReadBit(m_InStream) << 1);
+ }
+ lens[i] = (Byte)len;
+ }
+ for (; i < kMaxAlphaSize; i++)
+ lens[i] = 0;
+ if(!m_HuffmanDecoders[t].SetCodeLengths(lens))
+ return S_FALSE;
+ }
+ while(++t < numTables);
+
+ {
+ for (int i = 0; i < 256; i++)
+ CharCounters[i] = 0;
+ }
+
+ UInt32 blockSize = 0;
+ {
+ UInt32 groupIndex = 0;
+ UInt32 groupSize = 0;
+ CHuffmanDecoder *huffmanDecoder = 0;
+ int runPower = 0;
+ UInt32 runCounter = 0;
+
+ for (;;)
+ {
+ if (groupSize == 0)
+ {
+ if (groupIndex >= numSelectors)
+ return S_FALSE;
+ groupSize = kGroupSize;
+ huffmanDecoder = &m_HuffmanDecoders[m_Selectors[groupIndex++]];
+ }
+ groupSize--;
+
+ UInt32 nextSym = huffmanDecoder->DecodeSymbol(m_InStream);
+
+ if (nextSym < 2)
+ {
+ runCounter += ((UInt32)(nextSym + 1) << runPower++);
+ if (blockSizeMax - blockSize < runCounter)
+ return S_FALSE;
+ continue;
+ }
+ if (runCounter != 0)
+ {
+ UInt32 b = (UInt32)mtf.GetHead();
+ CharCounters[b] += runCounter;
+ do
+ CharCounters[256 + blockSize++] = b;
+ while(--runCounter != 0);
+ runPower = 0;
+ }
+ if (nextSym <= (UInt32)numInUse)
+ {
+ UInt32 b = (UInt32)mtf.GetAndMove((int)nextSym - 1);
+ if (blockSize >= blockSizeMax)
+ return S_FALSE;
+ CharCounters[b]++;
+ CharCounters[256 + blockSize++] = b;
+ }
+ else if (nextSym == (UInt32)numInUse + 1)
+ break;
+ else
+ return S_FALSE;
+ }
+ }
+ *blockSizeRes = blockSize;
+ return (*origPtrRes < blockSize) ? S_OK : S_FALSE;
+}
+
+static void NO_INLINE DecodeBlock1(UInt32 *charCounters, UInt32 blockSize)
+{
+ {
+ UInt32 sum = 0;
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ sum += charCounters[i];
+ charCounters[i] = sum - charCounters[i];
+ }
+ }
+
+ UInt32 *tt = charCounters + 256;
+ // Compute the T^(-1) vector
+ UInt32 i = 0;
+ do
+ tt[charCounters[tt[i] & 0xFF]++] |= (i << 8);
+ while(++i < blockSize);
+}
+
+static UInt32 NO_INLINE DecodeBlock2(const UInt32 *tt, UInt32 blockSize, UInt32 OrigPtr, COutBuffer &m_OutStream)
+{
+ CBZip2Crc crc;
+
+ // it's for speed optimization: prefetch & prevByte_init;
+ UInt32 tPos = tt[tt[OrigPtr] >> 8];
+ unsigned prevByte = (unsigned)(tPos & 0xFF);
+
+ unsigned numReps = 0;
+
+ do
+ {
+ unsigned b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+
+ if (numReps == kRleModeRepSize)
+ {
+ for (; b > 0; b--)
+ {
+ crc.UpdateByte(prevByte);
+ m_OutStream.WriteByte((Byte)prevByte);
+ }
+ numReps = 0;
+ continue;
+ }
+ if (b != prevByte)
+ numReps = 0;
+ numReps++;
+ prevByte = b;
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+
+ /*
+ prevByte = b;
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ for (; --blockSize != 0;)
+ {
+ b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ if (b != prevByte)
+ {
+ prevByte = b;
+ continue;
+ }
+ if (--blockSize == 0)
+ break;
+
+ b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ if (b != prevByte)
+ {
+ prevByte = b;
+ continue;
+ }
+ if (--blockSize == 0)
+ break;
+
+ b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ if (b != prevByte)
+ {
+ prevByte = b;
+ continue;
+ }
+ --blockSize;
+ break;
+ }
+ if (blockSize == 0)
+ break;
+
+ b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+
+ for (; b > 0; b--)
+ {
+ crc.UpdateByte(prevByte);
+ m_OutStream.WriteByte((Byte)prevByte);
+ }
+ */
+ }
+ while(--blockSize != 0);
+ return crc.GetDigest();
+}
+
+static UInt32 NO_INLINE DecodeBlock2Rand(const UInt32 *tt, UInt32 blockSize, UInt32 OrigPtr, COutBuffer &m_OutStream)
+{
+ CBZip2Crc crc;
+
+ UInt32 randIndex = 1;
+ UInt32 randToGo = kRandNums[0] - 2;
+
+ unsigned numReps = 0;
+
+ // it's for speed optimization: prefetch & prevByte_init;
+ UInt32 tPos = tt[tt[OrigPtr] >> 8];
+ unsigned prevByte = (unsigned)(tPos & 0xFF);
+
+ do
+ {
+ unsigned b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+
+ {
+ if (randToGo == 0)
+ {
+ b ^= 1;
+ randToGo = kRandNums[randIndex++];
+ randIndex &= 0x1FF;
+ }
+ randToGo--;
+ }
+
+ if (numReps == kRleModeRepSize)
+ {
+ for (; b > 0; b--)
+ {
+ crc.UpdateByte(prevByte);
+ m_OutStream.WriteByte((Byte)prevByte);
+ }
+ numReps = 0;
+ continue;
+ }
+ if (b != prevByte)
+ numReps = 0;
+ numReps++;
+ prevByte = b;
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ }
+ while(--blockSize != 0);
+ return crc.GetDigest();
+}
+
+
+CDecoder::CDecoder()
+{
+ #ifndef _7ZIP_ST
+ m_States = 0;
+ m_NumThreadsPrev = 0;
+ NumThreads = 1;
+ #endif
+ _needInStreamInit = true;
+}
+
+#ifndef _7ZIP_ST
+
+CDecoder::~CDecoder()
+{
+ Free();
+}
+
+#define RINOK_THREAD(x) { WRes __result_ = (x); if(__result_ != 0) return __result_; }
+
+HRESULT CDecoder::Create()
+{
+ RINOK_THREAD(CanProcessEvent.CreateIfNotCreated());
+ RINOK_THREAD(CanStartWaitingEvent.CreateIfNotCreated());
+ if (m_States != 0 && m_NumThreadsPrev == NumThreads)
+ return S_OK;
+ Free();
+ MtMode = (NumThreads > 1);
+ m_NumThreadsPrev = NumThreads;
+ try
+ {
+ m_States = new CState[NumThreads];
+ if (!m_States)
+ return E_OUTOFMEMORY;
+ }
+ catch(...) { return E_OUTOFMEMORY; }
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CState &ti = m_States[t];
+ ti.Decoder = this;
+ if (MtMode)
+ {
+ HRESULT res = ti.Create();
+ if (res != S_OK)
+ {
+ NumThreads = t;
+ Free();
+ return res;
+ }
+ }
+ }
+ return S_OK;
+}
+
+void CDecoder::Free()
+{
+ if (!m_States)
+ return;
+ CloseThreads = true;
+ CanProcessEvent.Set();
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CState &s = m_States[t];
+ if (MtMode)
+ s.Thread.Wait();
+ s.Free();
+ }
+ delete []m_States;
+ m_States = 0;
+}
+
+#endif
+
+HRESULT CDecoder::ReadSignatures(bool &wasFinished, UInt32 &crc)
+{
+ wasFinished = false;
+ Byte s[6];
+ for (int i = 0; i < 6; i++)
+ s[i] = ReadByte();
+ crc = ReadCrc();
+ if (s[0] == kFinSig0)
+ {
+ if (s[1] != kFinSig1 ||
+ s[2] != kFinSig2 ||
+ s[3] != kFinSig3 ||
+ s[4] != kFinSig4 ||
+ s[5] != kFinSig5)
+ return S_FALSE;
+
+ wasFinished = true;
+ return (crc == CombinedCrc.GetDigest()) ? S_OK : S_FALSE;
+ }
+ if (s[0] != kBlockSig0 ||
+ s[1] != kBlockSig1 ||
+ s[2] != kBlockSig2 ||
+ s[3] != kBlockSig3 ||
+ s[4] != kBlockSig4 ||
+ s[5] != kBlockSig5)
+ return S_FALSE;
+ CombinedCrc.Update(crc);
+ return S_OK;
+}
+
+HRESULT CDecoder::DecodeFile(bool &isBZ, ICompressProgressInfo *progress)
+{
+ Progress = progress;
+ #ifndef _7ZIP_ST
+ RINOK(Create());
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CState &s = m_States[t];
+ if (!s.Alloc())
+ return E_OUTOFMEMORY;
+ if (MtMode)
+ {
+ RINOK(s.StreamWasFinishedEvent.Reset());
+ RINOK(s.WaitingWasStartedEvent.Reset());
+ RINOK(s.CanWriteEvent.Reset());
+ }
+ }
+ #else
+ if (!m_States[0].Alloc())
+ return E_OUTOFMEMORY;
+ #endif
+
+ isBZ = false;
+ Byte s[6];
+ int i;
+ for (i = 0; i < 4; i++)
+ s[i] = ReadByte();
+ if (s[0] != kArSig0 ||
+ s[1] != kArSig1 ||
+ s[2] != kArSig2 ||
+ s[3] <= kArSig3 ||
+ s[3] > kArSig3 + kBlockSizeMultMax)
+ return S_OK;
+ isBZ = true;
+ UInt32 dicSize = (UInt32)(s[3] - kArSig3) * kBlockSizeStep;
+
+ CombinedCrc.Init();
+ #ifndef _7ZIP_ST
+ if (MtMode)
+ {
+ NextBlockIndex = 0;
+ StreamWasFinished1 = StreamWasFinished2 = false;
+ CloseThreads = false;
+ CanStartWaitingEvent.Reset();
+ m_States[0].CanWriteEvent.Set();
+ BlockSizeMax = dicSize;
+ Result1 = Result2 = S_OK;
+ CanProcessEvent.Set();
+ UInt32 t;
+ for (t = 0; t < NumThreads; t++)
+ m_States[t].StreamWasFinishedEvent.Lock();
+ CanProcessEvent.Reset();
+ CanStartWaitingEvent.Set();
+ for (t = 0; t < NumThreads; t++)
+ m_States[t].WaitingWasStartedEvent.Lock();
+ CanStartWaitingEvent.Reset();
+ RINOK(Result2);
+ RINOK(Result1);
+ }
+ else
+ #endif
+ {
+ CState &state = m_States[0];
+ for (;;)
+ {
+ RINOK(SetRatioProgress(m_InStream.GetProcessedSize()));
+ bool wasFinished;
+ UInt32 crc;
+ RINOK(ReadSignatures(wasFinished, crc));
+ if (wasFinished)
+ return S_OK;
+
+ UInt32 blockSize, origPtr;
+ bool randMode;
+ RINOK(ReadBlock(&m_InStream, state.Counters, dicSize,
+ m_Selectors, m_HuffmanDecoders,
+ &blockSize, &origPtr, &randMode));
+ DecodeBlock1(state.Counters, blockSize);
+ if ((randMode ?
+ DecodeBlock2Rand(state.Counters + 256, blockSize, origPtr, m_OutStream) :
+ DecodeBlock2(state.Counters + 256, blockSize, origPtr, m_OutStream)) != crc)
+ return S_FALSE;
+ }
+ }
+ return SetRatioProgress(m_InStream.GetProcessedSize());
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ bool &isBZ, ICompressProgressInfo *progress)
+{
+ isBZ = false;
+ try
+ {
+
+ if (!m_InStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (!m_OutStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+
+ if (inStream)
+ m_InStream.SetStream(inStream);
+
+ CDecoderFlusher flusher(this, inStream != NULL);
+
+ if (_needInStreamInit)
+ {
+ m_InStream.Init();
+ _needInStreamInit = false;
+ }
+ _inStart = m_InStream.GetProcessedSize();
+
+ m_InStream.AlignToByte();
+
+ m_OutStream.SetStream(outStream);
+ m_OutStream.Init();
+
+ RINOK(DecodeFile(isBZ, progress));
+ flusher.NeedFlush = false;
+ return Flush();
+
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return E_FAIL; }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ _needInStreamInit = true;
+ bool isBZ;
+ RINOK(CodeReal(inStream, outStream, isBZ, progress));
+ return isBZ ? S_OK : S_FALSE;
+}
+
+HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, bool &isBZ, ICompressProgressInfo *progress)
+{
+ return CodeReal(NULL, outStream, isBZ, progress);
+}
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { m_InStream.SetStream(inStream); return S_OK; }
+STDMETHODIMP CDecoder::ReleaseInStream() { m_InStream.ReleaseStream(); return S_OK; }
+
+#ifndef _7ZIP_ST
+
+static THREAD_FUNC_DECL MFThread(void *p) { ((CState *)p)->ThreadFunc(); return 0; }
+
+HRESULT CState::Create()
+{
+ RINOK_THREAD(StreamWasFinishedEvent.CreateIfNotCreated());
+ RINOK_THREAD(WaitingWasStartedEvent.CreateIfNotCreated());
+ RINOK_THREAD(CanWriteEvent.CreateIfNotCreated());
+ RINOK_THREAD(Thread.Create(MFThread, this));
+ return S_OK;
+}
+
+void CState::FinishStream()
+{
+ Decoder->StreamWasFinished1 = true;
+ StreamWasFinishedEvent.Set();
+ Decoder->CS.Leave();
+ Decoder->CanStartWaitingEvent.Lock();
+ WaitingWasStartedEvent.Set();
+}
+
+void CState::ThreadFunc()
+{
+ for (;;)
+ {
+ Decoder->CanProcessEvent.Lock();
+ Decoder->CS.Enter();
+ if (Decoder->CloseThreads)
+ {
+ Decoder->CS.Leave();
+ return;
+ }
+ if (Decoder->StreamWasFinished1)
+ {
+ FinishStream();
+ continue;
+ }
+ HRESULT res = S_OK;
+
+ UInt32 blockIndex = Decoder->NextBlockIndex;
+ UInt32 nextBlockIndex = blockIndex + 1;
+ if (nextBlockIndex == Decoder->NumThreads)
+ nextBlockIndex = 0;
+ Decoder->NextBlockIndex = nextBlockIndex;
+ UInt32 crc;
+ UInt64 packSize = 0;
+ UInt32 blockSize = 0, origPtr = 0;
+ bool randMode = false;
+
+ try
+ {
+ bool wasFinished;
+ res = Decoder->ReadSignatures(wasFinished, crc);
+ if (res != S_OK)
+ {
+ Decoder->Result1 = res;
+ FinishStream();
+ continue;
+ }
+ if (wasFinished)
+ {
+ Decoder->Result1 = res;
+ FinishStream();
+ continue;
+ }
+
+ res = ReadBlock(&Decoder->m_InStream, Counters, Decoder->BlockSizeMax,
+ Decoder->m_Selectors, Decoder->m_HuffmanDecoders,
+ &blockSize, &origPtr, &randMode);
+ if (res != S_OK)
+ {
+ Decoder->Result1 = res;
+ FinishStream();
+ continue;
+ }
+ packSize = Decoder->m_InStream.GetProcessedSize();
+ }
+ catch(const CInBufferException &e) { res = e.ErrorCode; if (res != S_OK) res = E_FAIL; }
+ catch(...) { res = E_FAIL; }
+ if (res != S_OK)
+ {
+ Decoder->Result1 = res;
+ FinishStream();
+ continue;
+ }
+
+ Decoder->CS.Leave();
+
+ DecodeBlock1(Counters, blockSize);
+
+ bool needFinish = true;
+ try
+ {
+ Decoder->m_States[blockIndex].CanWriteEvent.Lock();
+ needFinish = Decoder->StreamWasFinished2;
+ if (!needFinish)
+ {
+ if ((randMode ?
+ DecodeBlock2Rand(Counters + 256, blockSize, origPtr, Decoder->m_OutStream) :
+ DecodeBlock2(Counters + 256, blockSize, origPtr, Decoder->m_OutStream)) == crc)
+ res = Decoder->SetRatioProgress(packSize);
+ else
+ res = S_FALSE;
+ }
+ }
+ catch(const COutBufferException &e) { res = e.ErrorCode; if (res != S_OK) res = E_FAIL; }
+ catch(...) { res = E_FAIL; }
+ if (res != S_OK)
+ {
+ Decoder->Result2 = res;
+ Decoder->StreamWasFinished2 = true;
+ }
+ Decoder->m_States[nextBlockIndex].CanWriteEvent.Set();
+ if (res != S_OK || needFinish)
+ {
+ StreamWasFinishedEvent.Set();
+ Decoder->CanStartWaitingEvent.Lock();
+ WaitingWasStartedEvent.Set();
+ }
+ }
+}
+
+STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)
+{
+ NumThreads = numThreads;
+ if (NumThreads < 1)
+ NumThreads = 1;
+ if (NumThreads > kNumThreadsMax)
+ NumThreads = kNumThreadsMax;
+ return S_OK;
+}
+
+#endif
+
+HRESULT CDecoder::SetRatioProgress(UInt64 packSize)
+{
+ if (!Progress)
+ return S_OK;
+ packSize -= _inStart;
+ UInt64 unpackSize = m_OutStream.GetProcessedSize();
+ return Progress->SetRatioInfo(&packSize, &unpackSize);
+}
+
+
+// ---------- NSIS ----------
+
+enum
+{
+ NSIS_STATE_INIT,
+ NSIS_STATE_NEW_BLOCK,
+ NSIS_STATE_DATA,
+ NSIS_STATE_FINISHED,
+ NSIS_STATE_ERROR
+};
+
+STDMETHODIMP CNsisDecoder::SetInStream(ISequentialInStream *inStream) { m_InStream.SetStream(inStream); return S_OK; }
+STDMETHODIMP CNsisDecoder::ReleaseInStream() { m_InStream.ReleaseStream(); return S_OK; }
+
+STDMETHODIMP CNsisDecoder::SetOutStreamSize(const UInt64 * /* outSize */)
+{
+ _nsisState = NSIS_STATE_INIT;
+ return S_OK;
+}
+
+STDMETHODIMP CNsisDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ try {
+
+ *processedSize = 0;
+ if (_nsisState == NSIS_STATE_FINISHED)
+ return S_OK;
+ if (_nsisState == NSIS_STATE_ERROR)
+ return S_FALSE;
+ if (size == 0)
+ return S_OK;
+
+ CState &state = m_State;
+
+ if (_nsisState == NSIS_STATE_INIT)
+ {
+ if (!m_InStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (!state.Alloc())
+ return E_OUTOFMEMORY;
+ m_InStream.Init();
+ _nsisState = NSIS_STATE_NEW_BLOCK;
+ }
+
+ if (_nsisState == NSIS_STATE_NEW_BLOCK)
+ {
+ Byte b = (Byte)m_InStream.ReadBits(8);
+ if (b == kFinSig0)
+ {
+ _nsisState = NSIS_STATE_FINISHED;
+ return S_OK;
+ }
+ if (b != kBlockSig0)
+ {
+ _nsisState = NSIS_STATE_ERROR;
+ return S_FALSE;
+ }
+ UInt32 origPtr;
+ RINOK(ReadBlock(&m_InStream, state.Counters, 9 * kBlockSizeStep,
+ m_Selectors, m_HuffmanDecoders, &_blockSize, &origPtr, NULL));
+ DecodeBlock1(state.Counters, _blockSize);
+ const UInt32 *tt = state.Counters + 256;
+ _tPos = tt[tt[origPtr] >> 8];
+ _prevByte = (unsigned)(_tPos & 0xFF);
+ _numReps = 0;
+ _repRem = 0;
+ _nsisState = NSIS_STATE_DATA;
+ }
+
+ UInt32 tPos = _tPos;
+ unsigned prevByte = _prevByte;
+ unsigned numReps = _numReps;
+ UInt32 blockSize = _blockSize;
+ const UInt32 *tt = state.Counters + 256;
+
+ while (_repRem)
+ {
+ _repRem--;
+ *(Byte *)data = (Byte)prevByte;
+ data = (Byte *)data + 1;
+ (*processedSize)++;
+ if (--size == 0)
+ return S_OK;
+ }
+
+ if (blockSize == 0)
+ {
+ _nsisState = NSIS_STATE_NEW_BLOCK;
+ return S_OK;
+ }
+
+ do
+ {
+ unsigned b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ blockSize--;
+
+ if (numReps == kRleModeRepSize)
+ {
+ numReps = 0;
+ while (b)
+ {
+ b--;
+ *(Byte *)data = (Byte)prevByte;
+ data = (Byte *)data + 1;
+ (*processedSize)++;
+ if (--size == 0)
+ break;
+ }
+ _repRem = b;
+ continue;
+ }
+ if (b != prevByte)
+ numReps = 0;
+ numReps++;
+ prevByte = b;
+ *(Byte *)data = (Byte)b;
+ data = (Byte *)data + 1;
+ (*processedSize)++;
+ size--;
+ }
+ while (size && blockSize);
+ _tPos = tPos;
+ _prevByte = prevByte;
+ _numReps = numReps;
+ _blockSize = blockSize;
+ return S_OK;
+
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Decoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Decoder.h
new file mode 100644
index 000000000..e6dec1eaa
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Decoder.h
@@ -0,0 +1,205 @@
+// Compress/BZip2Decoder.h
+
+#ifndef __COMPRESS_BZIP2_DECODER_H
+#define __COMPRESS_BZIP2_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#ifndef _7ZIP_ST
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+#endif
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "BitmDecoder.h"
+#include "BZip2Const.h"
+#include "BZip2Crc.h"
+#include "HuffmanDecoder.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+typedef NCompress::NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize> CHuffmanDecoder;
+
+class CDecoder;
+
+struct CState
+{
+ UInt32 *Counters;
+
+ #ifndef _7ZIP_ST
+
+ CDecoder *Decoder;
+ NWindows::CThread Thread;
+ bool m_OptimizeNumTables;
+
+ NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
+ NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
+
+ // it's not member of this thread. We just need one event per thread
+ NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
+
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+
+ HRESULT Create();
+ void FinishStream();
+ void ThreadFunc();
+
+ #endif
+
+ CState(): Counters(0) {}
+ ~CState() { Free(); }
+ bool Alloc();
+ void Free();
+};
+
+class CDecoder :
+ public ICompressCoder,
+ #ifndef _7ZIP_ST
+ public ICompressSetCoderMt,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ COutBuffer m_OutStream;
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+ NBitm::CDecoder<CInBuffer> m_InStream;
+ Byte m_Selectors[kNumSelectorsMax];
+ CHuffmanDecoder m_HuffmanDecoders[kNumTablesMax];
+ UInt64 _inStart;
+
+private:
+
+ bool _needInStreamInit;
+
+ UInt32 ReadBits(unsigned numBits);
+ Byte ReadByte();
+ bool ReadBit();
+ UInt32 ReadCrc();
+ HRESULT DecodeFile(bool &isBZ, ICompressProgressInfo *progress);
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ bool &isBZ, ICompressProgressInfo *progress);
+ class CDecoderFlusher
+ {
+ CDecoder *_decoder;
+ public:
+ bool NeedFlush;
+ bool ReleaseInStream;
+ CDecoderFlusher(CDecoder *decoder, bool releaseInStream):
+ _decoder(decoder),
+ ReleaseInStream(releaseInStream),
+ NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ _decoder->Flush();
+ _decoder->ReleaseStreams(ReleaseInStream);
+ }
+ };
+
+public:
+ CBZip2CombinedCrc CombinedCrc;
+ ICompressProgressInfo *Progress;
+
+ #ifndef _7ZIP_ST
+ CState *m_States;
+ UInt32 m_NumThreadsPrev;
+
+ NWindows::NSynchronization::CManualResetEvent CanProcessEvent;
+ NWindows::NSynchronization::CCriticalSection CS;
+ UInt32 NumThreads;
+ bool MtMode;
+ UInt32 NextBlockIndex;
+ bool CloseThreads;
+ bool StreamWasFinished1;
+ bool StreamWasFinished2;
+ NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
+
+ HRESULT Result1;
+ HRESULT Result2;
+
+ UInt32 BlockSizeMax;
+ ~CDecoder();
+ HRESULT Create();
+ void Free();
+
+ #else
+ CState m_States[1];
+ #endif
+
+ CDecoder();
+
+ HRESULT SetRatioProgress(UInt64 packSize);
+ HRESULT ReadSignatures(bool &wasFinished, UInt32 &crc);
+
+ HRESULT Flush() { return m_OutStream.Flush(); }
+ void ReleaseStreams(bool releaseInStream)
+ {
+ if (releaseInStream)
+ m_InStream.ReleaseStream();
+ m_OutStream.ReleaseStream();
+ }
+
+ MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
+ #ifndef _7ZIP_ST
+ MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
+ #endif
+
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+
+ HRESULT CodeResume(ISequentialOutStream *outStream, bool &isBZ, ICompressProgressInfo *progress);
+ UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); }
+
+ #ifndef _7ZIP_ST
+ STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
+ #endif
+};
+
+
+class CNsisDecoder :
+ public ISequentialInStream,
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public CMyUnknownImp
+{
+ NBitm::CDecoder<CInBuffer> m_InStream;
+ Byte m_Selectors[kNumSelectorsMax];
+ CHuffmanDecoder m_HuffmanDecoders[kNumTablesMax];
+ CState m_State;
+
+ int _nsisState;
+ UInt32 _tPos;
+ unsigned _prevByte;
+ unsigned _repRem;
+ unsigned _numReps;
+ UInt32 _blockSize;
+
+public:
+
+ MY_QUERYINTERFACE_BEGIN2(ISequentialInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Encoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Encoder.cpp
new file mode 100644
index 000000000..eaa108558
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Encoder.cpp
@@ -0,0 +1,895 @@
+// BZip2Encoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/BwtSort.h"
+#include "../../../C/HuffEnc.h"
+
+#include "BZip2Crc.h"
+#include "BZip2Encoder.h"
+#include "Mtf8.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+const int kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20
+
+static const UInt32 kBufferSize = (1 << 17);
+static const int kNumHuffPasses = 4;
+
+bool CThreadInfo::Alloc()
+{
+ if (m_BlockSorterIndex == 0)
+ {
+ m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32));
+ if (m_BlockSorterIndex == 0)
+ return false;
+ }
+
+ if (m_Block == 0)
+ {
+ m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10));
+ if (m_Block == 0)
+ return false;
+ m_MtfArray = m_Block + kBlockSizeMax;
+ m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
+ }
+ return true;
+}
+
+void CThreadInfo::Free()
+{
+ ::BigFree(m_BlockSorterIndex);
+ m_BlockSorterIndex = 0;
+ ::MidFree(m_Block);
+ m_Block = 0;
+}
+
+#ifndef _7ZIP_ST
+
+static THREAD_FUNC_DECL MFThread(void *threadCoderInfo)
+{
+ return ((CThreadInfo *)threadCoderInfo)->ThreadFunc();
+}
+
+#define RINOK_THREAD(x) { WRes __result_ = (x); if(__result_ != 0) return __result_; }
+
+HRESULT CThreadInfo::Create()
+{
+ RINOK_THREAD(StreamWasFinishedEvent.Create());
+ RINOK_THREAD(WaitingWasStartedEvent.Create());
+ RINOK_THREAD(CanWriteEvent.Create());
+ RINOK_THREAD(Thread.Create(MFThread, this));
+ return S_OK;
+}
+
+void CThreadInfo::FinishStream(bool needLeave)
+{
+ Encoder->StreamWasFinished = true;
+ StreamWasFinishedEvent.Set();
+ if (needLeave)
+ Encoder->CS.Leave();
+ Encoder->CanStartWaitingEvent.Lock();
+ WaitingWasStartedEvent.Set();
+}
+
+DWORD CThreadInfo::ThreadFunc()
+{
+ for (;;)
+ {
+ Encoder->CanProcessEvent.Lock();
+ Encoder->CS.Enter();
+ if (Encoder->CloseThreads)
+ {
+ Encoder->CS.Leave();
+ return 0;
+ }
+ if (Encoder->StreamWasFinished)
+ {
+ FinishStream(true);
+ continue;
+ }
+ HRESULT res = S_OK;
+ bool needLeave = true;
+ try
+ {
+ UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
+ m_PackSize = Encoder->m_InStream.GetProcessedSize();
+ m_BlockIndex = Encoder->NextBlockIndex;
+ if (++Encoder->NextBlockIndex == Encoder->NumThreads)
+ Encoder->NextBlockIndex = 0;
+ if (blockSize == 0)
+ {
+ FinishStream(true);
+ continue;
+ }
+ Encoder->CS.Leave();
+ needLeave = false;
+ res = EncodeBlock3(blockSize);
+ }
+ catch(const CInBufferException &e) { res = e.ErrorCode; }
+ catch(const COutBufferException &e) { res = e.ErrorCode; }
+ catch(...) { res = E_FAIL; }
+ if (res != S_OK)
+ {
+ Encoder->Result = res;
+ FinishStream(needLeave);
+ continue;
+ }
+ }
+}
+
+#endif
+
+CEncoder::CEncoder():
+ NumPasses(1),
+ m_OptimizeNumTables(false),
+ m_BlockSizeMult(kBlockSizeMultMax)
+{
+ #ifndef _7ZIP_ST
+ ThreadsInfo = 0;
+ m_NumThreadsPrev = 0;
+ NumThreads = 1;
+ #endif
+}
+
+#ifndef _7ZIP_ST
+CEncoder::~CEncoder()
+{
+ Free();
+}
+
+HRESULT CEncoder::Create()
+{
+ RINOK_THREAD(CanProcessEvent.CreateIfNotCreated());
+ RINOK_THREAD(CanStartWaitingEvent.CreateIfNotCreated());
+ if (ThreadsInfo != 0 && m_NumThreadsPrev == NumThreads)
+ return S_OK;
+ try
+ {
+ Free();
+ MtMode = (NumThreads > 1);
+ m_NumThreadsPrev = NumThreads;
+ ThreadsInfo = new CThreadInfo[NumThreads];
+ if (ThreadsInfo == 0)
+ return E_OUTOFMEMORY;
+ }
+ catch(...) { return E_OUTOFMEMORY; }
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CThreadInfo &ti = ThreadsInfo[t];
+ ti.Encoder = this;
+ if (MtMode)
+ {
+ HRESULT res = ti.Create();
+ if (res != S_OK)
+ {
+ NumThreads = t;
+ Free();
+ return res;
+ }
+ }
+ }
+ return S_OK;
+}
+
+void CEncoder::Free()
+{
+ if (!ThreadsInfo)
+ return;
+ CloseThreads = true;
+ CanProcessEvent.Set();
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CThreadInfo &ti = ThreadsInfo[t];
+ if (MtMode)
+ ti.Thread.Wait();
+ ti.Free();
+ }
+ delete []ThreadsInfo;
+ ThreadsInfo = 0;
+}
+#endif
+
+UInt32 CEncoder::ReadRleBlock(Byte *buffer)
+{
+ UInt32 i = 0;
+ Byte prevByte;
+ if (m_InStream.ReadByte(prevByte))
+ {
+ UInt32 blockSize = m_BlockSizeMult * kBlockSizeStep - 1;
+ int numReps = 1;
+ buffer[i++] = prevByte;
+ while (i < blockSize) // "- 1" to support RLE
+ {
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ break;
+ if (b != prevByte)
+ {
+ if (numReps >= kRleModeRepSize)
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ buffer[i++] = b;
+ numReps = 1;
+ prevByte = b;
+ continue;
+ }
+ numReps++;
+ if (numReps <= kRleModeRepSize)
+ buffer[i++] = b;
+ else if (numReps == kRleModeRepSize + 255)
+ {
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ numReps = 0;
+ }
+ }
+ // it's to support original BZip2 decoder
+ if (numReps >= kRleModeRepSize)
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ }
+ return i;
+}
+
+void CThreadInfo::WriteBits2(UInt32 value, UInt32 numBits)
+ { m_OutStreamCurrent->WriteBits(value, numBits); }
+void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b , 8); }
+void CThreadInfo::WriteBit2(bool v) { WriteBits2((v ? 1 : 0), 1); }
+void CThreadInfo::WriteCrc2(UInt32 v)
+{
+ for (int i = 0; i < 4; i++)
+ WriteByte2(((Byte)(v >> (24 - i * 8))));
+}
+
+void CEncoder::WriteBits(UInt32 value, UInt32 numBits)
+ { m_OutStream.WriteBits(value, numBits); }
+void CEncoder::WriteByte(Byte b) { WriteBits(b , 8); }
+void CEncoder::WriteBit(bool v) { WriteBits((v ? 1 : 0), 1); }
+void CEncoder::WriteCrc(UInt32 v)
+{
+ for (int i = 0; i < 4; i++)
+ WriteByte(((Byte)(v >> (24 - i * 8))));
+}
+
+
+// blockSize > 0
+void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
+{
+ WriteBit2(false); // Randomised = false
+
+ {
+ UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
+ // if (m_BlockSorterIndex[origPtr] != 0) throw 1;
+ m_BlockSorterIndex[origPtr] = blockSize;
+ WriteBits2(origPtr, kNumOrigBits);
+ }
+
+ CMtf8Encoder mtf;
+ int numInUse = 0;
+ {
+ bool inUse[256];
+ bool inUse16[16];
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ inUse[i] = false;
+ for (i = 0; i < 16; i++)
+ inUse16[i] = false;
+ for (i = 0; i < blockSize; i++)
+ inUse[block[i]] = true;
+ for (i = 0; i < 256; i++)
+ if (inUse[i])
+ {
+ inUse16[i >> 4] = true;
+ mtf.Buf[numInUse++] = (Byte)i;
+ }
+ for (i = 0; i < 16; i++)
+ WriteBit2(inUse16[i]);
+ for (i = 0; i < 256; i++)
+ if (inUse16[i >> 4])
+ WriteBit2(inUse[i]);
+ }
+ int alphaSize = numInUse + 2;
+
+ Byte *mtfs = m_MtfArray;
+ UInt32 mtfArraySize = 0;
+ UInt32 symbolCounts[kMaxAlphaSize];
+ {
+ for (int i = 0; i < kMaxAlphaSize; i++)
+ symbolCounts[i] = 0;
+ }
+
+ {
+ UInt32 rleSize = 0;
+ UInt32 i = 0;
+ const UInt32 *bsIndex = m_BlockSorterIndex;
+ block--;
+ do
+ {
+ int pos = mtf.FindAndMove(block[bsIndex[i]]);
+ if (pos == 0)
+ rleSize++;
+ else
+ {
+ while (rleSize != 0)
+ {
+ rleSize--;
+ mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
+ symbolCounts[rleSize & 1]++;
+ rleSize >>= 1;
+ }
+ if (pos >= 0xFE)
+ {
+ mtfs[mtfArraySize++] = 0xFF;
+ mtfs[mtfArraySize++] = (Byte)(pos - 0xFE);
+ }
+ else
+ mtfs[mtfArraySize++] = (Byte)(pos + 1);
+ symbolCounts[pos + 1]++;
+ }
+ }
+ while (++i < blockSize);
+
+ while (rleSize != 0)
+ {
+ rleSize--;
+ mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
+ symbolCounts[rleSize & 1]++;
+ rleSize >>= 1;
+ }
+
+ if (alphaSize < 256)
+ mtfs[mtfArraySize++] = (Byte)(alphaSize - 1);
+ else
+ {
+ mtfs[mtfArraySize++] = 0xFF;
+ mtfs[mtfArraySize++] = (Byte)(alphaSize - 256);
+ }
+ symbolCounts[alphaSize - 1]++;
+ }
+
+ UInt32 numSymbols = 0;
+ {
+ for (int i = 0; i < kMaxAlphaSize; i++)
+ numSymbols += symbolCounts[i];
+ }
+
+ int bestNumTables = kNumTablesMin;
+ UInt32 bestPrice = 0xFFFFFFFF;
+ UInt32 startPos = m_OutStreamCurrent->GetPos();
+ Byte startCurByte = m_OutStreamCurrent->GetCurByte();
+ for (int nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
+ {
+ int numTables;
+
+ if(m_OptimizeNumTables)
+ {
+ m_OutStreamCurrent->SetPos(startPos);
+ m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
+ if (nt <= kNumTablesMax)
+ numTables = nt;
+ else
+ numTables = bestNumTables;
+ }
+ else
+ {
+ if (numSymbols < 200) numTables = 2;
+ else if (numSymbols < 600) numTables = 3;
+ else if (numSymbols < 1200) numTables = 4;
+ else if (numSymbols < 2400) numTables = 5;
+ else numTables = 6;
+ }
+
+ WriteBits2(numTables, kNumTablesBits);
+
+ UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
+ WriteBits2(numSelectors, kNumSelectorsBits);
+
+ {
+ UInt32 remFreq = numSymbols;
+ int gs = 0;
+ int t = numTables;
+ do
+ {
+ UInt32 tFreq = remFreq / t;
+ int ge = gs;
+ UInt32 aFreq = 0;
+ while (aFreq < tFreq) // && ge < alphaSize)
+ aFreq += symbolCounts[ge++];
+
+ if (ge - 1 > gs && t != numTables && t != 1 && (((numTables - t) & 1) == 1))
+ aFreq -= symbolCounts[--ge];
+
+ Byte *lens = Lens[t - 1];
+ int i = 0;
+ do
+ lens[i] = (i >= gs && i < ge) ? 0 : 1;
+ while (++i < alphaSize);
+ gs = ge;
+ remFreq -= aFreq;
+ }
+ while(--t != 0);
+ }
+
+
+ for (int pass = 0; pass < kNumHuffPasses; pass++)
+ {
+ {
+ int t = 0;
+ do
+ memset(Freqs[t], 0, sizeof(Freqs[t]));
+ while(++t < numTables);
+ }
+
+ {
+ UInt32 mtfPos = 0;
+ UInt32 g = 0;
+ do
+ {
+ UInt32 symbols[kGroupSize];
+ int i = 0;
+ do
+ {
+ UInt32 symbol = mtfs[mtfPos++];
+ if (symbol >= 0xFF)
+ symbol += mtfs[mtfPos++];
+ symbols[i] = symbol;
+ }
+ while (++i < kGroupSize && mtfPos < mtfArraySize);
+
+ UInt32 bestPrice = 0xFFFFFFFF;
+ int t = 0;
+ do
+ {
+ const Byte *lens = Lens[t];
+ UInt32 price = 0;
+ int j = 0;
+ do
+ price += lens[symbols[j]];
+ while (++j < i);
+ if (price < bestPrice)
+ {
+ m_Selectors[g] = (Byte)t;
+ bestPrice = price;
+ }
+ }
+ while(++t < numTables);
+ UInt32 *freqs = Freqs[m_Selectors[g++]];
+ int j = 0;
+ do
+ freqs[symbols[j]]++;
+ while (++j < i);
+ }
+ while (mtfPos < mtfArraySize);
+ }
+
+ int t = 0;
+ do
+ {
+ UInt32 *freqs = Freqs[t];
+ int i = 0;
+ do
+ if (freqs[i] == 0)
+ freqs[i] = 1;
+ while(++i < alphaSize);
+ Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding);
+ }
+ while(++t < numTables);
+ }
+
+ {
+ Byte mtfSel[kNumTablesMax];
+ {
+ int t = 0;
+ do
+ mtfSel[t] = (Byte)t;
+ while(++t < numTables);
+ }
+
+ UInt32 i = 0;
+ do
+ {
+ Byte sel = m_Selectors[i];
+ int pos;
+ for (pos = 0; mtfSel[pos] != sel; pos++)
+ WriteBit2(true);
+ WriteBit2(false);
+ for (; pos > 0; pos--)
+ mtfSel[pos] = mtfSel[pos - 1];
+ mtfSel[0] = sel;
+ }
+ while(++i < numSelectors);
+ }
+
+ {
+ int t = 0;
+ do
+ {
+ const Byte *lens = Lens[t];
+ UInt32 len = lens[0];
+ WriteBits2(len, kNumLevelsBits);
+ int i = 0;
+ do
+ {
+ UInt32 level = lens[i];
+ while (len != level)
+ {
+ WriteBit2(true);
+ if (len < level)
+ {
+ WriteBit2(false);
+ len++;
+ }
+ else
+ {
+ WriteBit2(true);
+ len--;
+ }
+ }
+ WriteBit2(false);
+ }
+ while (++i < alphaSize);
+ }
+ while(++t < numTables);
+ }
+
+ {
+ UInt32 groupSize = 0;
+ UInt32 groupIndex = 0;
+ const Byte *lens = 0;
+ const UInt32 *codes = 0;
+ UInt32 mtfPos = 0;
+ do
+ {
+ UInt32 symbol = mtfs[mtfPos++];
+ if (symbol >= 0xFF)
+ symbol += mtfs[mtfPos++];
+ if (groupSize == 0)
+ {
+ groupSize = kGroupSize;
+ int t = m_Selectors[groupIndex++];
+ lens = Lens[t];
+ codes = Codes[t];
+ }
+ groupSize--;
+ m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
+ }
+ while (mtfPos < mtfArraySize);
+ }
+
+ if (!m_OptimizeNumTables)
+ break;
+ UInt32 price = m_OutStreamCurrent->GetPos() - startPos;
+ if (price <= bestPrice)
+ {
+ if (nt == kNumTablesMax)
+ break;
+ bestPrice = price;
+ bestNumTables = nt;
+ }
+ }
+}
+
+// blockSize > 0
+UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
+{
+ WriteByte2(kBlockSig0);
+ WriteByte2(kBlockSig1);
+ WriteByte2(kBlockSig2);
+ WriteByte2(kBlockSig3);
+ WriteByte2(kBlockSig4);
+ WriteByte2(kBlockSig5);
+
+ CBZip2Crc crc;
+ int numReps = 0;
+ Byte prevByte = block[0];
+ UInt32 i = 0;
+ do
+ {
+ Byte b = block[i];
+ if (numReps == kRleModeRepSize)
+ {
+ for (; b > 0; b--)
+ crc.UpdateByte(prevByte);
+ numReps = 0;
+ continue;
+ }
+ if (prevByte == b)
+ numReps++;
+ else
+ {
+ numReps = 1;
+ prevByte = b;
+ }
+ crc.UpdateByte(b);
+ }
+ while (++i < blockSize);
+ UInt32 crcRes = crc.GetDigest();
+ WriteCrc2(crcRes);
+ EncodeBlock(block, blockSize);
+ return crcRes;
+}
+
+void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
+{
+ UInt32 numCrcs = m_NumCrcs;
+ bool needCompare = false;
+
+ UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();
+ UInt32 startPos = m_OutStreamCurrent->GetPos();
+ Byte startCurByte = m_OutStreamCurrent->GetCurByte();
+ Byte endCurByte = 0;
+ UInt32 endPos = 0;
+ if (numPasses > 1 && blockSize >= (1 << 10))
+ {
+ UInt32 blockSize0 = blockSize / 2;
+ for (;(block[blockSize0] == block[blockSize0 - 1] ||
+ block[blockSize0 - 1] == block[blockSize0 - 2]) &&
+ blockSize0 < blockSize; blockSize0++);
+ if (blockSize0 < blockSize)
+ {
+ EncodeBlock2(block, blockSize0, numPasses - 1);
+ EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);
+ endPos = m_OutStreamCurrent->GetPos();
+ endCurByte = m_OutStreamCurrent->GetCurByte();
+ if ((endPos & 7) > 0)
+ WriteBits2(0, 8 - (endPos & 7));
+ m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
+ needCompare = true;
+ }
+ }
+
+ UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos();
+ UInt32 startPos2 = m_OutStreamCurrent->GetPos();
+ UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
+ UInt32 endPos2 = m_OutStreamCurrent->GetPos();
+
+ if (needCompare)
+ {
+ UInt32 size2 = endPos2 - startPos2;
+ if (size2 < endPos - startPos)
+ {
+ UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;
+ Byte *buffer = m_OutStreamCurrent->GetStream();
+ for (UInt32 i = 0; i < numBytes; i++)
+ buffer[startBytePos + i] = buffer[startBytePos2 + i];
+ m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
+ m_NumCrcs = numCrcs;
+ m_CRCs[m_NumCrcs++] = crcVal;
+ }
+ else
+ {
+ m_OutStreamCurrent->SetPos(endPos);
+ m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);
+ }
+ }
+ else
+ {
+ m_NumCrcs = numCrcs;
+ m_CRCs[m_NumCrcs++] = crcVal;
+ }
+}
+
+HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
+{
+ CMsbfEncoderTemp outStreamTemp;
+ outStreamTemp.SetStream(m_TempArray);
+ outStreamTemp.Init();
+ m_OutStreamCurrent = &outStreamTemp;
+
+ m_NumCrcs = 0;
+
+ EncodeBlock2(m_Block, blockSize, Encoder->NumPasses);
+
+ #ifndef _7ZIP_ST
+ if (Encoder->MtMode)
+ Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
+ #endif
+ for (UInt32 i = 0; i < m_NumCrcs; i++)
+ Encoder->CombinedCrc.Update(m_CRCs[i]);
+ Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());
+ HRESULT res = S_OK;
+ #ifndef _7ZIP_ST
+ if (Encoder->MtMode)
+ {
+ UInt32 blockIndex = m_BlockIndex + 1;
+ if (blockIndex == Encoder->NumThreads)
+ blockIndex = 0;
+
+ if (Encoder->Progress)
+ {
+ UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize();
+ res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize);
+ }
+
+ Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
+ }
+ #endif
+ return res;
+}
+
+void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
+{
+ UInt32 bytesSize = (sizeInBits / 8);
+ for (UInt32 i = 0; i < bytesSize; i++)
+ m_OutStream.WriteBits(data[i], 8);
+ WriteBits(lastByte, (sizeInBits & 7));
+}
+
+
+HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ #ifndef _7ZIP_ST
+ Progress = progress;
+ RINOK(Create());
+ for (UInt32 t = 0; t < NumThreads; t++)
+ #endif
+ {
+ #ifndef _7ZIP_ST
+ CThreadInfo &ti = ThreadsInfo[t];
+ if (MtMode)
+ {
+ RINOK(ti.StreamWasFinishedEvent.Reset());
+ RINOK(ti.WaitingWasStartedEvent.Reset());
+ RINOK(ti.CanWriteEvent.Reset());
+ }
+ #else
+ CThreadInfo &ti = ThreadsInfo;
+ ti.Encoder = this;
+ #endif
+
+ ti.m_OptimizeNumTables = m_OptimizeNumTables;
+
+ if (!ti.Alloc())
+ return E_OUTOFMEMORY;
+ }
+
+
+ if (!m_InStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (!m_OutStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+
+
+ m_InStream.SetStream(inStream);
+ m_InStream.Init();
+
+ m_OutStream.SetStream(outStream);
+ m_OutStream.Init();
+
+ CFlusher flusher(this);
+
+ CombinedCrc.Init();
+ #ifndef _7ZIP_ST
+ NextBlockIndex = 0;
+ StreamWasFinished = false;
+ CloseThreads = false;
+ CanStartWaitingEvent.Reset();
+ #endif
+
+ WriteByte(kArSig0);
+ WriteByte(kArSig1);
+ WriteByte(kArSig2);
+ WriteByte((Byte)(kArSig3 + m_BlockSizeMult));
+
+ #ifndef _7ZIP_ST
+
+ if (MtMode)
+ {
+ ThreadsInfo[0].CanWriteEvent.Set();
+ Result = S_OK;
+ CanProcessEvent.Set();
+ UInt32 t;
+ for (t = 0; t < NumThreads; t++)
+ ThreadsInfo[t].StreamWasFinishedEvent.Lock();
+ CanProcessEvent.Reset();
+ CanStartWaitingEvent.Set();
+ for (t = 0; t < NumThreads; t++)
+ ThreadsInfo[t].WaitingWasStartedEvent.Lock();
+ CanStartWaitingEvent.Reset();
+ RINOK(Result);
+ }
+ else
+ #endif
+ {
+ for (;;)
+ {
+ CThreadInfo &ti =
+ #ifndef _7ZIP_ST
+ ThreadsInfo[0];
+ #else
+ ThreadsInfo;
+ #endif
+ UInt32 blockSize = ReadRleBlock(ti.m_Block);
+ if (blockSize == 0)
+ break;
+ RINOK(ti.EncodeBlock3(blockSize));
+ if (progress)
+ {
+ UInt64 packSize = m_InStream.GetProcessedSize();
+ UInt64 unpackSize = m_OutStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
+ }
+ }
+ }
+ WriteByte(kFinSig0);
+ WriteByte(kFinSig1);
+ WriteByte(kFinSig2);
+ WriteByte(kFinSig3);
+ WriteByte(kFinSig4);
+ WriteByte(kFinSig5);
+
+ WriteCrc(CombinedCrc.GetDigest());
+ return Flush();
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ for(UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kNumPasses:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 numPasses = prop.ulVal;
+ if (numPasses == 0)
+ numPasses = 1;
+ if (numPasses > kNumPassesMax)
+ numPasses = kNumPassesMax;
+ NumPasses = numPasses;
+ m_OptimizeNumTables = (NumPasses > 1);
+ break;
+ }
+ case NCoderPropID::kDictionarySize:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 dictionary = prop.ulVal / kBlockSizeStep;
+ if (dictionary < kBlockSizeMultMin)
+ dictionary = kBlockSizeMultMin;
+ else if (dictionary > kBlockSizeMultMax)
+ dictionary = kBlockSizeMultMax;
+ m_BlockSizeMult = dictionary;
+ break;
+ }
+ case NCoderPropID::kNumThreads:
+ {
+ #ifndef _7ZIP_ST
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ NumThreads = prop.ulVal;
+ if (NumThreads < 1)
+ NumThreads = 1;
+ #endif
+ break;
+ }
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+#ifndef _7ZIP_ST
+STDMETHODIMP CEncoder::SetNumberOfThreads(UInt32 numThreads)
+{
+ NumThreads = numThreads;
+ if (NumThreads < 1)
+ NumThreads = 1;
+ return S_OK;
+}
+#endif
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Encoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Encoder.h
new file mode 100644
index 000000000..a863172fe
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Encoder.h
@@ -0,0 +1,245 @@
+// BZip2Encoder.h
+
+#ifndef __COMPRESS_BZIP2_ENCODER_H
+#define __COMPRESS_BZIP2_ENCODER_H
+
+#include "../../Common/Defs.h"
+#include "../../Common/MyCom.h"
+
+#ifndef _7ZIP_ST
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+#endif
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "BitmEncoder.h"
+#include "BZip2Const.h"
+#include "BZip2Crc.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+class CMsbfEncoderTemp
+{
+ UInt32 m_Pos;
+ int m_BitPos;
+ Byte m_CurByte;
+ Byte *Buffer;
+public:
+ void SetStream(Byte *buffer) { Buffer = buffer; }
+ Byte *GetStream() const { return Buffer; }
+
+ void Init()
+ {
+ m_Pos = 0;
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+
+ void Flush()
+ {
+ if (m_BitPos < 8)
+ WriteBits(0, m_BitPos);
+ }
+
+ void WriteBits(UInt32 value, int numBits)
+ {
+ while (numBits > 0)
+ {
+ int numNewBits = MyMin(numBits, m_BitPos);
+ numBits -= numNewBits;
+
+ m_CurByte <<= numNewBits;
+ UInt32 newBits = value >> numBits;
+ m_CurByte |= Byte(newBits);
+ value -= (newBits << numBits);
+
+ m_BitPos -= numNewBits;
+
+ if (m_BitPos == 0)
+ {
+ Buffer[m_Pos++] = m_CurByte;
+ m_BitPos = 8;
+ }
+ }
+ }
+
+ UInt32 GetBytePos() const { return m_Pos ; }
+ UInt32 GetPos() const { return m_Pos * 8 + (8 - m_BitPos); }
+ Byte GetCurByte() const { return m_CurByte; }
+ void SetPos(UInt32 bitPos)
+ {
+ m_Pos = bitPos / 8;
+ m_BitPos = 8 - ((int)bitPos & 7);
+ }
+ void SetCurState(int bitPos, Byte curByte)
+ {
+ m_BitPos = 8 - bitPos;
+ m_CurByte = curByte;
+ }
+};
+
+class CEncoder;
+
+const int kNumPassesMax = 10;
+
+class CThreadInfo
+{
+public:
+ Byte *m_Block;
+private:
+ Byte *m_MtfArray;
+ Byte *m_TempArray;
+ UInt32 *m_BlockSorterIndex;
+
+ CMsbfEncoderTemp *m_OutStreamCurrent;
+
+ Byte Lens[kNumTablesMax][kMaxAlphaSize];
+ UInt32 Freqs[kNumTablesMax][kMaxAlphaSize];
+ UInt32 Codes[kNumTablesMax][kMaxAlphaSize];
+
+ Byte m_Selectors[kNumSelectorsMax];
+
+ UInt32 m_CRCs[1 << kNumPassesMax];
+ UInt32 m_NumCrcs;
+
+ UInt32 m_BlockIndex;
+
+ void WriteBits2(UInt32 value, UInt32 numBits);
+ void WriteByte2(Byte b);
+ void WriteBit2(bool v);
+ void WriteCrc2(UInt32 v);
+
+ void EncodeBlock(const Byte *block, UInt32 blockSize);
+ UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize);
+ void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses);
+public:
+ bool m_OptimizeNumTables;
+ CEncoder *Encoder;
+ #ifndef _7ZIP_ST
+ NWindows::CThread Thread;
+
+ NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
+ NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
+
+ // it's not member of this thread. We just need one event per thread
+ NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
+
+ UInt64 m_PackSize;
+
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+ HRESULT Create();
+ void FinishStream(bool needLeave);
+ DWORD ThreadFunc();
+ #endif
+
+ CThreadInfo(): m_BlockSorterIndex(0), m_Block(0) {}
+ ~CThreadInfo() { Free(); }
+ bool Alloc();
+ void Free();
+
+ HRESULT EncodeBlock3(UInt32 blockSize);
+};
+
+class CEncoder :
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ #ifndef _7ZIP_ST
+ public ICompressSetCoderMt,
+ #endif
+ public CMyUnknownImp
+{
+ UInt32 m_BlockSizeMult;
+ bool m_OptimizeNumTables;
+
+ UInt32 m_NumPassesPrev;
+
+ UInt32 m_NumThreadsPrev;
+public:
+ CInBuffer m_InStream;
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+ CBitmEncoder<COutBuffer> m_OutStream;
+ UInt32 NumPasses;
+ CBZip2CombinedCrc CombinedCrc;
+
+ #ifndef _7ZIP_ST
+ CThreadInfo *ThreadsInfo;
+ NWindows::NSynchronization::CManualResetEvent CanProcessEvent;
+ NWindows::NSynchronization::CCriticalSection CS;
+ UInt32 NumThreads;
+ bool MtMode;
+ UInt32 NextBlockIndex;
+
+ bool CloseThreads;
+ bool StreamWasFinished;
+ NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
+
+ HRESULT Result;
+ ICompressProgressInfo *Progress;
+ #else
+ CThreadInfo ThreadsInfo;
+ #endif
+
+ UInt32 ReadRleBlock(Byte *buffer);
+ void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte);
+
+ void WriteBits(UInt32 value, UInt32 numBits);
+ void WriteByte(Byte b);
+ void WriteBit(bool v);
+ void WriteCrc(UInt32 v);
+
+ #ifndef _7ZIP_ST
+ HRESULT Create();
+ void Free();
+ #endif
+
+public:
+ CEncoder();
+ #ifndef _7ZIP_ST
+ ~CEncoder();
+ #endif
+
+ HRESULT Flush() { return m_OutStream.Flush(); }
+
+ void ReleaseStreams()
+ {
+ m_InStream.ReleaseStream();
+ m_OutStream.ReleaseStream();
+ }
+
+ class CFlusher
+ {
+ CEncoder *_coder;
+ public:
+ CFlusher(CEncoder *coder): _coder(coder) {}
+ ~CFlusher()
+ {
+ _coder->ReleaseStreams();
+ }
+ };
+
+ #ifndef _7ZIP_ST
+ MY_UNKNOWN_IMP2(ICompressSetCoderMt, ICompressSetCoderProperties)
+ #else
+ MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
+ #endif
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+
+ #ifndef _7ZIP_ST
+ STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
+ #endif
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Register.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Register.cpp
new file mode 100644
index 000000000..ef14204b0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BZip2Register.cpp
@@ -0,0 +1,20 @@
+// BZip2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BZip2Decoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NBZip2::CDecoder); }
+#if !defined(EXTRACT_ONLY) && !defined(BZIP2_EXTRACT_ONLY)
+#include "BZip2Encoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NBZip2::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x040202, L"BZip2", 1, false };
+
+REGISTER_CODEC(BZip2)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp
new file mode 100644
index 000000000..684da5abf
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.cpp
@@ -0,0 +1,386 @@
+// Bcj2Coder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "Bcj2Coder.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); }
+inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); }
+inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); }
+
+#ifndef EXTRACT_ONLY
+
+static const int kBufferSize = 1 << 17;
+
+static bool inline Test86MSByte(Byte b)
+{
+ return (b == 0 || b == 0xFF);
+}
+
+bool CEncoder::Create()
+{
+ if (!_mainStream.Create(1 << 18))
+ return false;
+ if (!_callStream.Create(1 << 18))
+ return false;
+ if (!_jumpStream.Create(1 << 18))
+ return false;
+ if (!_rangeEncoder.Create(1 << 20))
+ return false;
+ if (_buffer == 0)
+ {
+ _buffer = (Byte *)MidAlloc(kBufferSize);
+ if (_buffer == 0)
+ return false;
+ }
+ return true;
+}
+
+CEncoder::~CEncoder()
+{
+ ::MidFree(_buffer);
+}
+
+HRESULT CEncoder::Flush()
+{
+ RINOK(_mainStream.Flush());
+ RINOK(_callStream.Flush());
+ RINOK(_jumpStream.Flush());
+ _rangeEncoder.FlushData();
+ return _rangeEncoder.FlushStream();
+}
+
+const UInt32 kDefaultLimit = (1 << 24);
+
+HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 1 || numOutStreams != 4)
+ return E_INVALIDARG;
+
+ if (!Create())
+ return E_OUTOFMEMORY;
+
+ bool sizeIsDefined = false;
+ UInt64 inSize = 0;
+ if (inSizes != NULL)
+ if (inSizes[0] != NULL)
+ {
+ inSize = *inSizes[0];
+ if (inSize <= kDefaultLimit)
+ sizeIsDefined = true;
+ }
+
+ CCoderReleaser releaser(this);
+
+ ISequentialInStream *inStream = inStreams[0];
+
+ _mainStream.SetStream(outStreams[0]);
+ _mainStream.Init();
+ _callStream.SetStream(outStreams[1]);
+ _callStream.Init();
+ _jumpStream.SetStream(outStreams[2]);
+ _jumpStream.Init();
+ _rangeEncoder.SetStream(outStreams[3]);
+ _rangeEncoder.Init();
+ for (int i = 0; i < 256 + 2; i++)
+ _statusEncoder[i].Init();
+
+ CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
+ {
+ inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
+ }
+
+ UInt32 nowPos = 0;
+ UInt64 nowPos64 = 0;
+ UInt32 bufferPos = 0;
+
+ Byte prevByte = 0;
+
+ UInt64 subStreamIndex = 0;
+ UInt64 subStreamStartPos = 0;
+ UInt64 subStreamEndPos = 0;
+
+ for (;;)
+ {
+ UInt32 processedSize = 0;
+ for (;;)
+ {
+ UInt32 size = kBufferSize - (bufferPos + processedSize);
+ UInt32 processedSizeLoc;
+ if (size == 0)
+ break;
+ RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc));
+ if (processedSizeLoc == 0)
+ break;
+ processedSize += processedSizeLoc;
+ }
+ UInt32 endPos = bufferPos + processedSize;
+
+ if (endPos < 5)
+ {
+ // change it
+ for (bufferPos = 0; bufferPos < endPos; bufferPos++)
+ {
+ Byte b = _buffer[bufferPos];
+ _mainStream.WriteByte(b);
+ UInt32 index;
+ if (b == 0xE8)
+ index = prevByte;
+ else if (b == 0xE9)
+ index = 256;
+ else if (IsJcc(prevByte, b))
+ index = 257;
+ else
+ {
+ prevByte = b;
+ continue;
+ }
+ _statusEncoder[index].Encode(&_rangeEncoder, 0);
+ prevByte = b;
+ }
+ return Flush();
+ }
+
+ bufferPos = 0;
+
+ UInt32 limit = endPos - 5;
+ while(bufferPos <= limit)
+ {
+ Byte b = _buffer[bufferPos];
+ _mainStream.WriteByte(b);
+ if (!IsJ(prevByte, b))
+ {
+ bufferPos++;
+ prevByte = b;
+ continue;
+ }
+ Byte nextByte = _buffer[bufferPos + 4];
+ UInt32 src =
+ (UInt32(nextByte) << 24) |
+ (UInt32(_buffer[bufferPos + 3]) << 16) |
+ (UInt32(_buffer[bufferPos + 2]) << 8) |
+ (_buffer[bufferPos + 1]);
+ UInt32 dest = (nowPos + bufferPos + 5) + src;
+ // if (Test86MSByte(nextByte))
+ bool convert;
+ if (getSubStreamSize != NULL)
+ {
+ UInt64 currentPos = (nowPos64 + bufferPos);
+ while (subStreamEndPos < currentPos)
+ {
+ UInt64 subStreamSize;
+ HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
+ if (result == S_OK)
+ {
+ subStreamStartPos = subStreamEndPos;
+ subStreamEndPos += subStreamSize;
+ subStreamIndex++;
+ }
+ else if (result == S_FALSE || result == E_NOTIMPL)
+ {
+ getSubStreamSize.Release();
+ subStreamStartPos = 0;
+ subStreamEndPos = subStreamStartPos - 1;
+ }
+ else
+ return result;
+ }
+ if (getSubStreamSize == NULL)
+ {
+ if (sizeIsDefined)
+ convert = (dest < inSize);
+ else
+ convert = Test86MSByte(nextByte);
+ }
+ else if (subStreamEndPos - subStreamStartPos > kDefaultLimit)
+ convert = Test86MSByte(nextByte);
+ else
+ {
+ UInt64 dest64 = (currentPos + 5) + Int64(Int32(src));
+ convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos);
+ }
+ }
+ else if (sizeIsDefined)
+ convert = (dest < inSize);
+ else
+ convert = Test86MSByte(nextByte);
+ unsigned index = GetIndex(prevByte, b);
+ if (convert)
+ {
+ _statusEncoder[index].Encode(&_rangeEncoder, 1);
+ bufferPos += 5;
+ COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
+ for (int i = 24; i >= 0; i -= 8)
+ s.WriteByte((Byte)(dest >> i));
+ prevByte = nextByte;
+ }
+ else
+ {
+ _statusEncoder[index].Encode(&_rangeEncoder, 0);
+ bufferPos++;
+ prevByte = b;
+ }
+ }
+ nowPos += bufferPos;
+ nowPos64 += bufferPos;
+
+ if (progress != NULL)
+ {
+ /*
+ const UInt64 compressedSize =
+ _mainStream.GetProcessedSize() +
+ _callStream.GetProcessedSize() +
+ _jumpStream.GetProcessedSize() +
+ _rangeEncoder.GetProcessedSize();
+ */
+ RINOK(progress->SetRatioInfo(&nowPos64, NULL));
+ }
+
+ UInt32 i = 0;
+ while(bufferPos < endPos)
+ _buffer[i++] = _buffer[bufferPos++];
+ bufferPos = i;
+ }
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+#endif
+
+
+STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _inBufSizes[streamIndex] = size; return S_OK; }
+STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
+
+CDecoder::CDecoder():
+ _outBufSize(1 << 16)
+{
+ _inBufSizes[0] = 1 << 20;
+ _inBufSizes[1] = 1 << 20;
+ _inBufSizes[2] = 1 << 20;
+ _inBufSizes[3] = 1 << 20;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 4 || numOutStreams != 1)
+ return E_INVALIDARG;
+
+ if (!_mainInStream.Create(_inBufSizes[0]))
+ return E_OUTOFMEMORY;
+ if (!_callStream.Create(_inBufSizes[1]))
+ return E_OUTOFMEMORY;
+ if (!_jumpStream.Create(_inBufSizes[2]))
+ return E_OUTOFMEMORY;
+ if (!_rangeDecoder.Create(_inBufSizes[3]))
+ return E_OUTOFMEMORY;
+ if (!_outStream.Create(_outBufSize))
+ return E_OUTOFMEMORY;
+
+ CCoderReleaser releaser(this);
+
+ _mainInStream.SetStream(inStreams[0]);
+ _callStream.SetStream(inStreams[1]);
+ _jumpStream.SetStream(inStreams[2]);
+ _rangeDecoder.SetStream(inStreams[3]);
+ _outStream.SetStream(outStreams[0]);
+
+ _mainInStream.Init();
+ _callStream.Init();
+ _jumpStream.Init();
+ _rangeDecoder.Init();
+ _outStream.Init();
+
+ for (int i = 0; i < 256 + 2; i++)
+ _statusDecoder[i].Init();
+
+ Byte prevByte = 0;
+ UInt32 processedBytes = 0;
+ for (;;)
+ {
+ if (processedBytes >= (1 << 20) && progress != NULL)
+ {
+ /*
+ const UInt64 compressedSize =
+ _mainInStream.GetProcessedSize() +
+ _callStream.GetProcessedSize() +
+ _jumpStream.GetProcessedSize() +
+ _rangeDecoder.GetProcessedSize();
+ */
+ const UInt64 nowPos64 = _outStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(NULL, &nowPos64));
+ processedBytes = 0;
+ }
+ UInt32 i;
+ Byte b = 0;
+ const UInt32 kBurstSize = (1 << 18);
+ for (i = 0; i < kBurstSize; i++)
+ {
+ if (!_mainInStream.ReadByte(b))
+ return Flush();
+ _outStream.WriteByte(b);
+ if (IsJ(prevByte, b))
+ break;
+ prevByte = b;
+ }
+ processedBytes += i;
+ if (i == kBurstSize)
+ continue;
+ unsigned index = GetIndex(prevByte, b);
+ if (_statusDecoder[index].Decode(&_rangeDecoder) == 1)
+ {
+ UInt32 src = 0;
+ CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b0;
+ if(!s.ReadByte(b0))
+ return S_FALSE;
+ src <<= 8;
+ src |= ((UInt32)b0);
+ }
+ UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ;
+ _outStream.WriteByte((Byte)(dest));
+ _outStream.WriteByte((Byte)(dest >> 8));
+ _outStream.WriteByte((Byte)(dest >> 16));
+ _outStream.WriteByte((Byte)(dest >> 24));
+ prevByte = (Byte)(dest >> 24);
+ processedBytes += 4;
+ }
+ else
+ prevByte = b;
+ }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.h b/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.h
new file mode 100644
index 000000000..79a713f17
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Coder.h
@@ -0,0 +1,115 @@
+// Bcj2Coder.h
+
+#ifndef __COMPRESS_BCJ2_CODER_H
+#define __COMPRESS_BCJ2_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "RangeCoderBit.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+const int kNumMoveBits = 5;
+
+#ifndef EXTRACT_ONLY
+
+class CEncoder:
+ public ICompressCoder2,
+ public CMyUnknownImp
+{
+ Byte *_buffer;
+ bool Create();
+
+ COutBuffer _mainStream;
+ COutBuffer _callStream;
+ COutBuffer _jumpStream;
+ NCompress::NRangeCoder::CEncoder _rangeEncoder;
+ NCompress::NRangeCoder::CBitEncoder<kNumMoveBits> _statusEncoder[256 + 2];
+
+ HRESULT Flush();
+public:
+ void ReleaseStreams()
+ {
+ _mainStream.ReleaseStream();
+ _callStream.ReleaseStream();
+ _jumpStream.ReleaseStream();
+ _rangeEncoder.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CEncoder *_coder;
+ public:
+ CCoderReleaser(CEncoder *coder): _coder(coder) {}
+ ~CCoderReleaser() { _coder->ReleaseStreams(); }
+ };
+
+public:
+ MY_UNKNOWN_IMP
+
+ HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ CEncoder(): _buffer(0) {};
+ ~CEncoder();
+};
+
+#endif
+
+class CDecoder:
+ public ICompressCoder2,
+ public ICompressSetBufSize,
+ public CMyUnknownImp
+{
+ CInBuffer _mainInStream;
+ CInBuffer _callStream;
+ CInBuffer _jumpStream;
+ NCompress::NRangeCoder::CDecoder _rangeDecoder;
+ NCompress::NRangeCoder::CBitDecoder<kNumMoveBits> _statusDecoder[256 + 2];
+
+ COutBuffer _outStream;
+ UInt32 _inBufSizes[4];
+ UInt32 _outBufSize;
+
+public:
+ void ReleaseStreams()
+ {
+ _mainInStream.ReleaseStream();
+ _callStream.ReleaseStream();
+ _jumpStream.ReleaseStream();
+ _rangeDecoder.ReleaseStream();
+ _outStream.ReleaseStream();
+ }
+
+ HRESULT Flush() { return _outStream.Flush(); }
+ class CCoderReleaser
+ {
+ CDecoder *_coder;
+ public:
+ CCoderReleaser(CDecoder *coder): _coder(coder) {}
+ ~CCoderReleaser() { _coder->ReleaseStreams(); }
+ };
+
+public:
+ MY_UNKNOWN_IMP1(ICompressSetBufSize);
+ HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
+ CDecoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Register.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Register.cpp
new file mode 100644
index 000000000..8eb1e7360
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Bcj2Register.cpp
@@ -0,0 +1,19 @@
+// Bcj2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Bcj2Coder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CDecoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CEncoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x0303011B, L"BCJ2", 4, false };
+
+REGISTER_CODEC(BCJ2)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.cpp
new file mode 100644
index 000000000..0e34ef488
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.cpp
@@ -0,0 +1,15 @@
+// BcjCoder.cpp
+
+#include "StdAfx.h"
+
+#include "BcjCoder.h"
+
+UInt32 CBCJ_x86_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 1);
+}
+
+UInt32 CBCJ_x86_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 0);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.h
new file mode 100644
index 000000000..0754bcd23
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BcjCoder.h
@@ -0,0 +1,19 @@
+// BcjCoder.h
+
+#ifndef __COMPRESS_BCJ_CODER_H
+#define __COMPRESS_BCJ_CODER_H
+
+#include "../../../C/Bra.h"
+
+#include "BranchCoder.h"
+
+struct CBranch86
+{
+ UInt32 _prevMask;
+ void x86Init() { x86_Convert_Init(_prevMask); }
+};
+
+MyClassB(BCJ_x86, 0x01, 3, CBranch86 ,
+ virtual void SubInit() { x86Init(); })
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BcjRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BcjRegister.cpp
new file mode 100644
index 000000000..648ad8e03
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BcjRegister.cpp
@@ -0,0 +1,19 @@
+// BcjRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BcjCoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressFilter *)(new CBCJ_x86_Decoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new CBCJ_x86_Encoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x03030103, L"BCJ", 1, true };
+
+REGISTER_CODEC(BCJ)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BitlDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BitlDecoder.cpp
new file mode 100644
index 000000000..78665be8f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BitlDecoder.cpp
@@ -0,0 +1,24 @@
+// BitlDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "BitlDecoder.h"
+
+namespace NBitl {
+
+Byte kInvertTable[256];
+
+struct CInverterTableInitializer
+{
+ CInverterTableInitializer()
+ {
+ for (int i = 0; i < 256; i++)
+ {
+ int x = ((i & 0x55) << 1) | ((i & 0xAA) >> 1);
+ x = ((x & 0x33) << 2) | ((x & 0xCC) >> 2);
+ kInvertTable[i] = (Byte)(((x & 0x0F) << 4) | ((x & 0xF0) >> 4));
+ }
+ }
+} g_InverterTableInitializer;
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BitlDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/BitlDecoder.h
new file mode 100644
index 000000000..ff373bac6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BitlDecoder.h
@@ -0,0 +1,141 @@
+// BitlDecoder.h -- the Least Significant Bit of byte is First
+
+#ifndef __BITL_DECODER_H
+#define __BITL_DECODER_H
+
+#include "../IStream.h"
+
+namespace NBitl {
+
+const unsigned kNumBigValueBits = 8 * 4;
+const unsigned kNumValueBytes = 3;
+const unsigned kNumValueBits = 8 * kNumValueBytes;
+
+const UInt32 kMask = (1 << kNumValueBits) - 1;
+
+extern Byte kInvertTable[256];
+
+template<class TInByte>
+class CBaseDecoder
+{
+protected:
+ unsigned m_BitPos;
+ UInt32 m_Value;
+ TInByte m_Stream;
+public:
+ UInt32 NumExtraBytes;
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream); }
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = kNumBigValueBits;
+ m_Value = 0;
+ NumExtraBytes = 0;
+ }
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() + NumExtraBytes - (kNumBigValueBits - m_BitPos) / 8; }
+
+ void Normalize()
+ {
+ for (; m_BitPos >= 8; m_BitPos -= 8)
+ {
+ Byte b = 0;
+ if (!m_Stream.ReadByte(b))
+ {
+ b = 0xFF; // check it
+ NumExtraBytes++;
+ }
+ m_Value = (b << (kNumBigValueBits - m_BitPos)) | m_Value;
+ }
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ Normalize();
+ UInt32 res = m_Value & ((1 << numBits) - 1);
+ m_BitPos += numBits;
+ m_Value >>= numBits;
+ return res;
+ }
+
+ bool ExtraBitsWereRead() const
+ {
+ if (NumExtraBytes == 0)
+ return false;
+ return ((UInt32)(kNumBigValueBits - m_BitPos) < (NumExtraBytes << 3));
+ }
+};
+
+template<class TInByte>
+class CDecoder: public CBaseDecoder<TInByte>
+{
+ UInt32 m_NormalValue;
+
+public:
+ void Init()
+ {
+ CBaseDecoder<TInByte>::Init();
+ m_NormalValue = 0;
+ }
+
+ void Normalize()
+ {
+ for (; this->m_BitPos >= 8; this->m_BitPos -= 8)
+ {
+ Byte b = 0;
+ if (!this->m_Stream.ReadByte(b))
+ {
+ b = 0xFF; // check it
+ this->NumExtraBytes++;
+ }
+ m_NormalValue = (b << (kNumBigValueBits - this->m_BitPos)) | m_NormalValue;
+ this->m_Value = (this->m_Value << 8) | kInvertTable[b];
+ }
+ }
+
+ UInt32 GetValue(unsigned numBits)
+ {
+ Normalize();
+ return ((this->m_Value >> (8 - this->m_BitPos)) & kMask) >> (kNumValueBits - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ this->m_BitPos += numBits;
+ m_NormalValue >>= numBits;
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ Normalize();
+ UInt32 res = m_NormalValue & ((1 << numBits) - 1);
+ MovePos(numBits);
+ return res;
+ }
+
+ void AlignToByte() { MovePos((32 - this->m_BitPos) & 7); }
+
+ Byte ReadByte()
+ {
+ if (this->m_BitPos == kNumBigValueBits)
+ {
+ Byte b = 0;
+ if (!this->m_Stream.ReadByte(b))
+ {
+ b = 0xFF;
+ this->NumExtraBytes++;
+ }
+ return b;
+ }
+ {
+ Byte b = (Byte)(m_NormalValue & 0xFF);
+ MovePos(8);
+ return b;
+ }
+ }
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BitlEncoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/BitlEncoder.h
new file mode 100644
index 000000000..7de575456
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BitlEncoder.h
@@ -0,0 +1,57 @@
+// BitlEncoder.h -- the Least Significant Bit of byte is First
+
+#ifndef __BITL_ENCODER_H
+#define __BITL_ENCODER_H
+
+#include "../Common/OutBuffer.h"
+
+class CBitlEncoder
+{
+ COutBuffer m_Stream;
+ unsigned m_BitPos;
+ Byte m_CurByte;
+public:
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialOutStream *outStream) { m_Stream.SetStream(outStream); }
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+ UInt32 GetBitPosition() const { return (8 - m_BitPos); }
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() + (8 - m_BitPos + 7) /8; }
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ HRESULT Flush()
+ {
+ FlushByte();
+ return m_Stream.Flush();
+ }
+ void FlushByte()
+ {
+ if (m_BitPos < 8)
+ m_Stream.WriteByte(m_CurByte);
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ void WriteBits(UInt32 value, unsigned numBits)
+ {
+ while (numBits > 0)
+ {
+ if (numBits < m_BitPos)
+ {
+ m_CurByte |= (value & ((1 << numBits) - 1)) << (8 - m_BitPos);
+ m_BitPos -= numBits;
+ return;
+ }
+ numBits -= m_BitPos;
+ m_Stream.WriteByte((Byte)(m_CurByte | (value << (8 - m_BitPos))));
+ value >>= m_BitPos;
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ }
+ void WriteByte(Byte b) { m_Stream.WriteByte(b);}
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BitmDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/BitmDecoder.h
new file mode 100644
index 000000000..4369b4524
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BitmDecoder.h
@@ -0,0 +1,66 @@
+// BitmDecoder.h -- the Most Significant Bit of byte is First
+
+#ifndef __BITM_DECODER_H
+#define __BITM_DECODER_H
+
+#include "../IStream.h"
+
+namespace NBitm {
+
+const unsigned kNumBigValueBits = 8 * 4;
+const unsigned kNumValueBytes = 3;
+const unsigned kNumValueBits = 8 * kNumValueBytes;
+
+const UInt32 kMask = (1 << kNumValueBits) - 1;
+
+template<class TInByte>
+class CDecoder
+{
+ unsigned m_BitPos;
+ UInt32 m_Value;
+public:
+ TInByte m_Stream;
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);}
+ void ReleaseStream() { m_Stream.ReleaseStream();}
+
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = kNumBigValueBits;
+ Normalize();
+ }
+
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - (kNumBigValueBits - m_BitPos) / 8; }
+
+ void Normalize()
+ {
+ for (;m_BitPos >= 8; m_BitPos -= 8)
+ m_Value = (m_Value << 8) | m_Stream.ReadByte();
+ }
+
+ UInt32 GetValue(unsigned numBits) const
+ {
+ // return (m_Value << m_BitPos) >> (kNumBigValueBits - numBits);
+ return ((m_Value >> (8 - m_BitPos)) & kMask) >> (kNumValueBits - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ m_BitPos += numBits;
+ Normalize();
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ MovePos(numBits);
+ return res;
+ }
+
+ void AlignToByte() { MovePos((32 - m_BitPos) & 7); }
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BitmEncoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/BitmEncoder.h
new file mode 100644
index 000000000..a85dbff89
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BitmEncoder.h
@@ -0,0 +1,50 @@
+// BitmEncoder.h -- the Most Significant Bit of byte is First
+
+#ifndef __BITM_ENCODER_H
+#define __BITM_ENCODER_H
+
+#include "../IStream.h"
+
+template<class TOutByte>
+class CBitmEncoder
+{
+ TOutByte m_Stream;
+ unsigned m_BitPos;
+ Byte m_CurByte;
+public:
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialOutStream *outStream) { m_Stream.SetStream(outStream);}
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() + (8 - m_BitPos + 7) / 8; }
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ HRESULT Flush()
+ {
+ if (m_BitPos < 8)
+ WriteBits(0, m_BitPos);
+ return m_Stream.Flush();
+ }
+ void WriteBits(UInt32 value, unsigned numBits)
+ {
+ while (numBits > 0)
+ {
+ if (numBits < m_BitPos)
+ {
+ m_CurByte |= ((Byte)value << (m_BitPos -= numBits));
+ return;
+ }
+ numBits -= m_BitPos;
+ UInt32 newBits = (value >> numBits);
+ value -= (newBits << numBits);
+ m_Stream.WriteByte((Byte)(m_CurByte | newBits));
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.cpp
new file mode 100644
index 000000000..431709526
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.cpp
@@ -0,0 +1,19 @@
+// BranchCoder.cpp
+
+#include "StdAfx.h"
+
+#include "BranchCoder.h"
+
+STDMETHODIMP CBranchConverter::Init()
+{
+ _bufferPos = 0;
+ SubInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CBranchConverter::Filter(Byte *data, UInt32 size)
+{
+ UInt32 processedSize = SubFilter(data, size);
+ _bufferPos += processedSize;
+ return processedSize;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.h
new file mode 100644
index 000000000..0e3a5c4e1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BranchCoder.h
@@ -0,0 +1,44 @@
+// BranchCoder.h
+
+#ifndef __COMPRESS_BRANCH_CODER_H
+#define __COMPRESS_BRANCH_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+class CBranchConverter:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+protected:
+ UInt32 _bufferPos;
+ virtual void SubInit() {}
+ virtual UInt32 SubFilter(Byte *data, UInt32 size) = 0;
+public:
+ MY_UNKNOWN_IMP;
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+#define MyClassEncoderA(Name) class C ## Name: public CBranchConverter \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); };
+
+#define MyClassDecoderA(Name) class C ## Name: public CBranchConverter \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); };
+
+#define MyClassEncoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT};
+
+#define MyClassDecoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT};
+
+#define MyClassA(Name, id, subId) \
+MyClassEncoderA(Name ## _Encoder) \
+MyClassDecoderA(Name ## _Decoder)
+
+#define MyClassB(Name, id, subId, ADD_ITEMS, ADD_INIT) \
+MyClassEncoderB(Name ## _Encoder, ADD_ITEMS, ADD_INIT) \
+MyClassDecoderB(Name ## _Decoder, ADD_ITEMS, ADD_INIT)
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.cpp
new file mode 100644
index 000000000..423b723ab
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.cpp
@@ -0,0 +1,37 @@
+// BranchMisc.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Bra.h"
+
+#include "BranchMisc.h"
+
+UInt32 CBC_ARM_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::ARM_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_ARM_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::ARM_Convert(data, size, _bufferPos, 0); }
+
+UInt32 CBC_ARMT_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::ARMT_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_ARMT_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::ARMT_Convert(data, size, _bufferPos, 0); }
+
+UInt32 CBC_PPC_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::PPC_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_PPC_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::PPC_Convert(data, size, _bufferPos, 0); }
+
+UInt32 CBC_SPARC_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::SPARC_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_SPARC_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::SPARC_Convert(data, size, _bufferPos, 0); }
+
+UInt32 CBC_IA64_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::IA64_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_IA64_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::IA64_Convert(data, size, _bufferPos, 0); }
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.h b/src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.h
new file mode 100644
index 000000000..81198b21c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BranchMisc.h
@@ -0,0 +1,14 @@
+// BranchMisc.h
+
+#ifndef __COMPRESS_BRANCH_MISC_H
+#define __COMPRESS_BRANCH_MISC_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_ARM, 0x05, 1)
+MyClassA(BC_ARMT, 0x07, 1)
+MyClassA(BC_PPC, 0x02, 5)
+MyClassA(BC_SPARC, 0x08, 5)
+MyClassA(BC_IA64, 0x04, 1)
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/BranchRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/BranchRegister.cpp
new file mode 100644
index 000000000..380828c6d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/BranchRegister.cpp
@@ -0,0 +1,30 @@
+// BranchRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BranchMisc.h"
+
+#define CREATE_CODEC(x) \
+ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## _Decoder); } \
+ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## _Encoder); }
+
+CREATE_CODEC(BC_PPC)
+CREATE_CODEC(BC_IA64)
+CREATE_CODEC(BC_ARM)
+CREATE_CODEC(BC_ARMT)
+CREATE_CODEC(BC_SPARC)
+
+#define METHOD_ITEM(x, id1, id2, name) { CreateCodec ## x, CreateCodec ## x ## Out, 0x03030000 + (id1 * 256) + id2, name, 1, true }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ METHOD_ITEM(BC_PPC, 0x02, 0x05, L"PPC"),
+ METHOD_ITEM(BC_IA64, 0x04, 1, L"IA64"),
+ METHOD_ITEM(BC_ARM, 0x05, 1, L"ARM"),
+ METHOD_ITEM(BC_ARMT, 0x07, 1, L"ARMT"),
+ METHOD_ITEM(BC_SPARC, 0x08, 0x05, L"SPARC")
+};
+
+REGISTER_CODECS(Branch)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ByteSwap.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ByteSwap.cpp
new file mode 100644
index 000000000..645b6ffcd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ByteSwap.cpp
@@ -0,0 +1,73 @@
+// ByteSwap.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+class CByteSwap2:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+class CByteSwap4:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+STDMETHODIMP CByteSwap2::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size)
+{
+ const UInt32 kStep = 2;
+ UInt32 i;
+ for (i = 0; i + kStep <= size; i += kStep)
+ {
+ Byte b = data[i];
+ data[i] = data[i + 1];
+ data[i + 1] = b;
+ }
+ return i;
+}
+
+STDMETHODIMP CByteSwap4::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size)
+{
+ const UInt32 kStep = 4;
+ UInt32 i;
+ for (i = 0; i + kStep <= size; i += kStep)
+ {
+ Byte b0 = data[i];
+ Byte b1 = data[i + 1];
+ data[i] = data[i + 3];
+ data[i + 1] = data[i + 2];
+ data[i + 2] = b1;
+ data[i + 3] = b0;
+ }
+ return i;
+}
+
+static void *CreateCodec2() { return (void *)(ICompressFilter *)(new CByteSwap2); }
+static void *CreateCodec4() { return (void *)(ICompressFilter *)(new CByteSwap4); }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ { CreateCodec2, CreateCodec2, 0x020302, L"Swap2", 1, true },
+ { CreateCodec4, CreateCodec4, 0x020304, L"Swap4", 1, true }
+};
+
+REGISTER_CODECS(ByteSwap)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/CodecExports.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/CodecExports.cpp
new file mode 100644
index 000000000..4ff1c0fcb
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/CodecExports.cpp
@@ -0,0 +1,160 @@
+// CodecExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+extern unsigned int g_NumCodecs;
+extern const CCodecInfo *g_Codecs[];
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value)
+{
+ if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
+ value->vt = VT_BSTR;
+ return S_OK;
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
+{
+ return SetPropString((const char *)&guid, sizeof(GUID), value);
+}
+
+static HRESULT SetClassID(CMethodId id, bool encode, PROPVARIANT *value)
+{
+ GUID clsId = CLSID_CCodec;
+ for (int i = 0; i < sizeof(id); i++, id >>= 8)
+ clsId.Data4[i] = (Byte)(id & 0xFF);
+ if (encode)
+ clsId.Data3++;
+ return SetPropGUID(clsId, value);
+}
+
+static HRESULT FindCodecClassId(const GUID *clsID, UInt32 isCoder2, bool isFilter, bool &encode, int &index)
+{
+ index = -1;
+ if (clsID->Data1 != CLSID_CCodec.Data1 ||
+ clsID->Data2 != CLSID_CCodec.Data2 ||
+ (clsID->Data3 & ~1) != kDecodeId)
+ return S_OK;
+ encode = (clsID->Data3 != kDecodeId);
+ UInt64 id = 0;
+ for (int j = 0; j < 8; j++)
+ id |= ((UInt64)clsID->Data4[j]) << (8 * j);
+ for (unsigned i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (id != codec.Id || encode && !codec.CreateEncoder || !encode && !codec.CreateDecoder)
+ continue;
+ if (!isFilter && codec.IsFilter || isFilter && !codec.IsFilter ||
+ codec.NumInStreams != 1 && !isCoder2 || codec.NumInStreams == 1 && isCoder2)
+ return E_NOINTERFACE;
+ index = i;
+ return S_OK;
+ }
+ return S_OK;
+}
+
+STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject)
+{
+ COM_TRY_BEGIN
+ *outObject = 0;
+ bool isCoder = (*iid == IID_ICompressCoder) != 0;
+ bool isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+ bool isFilter = (*iid == IID_ICompressFilter) != 0;
+ const CCodecInfo &codec = *g_Codecs[index];
+ if (!isFilter && codec.IsFilter || isFilter && !codec.IsFilter ||
+ codec.NumInStreams != 1 && !isCoder2 || codec.NumInStreams == 1 && isCoder2)
+ return E_NOINTERFACE;
+ if (encode)
+ {
+ if (!codec.CreateEncoder)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ *outObject = codec.CreateEncoder();
+ }
+ else
+ {
+ if (!codec.CreateDecoder)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ *outObject = codec.CreateDecoder();
+ }
+ if (isCoder)
+ ((ICompressCoder *)*outObject)->AddRef();
+ else if (isCoder2)
+ ((ICompressCoder2 *)*outObject)->AddRef();
+ else
+ ((ICompressFilter *)*outObject)->AddRef();
+ return S_OK;
+ COM_TRY_END
+}
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ *outObject = 0;
+ bool isCoder = (*iid == IID_ICompressCoder) != 0;
+ bool isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+ bool isFilter = (*iid == IID_ICompressFilter) != 0;
+ if (!isCoder && !isCoder2 && !isFilter)
+ return E_NOINTERFACE;
+ bool encode;
+ int codecIndex;
+ HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
+ if (res != S_OK)
+ return res;
+ if (codecIndex < 0)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ return CreateCoder2(encode, codecIndex, iid, outObject);
+}
+
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
+{
+ ::VariantClear((VARIANTARG *)value);
+ const CCodecInfo &codec = *g_Codecs[codecIndex];
+ switch(propID)
+ {
+ case NMethodPropID::kID:
+ {
+ value->uhVal.QuadPart = (UInt64)codec.Id;
+ value->vt = VT_UI8;
+ break;
+ }
+ case NMethodPropID::kName:
+ if ((value->bstrVal = ::SysAllocString(codec.Name)) != 0)
+ value->vt = VT_BSTR;
+ break;
+ case NMethodPropID::kDecoder:
+ if (codec.CreateDecoder)
+ return SetClassID(codec.Id, false, value);
+ break;
+ case NMethodPropID::kEncoder:
+ if (codec.CreateEncoder)
+ return SetClassID(codec.Id, true, value);
+ break;
+ case NMethodPropID::kInStreams:
+ {
+ if (codec.NumInStreams != 1)
+ {
+ value->vt = VT_UI4;
+ value->ulVal = (ULONG)codec.NumInStreams;
+ }
+ break;
+ }
+ }
+ return S_OK;
+}
+
+STDAPI GetNumberOfMethods(UINT32 *numCodecs)
+{
+ *numCodecs = g_NumCodecs;
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.cpp
new file mode 100644
index 000000000..f71692a77
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.cpp
@@ -0,0 +1,67 @@
+// Compress/CopyCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "CopyCoder.h"
+
+namespace NCompress {
+
+static const UInt32 kBufferSize = 1 << 17;
+
+CCopyCoder::~CCopyCoder()
+{
+ ::MidFree(_buffer);
+}
+
+STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ if (_buffer == 0)
+ {
+ _buffer = (Byte *)::MidAlloc(kBufferSize);
+ if (_buffer == 0)
+ return E_OUTOFMEMORY;
+ }
+
+ TotalSize = 0;
+ for (;;)
+ {
+ UInt32 size = kBufferSize;
+ if (outSize != 0)
+ if (size > *outSize - TotalSize)
+ size = (UInt32)(*outSize - TotalSize);
+ RINOK(inStream->Read(_buffer, size, &size));
+ if (size == 0)
+ break;
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, _buffer, size));
+ }
+ TotalSize += size;
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)
+{
+ *value = TotalSize;
+ return S_OK;
+}
+
+HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+ return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.h
new file mode 100644
index 000000000..c5445ccf8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/CopyCoder.h
@@ -0,0 +1,34 @@
+// Compress/CopyCoder.h
+
+#ifndef __COMPRESS_COPY_CODER_H
+#define __COMPRESS_COPY_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+
+class CCopyCoder:
+ public ICompressCoder,
+ public ICompressGetInStreamProcessedSize,
+ public CMyUnknownImp
+{
+ Byte *_buffer;
+public:
+ UInt64 TotalSize;
+ CCopyCoder(): TotalSize(0), _buffer(0) {};
+ ~CCopyCoder();
+
+ MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+};
+
+HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/CopyRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/CopyRegister.cpp
new file mode 100644
index 000000000..efb9b9e95
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/CopyRegister.cpp
@@ -0,0 +1,14 @@
+// CopyRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "CopyCoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::CCopyCoder); }
+
+static CCodecInfo g_CodecInfo =
+{ CreateCodec, CreateCodec, 0x00, L"Copy", 1, false };
+
+REGISTER_CODEC(Copy)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Deflate64Register.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Deflate64Register.cpp
new file mode 100644
index 000000000..509e675a5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Deflate64Register.cpp
@@ -0,0 +1,20 @@
+// Deflate64Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "DeflateDecoder.h"
+
+static void *CreateCodecDeflate64() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NDecoder::CCOMCoder64); }
+#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY)
+#include "DeflateEncoder.h"
+static void *CreateCodecOutDeflate64() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NEncoder::CCOMCoder64); }
+#else
+#define CreateCodecOutDeflate64 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodecDeflate64, CreateCodecOutDeflate64, 0x040109, L"Deflate64", 1, false };
+
+REGISTER_CODEC(Deflate64)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DeflateConst.h b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateConst.h
new file mode 100644
index 000000000..00e5ab8bf
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateConst.h
@@ -0,0 +1,134 @@
+// DeflateConst.h
+
+#ifndef __DEFLATE_CONST_H
+#define __DEFLATE_CONST_H
+
+namespace NCompress {
+namespace NDeflate {
+
+const int kNumHuffmanBits = 15;
+
+const UInt32 kHistorySize32 = (1 << 15);
+const UInt32 kHistorySize64 = (1 << 16);
+
+const UInt32 kDistTableSize32 = 30;
+const UInt32 kDistTableSize64 = 32;
+
+const UInt32 kNumLenSymbols32 = 256;
+const UInt32 kNumLenSymbols64 = 255; // don't change it. It must be <= 255.
+const UInt32 kNumLenSymbolsMax = kNumLenSymbols32;
+
+const UInt32 kNumLenSlots = 29;
+
+const UInt32 kFixedDistTableSize = 32;
+const UInt32 kFixedLenTableSize = 31;
+
+const UInt32 kSymbolEndOfBlock = 0x100;
+const UInt32 kSymbolMatch = kSymbolEndOfBlock + 1;
+
+const UInt32 kMainTableSize = kSymbolMatch + kNumLenSlots;
+const UInt32 kFixedMainTableSize = kSymbolMatch + kFixedLenTableSize;
+
+const UInt32 kLevelTableSize = 19;
+
+const UInt32 kTableDirectLevels = 16;
+const UInt32 kTableLevelRepNumber = kTableDirectLevels;
+const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1;
+const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1;
+
+const UInt32 kLevelMask = 0xF;
+
+const Byte kLenStart32[kFixedLenTableSize] =
+ {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, 0, 0};
+const Byte kLenStart64[kFixedLenTableSize] =
+ {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, 0, 0};
+
+const Byte kLenDirectBits32[kFixedLenTableSize] =
+ {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, 0, 0};
+const Byte kLenDirectBits64[kFixedLenTableSize] =
+ {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, 0, 0};
+
+const UInt32 kDistStart[kDistTableSize64] =
+ {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,
+ 1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768,49152};
+const Byte kDistDirectBits[kDistTableSize64] =
+ {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};
+
+const Byte kLevelDirectBits[3] = {2, 3, 7};
+
+const Byte kCodeLengthAlphabetOrder[kLevelTableSize] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+const UInt32 kMatchMinLen = 3;
+const UInt32 kMatchMaxLen32 = kNumLenSymbols32 + kMatchMinLen - 1; //256 + 2
+const UInt32 kMatchMaxLen64 = kNumLenSymbols64 + kMatchMinLen - 1; //255 + 2
+const UInt32 kMatchMaxLen = kMatchMaxLen32;
+
+const int kFinalBlockFieldSize = 1;
+
+namespace NFinalBlockField
+{
+ enum
+ {
+ kNotFinalBlock = 0,
+ kFinalBlock = 1
+ };
+}
+
+const int kBlockTypeFieldSize = 2;
+
+namespace NBlockType
+{
+ enum
+ {
+ kStored = 0,
+ kFixedHuffman = 1,
+ kDynamicHuffman = 2
+ };
+}
+
+const int kNumLenCodesFieldSize = 5;
+const int kNumDistCodesFieldSize = 5;
+const int kNumLevelCodesFieldSize = 4;
+
+const UInt32 kNumLitLenCodesMin = 257;
+const UInt32 kNumDistCodesMin = 1;
+const UInt32 kNumLevelCodesMin = 4;
+
+const int kLevelFieldSize = 3;
+
+const int kStoredBlockLengthFieldSize = 16;
+
+struct CLevels
+{
+ Byte litLenLevels[kFixedMainTableSize];
+ Byte distLevels[kFixedDistTableSize];
+
+ void SubClear()
+ {
+ UInt32 i;
+ for(i = kNumLitLenCodesMin; i < kFixedMainTableSize; i++)
+ litLenLevels[i] = 0;
+ for(i = 0; i < kFixedDistTableSize; i++)
+ distLevels[i] = 0;
+ }
+
+ void SetFixedLevels()
+ {
+ int i;
+
+ for (i = 0; i < 144; i++)
+ litLenLevels[i] = 8;
+ for (; i < 256; i++)
+ litLenLevels[i] = 9;
+ for (; i < 280; i++)
+ litLenLevels[i] = 7;
+ for (; i < 288; i++)
+ litLenLevels[i] = 8;
+ for (i = 0; i < kFixedDistTableSize; i++) // test it: InfoZip only uses kDistTableSize
+ distLevels[i] = 5;
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DeflateDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateDecoder.cpp
new file mode 100644
index 000000000..2848cd812
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateDecoder.cpp
@@ -0,0 +1,353 @@
+// DeflateDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "DeflateDecoder.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NDecoder {
+
+static const int kLenIdFinished = -1;
+static const int kLenIdNeedInit = -2;
+
+CCoder::CCoder(bool deflate64Mode, bool deflateNSIS):
+ _deflate64Mode(deflate64Mode),
+ _deflateNSIS(deflateNSIS),
+ _keepHistory(false),
+ _needInitInStream(true),
+ ZlibMode(false) {}
+
+UInt32 CCoder::ReadBits(int numBits)
+{
+ return m_InBitStream.ReadBits(numBits);
+}
+
+bool CCoder::DeCodeLevelTable(Byte *values, int numSymbols)
+{
+ int i = 0;
+ do
+ {
+ UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < kTableDirectLevels)
+ values[i++] = (Byte)number;
+ else if (number < kLevelTableSize)
+ {
+ if (number == kTableLevelRepNumber)
+ {
+ if (i == 0)
+ return false;
+ int num = ReadBits(2) + 3;
+ for (; num > 0 && i < numSymbols; num--, i++)
+ values[i] = values[i - 1];
+ }
+ else
+ {
+ int num;
+ if (number == kTableLevel0Number)
+ num = ReadBits(3) + 3;
+ else
+ num = ReadBits(7) + 11;
+ for (;num > 0 && i < numSymbols; num--)
+ values[i++] = 0;
+ }
+ }
+ else
+ return false;
+ }
+ while(i < numSymbols);
+ return true;
+}
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CCoder::ReadTables(void)
+{
+ m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
+ UInt32 blockType = ReadBits(kBlockTypeFieldSize);
+ if (blockType > NBlockType::kDynamicHuffman)
+ return false;
+
+ if (blockType == NBlockType::kStored)
+ {
+ m_StoredMode = true;
+ m_InBitStream.AlignToByte();
+ m_StoredBlockSize = ReadBits(kStoredBlockLengthFieldSize);
+ if (_deflateNSIS)
+ return true;
+ return (m_StoredBlockSize == (UInt16)~ReadBits(kStoredBlockLengthFieldSize));
+ }
+
+ m_StoredMode = false;
+
+ CLevels levels;
+ if (blockType == NBlockType::kFixedHuffman)
+ {
+ levels.SetFixedLevels();
+ _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
+ }
+ else
+ {
+ int numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
+ _numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
+ int numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
+
+ if (!_deflate64Mode)
+ if (_numDistLevels > kDistTableSize32)
+ return false;
+
+ Byte levelLevels[kLevelTableSize];
+ for (int i = 0; i < kLevelTableSize; i++)
+ {
+ int position = kCodeLengthAlphabetOrder[i];
+ if(i < numLevelCodes)
+ levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
+ else
+ levelLevels[position] = 0;
+ }
+
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+
+ Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
+ if (!DeCodeLevelTable(tmpLevels, numLitLenLevels + _numDistLevels))
+ return false;
+
+ levels.SubClear();
+ memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
+ memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
+ }
+ RIF(m_MainDecoder.SetCodeLengths(levels.litLenLevels));
+ return m_DistDecoder.SetCodeLengths(levels.distLevels);
+}
+
+HRESULT CCoder::CodeSpec(UInt32 curSize)
+{
+ if (_remainLen == kLenIdFinished)
+ return S_OK;
+ if (_remainLen == kLenIdNeedInit)
+ {
+ if (!_keepHistory)
+ if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
+ return E_OUTOFMEMORY;
+ RINOK(InitInStream(_needInitInStream));
+ m_OutWindowStream.Init(_keepHistory);
+ m_FinalBlock = false;
+ _remainLen = 0;
+ _needReadTable = true;
+ }
+
+ if (curSize == 0)
+ return S_OK;
+
+ while(_remainLen > 0 && curSize > 0)
+ {
+ _remainLen--;
+ Byte b = m_OutWindowStream.GetByte(_rep0);
+ m_OutWindowStream.PutByte(b);
+ curSize--;
+ }
+
+ while(curSize > 0)
+ {
+ if (_needReadTable)
+ {
+ if (m_FinalBlock)
+ {
+ _remainLen = kLenIdFinished;
+ break;
+ }
+ if (!ReadTables())
+ return S_FALSE;
+ _needReadTable = false;
+ }
+
+ if(m_StoredMode)
+ {
+ for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)
+ m_OutWindowStream.PutByte(m_InBitStream.ReadByte());
+ _needReadTable = (m_StoredBlockSize == 0);
+ continue;
+ }
+ while(curSize > 0)
+ {
+ if (m_InBitStream.NumExtraBytes > 4)
+ return S_FALSE;
+
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < 0x100)
+ {
+ m_OutWindowStream.PutByte((Byte)number);
+ curSize--;
+ continue;
+ }
+ else if (number == kSymbolEndOfBlock)
+ {
+ _needReadTable = true;
+ break;
+ }
+ else if (number < kMainTableSize)
+ {
+ number -= kSymbolMatch;
+ UInt32 len;
+ {
+ int numBits;
+ if (_deflate64Mode)
+ {
+ len = kLenStart64[number];
+ numBits = kLenDirectBits64[number];
+ }
+ else
+ {
+ len = kLenStart32[number];
+ numBits = kLenDirectBits32[number];
+ }
+ len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
+ }
+ UInt32 locLen = len;
+ if (locLen > curSize)
+ locLen = (UInt32)curSize;
+ number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
+ if (number >= _numDistLevels)
+ return S_FALSE;
+ UInt32 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
+ if (!m_OutWindowStream.CopyBlock(distance, locLen))
+ return S_FALSE;
+ curSize -= locLen;
+ len -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (Int32)len;
+ _rep0 = distance;
+ break;
+ }
+ }
+ else
+ return S_FALSE;
+ }
+ }
+ return S_OK;
+}
+
+#ifdef _NO_EXCEPTIONS
+
+#define DEFLATE_TRY_BEGIN
+#define DEFLATE_TRY_END
+
+#else
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } \
+ catch(const CInBufferException &e) { return e.ErrorCode; } \
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; } \
+ catch(...) { return S_FALSE; }
+
+#endif
+
+HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
+ const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ DEFLATE_TRY_BEGIN
+ m_OutWindowStream.SetStream(outStream);
+ CCoderReleaser flusher(this);
+
+ const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
+ const UInt64 start = m_OutWindowStream.GetProcessedSize();
+ for (;;)
+ {
+ UInt32 curSize = 1 << 18;
+ if (outSize != 0)
+ {
+ const UInt64 rem = *outSize - (m_OutWindowStream.GetProcessedSize() - start);
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ }
+ if (curSize == 0)
+ break;
+ RINOK(CodeSpec(curSize));
+ if (_remainLen == kLenIdFinished)
+ break;
+ if (progress != NULL)
+ {
+ const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
+ const UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+ }
+ }
+ if (_remainLen == kLenIdFinished && ZlibMode)
+ {
+ m_InBitStream.AlignToByte();
+ for (int i = 0; i < 4; i++)
+ ZlibFooter[i] = m_InBitStream.ReadByte();
+ }
+ flusher.NeedFlush = false;
+ HRESULT res = Flush();
+ if (res == S_OK && InputEofError())
+ return S_FALSE;
+ return res;
+ DEFLATE_TRY_END
+}
+
+HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ SetInStream(inStream);
+ SetOutStreamSize(outSize);
+ HRESULT res = CodeReal(outStream, outSize, progress);
+ ReleaseInStream();
+ return res;
+}
+
+STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
+{
+ if (value == NULL)
+ return E_INVALIDARG;
+ *value = m_InBitStream.GetProcessedSize();
+ return S_OK;
+}
+
+STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)
+{
+ m_InBitStream.SetStream(inStream);
+ return S_OK;
+}
+
+STDMETHODIMP CCoder::ReleaseInStream()
+{
+ m_InBitStream.ReleaseStream();
+ return S_OK;
+}
+
+STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 * /* outSize */)
+{
+ _remainLen = kLenIdNeedInit;
+ _needInitInStream = true;
+ m_OutWindowStream.Init(_keepHistory);
+ return S_OK;
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ DEFLATE_TRY_BEGIN
+ if (processedSize)
+ *processedSize = 0;
+ const UInt64 startPos = m_OutWindowStream.GetProcessedSize();
+ m_OutWindowStream.SetMemStream((Byte *)data);
+ RINOK(CodeSpec(size));
+ if (processedSize)
+ *processedSize = (UInt32)(m_OutWindowStream.GetProcessedSize() - startPos);
+ return Flush();
+ DEFLATE_TRY_END
+}
+
+#endif
+
+STDMETHODIMP CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ _remainLen = kLenIdNeedInit;
+ m_OutWindowStream.Init(_keepHistory);
+ return CodeReal(outStream, outSize, progress);
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DeflateDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateDecoder.h
new file mode 100644
index 000000000..56ab2bea2
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateDecoder.h
@@ -0,0 +1,157 @@
+// DeflateDecoder.h
+
+#ifndef __DEFLATE_DECODER_H
+#define __DEFLATE_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitlDecoder.h"
+#include "DeflateConst.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NDecoder {
+
+class CCoder:
+ public ICompressCoder,
+ public ICompressGetInStreamProcessedSize,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitl::CDecoder<CInBuffer> m_InBitStream;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedMainTableSize> m_MainDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedDistTableSize> m_DistDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ UInt32 m_StoredBlockSize;
+
+ bool m_FinalBlock;
+ bool m_StoredMode;
+ UInt32 _numDistLevels;
+
+
+ bool _deflateNSIS;
+ bool _deflate64Mode;
+ bool _keepHistory;
+ bool _needInitInStream;
+ Int32 _remainLen;
+ UInt32 _rep0;
+ bool _needReadTable;
+
+ UInt32 ReadBits(int numBits);
+
+ bool DeCodeLevelTable(Byte *values, int numSymbols);
+ bool ReadTables();
+
+ HRESULT Flush() { return m_OutWindowStream.Flush(); }
+ class CCoderReleaser
+ {
+ CCoder *_coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): _coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ _coder->Flush();
+ _coder->ReleaseOutStream();
+ }
+ };
+ friend class CCoderReleaser;
+
+ HRESULT CodeSpec(UInt32 curSize);
+public:
+ bool ZlibMode;
+ Byte ZlibFooter[4];
+
+ CCoder(bool deflate64Mode, bool deflateNSIS = false);
+ virtual ~CCoder() {};
+
+ void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+
+ void ReleaseOutStream()
+ {
+ m_OutWindowStream.ReleaseStream();
+ }
+
+ HRESULT CodeReal(ISequentialOutStream *outStream,
+ const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ #ifndef NO_READ_FROM_CODER
+ MY_UNKNOWN_IMP4(
+ ICompressGetInStreamProcessedSize,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream
+ )
+ #else
+ MY_UNKNOWN_IMP1(
+ ICompressGetInStreamProcessedSize)
+ #endif
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ #ifndef NO_READ_FROM_CODER
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+ STDMETHOD(CodeResume)(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ HRESULT InitInStream(bool needInit)
+ {
+ if (!m_InBitStream.Create(1 << 17))
+ return E_OUTOFMEMORY;
+ if (needInit)
+ {
+ m_InBitStream.Init();
+ _needInitInStream = false;
+ }
+ return S_OK;
+ }
+
+ void AlignToByte() { m_InBitStream.AlignToByte(); }
+ Byte ReadByte() { return (Byte)m_InBitStream.ReadBits(8); }
+ bool InputEofError() const { return m_InBitStream.ExtraBitsWereRead(); }
+ UInt64 GetInputProcessedSize() const { return m_InBitStream.GetProcessedSize(); }
+
+ // IGetInStreamProcessedSize
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+};
+
+class CCOMCoder : public CCoder
+{
+public:
+ CCOMCoder(): CCoder(false) {}
+};
+
+class CNsisCOMCoder : public CCoder
+{
+public:
+ CNsisCOMCoder(): CCoder(false, true) {}
+};
+
+class CCOMCoder64 : public CCoder
+{
+public:
+ CCOMCoder64(): CCoder(true) {}
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DeflateEncoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateEncoder.cpp
new file mode 100644
index 000000000..35a81cae4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateEncoder.cpp
@@ -0,0 +1,986 @@
+// DeflateEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/HuffEnc.h"
+
+#include "Common/ComTry.h"
+
+#include "DeflateEncoder.h"
+
+#undef NO_INLINE
+
+#ifdef _MSC_VER
+#define NO_INLINE MY_NO_INLINE
+#else
+#define NO_INLINE
+#endif
+
+namespace NCompress {
+namespace NDeflate {
+namespace NEncoder {
+
+const int kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio.
+const UInt32 kNumTables = (1 << kNumDivPassesMax);
+
+static UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio.
+static UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio.
+static UInt32 kDivideBlockSizeMin = (1 << 6); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio.
+
+static const UInt32 kMaxUncompressedBlockSize = ((1 << 16) - 1) * 1; // [1, (1 << 32))
+static const UInt32 kMatchArraySize = kMaxUncompressedBlockSize * 10; // [kMatchMaxLen * 2, (1 << 32))
+static const UInt32 kMatchArrayLimit = kMatchArraySize - kMatchMaxLen * 4 * sizeof(UInt16);
+static const UInt32 kBlockUncompressedSizeThreshold = kMaxUncompressedBlockSize -
+ kMatchMaxLen - kNumOpts;
+
+static const int kMaxCodeBitLength = 11;
+static const int kMaxLevelBitLength = 7;
+
+static Byte kNoLiteralStatPrice = 11;
+static Byte kNoLenStatPrice = 11;
+static Byte kNoPosStatPrice = 6;
+
+static Byte g_LenSlots[kNumLenSymbolsMax];
+static Byte g_FastPos[1 << 9];
+
+class CFastPosInit
+{
+public:
+ CFastPosInit()
+ {
+ int i;
+ for(i = 0; i < kNumLenSlots; i++)
+ {
+ int c = kLenStart32[i];
+ int j = 1 << kLenDirectBits32[i];
+ for(int k = 0; k < j; k++, c++)
+ g_LenSlots[c] = (Byte)i;
+ }
+
+ const int kFastSlots = 18;
+ int c = 0;
+ for (Byte slotFast = 0; slotFast < kFastSlots; slotFast++)
+ {
+ UInt32 k = (1 << kDistDirectBits[slotFast]);
+ for (UInt32 j = 0; j < k; j++, c++)
+ g_FastPos[c] = slotFast;
+ }
+ }
+};
+
+static CFastPosInit g_FastPosInit;
+
+
+inline UInt32 GetPosSlot(UInt32 pos)
+{
+ if (pos < 0x200)
+ return g_FastPos[pos];
+ return g_FastPos[pos >> 8] + 16;
+}
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CCoder::CCoder(bool deflate64Mode):
+ m_Deflate64Mode(deflate64Mode),
+ m_NumPasses(1),
+ m_NumDivPasses(1),
+ m_NumFastBytes(32),
+ _fastMode(false),
+ _btMode(true),
+ m_OnePosMatchesMemory(0),
+ m_DistanceMemory(0),
+ m_Created(false),
+ m_Values(0),
+ m_Tables(0),
+ m_MatchFinderCycles(0)
+ // m_SetMfPasses(0)
+{
+ m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32;
+ m_NumLenCombinations = deflate64Mode ? kNumLenSymbols64 : kNumLenSymbols32;
+ m_LenStart = deflate64Mode ? kLenStart64 : kLenStart32;
+ m_LenDirectBits = deflate64Mode ? kLenDirectBits64 : kLenDirectBits32;
+ MatchFinder_Construct(&_lzInWindow);
+}
+
+HRESULT CCoder::Create()
+{
+ COM_TRY_BEGIN
+ if (m_Values == 0)
+ {
+ m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue));
+ if (m_Values == 0)
+ return E_OUTOFMEMORY;
+ }
+ if (m_Tables == 0)
+ {
+ m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables));
+ if (m_Tables == 0)
+ return E_OUTOFMEMORY;
+ }
+
+ if (m_IsMultiPass)
+ {
+ if (m_OnePosMatchesMemory == 0)
+ {
+ m_OnePosMatchesMemory = (UInt16 *)::MidAlloc(kMatchArraySize * sizeof(UInt16));
+ if (m_OnePosMatchesMemory == 0)
+ return E_OUTOFMEMORY;
+ }
+ }
+ else
+ {
+ if (m_DistanceMemory == 0)
+ {
+ m_DistanceMemory = (UInt16 *)MyAlloc((kMatchMaxLen + 2) * 2 * sizeof(UInt16));
+ if (m_DistanceMemory == 0)
+ return E_OUTOFMEMORY;
+ m_MatchDistances = m_DistanceMemory;
+ }
+ }
+
+ if (!m_Created)
+ {
+ _lzInWindow.btMode = _btMode ? 1 : 0;
+ _lzInWindow.numHashBytes = 3;
+ if (!MatchFinder_Create(&_lzInWindow,
+ m_Deflate64Mode ? kHistorySize64 : kHistorySize32,
+ kNumOpts + kMaxUncompressedBlockSize,
+ m_NumFastBytes, m_MatchMaxLen - m_NumFastBytes, &g_Alloc))
+ return E_OUTOFMEMORY;
+ if (!m_OutStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ }
+ if (m_MatchFinderCycles != 0)
+ _lzInWindow.cutValue = m_MatchFinderCycles;
+ m_Created = true;
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kNumPasses:
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ m_NumDivPasses = prop.ulVal;
+ if (m_NumDivPasses == 0)
+ m_NumDivPasses = 1;
+ if (m_NumDivPasses == 1)
+ m_NumPasses = 1;
+ else if (m_NumDivPasses <= kNumDivPassesMax)
+ m_NumPasses = 2;
+ else
+ {
+ m_NumPasses = 2 + (m_NumDivPasses - kNumDivPassesMax);
+ m_NumDivPasses = kNumDivPassesMax;
+ }
+ break;
+ case NCoderPropID::kNumFastBytes:
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ m_NumFastBytes = prop.ulVal;
+ if(m_NumFastBytes < kMatchMinLen || m_NumFastBytes > m_MatchMaxLen)
+ return E_INVALIDARG;
+ break;
+ case NCoderPropID::kMatchFinderCycles:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ m_MatchFinderCycles = prop.ulVal;
+ break;
+ }
+ case NCoderPropID::kAlgorithm:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 maximize = prop.ulVal;
+ _fastMode = (maximize == 0);
+ _btMode = !_fastMode;
+ break;
+ }
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+void CCoder::Free()
+{
+ ::MidFree(m_OnePosMatchesMemory); m_OnePosMatchesMemory = 0;
+ ::MyFree(m_DistanceMemory); m_DistanceMemory = 0;
+ ::MyFree(m_Values); m_Values = 0;
+ ::MyFree(m_Tables); m_Tables = 0;
+}
+
+CCoder::~CCoder()
+{
+ Free();
+ MatchFinder_Free(&_lzInWindow, &g_Alloc);
+}
+
+NO_INLINE void CCoder::GetMatches()
+{
+ if (m_IsMultiPass)
+ {
+ m_MatchDistances = m_OnePosMatchesMemory + m_Pos;
+ if (m_SecondPass)
+ {
+ m_Pos += *m_MatchDistances + 1;
+ return;
+ }
+ }
+
+ UInt32 distanceTmp[kMatchMaxLen * 2 + 3];
+
+ UInt32 numPairs = (_btMode) ?
+ Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp):
+ Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp);
+
+ *m_MatchDistances = (UInt16)numPairs;
+
+ if (numPairs > 0)
+ {
+ UInt32 i;
+ for(i = 0; i < numPairs; i += 2)
+ {
+ m_MatchDistances[i + 1] = (UInt16)distanceTmp[i];
+ m_MatchDistances[i + 2] = (UInt16)distanceTmp[i + 1];
+ }
+ UInt32 len = distanceTmp[numPairs - 2];
+ if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen)
+ {
+ UInt32 numAvail = Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) + 1;
+ const Byte *pby = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - 1;
+ const Byte *pby2 = pby - (distanceTmp[numPairs - 1] + 1);
+ if (numAvail > m_MatchMaxLen)
+ numAvail = m_MatchMaxLen;
+ for (; len < numAvail && pby[len] == pby2[len]; len++);
+ m_MatchDistances[i - 1] = (UInt16)len;
+ }
+ }
+ if (m_IsMultiPass)
+ m_Pos += numPairs + 1;
+ if (!m_SecondPass)
+ m_AdditionalOffset++;
+}
+
+void CCoder::MovePos(UInt32 num)
+{
+ if (!m_SecondPass && num > 0)
+ {
+ if (_btMode)
+ Bt3Zip_MatchFinder_Skip(&_lzInWindow, num);
+ else
+ Hc3Zip_MatchFinder_Skip(&_lzInWindow, num);
+ m_AdditionalOffset += num;
+ }
+}
+
+static const UInt32 kIfinityPrice = 0xFFFFFFF;
+
+NO_INLINE UInt32 CCoder::Backward(UInt32 &backRes, UInt32 cur)
+{
+ m_OptimumEndIndex = cur;
+ UInt32 posMem = m_Optimum[cur].PosPrev;
+ UInt16 backMem = m_Optimum[cur].BackPrev;
+ do
+ {
+ UInt32 posPrev = posMem;
+ UInt16 backCur = backMem;
+ backMem = m_Optimum[posPrev].BackPrev;
+ posMem = m_Optimum[posPrev].PosPrev;
+ m_Optimum[posPrev].BackPrev = backCur;
+ m_Optimum[posPrev].PosPrev = (UInt16)cur;
+ cur = posPrev;
+ }
+ while(cur > 0);
+ backRes = m_Optimum[0].BackPrev;
+ m_OptimumCurrentIndex = m_Optimum[0].PosPrev;
+ return m_OptimumCurrentIndex;
+}
+
+NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
+{
+ if(m_OptimumEndIndex != m_OptimumCurrentIndex)
+ {
+ UInt32 len = m_Optimum[m_OptimumCurrentIndex].PosPrev - m_OptimumCurrentIndex;
+ backRes = m_Optimum[m_OptimumCurrentIndex].BackPrev;
+ m_OptimumCurrentIndex = m_Optimum[m_OptimumCurrentIndex].PosPrev;
+ return len;
+ }
+ m_OptimumCurrentIndex = m_OptimumEndIndex = 0;
+
+ GetMatches();
+
+ UInt32 numDistancePairs = m_MatchDistances[0];
+ if(numDistancePairs == 0)
+ return 1;
+
+ const UInt16 *matchDistances = m_MatchDistances + 1;
+ UInt32 lenMain = matchDistances[numDistancePairs - 2];
+
+ if(lenMain > m_NumFastBytes)
+ {
+ backRes = matchDistances[numDistancePairs - 1];
+ MovePos(lenMain - 1);
+ return lenMain;
+ }
+ m_Optimum[1].Price = m_LiteralPrices[Inline_MatchFinder_GetIndexByte(&_lzInWindow, 0 - m_AdditionalOffset)];
+ m_Optimum[1].PosPrev = 0;
+
+ m_Optimum[2].Price = kIfinityPrice;
+ m_Optimum[2].PosPrev = 1;
+
+
+ UInt32 offs = 0;
+ for(UInt32 i = kMatchMinLen; i <= lenMain; i++)
+ {
+ UInt32 distance = matchDistances[offs + 1];
+ m_Optimum[i].PosPrev = 0;
+ m_Optimum[i].BackPrev = (UInt16)distance;
+ m_Optimum[i].Price = m_LenPrices[i - kMatchMinLen] + m_PosPrices[GetPosSlot(distance)];
+ if (i == matchDistances[offs])
+ offs += 2;
+ }
+
+ UInt32 cur = 0;
+ UInt32 lenEnd = lenMain;
+ for (;;)
+ {
+ ++cur;
+ if(cur == lenEnd || cur == kNumOptsBase || m_Pos >= kMatchArrayLimit)
+ return Backward(backRes, cur);
+ GetMatches();
+ matchDistances = m_MatchDistances + 1;
+
+ UInt32 numDistancePairs = m_MatchDistances[0];
+ UInt32 newLen = 0;
+ if(numDistancePairs != 0)
+ {
+ newLen = matchDistances[numDistancePairs - 2];
+ if(newLen > m_NumFastBytes)
+ {
+ UInt32 len = Backward(backRes, cur);
+ m_Optimum[cur].BackPrev = matchDistances[numDistancePairs - 1];
+ m_OptimumEndIndex = cur + newLen;
+ m_Optimum[cur].PosPrev = (UInt16)m_OptimumEndIndex;
+ MovePos(newLen - 1);
+ return len;
+ }
+ }
+ UInt32 curPrice = m_Optimum[cur].Price;
+ UInt32 curAnd1Price = curPrice + m_LiteralPrices[Inline_MatchFinder_GetIndexByte(&_lzInWindow, cur - m_AdditionalOffset)];
+ COptimal &optimum = m_Optimum[cur + 1];
+ if (curAnd1Price < optimum.Price)
+ {
+ optimum.Price = curAnd1Price;
+ optimum.PosPrev = (UInt16)cur;
+ }
+ if(numDistancePairs == 0)
+ continue;
+ while(lenEnd < cur + newLen)
+ m_Optimum[++lenEnd].Price = kIfinityPrice;
+ offs = 0;
+ UInt32 distance = matchDistances[offs + 1];
+ curPrice += m_PosPrices[GetPosSlot(distance)];
+ for(UInt32 lenTest = kMatchMinLen; ; lenTest++)
+ {
+ UInt32 curAndLenPrice = curPrice + m_LenPrices[lenTest - kMatchMinLen];
+ COptimal &optimum = m_Optimum[cur + lenTest];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = (UInt16)cur;
+ optimum.BackPrev = (UInt16)distance;
+ }
+ if (lenTest == matchDistances[offs])
+ {
+ offs += 2;
+ if (offs == numDistancePairs)
+ break;
+ curPrice -= m_PosPrices[GetPosSlot(distance)];
+ distance = matchDistances[offs + 1];
+ curPrice += m_PosPrices[GetPosSlot(distance)];
+ }
+ }
+ }
+}
+
+UInt32 CCoder::GetOptimalFast(UInt32 &backRes)
+{
+ GetMatches();
+ UInt32 numDistancePairs = m_MatchDistances[0];
+ if (numDistancePairs == 0)
+ return 1;
+ UInt32 lenMain = m_MatchDistances[numDistancePairs - 1];
+ backRes = m_MatchDistances[numDistancePairs];
+ MovePos(lenMain - 1);
+ return lenMain;
+}
+
+void CTables::InitStructures()
+{
+ UInt32 i;
+ for(i = 0; i < 256; i++)
+ litLenLevels[i] = 8;
+ litLenLevels[i++] = 13;
+ for(;i < kFixedMainTableSize; i++)
+ litLenLevels[i] = 5;
+ for(i = 0; i < kFixedDistTableSize; i++)
+ distLevels[i] = 5;
+}
+
+NO_INLINE void CCoder::LevelTableDummy(const Byte *levels, int numLevels, UInt32 *freqs)
+{
+ int prevLen = 0xFF;
+ int nextLen = levels[0];
+ int count = 0;
+ int maxCount = 7;
+ int minCount = 4;
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ for (int n = 0; n < numLevels; n++)
+ {
+ int curLen = nextLen;
+ nextLen = (n < numLevels - 1) ? levels[n + 1] : 0xFF;
+ count++;
+ if (count < maxCount && curLen == nextLen)
+ continue;
+
+ if (count < minCount)
+ freqs[curLen] += (UInt32)count;
+ else if (curLen != 0)
+ {
+ if (curLen != prevLen)
+ {
+ freqs[curLen]++;
+ count--;
+ }
+ freqs[kTableLevelRepNumber]++;
+ }
+ else if (count <= 10)
+ freqs[kTableLevel0Number]++;
+ else
+ freqs[kTableLevel0Number2]++;
+
+ count = 0;
+ prevLen = curLen;
+
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ else if (curLen == nextLen)
+ {
+ maxCount = 6;
+ minCount = 3;
+ }
+ else
+ {
+ maxCount = 7;
+ minCount = 4;
+ }
+ }
+}
+
+NO_INLINE void CCoder::WriteBits(UInt32 value, int numBits)
+{
+ m_OutStream.WriteBits(value, numBits);
+}
+
+#define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i])
+#define WRITE_HF(i) WriteBits(codes[i], lens[i])
+
+NO_INLINE void CCoder::LevelTableCode(const Byte *levels, int numLevels, const Byte *lens, const UInt32 *codes)
+{
+ int prevLen = 0xFF;
+ int nextLen = levels[0];
+ int count = 0;
+ int maxCount = 7;
+ int minCount = 4;
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ for (int n = 0; n < numLevels; n++)
+ {
+ int curLen = nextLen;
+ nextLen = (n < numLevels - 1) ? levels[n + 1] : 0xFF;
+ count++;
+ if (count < maxCount && curLen == nextLen)
+ continue;
+
+ if (count < minCount)
+ for(int i = 0; i < count; i++)
+ WRITE_HF(curLen);
+ else if (curLen != 0)
+ {
+ if (curLen != prevLen)
+ {
+ WRITE_HF(curLen);
+ count--;
+ }
+ WRITE_HF(kTableLevelRepNumber);
+ WriteBits(count - 3, 2);
+ }
+ else if (count <= 10)
+ {
+ WRITE_HF(kTableLevel0Number);
+ WriteBits(count - 3, 3);
+ }
+ else
+ {
+ WRITE_HF(kTableLevel0Number2);
+ WriteBits(count - 11, 7);
+ }
+
+ count = 0;
+ prevLen = curLen;
+
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ else if (curLen == nextLen)
+ {
+ maxCount = 6;
+ minCount = 3;
+ }
+ else
+ {
+ maxCount = 7;
+ minCount = 4;
+ }
+ }
+}
+
+NO_INLINE void CCoder::MakeTables(unsigned maxHuffLen)
+{
+ Huffman_Generate(mainFreqs, mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize, maxHuffLen);
+ Huffman_Generate(distFreqs, distCodes, m_NewLevels.distLevels, kDistTableSize64, maxHuffLen);
+}
+
+NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens, UInt32 num)
+{
+ UInt32 price = 0;
+ UInt32 i;
+ for (i = 0; i < num; i++)
+ price += lens[i] * freqs[i];
+ return price;
+}
+
+NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase)
+{
+ return Huffman_GetPrice(freqs, lens, num) +
+ Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase);
+}
+
+NO_INLINE UInt32 CCoder::GetLzBlockPrice() const
+{
+ return
+ Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) +
+ Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0);
+}
+
+NO_INLINE void CCoder::TryBlock()
+{
+ memset(mainFreqs, 0, sizeof(mainFreqs));
+ memset(distFreqs, 0, sizeof(distFreqs));
+
+ m_ValueIndex = 0;
+ UInt32 blockSize = BlockSizeRes;
+ BlockSizeRes = 0;
+ for (;;)
+ {
+ if (m_OptimumCurrentIndex == m_OptimumEndIndex)
+ {
+ if (m_Pos >= kMatchArrayLimit || BlockSizeRes >= blockSize || !m_SecondPass &&
+ ((Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0) || m_ValueIndex >= m_ValueBlockSize))
+ break;
+ }
+ UInt32 pos;
+ UInt32 len;
+ if (_fastMode)
+ len = GetOptimalFast(pos);
+ else
+ len = GetOptimal(pos);
+ CCodeValue &codeValue = m_Values[m_ValueIndex++];
+ if (len >= kMatchMinLen)
+ {
+ UInt32 newLen = len - kMatchMinLen;
+ codeValue.Len = (UInt16)newLen;
+ mainFreqs[kSymbolMatch + g_LenSlots[newLen]]++;
+ codeValue.Pos = (UInt16)pos;
+ distFreqs[GetPosSlot(pos)]++;
+ }
+ else
+ {
+ Byte b = Inline_MatchFinder_GetIndexByte(&_lzInWindow, 0 - m_AdditionalOffset);
+ mainFreqs[b]++;
+ codeValue.SetAsLiteral();
+ codeValue.Pos = b;
+ }
+ m_AdditionalOffset -= len;
+ BlockSizeRes += len;
+ }
+ mainFreqs[kSymbolEndOfBlock]++;
+ m_AdditionalOffset += BlockSizeRes;
+ m_SecondPass = true;
+}
+
+NO_INLINE void CCoder::SetPrices(const CLevels &levels)
+{
+ if (_fastMode)
+ return;
+ UInt32 i;
+ for(i = 0; i < 256; i++)
+ {
+ Byte price = levels.litLenLevels[i];
+ m_LiteralPrices[i] = ((price != 0) ? price : kNoLiteralStatPrice);
+ }
+
+ for(i = 0; i < m_NumLenCombinations; i++)
+ {
+ UInt32 slot = g_LenSlots[i];
+ Byte price = levels.litLenLevels[kSymbolMatch + slot];
+ m_LenPrices[i] = (Byte)(((price != 0) ? price : kNoLenStatPrice) + m_LenDirectBits[slot]);
+ }
+
+ for(i = 0; i < kDistTableSize64; i++)
+ {
+ Byte price = levels.distLevels[i];
+ m_PosPrices[i] = (Byte)(((price != 0) ? price: kNoPosStatPrice) + kDistDirectBits[i]);
+ }
+}
+
+NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num)
+{
+ for (UInt32 i = 0; i < num; i++)
+ {
+ UInt32 x = codes[i];
+ x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1);
+ x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2);
+ x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4);
+ codes[i] = (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)) >> (16 - lens[i]);
+ }
+}
+
+NO_INLINE void CCoder::WriteBlock()
+{
+ Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize);
+ Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64);
+
+ for (UInt32 i = 0; i < m_ValueIndex; i++)
+ {
+ const CCodeValue &codeValue = m_Values[i];
+ if (codeValue.IsLiteral())
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, codeValue.Pos);
+ else
+ {
+ UInt32 len = codeValue.Len;
+ UInt32 lenSlot = g_LenSlots[len];
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot);
+ m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]);
+ UInt32 dist = codeValue.Pos;
+ UInt32 posSlot = GetPosSlot(dist);
+ WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot);
+ m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]);
+ }
+ }
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock);
+}
+
+static UInt32 GetStorePrice(UInt32 blockSize, int bitPosition)
+{
+ UInt32 price = 0;
+ do
+ {
+ UInt32 nextBitPosition = (bitPosition + kFinalBlockFieldSize + kBlockTypeFieldSize) & 7;
+ int numBitsForAlign = nextBitPosition > 0 ? (8 - nextBitPosition): 0;
+ UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1;
+ price += kFinalBlockFieldSize + kBlockTypeFieldSize + numBitsForAlign + (2 + 2) * 8 + curBlockSize * 8;
+ bitPosition = 0;
+ blockSize -= curBlockSize;
+ }
+ while(blockSize != 0);
+ return price;
+}
+
+void CCoder::WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock)
+{
+ do
+ {
+ UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1;
+ blockSize -= curBlockSize;
+ WriteBits((finalBlock && (blockSize == 0) ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize);
+ WriteBits(NBlockType::kStored, kBlockTypeFieldSize);
+ m_OutStream.FlushByte();
+ WriteBits((UInt16)curBlockSize, kStoredBlockLengthFieldSize);
+ WriteBits((UInt16)~curBlockSize, kStoredBlockLengthFieldSize);
+ const Byte *data = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow)- additionalOffset;
+ for(UInt32 i = 0; i < curBlockSize; i++)
+ m_OutStream.WriteByte(data[i]);
+ additionalOffset -= curBlockSize;
+ }
+ while(blockSize != 0);
+}
+
+NO_INLINE UInt32 CCoder::TryDynBlock(int tableIndex, UInt32 numPasses)
+{
+ CTables &t = m_Tables[tableIndex];
+ BlockSizeRes = t.BlockSizeRes;
+ UInt32 posTemp = t.m_Pos;
+ SetPrices(t);
+
+ for (UInt32 p = 0; p < numPasses; p++)
+ {
+ m_Pos = posTemp;
+ TryBlock();
+ unsigned numHuffBits =
+ (m_ValueIndex > 18000 ? 12 :
+ (m_ValueIndex > 7000 ? 11 :
+ (m_ValueIndex > 2000 ? 10 : 9)));
+ MakeTables(numHuffBits);
+ SetPrices(m_NewLevels);
+ }
+
+ (CLevels &)t = m_NewLevels;
+
+ m_NumLitLenLevels = kMainTableSize;
+ while(m_NumLitLenLevels > kNumLitLenCodesMin && m_NewLevels.litLenLevels[m_NumLitLenLevels - 1] == 0)
+ m_NumLitLenLevels--;
+
+ m_NumDistLevels = kDistTableSize64;
+ while(m_NumDistLevels > kNumDistCodesMin && m_NewLevels.distLevels[m_NumDistLevels - 1] == 0)
+ m_NumDistLevels--;
+
+ UInt32 levelFreqs[kLevelTableSize];
+ memset(levelFreqs, 0, sizeof(levelFreqs));
+
+ LevelTableDummy(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelFreqs);
+ LevelTableDummy(m_NewLevels.distLevels, m_NumDistLevels, levelFreqs);
+
+ Huffman_Generate(levelFreqs, levelCodes, levelLens, kLevelTableSize, kMaxLevelBitLength);
+
+ m_NumLevelCodes = kNumLevelCodesMin;
+ for (UInt32 i = 0; i < kLevelTableSize; i++)
+ {
+ Byte level = levelLens[kCodeLengthAlphabetOrder[i]];
+ if (level > 0 && i >= m_NumLevelCodes)
+ m_NumLevelCodes = i + 1;
+ m_LevelLevels[i] = level;
+ }
+
+ return GetLzBlockPrice() +
+ Huffman_GetPrice_Spec(levelFreqs, levelLens, kLevelTableSize, kLevelDirectBits, kTableDirectLevels) +
+ kNumLenCodesFieldSize + kNumDistCodesFieldSize + kNumLevelCodesFieldSize +
+ m_NumLevelCodes * kLevelFieldSize + kFinalBlockFieldSize + kBlockTypeFieldSize;
+}
+
+NO_INLINE UInt32 CCoder::TryFixedBlock(int tableIndex)
+{
+ CTables &t = m_Tables[tableIndex];
+ BlockSizeRes = t.BlockSizeRes;
+ m_Pos = t.m_Pos;
+ m_NewLevels.SetFixedLevels();
+ SetPrices(m_NewLevels);
+ TryBlock();
+ return kFinalBlockFieldSize + kBlockTypeFieldSize + GetLzBlockPrice();
+}
+
+NO_INLINE UInt32 CCoder::GetBlockPrice(int tableIndex, int numDivPasses)
+{
+ CTables &t = m_Tables[tableIndex];
+ t.StaticMode = false;
+ UInt32 price = TryDynBlock(tableIndex, m_NumPasses);
+ t.BlockSizeRes = BlockSizeRes;
+ UInt32 numValues = m_ValueIndex;
+ UInt32 posTemp = m_Pos;
+ UInt32 additionalOffsetEnd = m_AdditionalOffset;
+
+ if (m_CheckStatic && m_ValueIndex <= kFixedHuffmanCodeBlockSizeMax)
+ {
+ const UInt32 fixedPrice = TryFixedBlock(tableIndex);
+ t.StaticMode = (fixedPrice < price);
+ if (t.StaticMode)
+ price = fixedPrice;
+ }
+
+ const UInt32 storePrice = GetStorePrice(BlockSizeRes, 0); // bitPosition
+ t.StoreMode = (storePrice <= price);
+ if (t.StoreMode)
+ price = storePrice;
+
+ t.UseSubBlocks = false;
+
+ if (numDivPasses > 1 && numValues >= kDivideCodeBlockSizeMin)
+ {
+ CTables &t0 = m_Tables[(tableIndex << 1)];
+ (CLevels &)t0 = t;
+ t0.BlockSizeRes = t.BlockSizeRes >> 1;
+ t0.m_Pos = t.m_Pos;
+ UInt32 subPrice = GetBlockPrice((tableIndex << 1), numDivPasses - 1);
+
+ UInt32 blockSize2 = t.BlockSizeRes - t0.BlockSizeRes;
+ if (t0.BlockSizeRes >= kDivideBlockSizeMin && blockSize2 >= kDivideBlockSizeMin)
+ {
+ CTables &t1 = m_Tables[(tableIndex << 1) + 1];
+ (CLevels &)t1 = t;
+ t1.BlockSizeRes = blockSize2;
+ t1.m_Pos = m_Pos;
+ m_AdditionalOffset -= t0.BlockSizeRes;
+ subPrice += GetBlockPrice((tableIndex << 1) + 1, numDivPasses - 1);
+ t.UseSubBlocks = (subPrice < price);
+ if (t.UseSubBlocks)
+ price = subPrice;
+ }
+ }
+ m_AdditionalOffset = additionalOffsetEnd;
+ m_Pos = posTemp;
+ return price;
+}
+
+void CCoder::CodeBlock(int tableIndex, bool finalBlock)
+{
+ CTables &t = m_Tables[tableIndex];
+ if (t.UseSubBlocks)
+ {
+ CodeBlock((tableIndex << 1), false);
+ CodeBlock((tableIndex << 1) + 1, finalBlock);
+ }
+ else
+ {
+ if (t.StoreMode)
+ WriteStoreBlock(t.BlockSizeRes, m_AdditionalOffset, finalBlock);
+ else
+ {
+ WriteBits((finalBlock ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize);
+ if (t.StaticMode)
+ {
+ WriteBits(NBlockType::kFixedHuffman, kBlockTypeFieldSize);
+ TryFixedBlock(tableIndex);
+ int i;
+ const int kMaxStaticHuffLen = 9;
+ for (i = 0; i < kFixedMainTableSize; i++)
+ mainFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.litLenLevels[i]);
+ for (i = 0; i < kFixedDistTableSize; i++)
+ distFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.distLevels[i]);
+ MakeTables(kMaxStaticHuffLen);
+ }
+ else
+ {
+ if (m_NumDivPasses > 1 || m_CheckStatic)
+ TryDynBlock(tableIndex, 1);
+ WriteBits(NBlockType::kDynamicHuffman, kBlockTypeFieldSize);
+ WriteBits(m_NumLitLenLevels - kNumLitLenCodesMin, kNumLenCodesFieldSize);
+ WriteBits(m_NumDistLevels - kNumDistCodesMin, kNumDistCodesFieldSize);
+ WriteBits(m_NumLevelCodes - kNumLevelCodesMin, kNumLevelCodesFieldSize);
+
+ for (UInt32 i = 0; i < m_NumLevelCodes; i++)
+ WriteBits(m_LevelLevels[i], kLevelFieldSize);
+
+ Huffman_ReverseBits(levelCodes, levelLens, kLevelTableSize);
+ LevelTableCode(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelLens, levelCodes);
+ LevelTableCode(m_NewLevels.distLevels, m_NumDistLevels, levelLens, levelCodes);
+ }
+ WriteBlock();
+ }
+ m_AdditionalOffset -= t.BlockSizeRes;
+ }
+}
+
+SRes Read(void *object, void *data, size_t *size)
+{
+ const UInt32 kStepSize = (UInt32)1 << 31;
+ UInt32 curSize = ((*size < kStepSize) ? (UInt32)*size : kStepSize);
+ HRESULT res = ((CSeqInStream *)object)->RealStream->Read(data, curSize, &curSize);
+ *size = curSize;
+ return (SRes)res;
+}
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */ , const UInt64 * /* outSize */ , ICompressProgressInfo *progress)
+{
+ m_CheckStatic = (m_NumPasses != 1 || m_NumDivPasses != 1);
+ m_IsMultiPass = (m_CheckStatic || (m_NumPasses != 1 || m_NumDivPasses != 1));
+
+ RINOK(Create());
+
+ m_ValueBlockSize = (7 << 10) + (1 << 12) * m_NumDivPasses;
+
+ UInt64 nowPos = 0;
+
+ _seqInStream.RealStream = inStream;
+ _seqInStream.SeqInStream.Read = Read;
+ _lzInWindow.stream = &_seqInStream.SeqInStream;
+
+ MatchFinder_Init(&_lzInWindow);
+ m_OutStream.SetStream(outStream);
+ m_OutStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ m_OptimumEndIndex = m_OptimumCurrentIndex = 0;
+
+ CTables &t = m_Tables[1];
+ t.m_Pos = 0;
+ t.InitStructures();
+
+ m_AdditionalOffset = 0;
+ do
+ {
+ t.BlockSizeRes = kBlockUncompressedSizeThreshold;
+ m_SecondPass = false;
+ GetBlockPrice(1, m_NumDivPasses);
+ CodeBlock(1, Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0);
+ nowPos += m_Tables[1].BlockSizeRes;
+ if (progress != NULL)
+ {
+ UInt64 packSize = m_OutStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&nowPos, &packSize));
+ }
+ }
+ while (Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) != 0);
+ if (_lzInWindow.result != SZ_OK)
+ return _lzInWindow.result;
+ return m_OutStream.Flush();
+}
+
+HRESULT CCoder::BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return E_FAIL; }
+}
+
+STDMETHODIMP CCOMCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+ { return BaseCode(inStream, outStream, inSize, outSize, progress); }
+
+STDMETHODIMP CCOMCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+ { return BaseSetEncoderProperties2(propIDs, props, numProps); }
+
+STDMETHODIMP CCOMCoder64::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+ { return BaseCode(inStream, outStream, inSize, outSize, progress); }
+
+STDMETHODIMP CCOMCoder64::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+ { return BaseSetEncoderProperties2(propIDs, props, numProps); }
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DeflateEncoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateEncoder.h
new file mode 100644
index 000000000..71c39e4e5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateEncoder.h
@@ -0,0 +1,211 @@
+// DeflateEncoder.h
+
+#ifndef __DEFLATE_ENCODER_H
+#define __DEFLATE_ENCODER_H
+
+#include "../../../C/LzFind.h"
+
+#include "Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "BitlEncoder.h"
+#include "DeflateConst.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NEncoder {
+
+struct CCodeValue
+{
+ UInt16 Len;
+ UInt16 Pos;
+ void SetAsLiteral() { Len = (1 << 15); }
+ bool IsLiteral() const { return (Len >= (1 << 15)); }
+};
+
+struct COptimal
+{
+ UInt32 Price;
+ UInt16 PosPrev;
+ UInt16 BackPrev;
+};
+
+const UInt32 kNumOptsBase = 1 << 12;
+const UInt32 kNumOpts = kNumOptsBase + kMatchMaxLen;
+
+class CCoder;
+
+struct CTables: public CLevels
+{
+ bool UseSubBlocks;
+ bool StoreMode;
+ bool StaticMode;
+ UInt32 BlockSizeRes;
+ UInt32 m_Pos;
+ void InitStructures();
+};
+
+typedef struct _CSeqInStream
+{
+ ISeqInStream SeqInStream;
+ CMyComPtr<ISequentialInStream> RealStream;
+} CSeqInStream;
+
+class CCoder
+{
+ CMatchFinder _lzInWindow;
+ CBitlEncoder m_OutStream;
+
+ CSeqInStream _seqInStream;
+
+public:
+ CCodeValue *m_Values;
+
+ UInt16 *m_MatchDistances;
+ UInt32 m_NumFastBytes;
+ bool _fastMode;
+ bool _btMode;
+
+ UInt16 *m_OnePosMatchesMemory;
+ UInt16 *m_DistanceMemory;
+
+ UInt32 m_Pos;
+
+ int m_NumPasses;
+ int m_NumDivPasses;
+ bool m_CheckStatic;
+ bool m_IsMultiPass;
+ UInt32 m_ValueBlockSize;
+
+ UInt32 m_NumLenCombinations;
+ UInt32 m_MatchMaxLen;
+ const Byte *m_LenStart;
+ const Byte *m_LenDirectBits;
+
+ bool m_Created;
+ bool m_Deflate64Mode;
+
+ Byte m_LevelLevels[kLevelTableSize];
+ int m_NumLitLenLevels;
+ int m_NumDistLevels;
+ UInt32 m_NumLevelCodes;
+ UInt32 m_ValueIndex;
+
+ bool m_SecondPass;
+ UInt32 m_AdditionalOffset;
+
+ UInt32 m_OptimumEndIndex;
+ UInt32 m_OptimumCurrentIndex;
+
+ Byte m_LiteralPrices[256];
+ Byte m_LenPrices[kNumLenSymbolsMax];
+ Byte m_PosPrices[kDistTableSize64];
+
+ CLevels m_NewLevels;
+ UInt32 mainFreqs[kFixedMainTableSize];
+ UInt32 distFreqs[kDistTableSize64];
+ UInt32 mainCodes[kFixedMainTableSize];
+ UInt32 distCodes[kDistTableSize64];
+ UInt32 levelCodes[kLevelTableSize];
+ Byte levelLens[kLevelTableSize];
+
+ UInt32 BlockSizeRes;
+
+ CTables *m_Tables;
+ COptimal m_Optimum[kNumOpts];
+
+ UInt32 m_MatchFinderCycles;
+ // IMatchFinderSetNumPasses *m_SetMfPasses;
+
+ void GetMatches();
+ void MovePos(UInt32 num);
+ UInt32 Backward(UInt32 &backRes, UInt32 cur);
+ UInt32 GetOptimal(UInt32 &backRes);
+ UInt32 GetOptimalFast(UInt32 &backRes);
+
+ void LevelTableDummy(const Byte *levels, int numLevels, UInt32 *freqs);
+
+ void WriteBits(UInt32 value, int numBits);
+ void LevelTableCode(const Byte *levels, int numLevels, const Byte *lens, const UInt32 *codes);
+
+ void MakeTables(unsigned maxHuffLen);
+ UInt32 GetLzBlockPrice() const;
+ void TryBlock();
+ UInt32 TryDynBlock(int tableIndex, UInt32 numPasses);
+
+ UInt32 TryFixedBlock(int tableIndex);
+
+ void SetPrices(const CLevels &levels);
+ void WriteBlock();
+
+ HRESULT Create();
+ void Free();
+
+ void WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock);
+ void WriteTables(bool writeMode, bool finalBlock);
+
+ void WriteBlockData(bool writeMode, bool finalBlock);
+
+ void ReleaseStreams()
+ {
+ _seqInStream.RealStream.Release();
+ m_OutStream.ReleaseStream();
+ }
+ class CCoderReleaser
+ {
+ CCoder *m_Coder;
+ public:
+ CCoderReleaser(CCoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
+ };
+ friend class CCoderReleaser;
+
+ UInt32 GetBlockPrice(int tableIndex, int numDivPasses);
+ void CodeBlock(int tableIndex, bool finalBlock);
+
+public:
+ CCoder(bool deflate64Mode = false);
+ ~CCoder();
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ HRESULT BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ HRESULT BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+};
+
+
+class CCOMCoder :
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public CMyUnknownImp,
+ public CCoder
+{
+public:
+ MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
+ CCOMCoder(): CCoder(false) {};
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+};
+
+class CCOMCoder64 :
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public CMyUnknownImp,
+ public CCoder
+{
+public:
+ MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
+ CCOMCoder64(): CCoder(true) {};
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DeflateNsisRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateNsisRegister.cpp
new file mode 100644
index 000000000..ffad96c21
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateNsisRegister.cpp
@@ -0,0 +1,14 @@
+// DeflateNsisRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "DeflateDecoder.h"
+
+static void *CreateCodecDeflateNsis() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NDecoder::CNsisCOMCoder); }
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodecDeflateNsis, 0, 0x040901, L"DeflateNSIS", 1, false };
+
+REGISTER_CODEC(DeflateNsis)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DeflateRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateRegister.cpp
new file mode 100644
index 000000000..45f55219e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DeflateRegister.cpp
@@ -0,0 +1,21 @@
+// DeflateRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "DeflateDecoder.h"
+
+static void *CreateCodecDeflate() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NDecoder::CCOMCoder); }
+
+#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY)
+#include "DeflateEncoder.h"
+static void *CreateCodecOutDeflate() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NEncoder::CCOMCoder); }
+#else
+#define CreateCodecOutDeflate 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodecDeflate, CreateCodecOutDeflate, 0x040108, L"Deflate", 1, false };
+
+REGISTER_CODEC(Deflate)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DeltaFilter.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/DeltaFilter.cpp
new file mode 100644
index 000000000..2e421acf4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DeltaFilter.cpp
@@ -0,0 +1,112 @@
+// DeltaFilter.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Delta.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BranchCoder.h"
+
+struct CDelta
+{
+ unsigned _delta;
+ Byte _state[DELTA_STATE_SIZE];
+ CDelta(): _delta(1) {}
+ void DeltaInit() { Delta_Init(_state); }
+};
+
+class CDeltaEncoder:
+ public ICompressFilter,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ CDelta,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+};
+
+class CDeltaDecoder:
+ public ICompressFilter,
+ public ICompressSetDecoderProperties2,
+ CDelta,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+STDMETHODIMP CDeltaEncoder::Init()
+{
+ DeltaInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDeltaEncoder::Filter(Byte *data, UInt32 size)
+{
+ Delta_Encode(_state, _delta, data, size);
+ return size;
+}
+
+STDMETHODIMP CDeltaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ UInt32 delta = _delta;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ if (propIDs[i] != NCoderPropID::kDefaultProp || prop.vt != VT_UI4 || prop.ulVal < 1 || prop.ulVal > 256)
+ return E_INVALIDARG;
+ delta = prop.ulVal;
+ }
+ _delta = delta;
+ return S_OK;
+}
+
+STDMETHODIMP CDeltaEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte prop = (Byte)(_delta - 1);
+ return outStream->Write(&prop, 1, NULL);
+}
+
+STDMETHODIMP CDeltaDecoder::Init()
+{
+ DeltaInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDeltaDecoder::Filter(Byte *data, UInt32 size)
+{
+ Delta_Decode(_state, _delta, data, size);
+ return size;
+}
+
+STDMETHODIMP CDeltaDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
+{
+ if (size != 1)
+ return E_INVALIDARG;
+ _delta = (unsigned)props[0] + 1;
+ return S_OK;
+}
+
+#define CREATE_CODEC(x) \
+ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## Decoder); } \
+ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## Encoder); }
+
+CREATE_CODEC(Delta)
+
+#define METHOD_ITEM(x, id, name) { CreateCodec ## x, CreateCodec ## x ## Out, id, name, 1, true }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ METHOD_ITEM(Delta, 3, L"Delta")
+};
+
+REGISTER_CODECS(Delta)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DllExports.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/DllExports.cpp
new file mode 100644
index 000000000..a7ec90270
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DllExports.cpp
@@ -0,0 +1,39 @@
+// DllExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+static const unsigned int kNumCodecsMax = 32;
+unsigned int g_NumCodecs = 0;
+const CCodecInfo *g_Codecs[kNumCodecsMax];
+void RegisterCodec(const CCodecInfo *codecInfo)
+{
+ if (g_NumCodecs < kNumCodecsMax)
+ g_Codecs[g_NumCodecs++] = codecInfo;
+}
+
+#ifdef _WIN32
+extern "C"
+BOOL WINAPI DllMain(HINSTANCE /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/)
+{
+ return TRUE;
+}
+#endif
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ return CreateCoder(clsid, iid, outObject);
+}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/DllExports2.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/DllExports2.cpp
new file mode 100644
index 000000000..836f3fa42
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/DllExports2.cpp
@@ -0,0 +1,28 @@
+// DllExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+extern "C"
+BOOL WINAPI DllMain(HINSTANCE /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/)
+{
+ return TRUE;
+}
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ return CreateCoder(clsid, iid, outObject);
+}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/HuffmanDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/HuffmanDecoder.h
new file mode 100644
index 000000000..82a1e6f2d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/HuffmanDecoder.h
@@ -0,0 +1,89 @@
+// Compress/HuffmanDecoder.h
+
+#ifndef __COMPRESS_HUFFMAN_DECODER_H
+#define __COMPRESS_HUFFMAN_DECODER_H
+
+#include "../../Common/Types.h"
+
+namespace NCompress {
+namespace NHuffman {
+
+const int kNumTableBits = 9;
+
+template <int kNumBitsMax, UInt32 m_NumSymbols>
+class CDecoder
+{
+ UInt32 m_Limits[kNumBitsMax + 1]; // m_Limits[i] = value limit for symbols with length = i
+ UInt32 m_Positions[kNumBitsMax + 1]; // m_Positions[i] = index in m_Symbols[] of first symbol with length = i
+ UInt32 m_Symbols[m_NumSymbols];
+ Byte m_Lengths[1 << kNumTableBits]; // Table oh length for short codes.
+
+public:
+
+ bool SetCodeLengths(const Byte *codeLengths)
+ {
+ int lenCounts[kNumBitsMax + 1];
+ UInt32 tmpPositions[kNumBitsMax + 1];
+ int i;
+ for(i = 1; i <= kNumBitsMax; i++)
+ lenCounts[i] = 0;
+ UInt32 symbol;
+ for (symbol = 0; symbol < m_NumSymbols; symbol++)
+ {
+ int len = codeLengths[symbol];
+ if (len > kNumBitsMax)
+ return false;
+ lenCounts[len]++;
+ m_Symbols[symbol] = 0xFFFFFFFF;
+ }
+ lenCounts[0] = 0;
+ m_Positions[0] = m_Limits[0] = 0;
+ UInt32 startPos = 0;
+ UInt32 index = 0;
+ const UInt32 kMaxValue = (1 << kNumBitsMax);
+ for (i = 1; i <= kNumBitsMax; i++)
+ {
+ startPos += lenCounts[i] << (kNumBitsMax - i);
+ if (startPos > kMaxValue)
+ return false;
+ m_Limits[i] = (i == kNumBitsMax) ? kMaxValue : startPos;
+ m_Positions[i] = m_Positions[i - 1] + lenCounts[i - 1];
+ tmpPositions[i] = m_Positions[i];
+ if(i <= kNumTableBits)
+ {
+ UInt32 limit = (m_Limits[i] >> (kNumBitsMax - kNumTableBits));
+ for (; index < limit; index++)
+ m_Lengths[index] = (Byte)i;
+ }
+ }
+ for (symbol = 0; symbol < m_NumSymbols; symbol++)
+ {
+ int len = codeLengths[symbol];
+ if (len != 0)
+ m_Symbols[tmpPositions[len]++] = symbol;
+ }
+ return true;
+ }
+
+ template <class TBitDecoder>
+ UInt32 DecodeSymbol(TBitDecoder *bitStream)
+ {
+ int numBits;
+ UInt32 value = bitStream->GetValue(kNumBitsMax);
+ if (value < m_Limits[kNumTableBits])
+ numBits = m_Lengths[value >> (kNumBitsMax - kNumTableBits)];
+ else
+ for (numBits = kNumTableBits + 1; value >= m_Limits[numBits]; numBits++);
+ bitStream->MovePos(numBits);
+ UInt32 index = m_Positions[numBits] +
+ ((value - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits));
+ if (index >= m_NumSymbols)
+ // throw CDecoderException(); // test it
+ return 0xFFFFFFFF;
+ return m_Symbols[index];
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeDecoder.cpp
new file mode 100644
index 000000000..f84a013c2
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeDecoder.cpp
@@ -0,0 +1,219 @@
+// Implode/Decoder.cpp
+
+#include "StdAfx.h"
+
+#include "ImplodeDecoder.h"
+#include "Common/Defs.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NDecoder {
+
+class CException
+{
+public:
+ enum ECauseType
+ {
+ kData
+ } m_Cause;
+ CException(ECauseType cause): m_Cause(cause) {}
+};
+
+static const int kNumDistanceLowDirectBitsForBigDict = 7;
+static const int kNumDistanceLowDirectBitsForSmallDict = 6;
+
+static const int kNumBitsInByte = 8;
+
+// static const int kLevelStructuresNumberFieldSize = kNumBitsInByte;
+static const int kLevelStructuresNumberAdditionalValue = 1;
+
+static const int kNumLevelStructureLevelBits = 4;
+static const int kLevelStructureLevelAdditionalValue = 1;
+
+static const int kNumLevelStructureRepNumberBits = 4;
+static const int kLevelStructureRepNumberAdditionalValue = 1;
+
+
+static const int kLiteralTableSize = (1 << kNumBitsInByte);
+static const int kDistanceTableSize = 64;
+static const int kLengthTableSize = 64;
+
+static const UInt32 kHistorySize =
+ (1 << MyMax(kNumDistanceLowDirectBitsForBigDict,
+ kNumDistanceLowDirectBitsForSmallDict)) *
+ kDistanceTableSize; // = 8 KB;
+
+static const int kNumAdditionalLengthBits = 8;
+
+static const UInt32 kMatchMinLenWhenLiteralsOn = 3;
+static const UInt32 kMatchMinLenWhenLiteralsOff = 2;
+
+static const UInt32 kMatchMinLenMax = MyMax(kMatchMinLenWhenLiteralsOn,
+ kMatchMinLenWhenLiteralsOff); // 3
+
+// static const UInt32 kMatchMaxLenMax = kMatchMinLenMax + (kLengthTableSize - 1) + (1 << kNumAdditionalLengthBits) - 1; // or 2
+
+enum
+{
+ kMatchId = 0,
+ kLiteralId = 1
+};
+
+
+CCoder::CCoder():
+ m_LiteralDecoder(kLiteralTableSize),
+ m_LengthDecoder(kLengthTableSize),
+ m_DistanceDecoder(kDistanceTableSize)
+{
+}
+
+void CCoder::ReleaseStreams()
+{
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+}
+
+bool CCoder::ReadLevelItems(NImplode::NHuffman::CDecoder &decoder,
+ Byte *levels, int numLevelItems)
+{
+ int numCodedStructures = m_InBitStream.ReadBits(kNumBitsInByte) +
+ kLevelStructuresNumberAdditionalValue;
+ int currentIndex = 0;
+ for(int i = 0; i < numCodedStructures; i++)
+ {
+ int level = m_InBitStream.ReadBits(kNumLevelStructureLevelBits) +
+ kLevelStructureLevelAdditionalValue;
+ int rep = m_InBitStream.ReadBits(kNumLevelStructureRepNumberBits) +
+ kLevelStructureRepNumberAdditionalValue;
+ if (currentIndex + rep > numLevelItems)
+ throw CException(CException::kData);
+ for(int j = 0; j < rep; j++)
+ levels[currentIndex++] = (Byte)level;
+ }
+ if (currentIndex != numLevelItems)
+ return false;
+ return decoder.SetCodeLengths(levels);
+}
+
+
+bool CCoder::ReadTables(void)
+{
+ if (m_LiteralsOn)
+ {
+ Byte literalLevels[kLiteralTableSize];
+ if (!ReadLevelItems(m_LiteralDecoder, literalLevels, kLiteralTableSize))
+ return false;
+ }
+
+ Byte lengthLevels[kLengthTableSize];
+ if (!ReadLevelItems(m_LengthDecoder, lengthLevels, kLengthTableSize))
+ return false;
+
+ Byte distanceLevels[kDistanceTableSize];
+ return ReadLevelItems(m_DistanceDecoder, distanceLevels, kDistanceTableSize);
+}
+
+class CCoderReleaser
+{
+ CCoder *m_Coder;
+public:
+ CCoderReleaser(CCoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
+};
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (outSize == NULL)
+ return E_INVALIDARG;
+ UInt64 pos = 0, unPackSize = *outSize;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+ CCoderReleaser coderReleaser(this);
+
+ if (!ReadTables())
+ return S_FALSE;
+
+ while(pos < unPackSize)
+ {
+ if (progress != NULL && pos % (1 << 16) == 0)
+ {
+ UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ }
+ if(m_InBitStream.ReadBits(1) == kMatchId) // match
+ {
+ UInt32 lowDistBits = m_InBitStream.ReadBits(m_NumDistanceLowDirectBits);
+ UInt32 distance = m_DistanceDecoder.DecodeSymbol(&m_InBitStream);
+ if (distance >= kDistanceTableSize)
+ return S_FALSE;
+ distance = (distance << m_NumDistanceLowDirectBits) + lowDistBits;
+ UInt32 lengthSymbol = m_LengthDecoder.DecodeSymbol(&m_InBitStream);
+ if (lengthSymbol >= kLengthTableSize)
+ return S_FALSE;
+ UInt32 length = lengthSymbol + m_MinMatchLength;
+ if (lengthSymbol == kLengthTableSize - 1) // special symbol = 63
+ length += m_InBitStream.ReadBits(kNumAdditionalLengthBits);
+ while(distance >= pos && length > 0)
+ {
+ m_OutWindowStream.PutByte(0);
+ pos++;
+ length--;
+ }
+ if (length > 0)
+ m_OutWindowStream.CopyBlock(distance, length);
+ pos += length;
+ }
+ else
+ {
+ Byte b;
+ if (m_LiteralsOn)
+ {
+ UInt32 temp = m_LiteralDecoder.DecodeSymbol(&m_InBitStream);
+ if (temp >= kLiteralTableSize)
+ return S_FALSE;
+ b = (Byte)temp;
+ }
+ else
+ b = (Byte)m_InBitStream.ReadBits(kNumBitsInByte);
+ m_OutWindowStream.PutByte(b);
+ pos++;
+ }
+ }
+ if (pos > unPackSize)
+ return S_FALSE;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ Byte flag = data[0];
+ m_BigDictionaryOn = ((flag & 2) != 0);
+ m_NumDistanceLowDirectBits = m_BigDictionaryOn ?
+ kNumDistanceLowDirectBitsForBigDict:
+ kNumDistanceLowDirectBitsForSmallDict;
+ m_LiteralsOn = ((flag & 4) != 0);
+ m_MinMatchLength = m_LiteralsOn ?
+ kMatchMinLenWhenLiteralsOn :
+ kMatchMinLenWhenLiteralsOff;
+ return S_OK;
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeDecoder.h
new file mode 100644
index 000000000..7ea1553ee
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeDecoder.h
@@ -0,0 +1,57 @@
+// ImplodeDecoder.h
+
+#ifndef __COMPRESS_IMPLODE_DECODER_H
+#define __COMPRESS_IMPLODE_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "ImplodeHuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NDecoder {
+
+class CCoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitl::CDecoder<CInBuffer> m_InBitStream;
+
+ NImplode::NHuffman::CDecoder m_LiteralDecoder;
+ NImplode::NHuffman::CDecoder m_LengthDecoder;
+ NImplode::NHuffman::CDecoder m_DistanceDecoder;
+
+ bool m_BigDictionaryOn;
+ bool m_LiteralsOn;
+
+ int m_NumDistanceLowDirectBits;
+ UInt32 m_MinMatchLength;
+
+ bool ReadLevelItems(NImplode::NHuffman::CDecoder &table, Byte *levels, int numLevelItems);
+ bool ReadTables();
+ void DeCodeLevelTable(Byte *newLevels, int numLevels);
+public:
+ CCoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ void ReleaseStreams();
+ HRESULT Flush() { return m_OutWindowStream.Flush(); }
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp
new file mode 100644
index 000000000..64345e08b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp
@@ -0,0 +1,89 @@
+// ImplodeHuffmanDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "ImplodeHuffmanDecoder.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NHuffman {
+
+CDecoder::CDecoder(UInt32 numSymbols):
+ m_NumSymbols(numSymbols)
+{
+ m_Symbols = new UInt32[m_NumSymbols];
+}
+
+CDecoder::~CDecoder()
+{
+ delete []m_Symbols;
+}
+
+bool CDecoder::SetCodeLengths(const Byte *codeLengths)
+{
+ // int lenCounts[kNumBitsInLongestCode + 1], tmpPositions[kNumBitsInLongestCode + 1];
+ int lenCounts[kNumBitsInLongestCode + 2], tmpPositions[kNumBitsInLongestCode + 1];
+ int i;
+ for(i = 0; i <= kNumBitsInLongestCode; i++)
+ lenCounts[i] = 0;
+ UInt32 symbolIndex;
+ for (symbolIndex = 0; symbolIndex < m_NumSymbols; symbolIndex++)
+ lenCounts[codeLengths[symbolIndex]]++;
+ // lenCounts[0] = 0;
+
+ // tmpPositions[0] = m_Positions[0] = m_Limitits[0] = 0;
+ m_Limitits[kNumBitsInLongestCode + 1] = 0;
+ m_Positions[kNumBitsInLongestCode + 1] = 0;
+ lenCounts[kNumBitsInLongestCode + 1] = 0;
+
+
+ UInt32 startPos = 0;
+ static const UInt32 kMaxValue = (1 << kNumBitsInLongestCode);
+
+ for (i = kNumBitsInLongestCode; i > 0; i--)
+ {
+ startPos += lenCounts[i] << (kNumBitsInLongestCode - i);
+ if (startPos > kMaxValue)
+ return false;
+ m_Limitits[i] = startPos;
+ m_Positions[i] = m_Positions[i + 1] + lenCounts[i + 1];
+ tmpPositions[i] = m_Positions[i] + lenCounts[i];
+
+ }
+
+ // if _ZIP_MODE do not throw exception for trees containing only one node
+ // #ifndef _ZIP_MODE
+ if (startPos != kMaxValue)
+ return false;
+ // #endif
+
+ for (symbolIndex = 0; symbolIndex < m_NumSymbols; symbolIndex++)
+ if (codeLengths[symbolIndex] != 0)
+ m_Symbols[--tmpPositions[codeLengths[symbolIndex]]] = symbolIndex;
+ return true;
+}
+
+UInt32 CDecoder::DecodeSymbol(CInBit *inStream)
+{
+ UInt32 numBits = 0;
+ UInt32 value = inStream->GetValue(kNumBitsInLongestCode);
+ int i;
+ for(i = kNumBitsInLongestCode; i > 0; i--)
+ {
+ if (value < m_Limitits[i])
+ {
+ numBits = i;
+ break;
+ }
+ }
+ if (i == 0)
+ return 0xFFFFFFFF;
+ inStream->MovePos(numBits);
+ UInt32 index = m_Positions[numBits] +
+ ((value - m_Limitits[numBits + 1]) >> (kNumBitsInLongestCode - numBits));
+ if (index >= m_NumSymbols)
+ return 0xFFFFFFFF;
+ return m_Symbols[index];
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeHuffmanDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeHuffmanDecoder.h
new file mode 100644
index 000000000..6120a35ab
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ImplodeHuffmanDecoder.h
@@ -0,0 +1,34 @@
+// ImplodeHuffmanDecoder.h
+
+#ifndef __IMPLODE_HUFFMAN_DECODER_H
+#define __IMPLODE_HUFFMAN_DECODER_H
+
+#include "../Common/InBuffer.h"
+
+#include "BitlDecoder.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NHuffman {
+
+const int kNumBitsInLongestCode = 16;
+
+typedef NBitl::CDecoder<CInBuffer> CInBit;
+
+class CDecoder
+{
+ UInt32 m_Limitits[kNumBitsInLongestCode + 2]; // m_Limitits[i] = value limit for symbols with length = i
+ UInt32 m_Positions[kNumBitsInLongestCode + 2]; // m_Positions[i] = index in m_Symbols[] of first symbol with length = i
+ UInt32 m_NumSymbols; // number of symbols in m_Symbols
+ UInt32 *m_Symbols; // symbols: at first with len=1 then 2, ... 15.
+public:
+ CDecoder(UInt32 numSymbols);
+ ~CDecoder();
+
+ bool SetCodeLengths(const Byte *codeLengths);
+ UInt32 DecodeSymbol(CInBit *inStream);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp
new file mode 100644
index 000000000..e34e2ed72
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp
@@ -0,0 +1,531 @@
+// LzmaAlone.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+#include <fcntl.h>
+#include <io.h>
+#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
+#else
+#define MY_SET_BINARY_MODE(file)
+#endif
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../LzmaDecoder.h"
+#include "../LzmaEncoder.h"
+
+#include "LzmaBenchCon.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/System.h"
+#endif
+
+#include "../../../../C/7zVersion.h"
+#include "../../../../C/Alloc.h"
+#include "../../../../C/LzmaUtil/Lzma86Dec.h"
+#include "../../../../C/LzmaUtil/Lzma86Enc.h"
+
+using namespace NCommandLineParser;
+
+#ifdef _WIN32
+bool g_IsNT = false;
+static inline bool IsItWindowsNT()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+ if (!::GetVersionEx(&versionInfo))
+ return false;
+ return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+
+static const char *kCantAllocate = "Can not allocate memory";
+static const char *kReadError = "Read error";
+static const char *kWriteError = "Write error";
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kAlgo,
+ kDict,
+ kFb,
+ kMc,
+ kLc,
+ kLp,
+ kPb,
+ kMatchFinder,
+ kMultiThread,
+ kEOS,
+ kStdIn,
+ kStdOut,
+ kFilter86
+};
+}
+
+static const CSwitchForm kSwitchForms[] =
+{
+ { L"?", NSwitchType::kSimple, false },
+ { L"H", NSwitchType::kSimple, false },
+ { L"A", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"D", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"FB", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"MC", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"LC", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"LP", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"PB", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"MF", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"MT", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"EOS", NSwitchType::kSimple, false },
+ { L"SI", NSwitchType::kSimple, false },
+ { L"SO", NSwitchType::kSimple, false },
+ { L"F86", NSwitchType::kPostChar, false, 0, 0, L"+" }
+};
+
+static const int kNumSwitches = sizeof(kSwitchForms) / sizeof(kSwitchForms[0]);
+
+static void PrintHelp()
+{
+ fprintf(stderr, "\nUsage: LZMA <e|d> inputFile outputFile [<switches>...]\n"
+ " e: encode file\n"
+ " d: decode file\n"
+ " b: Benchmark\n"
+ "<Switches>\n"
+ " -a{N}: set compression mode - [0, 1], default: 1 (max)\n"
+ " -d{N}: set dictionary size - [12, 30], default: 23 (8MB)\n"
+ " -fb{N}: set number of fast bytes - [5, 273], default: 128\n"
+ " -mc{N}: set number of cycles for match finder\n"
+ " -lc{N}: set number of literal context bits - [0, 8], default: 3\n"
+ " -lp{N}: set number of literal pos bits - [0, 4], default: 0\n"
+ " -pb{N}: set number of pos bits - [0, 4], default: 2\n"
+ " -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, hc4], default: bt4\n"
+ " -mt{N}: set number of CPU threads\n"
+ " -eos: write End Of Stream marker\n"
+ " -si: read data from stdin\n"
+ " -so: write data to stdout\n"
+ );
+}
+
+static void PrintHelpAndExit(const char *s)
+{
+ fprintf(stderr, "\nError: %s\n\n", s);
+ PrintHelp();
+ throw -1;
+}
+
+static void IncorrectCommand()
+{
+ PrintHelpAndExit("Incorrect command");
+}
+
+static void WriteArgumentsToStringList(int numArguments, const char *arguments[],
+ UStringVector &strings)
+{
+ for(int i = 1; i < numArguments; i++)
+ strings.Add(MultiByteToUnicodeString(arguments[i]));
+}
+
+static bool GetNumber(const wchar_t *s, UInt32 &value)
+{
+ value = 0;
+ if (MyStringLen(s) == 0)
+ return false;
+ const wchar_t *end;
+ UInt64 res = ConvertStringToUInt64(s, &end);
+ if (*end != L'\0')
+ return false;
+ if (res > 0xFFFFFFFF)
+ return false;
+ value = UInt32(res);
+ return true;
+}
+
+static void ParseUInt32(const CParser &parser, int index, UInt32 &res)
+{
+ if (parser[index].ThereIs)
+ if (!GetNumber(parser[index].PostStrings[0], res))
+ IncorrectCommand();
+}
+
+int main2(int n, const char *args[])
+{
+ #ifdef _WIN32
+ g_IsNT = IsItWindowsNT();
+ #endif
+
+ fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");
+
+ if (n == 1)
+ {
+ PrintHelp();
+ return 0;
+ }
+
+ bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4);
+ if (unsupportedTypes)
+ {
+ fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
+ return 1;
+ }
+
+ UStringVector commandStrings;
+ WriteArgumentsToStringList(n, args, commandStrings);
+ CParser parser(kNumSwitches);
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ }
+ catch(...)
+ {
+ IncorrectCommand();
+ }
+
+ if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
+ {
+ PrintHelp();
+ return 0;
+ }
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+
+ int paramIndex = 0;
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &command = nonSwitchStrings[paramIndex++];
+
+ bool dictDefined = false;
+ UInt32 dict = (UInt32)-1;
+ if(parser[NKey::kDict].ThereIs)
+ {
+ UInt32 dicLog;
+ if (!GetNumber(parser[NKey::kDict].PostStrings[0], dicLog))
+ IncorrectCommand();
+ dict = 1 << dicLog;
+ dictDefined = true;
+ }
+ UString mf = L"BT4";
+ if (parser[NKey::kMatchFinder].ThereIs)
+ mf = parser[NKey::kMatchFinder].PostStrings[0];
+
+ UInt32 numThreads = (UInt32)-1;
+
+ #ifndef _7ZIP_ST
+ if (parser[NKey::kMultiThread].ThereIs)
+ {
+ UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+ const UString &s = parser[NKey::kMultiThread].PostStrings[0];
+ if (s.IsEmpty())
+ numThreads = numCPUs;
+ else
+ if (!GetNumber(s, numThreads))
+ IncorrectCommand();
+ }
+ #endif
+
+ if (command.CompareNoCase(L"b") == 0)
+ {
+ const UInt32 kNumDefaultItereations = 1;
+ UInt32 numIterations = kNumDefaultItereations;
+ {
+ if (paramIndex < nonSwitchStrings.Size())
+ if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
+ numIterations = kNumDefaultItereations;
+ }
+ return LzmaBenchCon(stderr, numIterations, numThreads, dict);
+ }
+
+ if (numThreads == (UInt32)-1)
+ numThreads = 1;
+
+ bool encodeMode = false;
+ if (command.CompareNoCase(L"e") == 0)
+ encodeMode = true;
+ else if (command.CompareNoCase(L"d") == 0)
+ encodeMode = false;
+ else
+ IncorrectCommand();
+
+ bool stdInMode = parser[NKey::kStdIn].ThereIs;
+ bool stdOutMode = parser[NKey::kStdOut].ThereIs;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ CInFileStream *inStreamSpec = 0;
+ if (stdInMode)
+ {
+ inStream = new CStdInFileStream;
+ MY_SET_BINARY_MODE(stdin);
+ }
+ else
+ {
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &inputName = nonSwitchStrings[paramIndex++];
+ inStreamSpec = new CInFileStream;
+ inStream = inStreamSpec;
+ if (!inStreamSpec->Open(GetSystemString(inputName)))
+ {
+ fprintf(stderr, "\nError: can not open input file %s\n",
+ (const char *)GetOemString(inputName));
+ return 1;
+ }
+ }
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ COutFileStream *outStreamSpec = NULL;
+ if (stdOutMode)
+ {
+ outStream = new CStdOutFileStream;
+ MY_SET_BINARY_MODE(stdout);
+ }
+ else
+ {
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &outputName = nonSwitchStrings[paramIndex++];
+ outStreamSpec = new COutFileStream;
+ outStream = outStreamSpec;
+ if (!outStreamSpec->Create(GetSystemString(outputName), true))
+ {
+ fprintf(stderr, "\nError: can not open output file %s\n",
+ (const char *)GetOemString(outputName));
+ return 1;
+ }
+ }
+
+ if (parser[NKey::kFilter86].ThereIs)
+ {
+ // -f86 switch is for x86 filtered mode: BCJ + LZMA.
+ if (parser[NKey::kEOS].ThereIs || stdInMode)
+ throw "Can not use stdin in this mode";
+ UInt64 fileSize;
+ inStreamSpec->File.GetLength(fileSize);
+ if (fileSize > 0xF0000000)
+ throw "File is too big";
+ size_t inSize = (size_t)fileSize;
+ Byte *inBuffer = 0;
+ if (inSize != 0)
+ {
+ inBuffer = (Byte *)MyAlloc((size_t)inSize);
+ if (inBuffer == 0)
+ throw kCantAllocate;
+ }
+
+ if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK)
+ throw "Can not read";
+
+ Byte *outBuffer = 0;
+ size_t outSize;
+ if (encodeMode)
+ {
+ // we allocate 105% of original size for output buffer
+ outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
+ if (outSize != 0)
+ {
+ outBuffer = (Byte *)MyAlloc((size_t)outSize);
+ if (outBuffer == 0)
+ throw kCantAllocate;
+ }
+ if (!dictDefined)
+ dict = 1 << 23;
+ int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize,
+ 5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
+ if (res != 0)
+ {
+ fprintf(stderr, "\nEncoder error = %d\n", (int)res);
+ return 1;
+ }
+ }
+ else
+ {
+ UInt64 outSize64;
+ if (Lzma86_GetUnpackSize(inBuffer, inSize, &outSize64) != 0)
+ throw "data error";
+ outSize = (size_t)outSize64;
+ if (outSize != outSize64)
+ throw "too big";
+ if (outSize != 0)
+ {
+ outBuffer = (Byte *)MyAlloc(outSize);
+ if (outBuffer == 0)
+ throw kCantAllocate;
+ }
+ int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize);
+ if (inSize != (size_t)fileSize)
+ throw "incorrect processed size";
+ if (res != 0)
+ throw "LzmaDecoder error";
+ }
+ if (WriteStream(outStream, outBuffer, outSize) != S_OK)
+ throw kWriteError;
+ MyFree(outBuffer);
+ MyFree(inBuffer);
+ return 0;
+ }
+
+
+ UInt64 fileSize;
+ if (encodeMode)
+ {
+ NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ if (!dictDefined)
+ dict = 1 << 23;
+
+ UInt32 pb = 2;
+ UInt32 lc = 3; // = 0; for 32-bit data
+ UInt32 lp = 0; // = 2; for 32-bit data
+ UInt32 algo = 1;
+ UInt32 fb = 128;
+ UInt32 mc = 16 + fb / 2;
+ bool mcDefined = false;
+
+ bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
+
+ ParseUInt32(parser, NKey::kAlgo, algo);
+ ParseUInt32(parser, NKey::kFb, fb);
+ ParseUInt32(parser, NKey::kLc, lc);
+ ParseUInt32(parser, NKey::kLp, lp);
+ ParseUInt32(parser, NKey::kPb, pb);
+
+ mcDefined = parser[NKey::kMc].ThereIs;
+ if (mcDefined)
+ if (!GetNumber(parser[NKey::kMc].PostStrings[0], mc))
+ IncorrectCommand();
+
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kPosStateBits,
+ NCoderPropID::kLitContextBits,
+ NCoderPropID::kLitPosBits,
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinder,
+ NCoderPropID::kEndMarker,
+ NCoderPropID::kNumThreads,
+ NCoderPropID::kMatchFinderCycles,
+ };
+ const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);
+
+ PROPVARIANT props[kNumPropsMax];
+ for (int p = 0; p < 6; p++)
+ props[p].vt = VT_UI4;
+
+ props[0].ulVal = (UInt32)dict;
+ props[1].ulVal = (UInt32)pb;
+ props[2].ulVal = (UInt32)lc;
+ props[3].ulVal = (UInt32)lp;
+ props[4].ulVal = (UInt32)algo;
+ props[5].ulVal = (UInt32)fb;
+
+ props[6].vt = VT_BSTR;
+ props[6].bstrVal = (BSTR)(const wchar_t *)mf;
+
+ props[7].vt = VT_BOOL;
+ props[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
+
+ props[8].vt = VT_UI4;
+ props[8].ulVal = (UInt32)numThreads;
+
+ // it must be last in property list
+ props[9].vt = VT_UI4;
+ props[9].ulVal = (UInt32)mc;
+
+ int numProps = kNumPropsMax;
+ if (!mcDefined)
+ numProps--;
+
+ if (encoderSpec->SetCoderProperties(propIDs, props, numProps) != S_OK)
+ IncorrectCommand();
+ encoderSpec->WriteCoderProperties(outStream);
+
+ if (eos || stdInMode)
+ fileSize = (UInt64)(Int64)-1;
+ else
+ inStreamSpec->File.GetLength(fileSize);
+
+ for (int i = 0; i < 8; i++)
+ {
+ Byte b = Byte(fileSize >> (8 * i));
+ if (outStream->Write(&b, 1, 0) != S_OK)
+ {
+ fprintf(stderr, kWriteError);
+ return 1;
+ }
+ }
+ HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
+ if (result == E_OUTOFMEMORY)
+ {
+ fprintf(stderr, "\nError: Can not allocate memory\n");
+ return 1;
+ }
+ else if (result != S_OK)
+ {
+ fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
+ return 1;
+ }
+ }
+ else
+ {
+ NCompress::NLzma::CDecoder *decoderSpec = new NCompress::NLzma::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+ decoderSpec->FinishStream = true;
+ const UInt32 kPropertiesSize = 5;
+ Byte header[kPropertiesSize + 8];
+ if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK)
+ {
+ fprintf(stderr, kReadError);
+ return 1;
+ }
+ if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK)
+ {
+ fprintf(stderr, "SetDecoderProperties error");
+ return 1;
+ }
+ fileSize = 0;
+ for (int i = 0; i < 8; i++)
+ fileSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i);
+
+ if (decoder->Code(inStream, outStream, 0, (fileSize == (UInt64)(Int64)-1) ? 0 : &fileSize, 0) != S_OK)
+ {
+ fprintf(stderr, "Decoder error");
+ return 1;
+ }
+ }
+ if (outStreamSpec != NULL)
+ {
+ if (outStreamSpec->Close() != S_OK)
+ {
+ fprintf(stderr, "File closing error");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int MY_CDECL main(int n, const char *args[])
+{
+ try { return main2(n, args); }
+ catch(const char *s)
+ {
+ fprintf(stderr, "\nError: %s\n", s);
+ return 1;
+ }
+ catch(...)
+ {
+ fprintf(stderr, "\nError\n");
+ return 1;
+ }
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp
new file mode 100644
index 000000000..6a325fe06
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp
@@ -0,0 +1,1018 @@
+// LzmaBench.cpp
+
+#include "StdAfx.h"
+
+#include "LzmaBench.h"
+
+#ifndef _WIN32
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#endif
+#endif
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/Alloc.h"
+
+#include "../../../Common/MyCom.h"
+
+#ifdef BENCH_MT
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/Thread.h"
+#endif
+
+#ifdef EXTERNAL_LZMA
+#include "../../../Windows/PropVariant.h"
+#include "../../ICoder.h"
+#else
+#include "../LzmaDecoder.h"
+#include "../LzmaEncoder.h"
+#endif
+
+static const UInt32 kUncompressMinBlockSize = 1 << 26;
+static const UInt32 kAdditionalSize = (1 << 16);
+static const UInt32 kCompressedAdditionalSize = (1 << 10);
+static const UInt32 kMaxLzmaPropSize = 5;
+
+class CBaseRandomGenerator
+{
+ UInt32 A1;
+ UInt32 A2;
+public:
+ CBaseRandomGenerator() { Init(); }
+ void Init() { A1 = 362436069; A2 = 521288629;}
+ UInt32 GetRnd()
+ {
+ return
+ ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
+ ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
+ }
+};
+
+class CBenchBuffer
+{
+public:
+ size_t BufferSize;
+ Byte *Buffer;
+ CBenchBuffer(): Buffer(0) {}
+ virtual ~CBenchBuffer() { Free(); }
+ void Free()
+ {
+ ::MidFree(Buffer);
+ Buffer = 0;
+ }
+ bool Alloc(size_t bufferSize)
+ {
+ if (Buffer != 0 && BufferSize == bufferSize)
+ return true;
+ Free();
+ Buffer = (Byte *)::MidAlloc(bufferSize);
+ BufferSize = bufferSize;
+ return (Buffer != 0);
+ }
+};
+
+class CBenchRandomGenerator: public CBenchBuffer
+{
+ CBaseRandomGenerator *RG;
+public:
+ void Set(CBaseRandomGenerator *rg) { RG = rg; }
+ UInt32 GetVal(UInt32 &res, int numBits)
+ {
+ UInt32 val = res & (((UInt32)1 << numBits) - 1);
+ res >>= numBits;
+ return val;
+ }
+ UInt32 GetLen(UInt32 &res)
+ {
+ UInt32 len = GetVal(res, 2);
+ return GetVal(res, 1 + len);
+ }
+ void Generate()
+ {
+ UInt32 pos = 0;
+ UInt32 rep0 = 1;
+ while (pos < BufferSize)
+ {
+ UInt32 res = RG->GetRnd();
+ res >>= 1;
+ if (GetVal(res, 1) == 0 || pos < 1024)
+ Buffer[pos++] = (Byte)(res & 0xFF);
+ else
+ {
+ UInt32 len;
+ len = 1 + GetLen(res);
+ if (GetVal(res, 3) != 0)
+ {
+ len += GetLen(res);
+ do
+ {
+ UInt32 ppp = GetVal(res, 5) + 6;
+ res = RG->GetRnd();
+ if (ppp > 30)
+ continue;
+ rep0 = /* (1 << ppp) +*/ GetVal(res, ppp);
+ res = RG->GetRnd();
+ }
+ while (rep0 >= pos);
+ rep0++;
+ }
+
+ for (UInt32 i = 0; i < len && pos < BufferSize; i++, pos++)
+ Buffer[pos] = Buffer[pos - rep0];
+ }
+ }
+ }
+};
+
+
+class CBenchmarkInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ const Byte *Data;
+ size_t Pos;
+ size_t Size;
+public:
+ MY_UNKNOWN_IMP
+ void Init(const Byte *data, size_t size)
+ {
+ Data = data;
+ Size = size;
+ Pos = 0;
+ }
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t remain = Size - Pos;
+ UInt32 kMaxBlockSize = (1 << 20);
+ if (size > kMaxBlockSize)
+ size = kMaxBlockSize;
+ if (size > remain)
+ size = (UInt32)remain;
+ for (UInt32 i = 0; i < size; i++)
+ ((Byte *)data)[i] = Data[Pos + i];
+ Pos += size;
+ if(processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+class CBenchmarkOutStream:
+ public ISequentialOutStream,
+ public CBenchBuffer,
+ public CMyUnknownImp
+{
+ // bool _overflow;
+public:
+ UInt32 Pos;
+ // CBenchmarkOutStream(): _overflow(false) {}
+ void Init()
+ {
+ // _overflow = false;
+ Pos = 0;
+ }
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t curSize = BufferSize - Pos;
+ if (curSize > size)
+ curSize = size;
+ memcpy(Buffer + Pos, data, curSize);
+ Pos += (UInt32)curSize;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)curSize;
+ if (curSize != size)
+ {
+ // _overflow = true;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+class CCrcOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ UInt32 Crc;
+ MY_UNKNOWN_IMP
+ void Init() { Crc = CRC_INIT_VAL; }
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ Crc = CrcUpdate(Crc, data, size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+static UInt64 GetTimeCount()
+{
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ timeval v;
+ if (gettimeofday(&v, 0) == 0)
+ return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec;
+ return (UInt64)time(NULL) * 1000000;
+ #else
+ return time(NULL);
+ #endif
+ #else
+ /*
+ LARGE_INTEGER value;
+ if (::QueryPerformanceCounter(&value))
+ return value.QuadPart;
+ */
+ return GetTickCount();
+ #endif
+}
+
+static UInt64 GetFreq()
+{
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ return 1000000;
+ #else
+ return 1;
+ #endif
+ #else
+ /*
+ LARGE_INTEGER value;
+ if (::QueryPerformanceFrequency(&value))
+ return value.QuadPart;
+ */
+ return 1000;
+ #endif
+}
+
+#ifndef USE_POSIX_TIME
+static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
+#endif
+static UInt64 GetUserTime()
+{
+ #ifdef USE_POSIX_TIME
+ return clock();
+ #else
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ if (::GetProcessTimes(::GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime) != 0)
+ return GetTime64(userTime) + GetTime64(kernelTime);
+ return (UInt64)GetTickCount() * 10000;
+ #endif
+}
+
+static UInt64 GetUserFreq()
+{
+ #ifdef USE_POSIX_TIME
+ return CLOCKS_PER_SEC;
+ #else
+ return 10000000;
+ #endif
+}
+
+class CBenchProgressStatus
+{
+ #ifdef BENCH_MT
+ NWindows::NSynchronization::CCriticalSection CS;
+ #endif
+public:
+ HRESULT Res;
+ bool EncodeMode;
+ void SetResult(HRESULT res)
+ {
+ #ifdef BENCH_MT
+ NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+ #endif
+ Res = res;
+ }
+ HRESULT GetResult()
+ {
+ #ifdef BENCH_MT
+ NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+ #endif
+ return Res;
+ }
+};
+
+class CBenchProgressInfo:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ CBenchProgressStatus *Status;
+ CBenchInfo BenchInfo;
+ HRESULT Res;
+ IBenchCallback *callback;
+ CBenchProgressInfo(): callback(0) {}
+ MY_UNKNOWN_IMP
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void SetStartTime(CBenchInfo &bi)
+{
+ bi.GlobalFreq = GetFreq();
+ bi.UserFreq = GetUserFreq();
+ bi.GlobalTime = ::GetTimeCount();
+ bi.UserTime = ::GetUserTime();
+}
+
+void SetFinishTime(const CBenchInfo &biStart, CBenchInfo &dest)
+{
+ dest.GlobalFreq = GetFreq();
+ dest.UserFreq = GetUserFreq();
+ dest.GlobalTime = ::GetTimeCount() - biStart.GlobalTime;
+ dest.UserTime = ::GetUserTime() - biStart.UserTime;
+}
+
+STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ HRESULT res = Status->GetResult();
+ if (res != S_OK)
+ return res;
+ if (!callback)
+ return res;
+ CBenchInfo info = BenchInfo;
+ SetFinishTime(BenchInfo, info);
+ if (Status->EncodeMode)
+ {
+ info.UnpackSize = *inSize;
+ info.PackSize = *outSize;
+ res = callback->SetEncodeResult(info, false);
+ }
+ else
+ {
+ info.PackSize = BenchInfo.PackSize + *inSize;
+ info.UnpackSize = BenchInfo.UnpackSize + *outSize;
+ res = callback->SetDecodeResult(info, false);
+ }
+ if (res != S_OK)
+ Status->SetResult(res);
+ return res;
+}
+
+static const int kSubBits = 8;
+
+static UInt32 GetLogSize(UInt32 size)
+{
+ for (int i = kSubBits; i < 32; i++)
+ for (UInt32 j = 0; j < (1 << kSubBits); j++)
+ if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
+ return (i << kSubBits) + j;
+ return (32 << kSubBits);
+}
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ while (v1 > 1000000)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+UInt64 GetUsage(const CBenchInfo &info)
+{
+ UInt64 userTime = info.UserTime;
+ UInt64 userFreq = info.UserFreq;
+ UInt64 globalTime = info.GlobalTime;
+ UInt64 globalFreq = info.GlobalFreq;
+ NormalizeVals(userTime, userFreq);
+ NormalizeVals(globalFreq, globalTime);
+ if (userFreq == 0)
+ userFreq = 1;
+ if (globalTime == 0)
+ globalTime = 1;
+ return userTime * globalFreq * 1000000 / userFreq / globalTime;
+}
+
+UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating)
+{
+ UInt64 userTime = info.UserTime;
+ UInt64 userFreq = info.UserFreq;
+ UInt64 globalTime = info.GlobalTime;
+ UInt64 globalFreq = info.GlobalFreq;
+ NormalizeVals(userFreq, userTime);
+ NormalizeVals(globalTime, globalFreq);
+ if (globalFreq == 0)
+ globalFreq = 1;
+ if (userTime == 0)
+ userTime = 1;
+ return userFreq * globalTime / globalFreq * rating / userTime;
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
+{
+ UInt64 elTime = elapsedTime;
+ NormalizeVals(freq, elTime);
+ if (elTime == 0)
+ elTime = 1;
+ return value * freq / elTime;
+}
+
+UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
+{
+ UInt64 t = GetLogSize(dictionarySize) - (kBenchMinDicLogSize << kSubBits);
+ UInt64 numCommandsForOne = 870 + ((t * t * 5) >> (2 * kSubBits));
+ UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
+ return MyMultDiv64(numCommands, elapsedTime, freq);
+}
+
+UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations)
+{
+ UInt64 numCommands = (inSize * 200 + outSize * 4) * numIterations;
+ return MyMultDiv64(numCommands, elapsedTime, freq);
+}
+
+#ifdef EXTERNAL_LZMA
+typedef UInt32 (WINAPI * CreateObjectPointer)(const GUID *clsID,
+ const GUID *interfaceID, void **outObject);
+#endif
+
+struct CEncoderInfo;
+
+struct CEncoderInfo
+{
+ #ifdef BENCH_MT
+ NWindows::CThread thread[2];
+ #endif
+ CMyComPtr<ICompressCoder> encoder;
+ CBenchProgressInfo *progressInfoSpec[2];
+ CMyComPtr<ICompressProgressInfo> progressInfo[2];
+ UInt32 NumIterations;
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+
+ struct CDecoderInfo
+ {
+ CEncoderInfo *Encoder;
+ UInt32 DecoderIndex;
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+ bool CallbackMode;
+ };
+ CDecoderInfo decodersInfo[2];
+
+ CMyComPtr<ICompressCoder> decoders[2];
+ HRESULT Results[2];
+ CBenchmarkOutStream *outStreamSpec;
+ CMyComPtr<ISequentialOutStream> outStream;
+ IBenchCallback *callback;
+ UInt32 crc;
+ UInt32 kBufferSize;
+ UInt32 compressedSize;
+ CBenchRandomGenerator rg;
+ CBenchmarkOutStream *propStreamSpec;
+ CMyComPtr<ISequentialOutStream> propStream;
+ HRESULT Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rg);
+ HRESULT Encode();
+ HRESULT Decode(UInt32 decoderIndex);
+
+ CEncoderInfo(): outStreamSpec(0), callback(0), propStreamSpec(0) {}
+
+ #ifdef BENCH_MT
+ static THREAD_FUNC_DECL EncodeThreadFunction(void *param)
+ {
+ CEncoderInfo *encoder = (CEncoderInfo *)param;
+ #ifdef USE_ALLOCA
+ alloca(encoder->AllocaSize);
+ #endif
+ HRESULT res = encoder->Encode();
+ encoder->Results[0] = res;
+ if (res != S_OK)
+ encoder->progressInfoSpec[0]->Status->SetResult(res);
+
+ return 0;
+ }
+ static THREAD_FUNC_DECL DecodeThreadFunction(void *param)
+ {
+ CDecoderInfo *decoder = (CDecoderInfo *)param;
+ #ifdef USE_ALLOCA
+ alloca(decoder->AllocaSize);
+ #endif
+ CEncoderInfo *encoder = decoder->Encoder;
+ encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);
+ return 0;
+ }
+
+ HRESULT CreateEncoderThread()
+ {
+ return thread[0].Create(EncodeThreadFunction, this);
+ }
+
+ HRESULT CreateDecoderThread(int index, bool callbackMode
+ #ifdef USE_ALLOCA
+ , size_t allocaSize
+ #endif
+ )
+ {
+ CDecoderInfo &decoder = decodersInfo[index];
+ decoder.DecoderIndex = index;
+ decoder.Encoder = this;
+ #ifdef USE_ALLOCA
+ decoder.AllocaSize = allocaSize;
+ #endif
+ decoder.CallbackMode = callbackMode;
+ return thread[index].Create(DecodeThreadFunction, &decoder);
+ }
+ #endif
+};
+
+HRESULT CEncoderInfo::Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rgLoc)
+{
+ rg.Set(rgLoc);
+ kBufferSize = dictionarySize + kAdditionalSize;
+ UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
+ if (!rg.Alloc(kBufferSize))
+ return E_OUTOFMEMORY;
+ rg.Generate();
+ crc = CrcCalc(rg.Buffer, rg.BufferSize);
+
+ outStreamSpec = new CBenchmarkOutStream;
+ if (!outStreamSpec->Alloc(kCompressedBufferSize))
+ return E_OUTOFMEMORY;
+
+ outStream = outStreamSpec;
+
+ propStreamSpec = 0;
+ if (!propStream)
+ {
+ propStreamSpec = new CBenchmarkOutStream;
+ propStream = propStreamSpec;
+ }
+ if (!propStreamSpec->Alloc(kMaxLzmaPropSize))
+ return E_OUTOFMEMORY;
+ propStreamSpec->Init();
+
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumThreads
+ };
+ const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ PROPVARIANT props[kNumProps];
+ props[0].vt = VT_UI4;
+ props[0].ulVal = dictionarySize;
+
+ props[1].vt = VT_UI4;
+ props[1].ulVal = numThreads;
+
+ {
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ RINOK(encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties));
+ if (!setCoderProperties)
+ return E_FAIL;
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, kNumProps));
+
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+ encoder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProperties);
+ if (writeCoderProperties)
+ {
+ RINOK(writeCoderProperties->WriteCoderProperties(propStream));
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CEncoderInfo::Encode()
+{
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ inStreamSpec->Init(rg.Buffer, rg.BufferSize);
+ outStreamSpec->Init();
+
+ RINOK(encoder->Code(inStream, outStream, 0, 0, progressInfo[0]));
+ compressedSize = outStreamSpec->Pos;
+ encoder.Release();
+ return S_OK;
+}
+
+HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)
+{
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ CMyComPtr<ICompressCoder> &decoder = decoders[decoderIndex];
+
+ CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
+ decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &compressSetDecoderProperties);
+ if (!compressSetDecoderProperties)
+ return E_FAIL;
+
+ CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
+ CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
+
+ CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
+ pi->BenchInfo.UnpackSize = 0;
+ pi->BenchInfo.PackSize = 0;
+
+ for (UInt32 j = 0; j < NumIterations; j++)
+ {
+ inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
+ crcOutStreamSpec->Init();
+
+ RINOK(compressSetDecoderProperties->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos));
+ UInt64 outSize = kBufferSize;
+ RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex]));
+ if (CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc)
+ return S_FALSE;
+ pi->BenchInfo.UnpackSize += kBufferSize;
+ pi->BenchInfo.PackSize += compressedSize;
+ }
+ decoder.Release();
+ return S_OK;
+}
+
+static const UInt32 kNumThreadsMax = (1 << 16);
+
+struct CBenchEncoders
+{
+ CEncoderInfo *encoders;
+ CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; }
+ ~CBenchEncoders() { delete []encoders; }
+};
+
+HRESULT LzmaBench(
+ #ifdef EXTERNAL_LZMA
+ CCodecs *codecs,
+ #endif
+ UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback)
+{
+ UInt32 numEncoderThreads =
+ #ifdef BENCH_MT
+ (numThreads > 1 ? numThreads / 2 : 1);
+ #else
+ 1;
+ #endif
+ UInt32 numSubDecoderThreads =
+ #ifdef BENCH_MT
+ (numThreads > 1 ? 2 : 1);
+ #else
+ 1;
+ #endif
+ if (dictionarySize < (1 << kBenchMinDicLogSize) || numThreads < 1 || numEncoderThreads > kNumThreadsMax)
+ {
+ return E_INVALIDARG;
+ }
+
+ CBenchEncoders encodersSpec(numEncoderThreads);
+ CEncoderInfo *encoders = encodersSpec.encoders;
+
+ #ifdef EXTERNAL_LZMA
+ UString name = L"LZMA";
+ #endif
+
+ UInt32 i;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.callback = (i == 0) ? callback : 0;
+
+ #ifdef EXTERNAL_LZMA
+ RINOK(codecs->CreateCoder(name, true, encoder.encoder));
+ #else
+ encoder.encoder = new NCompress::NLzma::CEncoder;
+ #endif
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ #ifdef EXTERNAL_LZMA
+ RINOK(codecs->CreateCoder(name, false, encoder.decoders[j]));
+ #else
+ encoder.decoders[j] = new NCompress::NLzma::CDecoder;
+ #endif
+ }
+ }
+
+ CBaseRandomGenerator rg;
+ rg.Init();
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ RINOK(encoders[i].Init(dictionarySize, numThreads, &rg));
+ }
+
+ CBenchProgressStatus status;
+ status.Res = S_OK;
+ status.EncodeMode = true;
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ for (int j = 0; j < 2; j++)
+ {
+ encoder.progressInfo[j] = encoder.progressInfoSpec[j] = new CBenchProgressInfo;
+ encoder.progressInfoSpec[j]->Status = &status;
+ }
+ if (i == 0)
+ {
+ encoder.progressInfoSpec[0]->callback = callback;
+ encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numEncoderThreads;
+ SetStartTime(encoder.progressInfoSpec[0]->BenchInfo);
+ }
+
+ #ifdef BENCH_MT
+ if (numEncoderThreads > 1)
+ {
+ #ifdef USE_ALLOCA
+ encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
+ #endif
+ RINOK(encoder.CreateEncoderThread())
+ }
+ else
+ #endif
+ {
+ RINOK(encoder.Encode());
+ }
+ }
+ #ifdef BENCH_MT
+ if (numEncoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ encoders[i].thread[0].Wait();
+ #endif
+
+ RINOK(status.Res);
+
+ CBenchInfo info;
+
+ SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info);
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = 1; // progressInfoSpec->NumIterations;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ info.UnpackSize += encoder.kBufferSize;
+ info.PackSize += encoder.compressedSize;
+ }
+ RINOK(callback->SetEncodeResult(info, true));
+
+
+ status.Res = S_OK;
+ status.EncodeMode = false;
+
+ UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.NumIterations = 2 + kUncompressMinBlockSize / encoder.kBufferSize;
+
+ if (i == 0)
+ {
+ encoder.progressInfoSpec[0]->callback = callback;
+ encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numDecoderThreads;
+ SetStartTime(encoder.progressInfoSpec[0]->BenchInfo);
+ }
+
+ #ifdef BENCH_MT
+ if (numDecoderThreads > 1)
+ {
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
+ #ifdef USE_ALLOCA
+ , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
+ #endif
+ );
+ RINOK(res);
+ }
+ }
+ else
+ #endif
+ {
+ RINOK(encoder.Decode(0));
+ }
+ }
+ #ifdef BENCH_MT
+ HRESULT res = S_OK;
+ if (numDecoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.thread[j].Wait();
+ if (encoder.Results[j] != S_OK)
+ res = encoder.Results[j];
+ }
+ RINOK(res);
+ #endif
+ RINOK(status.Res);
+ SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info);
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ info.UnpackSize += encoder.kBufferSize;
+ info.PackSize += encoder.compressedSize;
+ }
+ RINOK(callback->SetDecodeResult(info, false));
+ RINOK(callback->SetDecodeResult(info, true));
+ return S_OK;
+}
+
+
+inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)
+{
+ UInt32 hs = dictionary - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ hs |= 0xFFFF;
+ if (hs > (1 << 24))
+ hs >>= 1;
+ hs++;
+ return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 +
+ (1 << 20) + (multiThread ? (6 << 20) : 0);
+}
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary)
+{
+ const UInt32 kBufferSize = dictionary;
+ const UInt32 kCompressedBufferSize = (kBufferSize / 2);
+ UInt32 numSubThreads = (numThreads > 1) ? 2 : 1;
+ UInt32 numBigThreads = numThreads / numSubThreads;
+ return (kBufferSize + kCompressedBufferSize +
+ GetLZMAUsage((numThreads > 1), dictionary) + (2 << 20)) * numBigThreads;
+}
+
+static bool CrcBig(const void *data, UInt32 size, UInt32 numCycles, UInt32 crcBase)
+{
+ for (UInt32 i = 0; i < numCycles; i++)
+ if (CrcCalc(data, size) != crcBase)
+ return false;
+ return true;
+}
+
+#ifdef BENCH_MT
+struct CCrcInfo
+{
+ NWindows::CThread Thread;
+ const Byte *Data;
+ UInt32 Size;
+ UInt32 NumCycles;
+ UInt32 Crc;
+ bool Res;
+ void Wait()
+ {
+ Thread.Wait();
+ Thread.Close();
+ }
+};
+
+static THREAD_FUNC_DECL CrcThreadFunction(void *param)
+{
+ CCrcInfo *p = (CCrcInfo *)param;
+ p->Res = CrcBig(p->Data, p->Size, p->NumCycles, p->Crc);
+ return 0;
+}
+
+struct CCrcThreads
+{
+ UInt32 NumThreads;
+ CCrcInfo *Items;
+ CCrcThreads(): Items(0), NumThreads(0) {}
+ void WaitAll()
+ {
+ for (UInt32 i = 0; i < NumThreads; i++)
+ Items[i].Wait();
+ NumThreads = 0;
+ }
+ ~CCrcThreads()
+ {
+ WaitAll();
+ delete []Items;
+ }
+};
+#endif
+
+static UInt32 CrcCalc1(const Byte *buf, UInt32 size)
+{
+ UInt32 crc = CRC_INIT_VAL;;
+ for (UInt32 i = 0; i < size; i++)
+ crc = CRC_UPDATE_BYTE(crc, buf[i]);
+ return CRC_GET_DIGEST(crc);
+}
+
+static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+ for (UInt32 i = 0; i < size; i++)
+ buf[i] = (Byte)RG.GetRnd();
+}
+
+static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+ RandGen(buf, size, RG);
+ return CrcCalc1(buf, size);
+}
+
+bool CrcInternalTest()
+{
+ CBenchBuffer buffer;
+ const UInt32 kBufferSize0 = (1 << 8);
+ const UInt32 kBufferSize1 = (1 << 10);
+ const UInt32 kCheckSize = (1 << 5);
+ if (!buffer.Alloc(kBufferSize0 + kBufferSize1))
+ return false;
+ Byte *buf = buffer.Buffer;
+ UInt32 i;
+ for (i = 0; i < kBufferSize0; i++)
+ buf[i] = (Byte)i;
+ UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
+ if (crc1 != 0x29058C73)
+ return false;
+ CBaseRandomGenerator RG;
+ RandGen(buf + kBufferSize0, kBufferSize1, RG);
+ for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
+ for (UInt32 j = 0; j < kCheckSize; j++)
+ if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
+ return false;
+ return true;
+}
+
+HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed)
+{
+ if (numThreads == 0)
+ numThreads = 1;
+
+ CBenchBuffer buffer;
+ size_t totalSize = (size_t)bufferSize * numThreads;
+ if (totalSize / numThreads != bufferSize)
+ return E_OUTOFMEMORY;
+ if (!buffer.Alloc(totalSize))
+ return E_OUTOFMEMORY;
+
+ Byte *buf = buffer.Buffer;
+ CBaseRandomGenerator RG;
+ UInt32 numCycles = ((UInt32)1 << 30) / ((bufferSize >> 2) + 1) + 1;
+
+ UInt64 timeVal;
+ #ifdef BENCH_MT
+ CCrcThreads threads;
+ if (numThreads > 1)
+ {
+ threads.Items = new CCrcInfo[numThreads];
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &info = threads.Items[i];
+ Byte *data = buf + (size_t)bufferSize * i;
+ info.Data = data;
+ info.NumCycles = numCycles;
+ info.Size = bufferSize;
+ info.Crc = RandGenCrc(data, bufferSize, RG);
+ }
+ timeVal = GetTimeCount();
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &info = threads.Items[i];
+ RINOK(info.Thread.Create(CrcThreadFunction, &info));
+ threads.NumThreads++;
+ }
+ threads.WaitAll();
+ for (i = 0; i < numThreads; i++)
+ if (!threads.Items[i].Res)
+ return S_FALSE;
+ }
+ else
+ #endif
+ {
+ UInt32 crc = RandGenCrc(buf, bufferSize, RG);
+ timeVal = GetTimeCount();
+ if (!CrcBig(buf, bufferSize, numCycles, crc))
+ return S_FALSE;
+ }
+ timeVal = GetTimeCount() - timeVal;
+ if (timeVal == 0)
+ timeVal = 1;
+
+ UInt64 size = (UInt64)numCycles * totalSize;
+ speed = MyMultDiv64(size, timeVal, GetFreq());
+ return S_OK;
+}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h
new file mode 100644
index 000000000..f8aeb6be3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h
@@ -0,0 +1,48 @@
+// LzmaBench.h
+
+#ifndef __LZMABENCH_H
+#define __LZMABENCH_H
+
+#include <stdio.h>
+#include "../../../Common/Types.h"
+#ifdef EXTERNAL_LZMA
+#include "../../UI/Common/LoadCodecs.h"
+#endif
+
+struct CBenchInfo
+{
+ UInt64 GlobalTime;
+ UInt64 GlobalFreq;
+ UInt64 UserTime;
+ UInt64 UserFreq;
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt32 NumIterations;
+ CBenchInfo(): NumIterations(0) {}
+};
+
+struct IBenchCallback
+{
+ virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0;
+ virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0;
+};
+
+UInt64 GetUsage(const CBenchInfo &benchOnfo);
+UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating);
+UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
+UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations);
+
+HRESULT LzmaBench(
+ #ifdef EXTERNAL_LZMA
+ CCodecs *codecs,
+ #endif
+ UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback);
+
+const int kBenchMinDicLogSize = 18;
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary);
+
+bool CrcInternalTest();
+HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp
new file mode 100644
index 000000000..b1c455e97
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp
@@ -0,0 +1,311 @@
+// LzmaBenchCon.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "LzmaBench.h"
+#include "LzmaBenchCon.h"
+#include "../../../Common/IntToString.h"
+
+#if defined(BENCH_MT) || defined(_WIN32)
+#include "../../../Windows/System.h"
+#endif
+
+#ifdef BREAK_HANDLER
+#include "../../UI/Console/ConsoleClose.h"
+#endif
+#include "../../../Common/MyCom.h"
+
+struct CTotalBenchRes
+{
+ UInt64 NumIterations;
+ UInt64 Rating;
+ UInt64 Usage;
+ UInt64 RPU;
+ void Init() { NumIterations = 0; Rating = 0; Usage = 0; RPU = 0; }
+ void Normalize()
+ {
+ if (NumIterations == 0)
+ return;
+ Rating /= NumIterations;
+ Usage /= NumIterations;
+ RPU /= NumIterations;
+ NumIterations = 1;
+ }
+ void SetMid(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
+ {
+ Rating = (r1.Rating + r2.Rating) / 2;
+ Usage = (r1.Usage + r2.Usage) / 2;
+ RPU = (r1.RPU + r2.RPU) / 2;
+ NumIterations = (r1.NumIterations + r2.NumIterations) / 2;
+ }
+};
+
+struct CBenchCallback: public IBenchCallback
+{
+ CTotalBenchRes EncodeRes;
+ CTotalBenchRes DecodeRes;
+ FILE *f;
+ void Init() { EncodeRes.Init(); DecodeRes.Init(); }
+ void Normalize() { EncodeRes.Normalize(); DecodeRes.Normalize(); }
+ UInt32 dictionarySize;
+ HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
+ HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
+};
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ while (v1 > 1000000)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
+{
+ UInt64 elTime = elapsedTime;
+ NormalizeVals(freq, elTime);
+ if (elTime == 0)
+ elTime = 1;
+ return value * freq / elTime;
+}
+
+static void PrintNumber(FILE *f, UInt64 value, int size)
+{
+ char s[32];
+ ConvertUInt64ToString(value, s);
+ fprintf(f, " ");
+ for (int len = (int)strlen(s); len < size; len++)
+ fprintf(f, " ");
+ fprintf(f, "%s", s);
+}
+
+static void PrintRating(FILE *f, UInt64 rating)
+{
+ PrintNumber(f, rating / 1000000, 6);
+}
+
+static void PrintResults(FILE *f, UInt64 usage, UInt64 rpu, UInt64 rating)
+{
+ PrintNumber(f, (usage + 5000) / 10000, 5);
+ PrintRating(f, rpu);
+ PrintRating(f, rating);
+}
+
+
+static void PrintResults(FILE *f, const CBenchInfo &info, UInt64 rating, CTotalBenchRes &res)
+{
+ UInt64 speed = MyMultDiv64(info.UnpackSize, info.GlobalTime, info.GlobalFreq);
+ PrintNumber(f, speed / 1024, 7);
+ UInt64 usage = GetUsage(info);
+ UInt64 rpu = GetRatingPerUsage(info, rating);
+ PrintResults(f, usage, rpu, rating);
+ res.NumIterations++;
+ res.RPU += rpu;
+ res.Rating += rating;
+ res.Usage += usage;
+}
+
+static void PrintTotals(FILE *f, const CTotalBenchRes &res)
+{
+ fprintf(f, " ");
+ PrintResults(f, res.Usage, res.RPU, res.Rating);
+}
+
+
+HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
+{
+ #ifdef BREAK_HANDLER
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ #endif
+
+ if (final)
+ {
+ UInt64 rating = GetCompressRating(dictionarySize, info.GlobalTime, info.GlobalFreq, info.UnpackSize);
+ PrintResults(f, info, rating, EncodeRes);
+ }
+ return S_OK;
+}
+
+static const char *kSep = " | ";
+
+
+HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
+{
+ #ifdef BREAK_HANDLER
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ #endif
+ if (final)
+ {
+ UInt64 rating = GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
+ fprintf(f, kSep);
+ CBenchInfo info2 = info;
+ info2.UnpackSize *= info2.NumIterations;
+ info2.PackSize *= info2.NumIterations;
+ info2.NumIterations = 1;
+ PrintResults(f, info2, rating, DecodeRes);
+ }
+ return S_OK;
+}
+
+static void PrintRequirements(FILE *f, const char *sizeString, UInt64 size, const char *threadsString, UInt32 numThreads)
+{
+ fprintf(f, "\nRAM %s ", sizeString);
+ PrintNumber(f, (size >> 20), 5);
+ fprintf(f, " MB, # %s %3d", threadsString, (unsigned int)numThreads);
+}
+
+HRESULT LzmaBenchCon(
+ #ifdef EXTERNAL_LZMA
+ CCodecs *codecs,
+ #endif
+ FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
+{
+ if (!CrcInternalTest())
+ return S_FALSE;
+ #ifdef BENCH_MT
+ UInt64 ramSize = NWindows::NSystem::GetRamSize(); //
+ UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+ PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+ if (numThreads == (UInt32)-1)
+ numThreads = numCPUs;
+ if (numThreads > 1)
+ numThreads &= ~1;
+ if (dictionary == (UInt32)-1)
+ {
+ int dicSizeLog;
+ for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
+ if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
+ break;
+ dictionary = (1 << dicSizeLog);
+ }
+ #else
+ if (dictionary == (UInt32)-1)
+ dictionary = (1 << 22);
+ numThreads = 1;
+ #endif
+
+ PrintRequirements(f, "usage:", GetBenchMemoryUsage(numThreads, dictionary), "Benchmark threads: ", numThreads);
+
+ CBenchCallback callback;
+ callback.Init();
+ callback.f = f;
+
+ fprintf(f, "\n\nDict Compressing | Decompressing\n ");
+ int j;
+ for (j = 0; j < 2; j++)
+ {
+ fprintf(f, " Speed Usage R/U Rating");
+ if (j == 0)
+ fprintf(f, kSep);
+ }
+ fprintf(f, "\n ");
+ for (j = 0; j < 2; j++)
+ {
+ fprintf(f, " KB/s %% MIPS MIPS");
+ if (j == 0)
+ fprintf(f, kSep);
+ }
+ fprintf(f, "\n\n");
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ const int kStartDicLog = 22;
+ int pow = (dictionary < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
+ while (((UInt32)1 << pow) > dictionary)
+ pow--;
+ for (; ((UInt32)1 << pow) <= dictionary; pow++)
+ {
+ fprintf(f, "%2d:", pow);
+ callback.dictionarySize = (UInt32)1 << pow;
+ HRESULT res = LzmaBench(
+ #ifdef EXTERNAL_LZMA
+ codecs,
+ #endif
+ numThreads, callback.dictionarySize, &callback);
+ fprintf(f, "\n");
+ RINOK(res);
+ }
+ }
+ callback.Normalize();
+ fprintf(f, "----------------------------------------------------------------\nAvr:");
+ PrintTotals(f, callback.EncodeRes);
+ fprintf(f, " ");
+ PrintTotals(f, callback.DecodeRes);
+ fprintf(f, "\nTot:");
+ CTotalBenchRes midRes;
+ midRes.SetMid(callback.EncodeRes, callback.DecodeRes);
+ PrintTotals(f, midRes);
+ fprintf(f, "\n");
+ return S_OK;
+}
+
+struct CTempValues
+{
+ UInt64 *Values;
+ CTempValues(UInt32 num) { Values = new UInt64[num]; }
+ ~CTempValues() { delete []Values; }
+};
+
+HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
+{
+ if (!CrcInternalTest())
+ return S_FALSE;
+
+ #ifdef BENCH_MT
+ UInt64 ramSize = NWindows::NSystem::GetRamSize();
+ UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+ PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+ if (numThreads == (UInt32)-1)
+ numThreads = numCPUs;
+ #else
+ numThreads = 1;
+ #endif
+ if (dictionary == (UInt32)-1)
+ dictionary = (1 << 24);
+
+ CTempValues speedTotals(numThreads);
+ fprintf(f, "\n\nSize");
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ {
+ fprintf(f, " %5d", ti + 1);
+ speedTotals.Values[ti] = 0;
+ }
+ fprintf(f, "\n\n");
+
+ UInt64 numSteps = 0;
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ for (int pow = 10; pow < 32; pow++)
+ {
+ UInt32 bufSize = (UInt32)1 << pow;
+ if (bufSize > dictionary)
+ break;
+ fprintf(f, "%2d: ", pow);
+ UInt64 speed;
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ {
+ #ifdef BREAK_HANDLER
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ #endif
+ RINOK(CrcBench(ti + 1, bufSize, speed));
+ PrintNumber(f, (speed >> 20), 5);
+ speedTotals.Values[ti] += speed;
+ }
+ fprintf(f, "\n");
+ numSteps++;
+ }
+ }
+ if (numSteps != 0)
+ {
+ fprintf(f, "\nAvg:");
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), 5);
+ fprintf(f, "\n");
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h
new file mode 100644
index 000000000..ea8539d19
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h
@@ -0,0 +1,20 @@
+// LzmaBenchCon.h
+
+#ifndef __LZMABENCHCON_H
+#define __LZMABENCHCON_H
+
+#include <stdio.h>
+#include "../../../Common/Types.h"
+#ifdef EXTERNAL_LZMA
+#include "../../UI/Common/LoadCodecs.h"
+#endif
+HRESULT LzmaBenchCon(
+ #ifdef EXTERNAL_LZMA
+ CCodecs *codecs,
+ #endif
+ FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary);
+
+HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary);
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzOutWindow.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LzOutWindow.cpp
new file mode 100644
index 000000000..df46295bd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzOutWindow.cpp
@@ -0,0 +1,14 @@
+// LzOutWindow.cpp
+
+#include "StdAfx.h"
+
+#include "LzOutWindow.h"
+
+void CLzOutWindow::Init(bool solid)
+{
+ if (!solid)
+ COutBuffer::Init();
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzOutWindow.h b/src/libs/7zip/unix/CPP/7zip/Compress/LzOutWindow.h
new file mode 100644
index 000000000..d8d13c225
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzOutWindow.h
@@ -0,0 +1,66 @@
+// LzOutWindow.h
+
+#ifndef __LZ_OUT_WINDOW_H
+#define __LZ_OUT_WINDOW_H
+
+#include "../IStream.h"
+
+#include "../Common/OutBuffer.h"
+
+#ifndef _NO_EXCEPTIONS
+typedef COutBufferException CLzOutWindowException;
+#endif
+
+class CLzOutWindow: public COutBuffer
+{
+public:
+ void Init(bool solid = false);
+
+ // distance >= 0, len > 0,
+ bool CopyBlock(UInt32 distance, UInt32 len)
+ {
+ UInt32 pos = _pos - distance - 1;
+ if (distance >= _pos)
+ {
+ if (!_overDict || distance >= _bufferSize)
+ return false;
+ pos += _bufferSize;
+ }
+ if (_limitPos - _pos > len && _bufferSize - pos > len)
+ {
+ const Byte *src = _buffer + pos;
+ Byte *dest = _buffer + _pos;
+ _pos += len;
+ do
+ *dest++ = *src++;
+ while(--len != 0);
+ }
+ else do
+ {
+ if (pos == _bufferSize)
+ pos = 0;
+ _buffer[_pos++] = _buffer[pos++];
+ if (_pos == _limitPos)
+ FlushWithCheck();
+ }
+ while(--len != 0);
+ return true;
+ }
+
+ void PutByte(Byte b)
+ {
+ _buffer[_pos++] = b;
+ if (_pos == _limitPos)
+ FlushWithCheck();
+ }
+
+ Byte GetByte(UInt32 distance) const
+ {
+ UInt32 pos = _pos - distance - 1;
+ if (pos >= _bufferSize)
+ pos += _bufferSize;
+ return _buffer[pos];
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzhDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LzhDecoder.cpp
new file mode 100644
index 000000000..6f9b5065e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzhDecoder.cpp
@@ -0,0 +1,220 @@
+// LzhDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "LzhDecoder.h"
+
+#include "Windows/Defs.h"
+
+namespace NCompress{
+namespace NLzh {
+namespace NDecoder {
+
+static const UInt32 kHistorySize = (1 << 16);
+
+static const int kBlockSizeBits = 16;
+static const int kNumCBits = 9;
+static const int kNumLevelBits = 5; // smallest integer such that (1 << kNumLevelBits) > kNumLevelSymbols/
+
+UInt32 CCoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
+
+HRESULT CCoder::ReadLevelTable()
+{
+ int n = ReadBits(kNumLevelBits);
+ if (n == 0)
+ {
+ m_LevelHuffman.Symbol = ReadBits(kNumLevelBits);
+ if (m_LevelHuffman.Symbol >= kNumLevelSymbols)
+ return S_FALSE;
+ }
+ else
+ {
+ if (n > kNumLevelSymbols)
+ return S_FALSE;
+ m_LevelHuffman.Symbol = -1;
+ Byte lens[kNumLevelSymbols];
+ int i = 0;
+ while (i < n)
+ {
+ int c = m_InBitStream.ReadBits(3);
+ if (c == 7)
+ while (ReadBits(1))
+ if (c++ > kMaxHuffmanLen)
+ return S_FALSE;
+ lens[i++] = (Byte)c;
+ if (i == kNumSpecLevelSymbols)
+ {
+ c = ReadBits(2);
+ while (--c >= 0)
+ lens[i++] = 0;
+ }
+ }
+ while (i < kNumLevelSymbols)
+ lens[i++] = 0;
+ m_LevelHuffman.SetCodeLengths(lens);
+ }
+ return S_OK;
+}
+
+HRESULT CCoder::ReadPTable(int numBits)
+{
+ int n = ReadBits(numBits);
+ if (n == 0)
+ {
+ m_PHuffmanDecoder.Symbol = ReadBits(numBits);
+ if (m_PHuffmanDecoder.Symbol >= kNumDistanceSymbols)
+ return S_FALSE;
+ }
+ else
+ {
+ if (n > kNumDistanceSymbols)
+ return S_FALSE;
+ m_PHuffmanDecoder.Symbol = -1;
+ Byte lens[kNumDistanceSymbols];
+ int i = 0;
+ while (i < n)
+ {
+ int c = m_InBitStream.ReadBits(3);
+ if (c == 7)
+ while (ReadBits(1))
+ {
+ if (c > kMaxHuffmanLen)
+ return S_FALSE;
+ c++;
+ }
+ lens[i++] = (Byte)c;
+ }
+ while (i < kNumDistanceSymbols)
+ lens[i++] = 0;
+ m_PHuffmanDecoder.SetCodeLengths(lens);
+ }
+ return S_OK;
+}
+
+HRESULT CCoder::ReadCTable()
+{
+ int n = ReadBits(kNumCBits);
+ if (n == 0)
+ {
+ m_CHuffmanDecoder.Symbol = ReadBits(kNumCBits);
+ if (m_CHuffmanDecoder.Symbol >= kNumCSymbols)
+ return S_FALSE;
+ }
+ else
+ {
+ if (n > kNumCSymbols)
+ return S_FALSE;
+ m_CHuffmanDecoder.Symbol = -1;
+ Byte lens[kNumCSymbols];
+ int i = 0;
+ while (i < n)
+ {
+ int c = m_LevelHuffman.Decode(&m_InBitStream);
+ if (c < kNumSpecLevelSymbols)
+ {
+ if (c == 0)
+ c = 1;
+ else if (c == 1)
+ c = ReadBits(4) + 3;
+ else
+ c = ReadBits(kNumCBits) + 20;
+ while (--c >= 0)
+ {
+ if (i > kNumCSymbols)
+ return S_FALSE;
+ lens[i++] = 0;
+ }
+ }
+ else
+ lens[i++] = (Byte)(c - 2);
+ }
+ while (i < kNumCSymbols)
+ lens[i++] = 0;
+ m_CHuffmanDecoder.SetCodeLengths(lens);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CCoder::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ UInt64 pos = 0;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ int pbit;
+ if (m_NumDictBits <= 13)
+ pbit = 4;
+ else
+ pbit = 5;
+
+ UInt32 blockSize = 0;
+
+ while(pos < *outSize)
+ {
+ // for (i = 0; i < dictSize; i++) dtext[i] = 0x20;
+
+ if (blockSize == 0)
+ {
+ if (progress != NULL)
+ {
+ UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ }
+ blockSize = ReadBits(kBlockSizeBits);
+ ReadLevelTable();
+ ReadCTable();
+ RINOK(ReadPTable(pbit));
+ }
+ blockSize--;
+ UInt32 c = m_CHuffmanDecoder.Decode(&m_InBitStream);
+ if (c < 256)
+ {
+ m_OutWindowStream.PutByte((Byte)c);
+ pos++;
+ }
+ else if (c >= kNumCSymbols)
+ return S_FALSE;
+ else
+ {
+ // offset = (interface->method == LARC_METHOD_NUM) ? 0x100 - 2 : 0x100 - 3;
+ UInt32 len = c - 256 + kMinMatch;
+ UInt32 distance = m_PHuffmanDecoder.Decode(&m_InBitStream);
+ if (distance != 0)
+ distance = (1 << (distance - 1)) + ReadBits(distance - 1);
+ if (distance >= pos)
+ return S_FALSE;
+ if (pos + len > *outSize)
+ len = (UInt32)(*outSize - pos);
+ pos += len;
+ m_OutWindowStream.CopyBlock(distance, len);
+ }
+ }
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CCoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzhDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/LzhDecoder.h
new file mode 100644
index 000000000..4c32d63da
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzhDecoder.h
@@ -0,0 +1,106 @@
+// LzhDecoder.h
+
+#ifndef __COMPRESS_LZH_DECODER_H
+#define __COMPRESS_LZH_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NLzh {
+namespace NDecoder {
+
+const int kMaxHuffmanLen = 16; // Check it
+
+const int kNumSpecLevelSymbols = 3;
+const int kNumLevelSymbols = kNumSpecLevelSymbols + kMaxHuffmanLen;
+
+const int kDictBitsMax = 16;
+const int kNumDistanceSymbols = kDictBitsMax + 1;
+
+const int kMaxMatch = 256;
+const int kMinMatch = 3;
+const int kNumCSymbols = 256 + kMaxMatch + 2 - kMinMatch;
+
+template <UInt32 m_NumSymbols>
+class CHuffmanDecoder:public NCompress::NHuffman::CDecoder<kMaxHuffmanLen, m_NumSymbols>
+{
+public:
+ int Symbol;
+ template <class TBitDecoder>
+ UInt32 Decode(TBitDecoder *bitStream)
+ {
+ if (Symbol >= 0)
+ return (UInt32)Symbol;
+ return this->DecodeSymbol(bitStream);
+ }
+};
+
+class CCoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitm::CDecoder<CInBuffer> m_InBitStream;
+
+ int m_NumDictBits;
+
+ CHuffmanDecoder<kNumLevelSymbols> m_LevelHuffman;
+ CHuffmanDecoder<kNumDistanceSymbols> m_PHuffmanDecoder;
+ CHuffmanDecoder<kNumCSymbols> m_CHuffmanDecoder;
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CCoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+ void MakeTable(int nchar, Byte *bitlen, int tablebits,
+ UInt32 *table, int tablesize);
+
+ UInt32 ReadBits(int numBits);
+ HRESULT ReadLevelTable();
+ HRESULT ReadPTable(int numBits);
+ HRESULT ReadCTable();
+
+public:
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(CodeReal)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ void SetDictionary(int numDictBits) { m_NumDictBits = numDictBits; }
+ CCoder(): m_NumDictBits(0) {}
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.cpp
new file mode 100644
index 000000000..322015e29
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.cpp
@@ -0,0 +1,189 @@
+// Lzma2Decoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Lzma2Decoder.h"
+
+static HRESULT SResToHRESULT(SRes res)
+{
+ switch(res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PARAM: return E_INVALIDARG;
+ // case SZ_ERROR_PROGRESS: return E_ABORT;
+ case SZ_ERROR_DATA: return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+namespace NCompress {
+namespace NLzma2 {
+
+static const UInt32 kInBufSize = 1 << 20;
+
+CDecoder::CDecoder(): _inBuf(0), _outSizeDefined(false)
+{
+ Lzma2Dec_Construct(&_state);
+}
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CDecoder::~CDecoder()
+{
+ Lzma2Dec_Free(&_state, &g_Alloc);
+ MyFree(_inBuf);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
+{
+ if (size != 1) return SZ_ERROR_UNSUPPORTED;
+ RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc)));
+ if (_inBuf == 0)
+ {
+ _inBuf = (Byte *)MyAlloc(kInBufSize);
+ if (_inBuf == 0)
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; }
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
+STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+
+ Lzma2Dec_Init(&_state);
+
+ _inPos = _inSize = 0;
+ _inSizeProcessed = _outSizeProcessed = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 * /* inSize */,
+ const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0)
+ return S_FALSE;
+ SetOutStreamSize(outSize);
+
+ for (;;)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(inStream->Read(_inBuf, kInBufSize, &_inSize));
+ }
+
+ SizeT dicPos = _state.decoder.dicPos;
+ SizeT curSize = _state.decoder.dicBufSize - dicPos;
+ const UInt32 kStepSize = ((UInt32)1 << 22);
+ if (curSize > kStepSize)
+ curSize = (SizeT)kStepSize;
+
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < curSize)
+ {
+ curSize = (SizeT)rem;
+ /*
+ // finishMode = LZMA_FINISH_END;
+ we can't use LZMA_FINISH_END here to allow partial decoding
+ */
+ }
+ }
+
+ SizeT inSizeProcessed = _inSize - _inPos;
+ ELzmaStatus status;
+ SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
+
+ _inPos += (UInt32)inSizeProcessed;
+ _inSizeProcessed += inSizeProcessed;
+ SizeT outSizeProcessed = _state.decoder.dicPos - dicPos;
+ _outSizeProcessed += outSizeProcessed;
+
+ bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
+ bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
+
+ if (res != 0 || _state.decoder.dicPos == _state.decoder.dicBufSize || finished || stopDecoding)
+ {
+ HRESULT res2 = WriteStream(outStream, _state.decoder.dic, _state.decoder.dicPos);
+ if (res != 0)
+ return S_FALSE;
+ RINOK(res2);
+ if (stopDecoding)
+ return S_OK;
+ if (finished)
+ return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE);
+ }
+ if (_state.decoder.dicPos == _state.decoder.dicBufSize)
+ _state.decoder.dicPos = 0;
+
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed));
+ }
+ }
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ do
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, kInBufSize, &_inSize));
+ }
+ {
+ SizeT inProcessed = _inSize - _inPos;
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < size)
+ size = (UInt32)rem;
+ }
+
+ SizeT outProcessed = size;
+ ELzmaStatus status;
+ SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
+ _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
+ _inPos += (UInt32)inProcessed;
+ _inSizeProcessed += inProcessed;
+ _outSizeProcessed += outProcessed;
+ size -= (UInt32)outProcessed;
+ data = (Byte *)data + outProcessed;
+ if (processedSize)
+ *processedSize += (UInt32)outProcessed;
+ RINOK(SResToHRESULT(res));
+ if (inProcessed == 0 && outProcessed == 0)
+ return S_OK;
+ }
+ }
+ while (size != 0);
+ return S_OK;
+}
+
+#endif
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.h
new file mode 100644
index 000000000..fd7ca2f39
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Decoder.h
@@ -0,0 +1,73 @@
+// Lzma2Decoder.h
+
+#ifndef __LZMA2_DECODER_H
+#define __LZMA2_DECODER_H
+
+#include "../../../C/Lzma2Dec.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma2 {
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressGetInStreamProcessedSize,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _inStream;
+ Byte *_inBuf;
+ UInt32 _inPos;
+ UInt32 _inSize;
+ CLzma2Dec _state;
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _inSizeProcessed;
+ UInt64 _outSizeProcessed;
+public:
+
+ #ifndef NO_READ_FROM_CODER
+ MY_UNKNOWN_IMP5(
+ ICompressSetDecoderProperties2,
+ ICompressGetInStreamProcessedSize,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream)
+ #else
+ MY_UNKNOWN_IMP2(
+ ICompressSetDecoderProperties2,
+ ICompressGetInStreamProcessedSize)
+ #endif
+
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *_inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ #ifndef NO_READ_FROM_CODER
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+ CDecoder();
+ virtual ~CDecoder();
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.cpp
new file mode 100644
index 000000000..5e4c71bea
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.cpp
@@ -0,0 +1,94 @@
+// Lzma2Encoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/StreamUtils.h"
+
+#include "Lzma2Encoder.h"
+
+namespace NCompress {
+
+namespace NLzma {
+
+HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep);
+
+}
+
+namespace NLzma2 {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CEncoder::CEncoder()
+{
+ _encoder = 0;
+ _encoder = Lzma2Enc_Create(&g_Alloc, &g_BigAlloc);
+ if (_encoder == 0)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder != 0)
+ Lzma2Enc_Destroy(_encoder);
+}
+
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props)
+{
+ switch (propID)
+ {
+ case NCoderPropID::kBlockSize:
+ if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.blockSize = prop.ulVal; break;
+ case NCoderPropID::kNumThreads:
+ if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.numTotalThreads = (int)(prop.ulVal); break;
+ default:
+ RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps));
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps)
+{
+ CLzma2EncProps lzma2Props;
+ Lzma2EncProps_Init(&lzma2Props);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props));
+ }
+ return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props));
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte prop = Lzma2Enc_WriteProperties(_encoder);
+ return WriteStream(outStream, &prop, 1);
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CSeqInStreamWrap inWrap(inStream);
+ CSeqOutStreamWrap outWrap(outStream);
+ CCompressProgressWrap progressWrap(progress);
+
+ SRes res = Lzma2Enc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL);
+ if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
+ return inWrap.Res;
+ if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
+ return outWrap.Res;
+ if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
+ return progressWrap.Res;
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.h
new file mode 100644
index 000000000..f0fb74d33
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Encoder.h
@@ -0,0 +1,36 @@
+// Lzma2Encoder.h
+
+#ifndef __LZMA2_ENCODER_H
+#define __LZMA2_ENCODER_H
+
+#include "../../../C/Lzma2Enc.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma2 {
+
+class CEncoder:
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public CMyUnknownImp
+{
+ CLzma2EncHandle _encoder;
+public:
+ MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+
+ CEncoder();
+ virtual ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Register.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Register.cpp
new file mode 100644
index 000000000..cace871ef
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Lzma2Register.cpp
@@ -0,0 +1,20 @@
+// Lzma2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Lzma2Decoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "Lzma2Encoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x21, L"LZMA2", 1, false };
+
+REGISTER_CODEC(LZMA2)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.cpp
new file mode 100644
index 000000000..b7c260bd9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.cpp
@@ -0,0 +1,252 @@
+// LzmaDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "LzmaDecoder.h"
+
+static HRESULT SResToHRESULT(SRes res)
+{
+ switch(res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PARAM: return E_INVALIDARG;
+ case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
+ case SZ_ERROR_DATA: return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+namespace NCompress {
+namespace NLzma {
+
+CDecoder::CDecoder(): _inBuf(0), _propsWereSet(false), _outSizeDefined(false),
+ _inBufSize(1 << 20),
+ _outBufSize(1 << 22),
+ FinishStream(false)
+{
+ _inSizeProcessed = 0;
+ _inPos = _inSize = 0;
+ LzmaDec_Construct(&_state);
+}
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CDecoder::~CDecoder()
+{
+ LzmaDec_Free(&_state, &g_Alloc);
+ MyFree(_inBuf);
+}
+
+STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
+STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
+
+HRESULT CDecoder::CreateInputBuffer()
+{
+ if (_inBuf == 0 || _inBufSize != _inBufSizeAllocated)
+ {
+ MyFree(_inBuf);
+ _inBuf = (Byte *)MyAlloc(_inBufSize);
+ if (_inBuf == 0)
+ return E_OUTOFMEMORY;
+ _inBufSizeAllocated = _inBufSize;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
+{
+ RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_Alloc)));
+ _propsWereSet = true;
+ return CreateInputBuffer();
+}
+
+void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+ _outSizeProcessed = 0;
+ _wrPos = 0;
+ LzmaDec_Init(&_state);
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ _inSizeProcessed = 0;
+ _inPos = _inSize = 0;
+ SetOutStreamSizeResume(outSize);
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0 || !_propsWereSet)
+ return S_FALSE;
+
+ UInt64 startInProgress = _inSizeProcessed;
+
+ SizeT next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize);
+ for (;;)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ }
+
+ SizeT dicPos = _state.dicPos;
+ SizeT curSize = next - dicPos;
+
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem <= curSize)
+ {
+ curSize = (SizeT)rem;
+ if (FinishStream)
+ finishMode = LZMA_FINISH_END;
+ }
+ }
+
+ SizeT inSizeProcessed = _inSize - _inPos;
+ ELzmaStatus status;
+ SRes res = LzmaDec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
+
+ _inPos += (UInt32)inSizeProcessed;
+ _inSizeProcessed += inSizeProcessed;
+ SizeT outSizeProcessed = _state.dicPos - dicPos;
+ _outSizeProcessed += outSizeProcessed;
+
+ bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
+ bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
+
+ if (res != 0 || _state.dicPos == next || finished || stopDecoding)
+ {
+ HRESULT res2 = WriteStream(outStream, _state.dic + _wrPos, _state.dicPos - _wrPos);
+
+ _wrPos = _state.dicPos;
+ if (_state.dicPos == _state.dicBufSize)
+ {
+ _state.dicPos = 0;
+ _wrPos = 0;
+ }
+ next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize);
+
+ if (res != 0)
+ return S_FALSE;
+ RINOK(res2);
+ if (stopDecoding)
+ return S_OK;
+ if (finished)
+ return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE);
+ }
+ if (progress)
+ {
+ UInt64 inSize = _inSizeProcessed - startInProgress;
+ RINOK(progress->SetRatioInfo(&inSize, &_outSizeProcessed));
+ }
+ }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0)
+ return E_INVALIDARG;
+ SetOutStreamSize(outSize);
+ return CodeSpec(inStream, outStream, progress);
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
+STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ do
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ }
+ {
+ SizeT inProcessed = _inSize - _inPos;
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < size)
+ size = (UInt32)rem;
+ }
+
+ SizeT outProcessed = size;
+ ELzmaStatus status;
+ SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
+ _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
+ _inPos += (UInt32)inProcessed;
+ _inSizeProcessed += inProcessed;
+ _outSizeProcessed += outProcessed;
+ size -= (UInt32)outProcessed;
+ data = (Byte *)data + outProcessed;
+ if (processedSize)
+ *processedSize += (UInt32)outProcessed;
+ RINOK(SResToHRESULT(res));
+ if (inProcessed == 0 && outProcessed == 0)
+ return S_OK;
+ }
+ }
+ while (size != 0);
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ SetOutStreamSizeResume(outSize);
+ return CodeSpec(_inStream, outStream, progress);
+}
+
+HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)
+{
+ RINOK(CreateInputBuffer());
+ if (processedSize)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ if (_inSize == 0)
+ break;
+ }
+ {
+ UInt32 curSize = _inSize - _inPos;
+ if (curSize > size)
+ curSize = size;
+ memcpy(data, _inBuf + _inPos, curSize);
+ _inPos += curSize;
+ _inSizeProcessed += curSize;
+ size -= curSize;
+ data = (Byte *)data + curSize;
+ if (processedSize)
+ *processedSize += curSize;
+ }
+ }
+ return S_OK;
+}
+
+#endif
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.h
new file mode 100644
index 000000000..d28a4634b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaDecoder.h
@@ -0,0 +1,84 @@
+// LzmaDecoder.h
+
+#ifndef __LZMA_DECODER_H
+#define __LZMA_DECODER_H
+
+#include "../../../C/LzmaDec.h"
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressSetBufSize,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _inStream;
+ Byte *_inBuf;
+ UInt32 _inPos;
+ UInt32 _inSize;
+ CLzmaDec _state;
+ bool _propsWereSet;
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _inSizeProcessed;
+ UInt64 _outSizeProcessed;
+
+ UInt32 _inBufSizeAllocated;
+ UInt32 _inBufSize;
+ UInt32 _outBufSize;
+ SizeT _wrPos;
+
+ HRESULT CreateInputBuffer();
+ HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+ void SetOutStreamSizeResume(const UInt64 *outSize);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)
+ #ifndef NO_READ_FROM_CODER
+ MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
+ MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
+ #endif
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
+
+ #ifndef NO_READ_FROM_CODER
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize);
+ UInt64 GetInputProcessedSize() const { return _inSizeProcessed; }
+
+ #endif
+
+ bool FinishStream;
+
+ CDecoder();
+ virtual ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.cpp
new file mode 100644
index 000000000..9bdedaeb6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.cpp
@@ -0,0 +1,149 @@
+// LzmaEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/StreamUtils.h"
+
+#include "LzmaEncoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CEncoder::CEncoder()
+{
+ _encoder = 0;
+ _encoder = LzmaEnc_Create(&g_Alloc);
+ if (_encoder == 0)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder != 0)
+ LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc);
+}
+
+inline wchar_t GetUpperChar(wchar_t c)
+{
+ if (c >= 'a' && c <= 'z')
+ c -= 0x20;
+ return c;
+}
+
+static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
+{
+ wchar_t c = GetUpperChar(*s++);
+ if (c == L'H')
+ {
+ if (GetUpperChar(*s++) != L'C')
+ return 0;
+ int numHashBytesLoc = (int)(*s++ - L'0');
+ if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
+ return 0;
+ if (*s++ != 0)
+ return 0;
+ *btMode = 0;
+ *numHashBytes = numHashBytesLoc;
+ return 1;
+ }
+ if (c != L'B')
+ return 0;
+
+ if (GetUpperChar(*s++) != L'T')
+ return 0;
+ int numHashBytesLoc = (int)(*s++ - L'0');
+ if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
+ return 0;
+ c = GetUpperChar(*s++);
+ if (c != L'\0')
+ return 0;
+ *btMode = 1;
+ *numHashBytes = numHashBytesLoc;
+ return 1;
+}
+
+HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
+{
+ if (propID == NCoderPropID::kMatchFinder)
+ {
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
+ }
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = prop.ulVal;
+ switch (propID)
+ {
+ case NCoderPropID::kNumFastBytes: ep.fb = v; break;
+ case NCoderPropID::kMatchFinderCycles: ep.mc = v; break;
+ case NCoderPropID::kAlgorithm: ep.algo = v; break;
+ case NCoderPropID::kDictionarySize: ep.dictSize = v; break;
+ case NCoderPropID::kPosStateBits: ep.pb = v; break;
+ case NCoderPropID::kLitPosBits: ep.lp = v; break;
+ case NCoderPropID::kLitContextBits: ep.lc = v; break;
+ default: return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps)
+{
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ PROPID propID = propIDs[i];
+ switch (propID)
+ {
+ case NCoderPropID::kEndMarker:
+ if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal == VARIANT_TRUE); break;
+ case NCoderPropID::kNumThreads:
+ if (prop.vt != VT_UI4) return E_INVALIDARG; props.numThreads = prop.ulVal; break;
+ default:
+ RINOK(SetLzmaProp(propID, prop, props));
+ }
+ }
+ return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ size_t size = LZMA_PROPS_SIZE;
+ RINOK(LzmaEnc_WriteProperties(_encoder, props, &size));
+ return WriteStream(outStream, props, size);
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CSeqInStreamWrap inWrap(inStream);
+ CSeqOutStreamWrap outWrap(outStream);
+ CCompressProgressWrap progressWrap(progress);
+
+ SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc);
+ if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
+ return inWrap.Res;
+ if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
+ return outWrap.Res;
+ if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
+ return progressWrap.Res;
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.h
new file mode 100644
index 000000000..904c0002c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaEncoder.h
@@ -0,0 +1,36 @@
+// LzmaEncoder.h
+
+#ifndef __LZMA_ENCODER_H
+#define __LZMA_ENCODER_H
+
+#include "../../../C/LzmaEnc.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+class CEncoder:
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public CMyUnknownImp
+{
+ CLzmaEncHandle _encoder;
+public:
+ MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+
+ CEncoder();
+ virtual ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzmaRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaRegister.cpp
new file mode 100644
index 000000000..96ed0baed
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzmaRegister.cpp
@@ -0,0 +1,20 @@
+// LzmaRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "LzmaDecoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "LzmaEncoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x030101, L"LZMA", 1, false };
+
+REGISTER_CODEC(LZMA)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Lzx.h b/src/libs/7zip/unix/CPP/7zip/Compress/Lzx.h
new file mode 100644
index 000000000..09ab7f075
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Lzx.h
@@ -0,0 +1,61 @@
+// Lzx.h
+
+#ifndef __COMPRESS_LZX_H
+#define __COMPRESS_LZX_H
+
+namespace NCompress {
+namespace NLzx {
+
+const unsigned kNumHuffmanBits = 16;
+const UInt32 kNumRepDistances = 3;
+
+const UInt32 kNumLenSlots = 8;
+const UInt32 kMatchMinLen = 2;
+const UInt32 kNumLenSymbols = 249;
+const UInt32 kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1;
+
+const unsigned kNumAlignBits = 3;
+const UInt32 kAlignTableSize = 1 << kNumAlignBits;
+
+const UInt32 kNumPosSlots = 50;
+const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
+
+const UInt32 kMainTableSize = 256 + kNumPosLenSlots;
+const UInt32 kLevelTableSize = 20;
+const UInt32 kMaxTableSize = kMainTableSize;
+
+const unsigned kNumBlockTypeBits = 3;
+const unsigned kBlockTypeVerbatim = 1;
+const unsigned kBlockTypeAligned = 2;
+const unsigned kBlockTypeUncompressed = 3;
+
+const unsigned kUncompressedBlockSizeNumBits = 24;
+
+const unsigned kNumBitsForPreTreeLevel = 4;
+
+const unsigned kLevelSymbolZeros = 17;
+const unsigned kLevelSymbolZerosBig = 18;
+const unsigned kLevelSymbolSame = 19;
+
+const unsigned kLevelSymbolZerosStartValue = 4;
+const unsigned kLevelSymbolZerosNumBits = 4;
+
+const unsigned kLevelSymbolZerosBigStartValue = kLevelSymbolZerosStartValue +
+ (1 << kLevelSymbolZerosNumBits);
+const unsigned kLevelSymbolZerosBigNumBits = 5;
+
+const unsigned kLevelSymbolSameNumBits = 1;
+const unsigned kLevelSymbolSameStartValue = 4;
+
+const unsigned kNumBitsForAlignLevel = 3;
+
+const unsigned kNumDictionaryBitsMin = 15;
+const unsigned kNumDictionaryBitsMax = 21;
+const UInt32 kDictionarySizeMax = (1 << kNumDictionaryBitsMax);
+
+const unsigned kNumLinearPosSlotBits = 17;
+const UInt32 kNumPowerPosSlots = 0x26;
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Lzx86Converter.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Lzx86Converter.cpp
new file mode 100644
index 000000000..9e53f18a9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Lzx86Converter.cpp
@@ -0,0 +1,90 @@
+// Lzx86Converter.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+
+#include "Lzx86Converter.h"
+
+namespace NCompress {
+namespace NLzx {
+
+static const int kResidue = 6 + 4;
+
+void Cx86ConvertOutStream::MakeTranslation()
+{
+ if (m_Pos <= kResidue)
+ return;
+ UInt32 numBytes = m_Pos - kResidue;
+ Byte *buffer = m_Buffer;
+ for (UInt32 i = 0; i < numBytes;)
+ {
+ if (buffer[i++] == 0xE8)
+ {
+ Int32 absValue = 0;
+ int j;
+ for(j = 0; j < 4; j++)
+ absValue += (UInt32)buffer[i + j] << (j * 8);
+ Int32 pos = (Int32)(m_ProcessedSize + i - 1);
+ if (absValue >= -pos && absValue < (Int32)m_TranslationSize)
+ {
+ UInt32 offset = (absValue >= 0) ?
+ absValue - pos :
+ absValue + m_TranslationSize;
+ for(j = 0; j < 4; j++)
+ {
+ buffer[i + j] = (Byte)(offset & 0xFF);
+ offset >>= 8;
+ }
+ }
+ i += 4;
+ }
+ }
+}
+
+STDMETHODIMP Cx86ConvertOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (!m_TranslationMode)
+ return m_Stream->Write(data, size, processedSize);
+ UInt32 realProcessedSize = 0;
+ while (realProcessedSize < size)
+ {
+ UInt32 writeSize = MyMin(size - realProcessedSize, kUncompressedBlockSize - m_Pos);
+ memmove(m_Buffer + m_Pos, (const Byte *)data + realProcessedSize, writeSize);
+ m_Pos += writeSize;
+ realProcessedSize += writeSize;
+ if (m_Pos == kUncompressedBlockSize)
+ {
+ RINOK(Flush());
+ }
+ }
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return S_OK;
+}
+
+HRESULT Cx86ConvertOutStream::Flush()
+{
+ if (m_Pos == 0)
+ return S_OK;
+ if (m_TranslationMode)
+ MakeTranslation();
+ UInt32 pos = 0;
+ do
+ {
+ UInt32 processed;
+ RINOK(m_Stream->Write(m_Buffer + pos, m_Pos - pos, &processed));
+ if (processed == 0)
+ return E_FAIL;
+ pos += processed;
+ }
+ while(pos < m_Pos);
+ m_ProcessedSize += m_Pos;
+ m_Pos = 0;
+ m_TranslationMode = (m_TranslationMode && (m_ProcessedSize < (1 << 30)));
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Lzx86Converter.h b/src/libs/7zip/unix/CPP/7zip/Compress/Lzx86Converter.h
new file mode 100644
index 000000000..9f110c29b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Lzx86Converter.h
@@ -0,0 +1,46 @@
+// Lzx86Converter.h
+
+#ifndef __LZX_86_CONVERTER_H
+#define __LZX_86_CONVERTER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../IStream.h"
+
+namespace NCompress {
+namespace NLzx {
+
+const int kUncompressedBlockSize = 1 << 15;
+
+class Cx86ConvertOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> m_Stream;
+ UInt32 m_ProcessedSize;
+ UInt32 m_Pos;
+ UInt32 m_TranslationSize;
+ bool m_TranslationMode;
+ Byte m_Buffer[kUncompressedBlockSize];
+
+ void MakeTranslation();
+public:
+ void SetStream(ISequentialOutStream *outStream) { m_Stream = outStream; }
+ void ReleaseStream() { m_Stream.Release(); }
+ void Init(bool translationMode, UInt32 translationSize)
+ {
+ m_TranslationMode = translationMode;
+ m_TranslationSize = translationSize;
+ m_ProcessedSize = 0;
+ m_Pos = 0;
+ }
+ HRESULT Flush();
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp
new file mode 100644
index 000000000..d1027f1f3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp
@@ -0,0 +1,387 @@
+// LzxDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+
+#include "LzxDecoder.h"
+
+namespace NCompress {
+namespace NLzx {
+
+const int kLenIdNeedInit = -2;
+
+CDecoder::CDecoder(bool wimMode):
+ _keepHistory(false),
+ _skipByte(false),
+ _wimMode(wimMode)
+{
+ m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;
+ m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;
+}
+
+void CDecoder::ReleaseStreams()
+{
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ m_x86ConvertOutStreamSpec->ReleaseStream();
+}
+
+STDMETHODIMP CDecoder::Flush()
+{
+ RINOK(m_OutWindowStream.Flush());
+ return m_x86ConvertOutStreamSpec->Flush();
+}
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols)
+{
+ Byte levelLevels[kLevelTableSize];
+ UInt32 i;
+ for (i = 0; i < kLevelTableSize; i++)
+ levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+ unsigned num = 0;
+ Byte symbol = 0;
+ for (i = 0; i < numSymbols;)
+ {
+ if (num != 0)
+ {
+ lastLevels[i] = newLevels[i] = symbol;
+ i++;
+ num--;
+ continue;
+ }
+ UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
+ if (number == kLevelSymbolZeros)
+ {
+ num = kLevelSymbolZerosStartValue + (unsigned)ReadBits(kLevelSymbolZerosNumBits);
+ symbol = 0;
+ }
+ else if (number == kLevelSymbolZerosBig)
+ {
+ num = kLevelSymbolZerosBigStartValue + (unsigned)ReadBits(kLevelSymbolZerosBigNumBits);
+ symbol = 0;
+ }
+ else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
+ {
+ if (number <= kNumHuffmanBits)
+ num = 1;
+ else
+ {
+ num = kLevelSymbolSameStartValue + (unsigned)ReadBits(kLevelSymbolSameNumBits);
+ number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
+ if (number > kNumHuffmanBits)
+ return false;
+ }
+ symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
+bool CDecoder::ReadTables(void)
+{
+ Byte newLevels[kMaxTableSize];
+ {
+ if (_skipByte)
+ m_InBitStream.DirectReadByte();
+ m_InBitStream.Normalize();
+
+ unsigned blockType = (unsigned)ReadBits(kNumBlockTypeBits);
+ if (blockType > kBlockTypeUncompressed)
+ return false;
+ if (_wimMode)
+ if (ReadBits(1) == 1)
+ m_UnCompressedBlockSize = (1 << 15);
+ else
+ m_UnCompressedBlockSize = ReadBits(16);
+ else
+ m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);
+
+ m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed);
+
+ _skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0));
+
+ if (m_IsUncompressedBlock)
+ {
+ ReadBits(16 - m_InBitStream.GetBitPosition());
+ if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))
+ return false;
+ m_RepDistances[0]--;
+ for (unsigned i = 1; i < kNumRepDistances; i++)
+ {
+ UInt32 rep = 0;
+ for (unsigned j = 0; j < 4; j++)
+ rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);
+ m_RepDistances[i] = rep - 1;
+ }
+ return true;
+ }
+ m_AlignIsUsed = (blockType == kBlockTypeAligned);
+ if (m_AlignIsUsed)
+ {
+ for (unsigned i = 0; i < kAlignTableSize; i++)
+ newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel);
+ RIF(m_AlignDecoder.SetCodeLengths(newLevels));
+ }
+ }
+
+ RIF(ReadTable(m_LastMainLevels, newLevels, 256));
+ RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));
+ for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)
+ newLevels[i] = 0;
+ RIF(m_MainDecoder.SetCodeLengths(newLevels));
+
+ RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));
+ return m_LenDecoder.SetCodeLengths(newLevels);
+}
+
+class CDecoderFlusher
+{
+ CDecoder *m_Decoder;
+public:
+ bool NeedFlush;
+ CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ m_Decoder->Flush();
+ m_Decoder->ReleaseStreams();
+ }
+};
+
+
+void CDecoder::ClearPrevLevels()
+{
+ unsigned i;
+ for (i = 0; i < kMainTableSize; i++)
+ m_LastMainLevels[i] = 0;
+ for (i = 0; i < kNumLenSymbols; i++)
+ m_LastLenLevels[i] = 0;
+}
+
+
+HRESULT CDecoder::CodeSpec(UInt32 curSize)
+{
+ if (_remainLen == kLenIdNeedInit)
+ {
+ _remainLen = 0;
+ m_InBitStream.Init();
+ if (!_keepHistory || !m_IsUncompressedBlock)
+ m_InBitStream.Normalize();
+ if (!_keepHistory)
+ {
+ _skipByte = false;
+ m_UnCompressedBlockSize = 0;
+ ClearPrevLevels();
+ UInt32 i86TranslationSize = 12000000;
+ bool translationMode = true;
+ if (!_wimMode)
+ {
+ translationMode = (ReadBits(1) != 0);
+ if (translationMode)
+ {
+ i86TranslationSize = ReadBits(16) << 16;
+ i86TranslationSize |= ReadBits(16);
+ }
+ }
+ m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);
+
+ for (unsigned i = 0 ; i < kNumRepDistances; i++)
+ m_RepDistances[i] = 0;
+ }
+ }
+
+ while (_remainLen > 0 && curSize > 0)
+ {
+ m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));
+ _remainLen--;
+ curSize--;
+ }
+
+ while (curSize > 0)
+ {
+ if (m_UnCompressedBlockSize == 0)
+ if (!ReadTables())
+ return S_FALSE;
+ UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);
+ curSize -= next;
+ m_UnCompressedBlockSize -= next;
+ if (m_IsUncompressedBlock)
+ {
+ while (next > 0)
+ {
+ m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());
+ next--;
+ }
+ }
+ else while (next > 0)
+ {
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < 256)
+ {
+ m_OutWindowStream.PutByte((Byte)number);
+ next--;
+ }
+ else
+ {
+ UInt32 posLenSlot = number - 256;
+ if (posLenSlot >= m_NumPosLenSlots)
+ return S_FALSE;
+ UInt32 posSlot = posLenSlot / kNumLenSlots;
+ UInt32 lenSlot = posLenSlot % kNumLenSlots;
+ UInt32 len = kMatchMinLen + lenSlot;
+ if (lenSlot == kNumLenSlots - 1)
+ {
+ UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);
+ if (lenTemp >= kNumLenSymbols)
+ return S_FALSE;
+ len += lenTemp;
+ }
+
+ if (posSlot < kNumRepDistances)
+ {
+ UInt32 distance = m_RepDistances[posSlot];
+ m_RepDistances[posSlot] = m_RepDistances[0];
+ m_RepDistances[0] = distance;
+ }
+ else
+ {
+ UInt32 distance;
+ unsigned numDirectBits;
+ if (posSlot < kNumPowerPosSlots)
+ {
+ numDirectBits = (unsigned)(posSlot >> 1) - 1;
+ distance = ((2 | (posSlot & 1)) << numDirectBits);
+ }
+ else
+ {
+ numDirectBits = kNumLinearPosSlotBits;
+ distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);
+ }
+
+ if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)
+ {
+ distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);
+ UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
+ if (alignTemp >= kAlignTableSize)
+ return S_FALSE;
+ distance += alignTemp;
+ }
+ else
+ distance += m_InBitStream.ReadBits(numDirectBits);
+ m_RepDistances[2] = m_RepDistances[1];
+ m_RepDistances[1] = m_RepDistances[0];
+ m_RepDistances[0] = distance - kNumRepDistances;
+ }
+
+ UInt32 locLen = len;
+ if (locLen > next)
+ locLen = next;
+
+ if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))
+ return S_FALSE;
+
+ len -= locLen;
+ next -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (int)len;
+ return S_OK;
+ }
+ }
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+ UInt64 size = *outSize;
+
+ RINOK(SetInStream(inStream));
+ m_x86ConvertOutStreamSpec->SetStream(outStream);
+ m_OutWindowStream.SetStream(m_x86ConvertOutStream);
+ RINOK(SetOutStreamSize(outSize));
+
+ CDecoderFlusher flusher(this);
+
+ const UInt64 start = m_OutWindowStream.GetProcessedSize();
+ for (;;)
+ {
+ UInt32 curSize = 1 << 18;
+ UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ if (curSize == 0)
+ break;
+ RINOK(CodeSpec(curSize));
+ if (progress != NULL)
+ {
+ UInt64 inSize = m_InBitStream.GetProcessedSize();
+ UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+ }
+ }
+ flusher.NeedFlush = false;
+ return Flush();
+}
+
+HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
+{
+ m_InBitStream.SetStream(inStream);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::ReleaseInStream()
+{
+ m_InBitStream.ReleaseStream();
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ if (outSize == NULL)
+ return E_FAIL;
+ _remainLen = kLenIdNeedInit;
+ m_OutWindowStream.Init(_keepHistory);
+ return S_OK;
+}
+
+HRESULT CDecoder::SetParams(unsigned numDictBits)
+{
+ if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)
+ return E_INVALIDARG;
+ UInt32 numPosSlots;
+ if (numDictBits < 20)
+ numPosSlots = 30 + (numDictBits - 15) * 2;
+ else if (numDictBits == 20)
+ numPosSlots = 42;
+ else
+ numPosSlots = 50;
+ m_NumPosLenSlots = numPosSlots * kNumLenSlots;
+ if (!m_OutWindowStream.Create(kDictionarySizeMax))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 16))
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.h
new file mode 100644
index 000000000..73a050619
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.h
@@ -0,0 +1,159 @@
+// LzxDecoder.h
+
+#ifndef __LZX_DECODER_H
+#define __LZX_DECODER_H
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+#include "Lzx.h"
+#include "Lzx86Converter.h"
+
+namespace NCompress {
+namespace NLzx {
+
+namespace NBitStream {
+
+const unsigned kNumBigValueBits = 8 * 4;
+const unsigned kNumValueBits = 17;
+const UInt32 kBitDecoderValueMask = (1 << kNumValueBits) - 1;
+
+class CDecoder
+{
+ CInBuffer m_Stream;
+ UInt32 m_Value;
+ unsigned m_BitPos;
+public:
+ CDecoder() {}
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+
+ void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); }
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = kNumBigValueBits;
+ }
+
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - (kNumBigValueBits - m_BitPos) / 8; }
+
+ unsigned GetBitPosition() const { return m_BitPos & 0xF; }
+
+ void Normalize()
+ {
+ for (; m_BitPos >= 16; m_BitPos -= 16)
+ {
+ Byte b0 = m_Stream.ReadByte();
+ Byte b1 = m_Stream.ReadByte();
+ m_Value = (m_Value << 8) | b1;
+ m_Value = (m_Value << 8) | b0;
+ }
+ }
+
+ UInt32 GetValue(unsigned numBits) const
+ {
+ return ((m_Value >> ((32 - kNumValueBits) - m_BitPos)) & kBitDecoderValueMask) >> (kNumValueBits - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ m_BitPos += numBits;
+ Normalize();
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ MovePos(numBits);
+ return res;
+ }
+
+ UInt32 ReadBitsBig(unsigned numBits)
+ {
+ unsigned numBits0 = numBits / 2;
+ unsigned numBits1 = numBits - numBits0;
+ UInt32 res = ReadBits(numBits0) << numBits1;
+ return res + ReadBits(numBits1);
+ }
+
+ bool ReadUInt32(UInt32 &v)
+ {
+ if (m_BitPos != 0)
+ return false;
+ v = ((m_Value >> 16) & 0xFFFF) | ((m_Value << 16) & 0xFFFF0000);
+ m_BitPos = kNumBigValueBits;
+ return true;
+ }
+
+ Byte DirectReadByte() { return m_Stream.ReadByte(); }
+
+};
+}
+
+class CDecoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ NBitStream::CDecoder m_InBitStream;
+ CLzOutWindow m_OutWindowStream;
+
+ UInt32 m_RepDistances[kNumRepDistances];
+ UInt32 m_NumPosLenSlots;
+
+ bool m_IsUncompressedBlock;
+ bool m_AlignIsUsed;
+
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kNumLenSymbols> m_LenDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ Byte m_LastMainLevels[kMainTableSize];
+ Byte m_LastLenLevels[kNumLenSymbols];
+
+ Cx86ConvertOutStream *m_x86ConvertOutStreamSpec;
+ CMyComPtr<ISequentialOutStream> m_x86ConvertOutStream;
+
+ UInt32 m_UnCompressedBlockSize;
+
+ bool _keepHistory;
+ int _remainLen;
+ bool _skipByte;
+
+ bool _wimMode;
+
+ UInt32 ReadBits(unsigned numBits);
+ bool ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols);
+ bool ReadTables();
+ void ClearPrevLevels();
+
+ HRESULT CodeSpec(UInt32 size);
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+public:
+ CDecoder(bool wimMode = false);
+
+ MY_UNKNOWN_IMP
+
+ void ReleaseStreams();
+ STDMETHOD(Flush)();
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ HRESULT SetParams(unsigned numDictBits);
+ void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Mtf8.h b/src/libs/7zip/unix/CPP/7zip/Compress/Mtf8.h
new file mode 100644
index 000000000..d15dd4a56
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Mtf8.h
@@ -0,0 +1,193 @@
+// Mtf8.h
+
+#ifndef __COMPRESS_MTF8_H
+#define __COMPRESS_MTF8_H
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/Types.h"
+
+namespace NCompress {
+
+struct CMtf8Encoder
+{
+ Byte Buf[256];
+
+ int FindAndMove(Byte v)
+ {
+ int pos;
+ for (pos = 0; Buf[pos] != v; pos++);
+ int resPos = pos;
+ for (; pos >= 8; pos -= 8)
+ {
+ Buf[pos] = Buf[pos - 1];
+ Buf[pos - 1] = Buf[pos - 2];
+ Buf[pos - 2] = Buf[pos - 3];
+ Buf[pos - 3] = Buf[pos - 4];
+ Buf[pos - 4] = Buf[pos - 5];
+ Buf[pos - 5] = Buf[pos - 6];
+ Buf[pos - 6] = Buf[pos - 7];
+ Buf[pos - 7] = Buf[pos - 8];
+ }
+ for (; pos > 0; pos--)
+ Buf[pos] = Buf[pos - 1];
+ Buf[0] = v;
+ return resPos;
+ }
+};
+
+/*
+struct CMtf8Decoder
+{
+ Byte Buf[256];
+
+ void Init(int) {};
+ Byte GetHead() const { return Buf[0]; }
+ Byte GetAndMove(int pos)
+ {
+ Byte res = Buf[pos];
+ for (; pos >= 8; pos -= 8)
+ {
+ Buf[pos] = Buf[pos - 1];
+ Buf[pos - 1] = Buf[pos - 2];
+ Buf[pos - 2] = Buf[pos - 3];
+ Buf[pos - 3] = Buf[pos - 4];
+ Buf[pos - 4] = Buf[pos - 5];
+ Buf[pos - 5] = Buf[pos - 6];
+ Buf[pos - 6] = Buf[pos - 7];
+ Buf[pos - 7] = Buf[pos - 8];
+ }
+ for (; pos > 0; pos--)
+ Buf[pos] = Buf[pos - 1];
+ Buf[0] = res;
+ return res;
+ }
+};
+*/
+
+#ifdef MY_CPU_64BIT
+typedef UInt64 CMtfVar;
+#define MTF_MOVS 3
+#else
+typedef UInt32 CMtfVar;
+#define MTF_MOVS 2
+#endif
+
+#define MTF_MASK ((1 << MTF_MOVS) - 1)
+
+
+struct CMtf8Decoder
+{
+ CMtfVar Buf[256 >> MTF_MOVS];
+
+ void StartInit() { memset(Buf, 0, sizeof(Buf)); }
+ void Add(unsigned int pos, Byte val) { Buf[pos >> MTF_MOVS] |= ((CMtfVar)val << ((pos & MTF_MASK) << 3)); }
+ Byte GetHead() const { return (Byte)Buf[0]; }
+ Byte GetAndMove(unsigned int pos)
+ {
+ UInt32 lim = ((UInt32)pos >> MTF_MOVS);
+ pos = (pos & MTF_MASK) << 3;
+ CMtfVar prev = (Buf[lim] >> pos) & 0xFF;
+
+ UInt32 i = 0;
+ if ((lim & 1) != 0)
+ {
+ CMtfVar next = Buf[0];
+ Buf[0] = (next << 8) | prev;
+ prev = (next >> (MTF_MASK << 3));
+ i = 1;
+ lim -= 1;
+ }
+ for (; i < lim; i += 2)
+ {
+ CMtfVar n0 = Buf[i];
+ CMtfVar n1 = Buf[i + 1];
+ Buf[i ] = (n0 << 8) | prev;
+ Buf[i + 1] = (n1 << 8) | (n0 >> (MTF_MASK << 3));
+ prev = (n1 >> (MTF_MASK << 3));
+ }
+ CMtfVar next = Buf[i];
+ CMtfVar mask = (((CMtfVar)0x100 << pos) - 1);
+ Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask);
+ return (Byte)Buf[0];
+ }
+};
+
+/*
+const int kSmallSize = 64;
+class CMtf8Decoder
+{
+ Byte SmallBuffer[kSmallSize];
+ int SmallSize;
+ Byte Counts[16];
+ int Size;
+public:
+ Byte Buf[256];
+
+ Byte GetHead() const
+ {
+ if (SmallSize > 0)
+ return SmallBuffer[kSmallSize - SmallSize];
+ return Buf[0];
+ }
+
+ void Init(int size)
+ {
+ Size = size;
+ SmallSize = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ Counts[i] = ((size >= 16) ? 16 : size);
+ size -= Counts[i];
+ }
+ }
+
+ Byte GetAndMove(int pos)
+ {
+ if (pos < SmallSize)
+ {
+ Byte *p = SmallBuffer + kSmallSize - SmallSize;
+ Byte res = p[pos];
+ for (; pos > 0; pos--)
+ p[pos] = p[pos - 1];
+ SmallBuffer[kSmallSize - SmallSize] = res;
+ return res;
+ }
+ if (SmallSize == kSmallSize)
+ {
+ int i = Size - 1;
+ int g = 16;
+ do
+ {
+ g--;
+ int offset = (g << 4);
+ for (int t = Counts[g] - 1; t >= 0; t--, i--)
+ Buf[i] = Buf[offset + t];
+ }
+ while(g != 0);
+
+ for (i = kSmallSize - 1; i >= 0; i--)
+ Buf[i] = SmallBuffer[i];
+ Init(Size);
+ }
+ pos -= SmallSize;
+ int g;
+ for (g = 0; pos >= Counts[g]; g++)
+ pos -= Counts[g];
+ int offset = (g << 4);
+ Byte res = Buf[offset + pos];
+ for (pos; pos < 16 - 1; pos++)
+ Buf[offset + pos] = Buf[offset + pos + 1];
+
+ SmallSize++;
+ SmallBuffer[kSmallSize - SmallSize] = res;
+
+ Counts[g]--;
+ return res;
+ }
+};
+*/
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PPMD_Alone/PpmdAlone.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/PPMD_Alone/PpmdAlone.cpp
new file mode 100644
index 000000000..25df0a0d0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PPMD_Alone/PpmdAlone.cpp
@@ -0,0 +1,348 @@
+// PpmdAlone.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+#include <fcntl.h>
+#include <io.h>
+#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
+#else
+#define MY_SET_BINARY_MODE(file)
+#endif
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../PpmdDecoder.h"
+#include "../PpmdEncoder.h"
+
+using namespace NCommandLineParser;
+
+#ifdef _WIN32
+bool g_IsNT = false;
+static inline bool IsItWindowsNT()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+ if (!::GetVersionEx(&versionInfo))
+ return false;
+ return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+
+static const char *kCantAllocate = "Can not allocate memory";
+static const char *kReadError = "Read error";
+static const char *kWriteError = "Write error";
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kOrder,
+ kUsedMemorySize,
+ kStdIn,
+ kStdOut
+};
+}
+
+static const CSwitchForm kSwitchForms[] =
+{
+ { L"?", NSwitchType::kSimple, false },
+ { L"H", NSwitchType::kSimple, false },
+ { L"O", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"M", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"SI", NSwitchType::kSimple, false },
+ { L"SO", NSwitchType::kSimple, false }
+};
+
+static const int kNumSwitches = sizeof(kSwitchForms) / sizeof(kSwitchForms[0]);
+
+static void PrintHelp()
+{
+ fprintf(stderr, "\nUsage: PPMD <e|d> inputFile outputFile [<switches>...]\n"
+ " e: encode file\n"
+ " d: decode file\n"
+/*
+ " b: Benchmark\n"
+*/
+ "<Switches>\n"
+ " -o{N}: set order - [4, 32], default: 4\n"
+ " -m{N}: set memory size - [4,512], default: 4 (4 MB)\n"
+ " -si: read data from stdin (only with d)\n"
+ " -so: write data to stdout\n"
+ );
+}
+
+static void PrintHelpAndExit(const char *s)
+{
+ fprintf(stderr, "\nError: %s\n\n", s);
+ PrintHelp();
+ throw -1;
+}
+
+static void IncorrectCommand()
+{
+ PrintHelpAndExit("Incorrect command");
+}
+
+static void WriteArgumentsToStringList(int numArguments, const char *arguments[],
+ UStringVector &strings)
+{
+ for(int i = 1; i < numArguments; i++)
+ strings.Add(MultiByteToUnicodeString(arguments[i]));
+}
+
+static bool GetNumber(const wchar_t *s, UInt32 &value)
+{
+ value = 0;
+ if (MyStringLen(s) == 0)
+ return false;
+ const wchar_t *end;
+ UInt64 res = ConvertStringToUInt64(s, &end);
+ if (*end != L'\0')
+ return false;
+ if (res > 0xFFFFFFFF)
+ return false;
+ value = UInt32(res);
+ return true;
+}
+
+int main2(int n, const char *args[])
+{
+ #ifdef _WIN32
+ g_IsNT = IsItWindowsNT();
+ #endif
+
+ fprintf(stderr, "\nPPMD 4.49 Copyright (c) 1999-2007 Igor Pavlov 2007-07-05\n");
+
+ if (n == 1)
+ {
+ PrintHelp();
+ return 0;
+ }
+
+ bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4);
+ if (unsupportedTypes)
+ {
+ fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
+ return 1;
+ }
+
+ UStringVector commandStrings;
+ WriteArgumentsToStringList(n, args, commandStrings);
+ CParser parser(kNumSwitches);
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ }
+ catch(...)
+ {
+ IncorrectCommand();
+ }
+
+ if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
+ {
+ PrintHelp();
+ return 0;
+ }
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+
+ int paramIndex = 0;
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &command = nonSwitchStrings[paramIndex++];
+
+/* FIXME
+ if (command.CompareNoCase(L"b") == 0)
+ {
+ const UInt32 kNumDefaultItereations = 1;
+ UInt32 numIterations = kNumDefaultItereations;
+ {
+ if (paramIndex < nonSwitchStrings.Size())
+ if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
+ numIterations = kNumDefaultItereations;
+ }
+ return LzmaBenchCon(stderr, numIterations, numThreads, dictionary);
+ }
+*/
+
+ bool encodeMode = false;
+ if (command.CompareNoCase(L"e") == 0)
+ encodeMode = true;
+ else if (command.CompareNoCase(L"d") == 0)
+ encodeMode = false;
+ else
+ IncorrectCommand();
+
+ bool stdInMode = parser[NKey::kStdIn].ThereIs;
+ bool stdOutMode = parser[NKey::kStdOut].ThereIs;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ CInFileStream *inStreamSpec = 0;
+ if (stdInMode)
+ {
+ inStream = new CStdInFileStream;
+ MY_SET_BINARY_MODE(stdin);
+ }
+ else
+ {
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &inputName = nonSwitchStrings[paramIndex++];
+ inStreamSpec = new CInFileStream;
+ inStream = inStreamSpec;
+ if (!inStreamSpec->Open(GetSystemString(inputName)))
+ {
+ fprintf(stderr, "\nError: can not open input file %s\n",
+ (const char *)GetOemString(inputName));
+ return 1;
+ }
+ }
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ if (stdOutMode)
+ {
+ outStream = new CStdOutFileStream;
+ MY_SET_BINARY_MODE(stdout);
+ }
+ else
+ {
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &outputName = nonSwitchStrings[paramIndex++];
+ COutFileStream *outStreamSpec = new COutFileStream;
+ outStream = outStreamSpec;
+ if (!outStreamSpec->Create(GetSystemString(outputName), true))
+ {
+ fprintf(stderr, "\nError: can not open output file %s\n",
+ (const char *)GetOemString(outputName));
+ return 1;
+ }
+ }
+
+ UInt64 fileSize;
+ if (encodeMode)
+ {
+ // NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
+ NCompress::NPpmd::CEncoder *encoderSpec = new NCompress::NPpmd::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ if (stdInMode)
+ IncorrectCommand();
+
+ UInt32 order = 4;
+ if(parser[NKey::kOrder].ThereIs)
+ if (!GetNumber(parser[NKey::kOrder].PostStrings[0], order))
+ IncorrectCommand();
+ if (order < 4) order = 4;
+
+ UInt32 memSize = 4;
+ if(parser[NKey::kUsedMemorySize].ThereIs)
+ if (!GetNumber(parser[NKey::kUsedMemorySize].PostStrings[0], memSize))
+ IncorrectCommand();
+ if (memSize < 4 ) memSize = 4;
+
+
+ PROPID propIDs[] =
+
+ {
+ NCoderPropID::kUsedMemorySize,
+ NCoderPropID::kOrder
+ };
+ const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);
+
+ PROPVARIANT properties[kNumPropsMax];
+ for (int p = 0; p < kNumPropsMax; p++)
+ properties[p].vt = VT_UI4;
+
+ properties[0].ulVal = memSize * 1024 * 1024; // memory
+ properties[1].ulVal = order;
+
+ int numProps = kNumPropsMax;
+
+ if (encoderSpec->SetCoderProperties(propIDs, properties, numProps) != S_OK)
+ IncorrectCommand();
+ encoderSpec->WriteCoderProperties(outStream);
+
+/*
+ if (eos || stdInMode)
+ fileSize = (UInt64)(Int64)-1;
+ else
+*/
+ inStreamSpec->File.GetLength(fileSize);
+
+ for (int i = 0; i < 8; i++)
+ {
+ Byte b = Byte(fileSize >> (8 * i));
+ if (outStream->Write(&b, 1, 0) != S_OK)
+ {
+ fprintf(stderr, kWriteError);
+ return 1;
+ }
+ }
+ HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
+ if (result == E_OUTOFMEMORY)
+ {
+ fprintf(stderr, "\nError: Can not allocate memory\n");
+ return 1;
+ }
+ else if (result != S_OK)
+ {
+ fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
+ return 1;
+ }
+ }
+ else
+ {
+ // NCompress::NLZMA::CDecoder *decoderSpec = new NCompress::NLZMA::CDecoder;
+ NCompress::NPpmd::CDecoder *decoderSpec = new NCompress::NPpmd::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+ const UInt32 kPropertiesSize = 5;
+ Byte header[kPropertiesSize + 8];
+ if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK)
+ {
+ fprintf(stderr, kReadError);
+ return 1;
+ }
+ if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK)
+ {
+ fprintf(stderr, "SetDecoderProperties error");
+ return 1;
+ }
+ fileSize = 0;
+ for (int i = 0; i < 8; i++)
+ fileSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i);
+
+ if (decoder->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
+ {
+ fprintf(stderr, "Decoder error");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int main(int n, const char *args[])
+{
+ try { return main2(n, args); }
+ catch(const char *s)
+ {
+ fprintf(stderr, "\nError: %s\n", s);
+ return 1;
+ }
+ catch(...)
+ {
+ fprintf(stderr, "\nError\n");
+ return 1;
+ }
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdContext.h b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdContext.h
new file mode 100644
index 000000000..cfff53eda
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdContext.h
@@ -0,0 +1,490 @@
+// PpmdContext.h
+// 2009-05-30 : Igor Pavlov : Public domain
+// This code is based on Dmitry Shkarin's PPMdH code (public domain)
+
+#ifndef __COMPRESS_PPMD_CONTEXT_H
+#define __COMPRESS_PPMD_CONTEXT_H
+
+#include "../../Common/Types.h"
+
+#include "PpmdSubAlloc.h"
+#include "RangeCoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS,
+ INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124;
+
+struct SEE2_CONTEXT
+{
+ // SEE-contexts for PPM-contexts with masked symbols
+ UInt16 Summ;
+ Byte Shift, Count;
+ void init(int InitVal) { Summ = (UInt16)(InitVal << (Shift=PERIOD_BITS-4)); Count=4; }
+ unsigned int getMean()
+ {
+ unsigned int RetVal=(Summ >> Shift);
+ Summ = (UInt16)(Summ - RetVal);
+ return RetVal+(RetVal == 0);
+ }
+ void update()
+ {
+ if (Shift < PERIOD_BITS && --Count == 0)
+ {
+ Summ <<= 1;
+ Count = (Byte)(3 << Shift++);
+ }
+ }
+};
+
+struct PPM_CONTEXT
+{
+ UInt16 NumStats; // sizeof(UInt16) > sizeof(Byte)
+ UInt16 SummFreq;
+
+ struct STATE
+ {
+ Byte Symbol, Freq;
+ UInt16 SuccessorLow;
+ UInt16 SuccessorHigh;
+
+ UInt32 GetSuccessor() const { return SuccessorLow | ((UInt32)SuccessorHigh << 16); }
+ void SetSuccessor(UInt32 v)
+ {
+ SuccessorLow = (UInt16)(v & 0xFFFF);
+ SuccessorHigh = (UInt16)((v >> 16) & 0xFFFF);
+ }
+ };
+
+ UInt32 Stats;
+ UInt32 Suffix;
+
+ PPM_CONTEXT* createChild(CSubAllocator &subAllocator, STATE* pStats, STATE& FirstState)
+ {
+ PPM_CONTEXT* pc = (PPM_CONTEXT*) subAllocator.AllocContext();
+ if (pc)
+ {
+ pc->NumStats = 1;
+ pc->oneState() = FirstState;
+ pc->Suffix = subAllocator.GetOffset(this);
+ pStats->SetSuccessor(subAllocator.GetOffsetNoCheck(pc));
+ }
+ return pc;
+ }
+
+ STATE& oneState() const { return (STATE&) SummFreq; }
+};
+
+/////////////////////////////////
+
+const UInt16 InitBinEsc[] =
+ {0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+struct CInfo
+{
+ CSubAllocator SubAllocator;
+ SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
+ PPM_CONTEXT * MinContext, * MaxContext;
+
+ PPM_CONTEXT::STATE* FoundState; // found next state transition
+ int NumMasked, InitEsc, OrderFall, RunLength, InitRL, MaxOrder;
+ Byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
+ Byte EscCount, PrintCount, PrevSuccess, HiBitsFlag;
+ UInt16 BinSumm[128][64]; // binary SEE-contexts
+
+ UInt16 &GetBinSumm(const PPM_CONTEXT::STATE &rs, int numStates)
+ {
+ HiBitsFlag = HB2Flag[FoundState->Symbol];
+ return BinSumm[rs.Freq - 1][
+ PrevSuccess + NS2BSIndx[numStates - 1] +
+ HiBitsFlag + 2 * HB2Flag[rs.Symbol] +
+ ((RunLength >> 26) & 0x20)];
+ }
+
+ PPM_CONTEXT *GetContext(UInt32 offset) const { return (PPM_CONTEXT *)SubAllocator.GetPtr(offset); }
+ PPM_CONTEXT *GetContextNoCheck(UInt32 offset) const { return (PPM_CONTEXT *)SubAllocator.GetPtrNoCheck(offset); }
+ PPM_CONTEXT::STATE *GetState(UInt32 offset) const { return (PPM_CONTEXT::STATE *)SubAllocator.GetPtr(offset); }
+ PPM_CONTEXT::STATE *GetStateNoCheck(UInt32 offset) const { return (PPM_CONTEXT::STATE *)SubAllocator.GetPtr(offset); }
+
+ void RestartModelRare()
+ {
+ int i, k, m;
+ memset(CharMask,0,sizeof(CharMask));
+ SubAllocator.InitSubAllocator();
+ InitRL = -((MaxOrder < 12) ? MaxOrder : 12) - 1;
+ MinContext = MaxContext = (PPM_CONTEXT*) SubAllocator.AllocContext();
+ MinContext->Suffix = 0;
+ OrderFall = MaxOrder;
+ MinContext->SummFreq = (UInt16)((MinContext->NumStats = 256) + 1);
+ FoundState = (PPM_CONTEXT::STATE*)SubAllocator.AllocUnits(256 / 2);
+ MinContext->Stats = SubAllocator.GetOffsetNoCheck(FoundState);
+ PrevSuccess = 0;
+ for (RunLength = InitRL, i = 0; i < 256; i++)
+ {
+ PPM_CONTEXT::STATE &state = FoundState[i];
+ state.Symbol = (Byte)i;
+ state.Freq = 1;
+ state.SetSuccessor(0);
+ }
+ for (i = 0; i < 128; i++)
+ for (k = 0; k < 8; k++)
+ for ( m=0; m < 64; m += 8)
+ BinSumm[i][k + m] = (UInt16)(BIN_SCALE - InitBinEsc[k] / (i + 2));
+ for (i = 0; i < 25; i++)
+ for (k = 0; k < 16; k++)
+ SEE2Cont[i][k].init(5*i+10);
+ }
+
+ void StartModelRare(int maxOrder)
+ {
+ int i, k, m ,Step;
+ EscCount=PrintCount=1;
+ if (maxOrder < 2)
+ {
+ memset(CharMask,0,sizeof(CharMask));
+ OrderFall = MaxOrder;
+ MinContext = MaxContext;
+ while (MinContext->Suffix != 0)
+ {
+ MinContext = GetContextNoCheck(MinContext->Suffix);
+ OrderFall--;
+ }
+ FoundState = GetState(MinContext->Stats);
+ MinContext = MaxContext;
+ }
+ else
+ {
+ MaxOrder = maxOrder;
+ RestartModelRare();
+ NS2BSIndx[0] = 2 * 0;
+ NS2BSIndx[1] = 2 * 1;
+ memset(NS2BSIndx + 2, 2 * 2, 9);
+ memset(NS2BSIndx + 11, 2 * 3, 256 - 11);
+ for (i = 0; i < 3; i++)
+ NS2Indx[i] = (Byte)i;
+ for (m = i, k = Step = 1; i < 256; i++)
+ {
+ NS2Indx[i] = (Byte)m;
+ if ( !--k )
+ {
+ k = ++Step;
+ m++;
+ }
+ }
+ memset(HB2Flag, 0, 0x40);
+ memset(HB2Flag + 0x40, 0x08, 0x100 - 0x40);
+ DummySEE2Cont.Shift = PERIOD_BITS;
+ }
+ }
+
+ PPM_CONTEXT* CreateSuccessors(bool skip, PPM_CONTEXT::STATE* p1)
+ {
+ // static UpState declaration bypasses IntelC bug
+ // static PPM_CONTEXT::STATE UpState;
+ PPM_CONTEXT::STATE UpState;
+
+ PPM_CONTEXT *pc = MinContext;
+ PPM_CONTEXT *UpBranch = GetContext(FoundState->GetSuccessor());
+ PPM_CONTEXT::STATE * p, * ps[MAX_O], ** pps = ps;
+ if ( !skip )
+ {
+ *pps++ = FoundState;
+ if ( !pc->Suffix )
+ goto NO_LOOP;
+ }
+ if ( p1 )
+ {
+ p = p1;
+ pc = GetContext(pc->Suffix);
+ goto LOOP_ENTRY;
+ }
+ do
+ {
+ pc = GetContext(pc->Suffix);
+ if (pc->NumStats != 1)
+ {
+ if ((p = GetStateNoCheck(pc->Stats))->Symbol != FoundState->Symbol)
+ do { p++; } while (p->Symbol != FoundState->Symbol);
+ }
+ else
+ p = &(pc->oneState());
+LOOP_ENTRY:
+ if (GetContext(p->GetSuccessor()) != UpBranch)
+ {
+ pc = GetContext(p->GetSuccessor());
+ break;
+ }
+ *pps++ = p;
+ }
+ while ( pc->Suffix );
+NO_LOOP:
+ if (pps == ps)
+ return pc;
+ UpState.Symbol = *(Byte*) UpBranch;
+ UpState.SetSuccessor(SubAllocator.GetOffset(UpBranch) + 1);
+ if (pc->NumStats != 1)
+ {
+ if ((p = GetStateNoCheck(pc->Stats))->Symbol != UpState.Symbol)
+ do { p++; } while (p->Symbol != UpState.Symbol);
+ unsigned int cf = p->Freq-1;
+ unsigned int s0 = pc->SummFreq - pc->NumStats - cf;
+ UpState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) :
+ ((2 * cf + 3 * s0 - 1) / (2 * s0))));
+ }
+ else
+ UpState.Freq = pc->oneState().Freq;
+ do
+ {
+ pc = pc->createChild(SubAllocator, *--pps, UpState);
+ if ( !pc )
+ return NULL;
+ }
+ while (pps != ps);
+ return pc;
+ }
+
+ void UpdateModel()
+ {
+ PPM_CONTEXT::STATE fs = *FoundState, * p = NULL;
+ PPM_CONTEXT* pc, * Successor;
+ unsigned int ns1, ns, cf, sf, s0;
+ if (fs.Freq < MAX_FREQ / 4 && MinContext->Suffix != 0)
+ {
+ pc = GetContextNoCheck(MinContext->Suffix);
+
+ if (pc->NumStats != 1)
+ {
+ if ((p = GetStateNoCheck(pc->Stats))->Symbol != fs.Symbol)
+ {
+ do { p++; } while (p->Symbol != fs.Symbol);
+ if (p[0].Freq >= p[-1].Freq)
+ {
+ _PPMD_SWAP(p[0],p[-1]);
+ p--;
+ }
+ }
+ if (p->Freq < MAX_FREQ-9)
+ {
+ p->Freq += 2;
+ pc->SummFreq += 2;
+ }
+ }
+ else
+ {
+ p = &(pc->oneState());
+ p->Freq = (Byte)(p->Freq + ((p->Freq < 32) ? 1 : 0));
+ }
+ }
+ if ( !OrderFall )
+ {
+ MinContext = MaxContext = CreateSuccessors(true, p);
+ FoundState->SetSuccessor(SubAllocator.GetOffset(MinContext));
+ if (MinContext == 0)
+ goto RESTART_MODEL;
+ return;
+ }
+ *SubAllocator.pText++ = fs.Symbol;
+ Successor = (PPM_CONTEXT*) SubAllocator.pText;
+ if (SubAllocator.pText >= SubAllocator.UnitsStart)
+ goto RESTART_MODEL;
+ if (fs.GetSuccessor() != 0)
+ {
+ if ((Byte *)GetContext(fs.GetSuccessor()) <= SubAllocator.pText)
+ {
+ PPM_CONTEXT* cs = CreateSuccessors(false, p);
+ fs.SetSuccessor(SubAllocator.GetOffset(cs));
+ if (cs == NULL)
+ goto RESTART_MODEL;
+ }
+ if ( !--OrderFall )
+ {
+ Successor = GetContext(fs.GetSuccessor());
+ SubAllocator.pText -= (MaxContext != MinContext);
+ }
+ }
+ else
+ {
+ FoundState->SetSuccessor(SubAllocator.GetOffsetNoCheck(Successor));
+ fs.SetSuccessor(SubAllocator.GetOffsetNoCheck(MinContext));
+ }
+ s0 = MinContext->SummFreq - (ns = MinContext->NumStats) - (fs.Freq - 1);
+ for (pc = MaxContext; pc != MinContext; pc = GetContext(pc->Suffix))
+ {
+ if ((ns1 = pc->NumStats) != 1)
+ {
+ if ((ns1 & 1) == 0)
+ {
+ void *ppp = SubAllocator.ExpandUnits(GetState(pc->Stats), ns1 >> 1);
+ pc->Stats = SubAllocator.GetOffset(ppp);
+ if (!ppp)
+ goto RESTART_MODEL;
+ }
+ pc->SummFreq = (UInt16)(pc->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) &
+ (pc->SummFreq <= 8 * ns1)));
+ }
+ else
+ {
+ p = (PPM_CONTEXT::STATE*) SubAllocator.AllocUnits(1);
+ if ( !p )
+ goto RESTART_MODEL;
+ *p = pc->oneState();
+ pc->Stats = SubAllocator.GetOffsetNoCheck(p);
+ if (p->Freq < MAX_FREQ / 4 - 1)
+ p->Freq <<= 1;
+ else
+ p->Freq = MAX_FREQ - 4;
+ pc->SummFreq = (UInt16)(p->Freq + InitEsc + (ns > 3));
+ }
+ cf = 2 * fs.Freq * (pc->SummFreq+6);
+ sf = s0 + pc->SummFreq;
+ if (cf < 6 * sf)
+ {
+ cf = 1 + (cf > sf)+(cf >= 4 * sf);
+ pc->SummFreq += 3;
+ }
+ else
+ {
+ cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
+ pc->SummFreq = (UInt16)(pc->SummFreq + cf);
+ }
+ p = GetState(pc->Stats) + ns1;
+ p->SetSuccessor(SubAllocator.GetOffset(Successor));
+ p->Symbol = fs.Symbol;
+ p->Freq = (Byte)cf;
+ pc->NumStats = (UInt16)++ns1;
+ }
+ MaxContext = MinContext = GetContext(fs.GetSuccessor());
+ return;
+RESTART_MODEL:
+ RestartModelRare();
+ EscCount = 0;
+ PrintCount = 0xFF;
+ }
+
+ void ClearMask()
+ {
+ EscCount = 1;
+ memset(CharMask, 0, sizeof(CharMask));
+ // if (++PrintCount == 0)
+ // PrintInfo(DecodedFile,EncodedFile);
+ }
+
+ void update1(PPM_CONTEXT::STATE* p)
+ {
+ (FoundState = p)->Freq += 4;
+ MinContext->SummFreq += 4;
+ if (p[0].Freq > p[-1].Freq)
+ {
+ _PPMD_SWAP(p[0],p[-1]);
+ FoundState = --p;
+ if (p->Freq > MAX_FREQ)
+ rescale();
+ }
+ }
+
+
+ void update2(PPM_CONTEXT::STATE* p)
+ {
+ (FoundState = p)->Freq += 4;
+ MinContext->SummFreq += 4;
+ if (p->Freq > MAX_FREQ)
+ rescale();
+ EscCount++;
+ RunLength = InitRL;
+ }
+
+ SEE2_CONTEXT* makeEscFreq2(int Diff, UInt32 &scale)
+ {
+ SEE2_CONTEXT* psee2c;
+ if (MinContext->NumStats != 256)
+ {
+ psee2c = SEE2Cont[NS2Indx[Diff-1]] +
+ (Diff < (GetContext(MinContext->Suffix))->NumStats - MinContext->NumStats) +
+ 2 * (MinContext->SummFreq < 11 * MinContext->NumStats) +
+ 4 * (NumMasked > Diff) +
+ HiBitsFlag;
+ scale = psee2c->getMean();
+ }
+ else
+ {
+ psee2c = &DummySEE2Cont;
+ scale = 1;
+ }
+ return psee2c;
+ }
+
+
+
+ void rescale()
+ {
+ int OldNS = MinContext->NumStats, i = MinContext->NumStats - 1, Adder, EscFreq;
+ PPM_CONTEXT::STATE* p1, * p;
+ PPM_CONTEXT::STATE *stats = GetStateNoCheck(MinContext->Stats);
+ for (p = FoundState; p != stats; p--)
+ _PPMD_SWAP(p[0], p[-1]);
+ stats->Freq += 4;
+ MinContext->SummFreq += 4;
+ EscFreq = MinContext->SummFreq - p->Freq;
+ Adder = (OrderFall != 0);
+ p->Freq = (Byte)((p->Freq + Adder) >> 1);
+ MinContext->SummFreq = p->Freq;
+ do
+ {
+ EscFreq -= (++p)->Freq;
+ p->Freq = (Byte)((p->Freq + Adder) >> 1);
+ MinContext->SummFreq = (UInt16)(MinContext->SummFreq + p->Freq);
+ if (p[0].Freq > p[-1].Freq)
+ {
+ PPM_CONTEXT::STATE tmp = *(p1 = p);
+ do
+ {
+ p1[0] = p1[-1];
+ }
+ while (--p1 != stats && tmp.Freq > p1[-1].Freq);
+ *p1 = tmp;
+ }
+ }
+ while ( --i );
+ if (p->Freq == 0)
+ {
+ do { i++; } while ((--p)->Freq == 0);
+ EscFreq += i;
+ MinContext->NumStats = (UInt16)(MinContext->NumStats - i);
+ if (MinContext->NumStats == 1)
+ {
+ PPM_CONTEXT::STATE tmp = *stats;
+ do { tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); EscFreq >>= 1; } while (EscFreq > 1);
+ SubAllocator.FreeUnits(stats, (OldNS+1) >> 1);
+ *(FoundState = &MinContext->oneState()) = tmp; return;
+ }
+ }
+ EscFreq -= (EscFreq >> 1);
+ MinContext->SummFreq = (UInt16)(MinContext->SummFreq + EscFreq);
+ int n0 = (OldNS+1) >> 1, n1 = (MinContext->NumStats + 1) >> 1;
+ if (n0 != n1)
+ MinContext->Stats = SubAllocator.GetOffset(SubAllocator.ShrinkUnits(stats, n0, n1));
+ FoundState = GetState(MinContext->Stats);
+ }
+
+ void NextContext()
+ {
+ PPM_CONTEXT *c = GetContext(FoundState->GetSuccessor());
+ if (!OrderFall && (Byte *)c > SubAllocator.pText)
+ MinContext = MaxContext = c;
+ else
+ {
+ UpdateModel();
+ if (EscCount == 0)
+ ClearMask();
+ }
+ }
+};
+
+// Tabulated escapes for exponential symbol distribution
+const Byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT))
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecode.h b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecode.h
new file mode 100644
index 000000000..fe6927bf8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecode.h
@@ -0,0 +1,156 @@
+// PpmdDecode.h
+// 2009-05-30 : Igor Pavlov : Public domain
+// This code is based on Dmitry Shkarin's PPMdH code (public domain)
+
+#ifndef __COMPRESS_PPMD_DECODE_H
+#define __COMPRESS_PPMD_DECODE_H
+
+#include "PpmdContext.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+class CRangeDecoderVirt
+{
+public:
+ virtual ~CRangeDecoderVirt() {}
+ virtual UInt32 GetThreshold(UInt32 total) = 0;
+ virtual void Decode(UInt32 start, UInt32 size) = 0;
+ virtual UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) = 0;
+};
+
+typedef NRangeCoder::CDecoder CRangeDecoderMy;
+
+class CRangeDecoder:public CRangeDecoderVirt, public CRangeDecoderMy
+{
+ UInt32 GetThreshold(UInt32 total) { return CRangeDecoderMy::GetThreshold(total); }
+ void Decode(UInt32 start, UInt32 size) { CRangeDecoderMy::Decode(start, size); }
+ UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) { return CRangeDecoderMy::DecodeBit(size0, numTotalBits); }
+};
+
+struct CDecodeInfo: public CInfo
+{
+ void DecodeBinSymbol(CRangeDecoderVirt *rangeDecoder)
+ {
+ PPM_CONTEXT::STATE& rs = MinContext->oneState();
+ UInt16& bs = GetBinSumm(rs, GetContextNoCheck(MinContext->Suffix)->NumStats);
+ if (rangeDecoder->DecodeBit(bs, TOT_BITS) == 0)
+ {
+ FoundState = &rs;
+ rs.Freq = (Byte)(rs.Freq + (rs.Freq < 128 ? 1: 0));
+ bs = (UInt16)(bs + INTERVAL - GET_MEAN(bs, PERIOD_BITS, 2));
+ PrevSuccess = 1;
+ RunLength++;
+ }
+ else
+ {
+ bs = (UInt16)(bs - GET_MEAN(bs, PERIOD_BITS, 2));
+ InitEsc = ExpEscape[bs >> 10];
+ NumMasked = 1;
+ CharMask[rs.Symbol] = EscCount;
+ PrevSuccess = 0;
+ FoundState = NULL;
+ }
+ }
+
+ void DecodeSymbol1(CRangeDecoderVirt *rangeDecoder)
+ {
+ PPM_CONTEXT::STATE* p = GetStateNoCheck(MinContext->Stats);
+ int i, count, hiCnt;
+ if ((count = rangeDecoder->GetThreshold(MinContext->SummFreq)) < (hiCnt = p->Freq))
+ {
+ PrevSuccess = (2 * hiCnt > MinContext->SummFreq);
+ RunLength += PrevSuccess;
+ rangeDecoder->Decode(0, p->Freq); // MinContext->SummFreq);
+ (FoundState = p)->Freq = (Byte)(hiCnt += 4);
+ MinContext->SummFreq += 4;
+ if (hiCnt > MAX_FREQ)
+ rescale();
+ return;
+ }
+ PrevSuccess = 0;
+ i = MinContext->NumStats - 1;
+ while ((hiCnt += (++p)->Freq) <= count)
+ if (--i == 0)
+ {
+ HiBitsFlag = HB2Flag[FoundState->Symbol];
+ rangeDecoder->Decode(hiCnt, MinContext->SummFreq - hiCnt); // , MinContext->SummFreq);
+ CharMask[p->Symbol] = EscCount;
+ i = (NumMasked = MinContext->NumStats)-1;
+ FoundState = NULL;
+ do { CharMask[(--p)->Symbol] = EscCount; } while ( --i );
+ return;
+ }
+ rangeDecoder->Decode(hiCnt - p->Freq, p->Freq); // , MinContext->SummFreq);
+ update1(p);
+ }
+
+
+ void DecodeSymbol2(CRangeDecoderVirt *rangeDecoder)
+ {
+ int count, hiCnt, i = MinContext->NumStats - NumMasked;
+ UInt32 freqSum;
+ SEE2_CONTEXT* psee2c = makeEscFreq2(i, freqSum);
+ PPM_CONTEXT::STATE* ps[256], ** pps = ps, * p = GetStateNoCheck(MinContext->Stats)-1;
+ hiCnt = 0;
+ do
+ {
+ do { p++; } while (CharMask[p->Symbol] == EscCount);
+ hiCnt += p->Freq;
+ *pps++ = p;
+ }
+ while ( --i );
+
+ freqSum += hiCnt;
+ count = rangeDecoder->GetThreshold(freqSum);
+
+ p = *(pps = ps);
+ if (count < hiCnt)
+ {
+ hiCnt = 0;
+ while ((hiCnt += p->Freq) <= count)
+ p=*++pps;
+ rangeDecoder->Decode(hiCnt - p->Freq, p->Freq); // , freqSum);
+
+ psee2c->update();
+ update2(p);
+ }
+ else
+ {
+ rangeDecoder->Decode(hiCnt, freqSum - hiCnt); // , freqSum);
+
+ i = MinContext->NumStats - NumMasked;
+ pps--;
+ do { CharMask[(*++pps)->Symbol] = EscCount; } while ( --i );
+ psee2c->Summ = (UInt16)(psee2c->Summ + freqSum);
+ NumMasked = MinContext->NumStats;
+ }
+ }
+
+ int DecodeSymbol(CRangeDecoderVirt *rangeDecoder)
+ {
+ if (MinContext->NumStats != 1)
+ DecodeSymbol1(rangeDecoder);
+ else
+ DecodeBinSymbol(rangeDecoder);
+ while ( !FoundState )
+ {
+ do
+ {
+ OrderFall++;
+ MinContext = GetContext(MinContext->Suffix);
+ if (MinContext == 0)
+ return -1;
+ }
+ while (MinContext->NumStats == NumMasked);
+ DecodeSymbol2(rangeDecoder);
+ }
+ Byte symbol = FoundState->Symbol;
+ NextContext();
+ return symbol;
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecoder.cpp
new file mode 100644
index 000000000..c02f44f16
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecoder.cpp
@@ -0,0 +1,167 @@
+// PpmdDecoder.cpp
+// 2009-03-11 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "PpmdDecoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+static const UInt32 kBufSize = (1 << 20);
+
+enum
+{
+ kStatus_NeedInit,
+ kStatus_Normal,
+ kStatus_Finished,
+ kStatus_Error
+};
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+CDecoder::~CDecoder()
+{
+ ::MidFree(_outBuf);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
+{
+ if (size < 5)
+ return E_INVALIDARG;
+ _order = props[0];
+ UInt32 memSize = GetUi32(props + 1);
+ if (_order < PPMD7_MIN_ORDER ||
+ _order > PPMD7_MAX_ORDER ||
+ memSize < PPMD7_MIN_MEM_SIZE ||
+ memSize > PPMD7_MAX_MEM_SIZE)
+ return E_NOTIMPL;
+ if (!_inStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
+{
+ switch(_status)
+ {
+ case kStatus_Finished: return S_OK;
+ case kStatus_Error: return S_FALSE;
+ case kStatus_NeedInit:
+ _inStream.Init();
+ if (!Ppmd7z_RangeDec_Init(&_rangeDec))
+ {
+ _status = kStatus_Error;
+ return S_FALSE;
+ }
+ _status = kStatus_Normal;
+ Ppmd7_Init(&_ppmd, _order);
+ break;
+ }
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _processedSize;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ UInt32 i;
+ int sym = 0;
+ for (i = 0; i != size; i++)
+ {
+ sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.p);
+ if (_inStream.Extra || sym < 0)
+ break;
+ memStream[i] = (Byte)sym;
+ }
+
+ _processedSize += i;
+ if (_inStream.Extra)
+ {
+ _status = kStatus_Error;
+ return _inStream.Res;
+ }
+ if (sym < 0)
+ _status = (sym < -1) ? kStatus_Error : kStatus_Finished;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (!_outBuf)
+ {
+ _outBuf = (Byte *)::MidAlloc(kBufSize);
+ if (!_outBuf)
+ return E_OUTOFMEMORY;
+ }
+
+ _inStream.Stream = inStream;
+ SetOutStreamSize(outSize);
+
+ do
+ {
+ const UInt64 startPos = _processedSize;
+ HRESULT res = CodeSpec(_outBuf, kBufSize);
+ size_t processed = (size_t)(_processedSize - startPos);
+ RINOK(WriteStream(outStream, _outBuf, processed));
+ RINOK(res);
+ if (_status == kStatus_Finished)
+ break;
+ if (progress)
+ {
+ UInt64 inSize = _inStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
+ }
+ }
+ while (!_outSizeDefined || _processedSize < _outSize);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+ _processedSize = 0;
+ _status = kStatus_NeedInit;
+ return S_OK;
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
+{
+ InSeqStream = inStream;
+ _inStream.Stream = inStream;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::ReleaseInStream()
+{
+ InSeqStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ const UInt64 startPos = _processedSize;
+ HRESULT res = CodeSpec((Byte *)data, size);
+ if (processedSize)
+ *processedSize = (UInt32)(_processedSize - startPos);
+ return res;
+}
+
+#endif
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecoder.h
new file mode 100644
index 000000000..8ebcd700c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdDecoder.h
@@ -0,0 +1,78 @@
+// PpmdDecoder.h
+// 2009-03-11 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_PPMD_DECODER_H
+#define __COMPRESS_PPMD_DECODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../Common/CWrappers.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+class CDecoder :
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ Byte *_outBuf;
+ CPpmd7z_RangeDec _rangeDec;
+ CByteInBufWrap _inStream;
+ CPpmd7 _ppmd;
+
+ Byte _order;
+ bool _outSizeDefined;
+ int _status;
+ UInt64 _outSize;
+ UInt64 _processedSize;
+
+ HRESULT CodeSpec(Byte *memStream, UInt32 size);
+
+public:
+
+ #ifndef NO_READ_FROM_CODER
+ CMyComPtr<ISequentialInStream> InSeqStream;
+ MY_UNKNOWN_IMP4(
+ ICompressSetDecoderProperties2,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream)
+ #else
+ MY_UNKNOWN_IMP1(
+ ICompressSetDecoderProperties2)
+ #endif
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ #ifndef NO_READ_FROM_CODER
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+ CDecoder(): _outBuf(NULL), _outSizeDefined(false)
+ {
+ Ppmd7z_RangeDec_CreateVTable(&_rangeDec);
+ _rangeDec.Stream = &_inStream.p;
+ Ppmd7_Construct(&_ppmd);
+ }
+
+ ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncode.h b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncode.h
new file mode 100644
index 000000000..012f859c8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncode.h
@@ -0,0 +1,142 @@
+// PpmdEncode.h
+// 2009-05-30 : Igor Pavlov : Public domain
+// This code is based on Dmitry Shkarin's PPMdH code (public domain)
+
+#ifndef __COMPRESS_PPMD_ENCODE_H
+#define __COMPRESS_PPMD_ENCODE_H
+
+#include "PpmdContext.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+struct CEncodeInfo: public CInfo
+{
+ void EncodeBinSymbol(int symbol, NRangeCoder::CEncoder *rangeEncoder)
+ {
+ PPM_CONTEXT::STATE& rs = MinContext->oneState();
+ UInt16 &bs = GetBinSumm(rs, GetContextNoCheck(MinContext->Suffix)->NumStats);
+ if (rs.Symbol == symbol)
+ {
+ FoundState = &rs;
+ rs.Freq = (Byte)(rs.Freq + (rs.Freq < 128 ? 1: 0));
+ rangeEncoder->EncodeBit(bs, TOT_BITS, 0);
+ bs = (UInt16)(bs + INTERVAL - GET_MEAN(bs, PERIOD_BITS, 2));
+ PrevSuccess = 1;
+ RunLength++;
+ }
+ else
+ {
+ rangeEncoder->EncodeBit(bs, TOT_BITS, 1);
+ bs = (UInt16)(bs - GET_MEAN(bs, PERIOD_BITS, 2));
+ InitEsc = ExpEscape[bs >> 10];
+ NumMasked = 1;
+ CharMask[rs.Symbol] = EscCount;
+ PrevSuccess = 0;
+ FoundState = NULL;
+ }
+ }
+
+ void EncodeSymbol1(int symbol, NRangeCoder::CEncoder *rangeEncoder)
+ {
+ PPM_CONTEXT::STATE* p = GetStateNoCheck(MinContext->Stats);
+ if (p->Symbol == symbol)
+ {
+ PrevSuccess = (2 * (p->Freq) > MinContext->SummFreq);
+ RunLength += PrevSuccess;
+ rangeEncoder->Encode(0, p->Freq, MinContext->SummFreq);
+ (FoundState = p)->Freq += 4;
+ MinContext->SummFreq += 4;
+ if (p->Freq > MAX_FREQ)
+ rescale();
+ return;
+ }
+ PrevSuccess = 0;
+ int LoCnt = p->Freq, i = MinContext->NumStats - 1;
+ while ((++p)->Symbol != symbol)
+ {
+ LoCnt += p->Freq;
+ if (--i == 0)
+ {
+ HiBitsFlag = HB2Flag[FoundState->Symbol];
+ CharMask[p->Symbol] = EscCount;
+ i=(NumMasked = MinContext->NumStats)-1;
+ FoundState = NULL;
+ do { CharMask[(--p)->Symbol] = EscCount; } while ( --i );
+ rangeEncoder->Encode(LoCnt, MinContext->SummFreq - LoCnt, MinContext->SummFreq);
+ return;
+ }
+ }
+ rangeEncoder->Encode(LoCnt, p->Freq, MinContext->SummFreq);
+ update1(p);
+ }
+
+ void EncodeSymbol2(int symbol, NRangeCoder::CEncoder *rangeEncoder)
+ {
+ int hiCnt, i = MinContext->NumStats - NumMasked;
+ UInt32 scale;
+ SEE2_CONTEXT* psee2c = makeEscFreq2(i, scale);
+ PPM_CONTEXT::STATE* p = GetStateNoCheck(MinContext->Stats) - 1;
+ hiCnt = 0;
+ do
+ {
+ do { p++; } while (CharMask[p->Symbol] == EscCount);
+ hiCnt += p->Freq;
+ if (p->Symbol == symbol)
+ goto SYMBOL_FOUND;
+ CharMask[p->Symbol] = EscCount;
+ }
+ while ( --i );
+
+ rangeEncoder->Encode(hiCnt, scale, hiCnt + scale);
+ scale += hiCnt;
+
+ psee2c->Summ = (UInt16)(psee2c->Summ + scale);
+ NumMasked = MinContext->NumStats;
+ return;
+SYMBOL_FOUND:
+
+ UInt32 highCount = hiCnt;
+ UInt32 lowCount = highCount - p->Freq;
+ if ( --i )
+ {
+ PPM_CONTEXT::STATE* p1 = p;
+ do
+ {
+ do { p1++; } while (CharMask[p1->Symbol] == EscCount);
+ hiCnt += p1->Freq;
+ }
+ while ( --i );
+ }
+ // SubRange.scale += hiCnt;
+ scale += hiCnt;
+ rangeEncoder->Encode(lowCount, highCount - lowCount, scale);
+ psee2c->update();
+ update2(p);
+ }
+
+ void EncodeSymbol(int c, NRangeCoder::CEncoder *rangeEncoder)
+ {
+ if (MinContext->NumStats != 1)
+ EncodeSymbol1(c, rangeEncoder);
+ else
+ EncodeBinSymbol(c, rangeEncoder);
+ while ( !FoundState )
+ {
+ do
+ {
+ OrderFall++;
+ MinContext = GetContext(MinContext->Suffix);
+ if (MinContext == 0)
+ return; // S_OK;
+ }
+ while (MinContext->NumStats == NumMasked);
+ EncodeSymbol2(c, rangeEncoder);
+ }
+ NextContext();
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncoder.cpp
new file mode 100644
index 000000000..d823ffe85
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncoder.cpp
@@ -0,0 +1,119 @@
+// PpmdEncoder.cpp
+// 2009-03-11 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "PpmdEncoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+static const UInt32 kBufSize = (1 << 20);
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+CEncoder::CEncoder():
+ _inBuf(NULL),
+ _usedMemSize(1 << 24),
+ _order(6)
+{
+ _rangeEnc.Stream = &_outStream.p;
+ Ppmd7_Construct(&_ppmd);
+}
+
+CEncoder::~CEncoder()
+{
+ ::MidFree(_inBuf);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = (UInt32)prop.ulVal;
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kUsedMemorySize:
+ if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0)
+ return E_INVALIDARG;
+ _usedMemSize = v;
+ break;
+ case NCoderPropID::kOrder:
+ if (v < 2 || v > 32)
+ return E_INVALIDARG;
+ _order = (Byte)v;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ const UInt32 kPropSize = 5;
+ Byte props[kPropSize];
+ props[0] = _order;
+ SetUi32(props + 1, _usedMemSize);
+ return WriteStream(outStream, props, kPropSize);
+}
+
+HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ if (!_inBuf)
+ {
+ _inBuf = (Byte *)::MidAlloc(kBufSize);
+ if (!_inBuf)
+ return E_OUTOFMEMORY;
+ }
+ if (!_outStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd7_Alloc(&_ppmd, _usedMemSize, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ _outStream.Stream = outStream;
+ _outStream.Init();
+
+ Ppmd7z_RangeEnc_Init(&_rangeEnc);
+ Ppmd7_Init(&_ppmd, _order);
+
+ UInt64 processed = 0;
+ for (;;)
+ {
+ UInt32 size;
+ RINOK(inStream->Read(_inBuf, kBufSize, &size));
+ if (size == 0)
+ {
+ // We don't write EndMark in PPMD-7z.
+ // Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1);
+ Ppmd7z_RangeEnc_FlushData(&_rangeEnc);
+ return _outStream.Flush();
+ }
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]);
+ RINOK(_outStream.Res);
+ }
+ processed += size;
+ if (progress)
+ {
+ UInt64 outSize = _outStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&processed, &outSize));
+ }
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncoder.h
new file mode 100644
index 000000000..ed8b37131
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdEncoder.h
@@ -0,0 +1,48 @@
+// PpmdEncoder.h
+// 2009-03-11 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_PPMD_ENCODER_H
+#define __COMPRESS_PPMD_ENCODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/CWrappers.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+class CEncoder :
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public CMyUnknownImp
+{
+ Byte *_inBuf;
+ CByteOutBufWrap _outStream;
+ CPpmd7z_RangeEnc _rangeEnc;
+ CPpmd7 _ppmd;
+
+ UInt32 _usedMemSize;
+ Byte _order;
+
+public:
+ MY_UNKNOWN_IMP2(
+ ICompressSetCoderProperties,
+ ICompressWriteCoderProperties)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+
+ CEncoder();
+ ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdRegister.cpp
new file mode 100644
index 000000000..9f59fcdd3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdRegister.cpp
@@ -0,0 +1,21 @@
+// PpmdRegister.cpp
+// 2009-05-30 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "PpmdDecoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NPpmd::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "PpmdEncoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NPpmd::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x030401, L"PPMD", 1, false };
+
+REGISTER_CODEC(PPMD)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdSubAlloc.h b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdSubAlloc.h
new file mode 100644
index 000000000..f264f6376
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdSubAlloc.h
@@ -0,0 +1,293 @@
+// PpmdSubAlloc.h
+// 2009-05-30 : Igor Pavlov : Public domain
+// This code is based on Dmitry Shkarin's PPMdH code (public domain)
+
+#ifndef __COMPRESS_PPMD_SUB_ALLOC_H
+#define __COMPRESS_PPMD_SUB_ALLOC_H
+
+#include "../../../C/Alloc.h"
+
+#include "PpmdType.h"
+
+const UINT N1=4, N2=4, N3=4, N4=(128+3-1*N1-2*N2-3*N3)/4;
+const UINT UNIT_SIZE=12, N_INDEXES=N1+N2+N3+N4;
+
+// Extra 1 * UNIT_SIZE for NULL support
+// Extra 2 * UNIT_SIZE for s0 in GlueFreeBlocks()
+const UInt32 kExtraSize = (UNIT_SIZE * 3);
+const UInt32 kMaxMemBlockSize = 0xFFFFFFFF - kExtraSize;
+
+struct MEM_BLK
+{
+ UInt16 Stamp, NU;
+ UInt32 Next, Prev;
+ void InsertAt(Byte *Base, UInt32 p)
+ {
+ Prev = p;
+ MEM_BLK *pp = (MEM_BLK *)(Base + p);
+ Next = pp->Next;
+ pp->Next = ((MEM_BLK *)(Base + Next))->Prev = (UInt32)((Byte *)this - Base);
+ }
+ void Remove(Byte *Base)
+ {
+ ((MEM_BLK *)(Base + Prev))->Next = Next;
+ ((MEM_BLK *)(Base + Next))->Prev = Prev;
+ }
+};
+
+
+class CSubAllocator
+{
+ UInt32 SubAllocatorSize;
+ Byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount;
+ UInt32 FreeList[N_INDEXES];
+
+ Byte *Base;
+ Byte *HeapStart, *LoUnit, *HiUnit;
+public:
+ Byte *pText, *UnitsStart;
+ CSubAllocator():
+ SubAllocatorSize(0),
+ GlueCount(0),
+ LoUnit(0),
+ HiUnit(0),
+ pText(0),
+ UnitsStart(0)
+ {
+ memset(Indx2Units, 0, sizeof(Indx2Units));
+ memset(FreeList, 0, sizeof(FreeList));
+ }
+ ~CSubAllocator()
+ {
+ StopSubAllocator();
+ };
+
+ void *GetPtr(UInt32 offset) const { return (offset == 0) ? 0 : (void *)(Base + offset); }
+ void *GetPtrNoCheck(UInt32 offset) const { return (void *)(Base + offset); }
+ UInt32 GetOffset(void *ptr) const { return (ptr == 0) ? 0 : (UInt32)((Byte *)ptr - Base); }
+ UInt32 GetOffsetNoCheck(void *ptr) const { return (UInt32)((Byte *)ptr - Base); }
+ MEM_BLK *GetBlk(UInt32 offset) const { return (MEM_BLK *)(Base + offset); }
+ UInt32 *GetNode(UInt32 offset) const { return (UInt32 *)(Base + offset); }
+
+ void InsertNode(void* p, int indx)
+ {
+ *(UInt32 *)p = FreeList[indx];
+ FreeList[indx] = GetOffsetNoCheck(p);
+ }
+
+ void* RemoveNode(int indx)
+ {
+ UInt32 offset = FreeList[indx];
+ UInt32 *p = GetNode(offset);
+ FreeList[indx] = *p;
+ return (void *)p;
+ }
+
+ UINT U2B(int NU) const { return (UINT)(NU) * UNIT_SIZE; }
+
+ void SplitBlock(void* pv, int oldIndx, int newIndx)
+ {
+ int i, UDiff = Indx2Units[oldIndx] - Indx2Units[newIndx];
+ Byte* p = ((Byte*)pv) + U2B(Indx2Units[newIndx]);
+ if (Indx2Units[i = Units2Indx[UDiff-1]] != UDiff)
+ {
+ InsertNode(p, --i);
+ p += U2B(i = Indx2Units[i]);
+ UDiff -= i;
+ }
+ InsertNode(p, Units2Indx[UDiff - 1]);
+ }
+
+ UInt32 GetUsedMemory() const
+ {
+ UInt32 RetVal = SubAllocatorSize - (UInt32)(HiUnit - LoUnit) - (UInt32)(UnitsStart - pText);
+ for (UInt32 i = 0; i < N_INDEXES; i++)
+ for (UInt32 pn = FreeList[i]; pn != 0; RetVal -= (UInt32)Indx2Units[i] * UNIT_SIZE)
+ pn = *GetNode(pn);
+ return (RetVal >> 2);
+ }
+
+ UInt32 GetSubAllocatorSize() const { return SubAllocatorSize; }
+
+ void StopSubAllocator()
+ {
+ if (SubAllocatorSize != 0)
+ {
+ BigFree(Base);
+ SubAllocatorSize = 0;
+ Base = 0;
+ }
+ }
+
+ bool StartSubAllocator(UInt32 size)
+ {
+ if (SubAllocatorSize == size)
+ return true;
+ StopSubAllocator();
+ if (size == 0)
+ Base = 0;
+ else
+ {
+ if ((Base = (Byte *)::BigAlloc(size + kExtraSize)) == 0)
+ return false;
+ HeapStart = Base + UNIT_SIZE; // we need such code to support NULL;
+ }
+ SubAllocatorSize = size;
+ return true;
+ }
+
+ void InitSubAllocator()
+ {
+ unsigned int i, k;
+ memset(FreeList, 0, sizeof(FreeList));
+ HiUnit = (pText = HeapStart) + SubAllocatorSize;
+ UINT Diff = UNIT_SIZE * (SubAllocatorSize / 8 / UNIT_SIZE * 7);
+ LoUnit = UnitsStart = HiUnit - Diff;
+ for (i = 0, k=1; i < N1 ; i++, k += 1) Indx2Units[i] = (Byte)k;
+ for (k++; i < N1 + N2 ;i++, k += 2) Indx2Units[i] = (Byte)k;
+ for (k++; i < N1 + N2 + N3 ;i++,k += 3) Indx2Units[i] = (Byte)k;
+ for (k++; i < N1 + N2 + N3 + N4; i++, k += 4) Indx2Units[i] = (Byte)k;
+ GlueCount = 0;
+ for (k = i = 0; k < 128; k++)
+ {
+ i += (Indx2Units[i] < k+1);
+ Units2Indx[k] = (Byte)i;
+ }
+ }
+
+ void GlueFreeBlocks()
+ {
+ UInt32 s0 = (UInt32)(HeapStart + SubAllocatorSize - Base);
+
+ // We need add exta MEM_BLK with Stamp=0
+ GetBlk(s0)->Stamp = 0;
+ s0 += UNIT_SIZE;
+ MEM_BLK *ps0 = GetBlk(s0);
+
+ UInt32 p;
+ unsigned int i;
+ if (LoUnit != HiUnit)
+ *LoUnit=0;
+ ps0->Next = ps0->Prev = s0;
+
+ for (i = 0; i < N_INDEXES; i++)
+ while (FreeList[i] != 0)
+ {
+ MEM_BLK *pp = (MEM_BLK *)RemoveNode(i);
+ pp->InsertAt(Base, s0);
+ pp->Stamp = 0xFFFF;
+ pp->NU = Indx2Units[i];
+ }
+ for (p = ps0->Next; p != s0; p = GetBlk(p)->Next)
+ {
+ for (;;)
+ {
+ MEM_BLK *pp = GetBlk(p);
+ MEM_BLK *pp1 = GetBlk(p + pp->NU * UNIT_SIZE);
+ if (pp1->Stamp != 0xFFFF || int(pp->NU) + pp1->NU >= 0x10000)
+ break;
+ pp1->Remove(Base);
+ pp->NU = (UInt16)(pp->NU + pp1->NU);
+ }
+ }
+ while ((p = ps0->Next) != s0)
+ {
+ MEM_BLK *pp = GetBlk(p);
+ pp->Remove(Base);
+ int sz;
+ for (sz = pp->NU; sz > 128; sz -= 128, p += 128 * UNIT_SIZE)
+ InsertNode(Base + p, N_INDEXES - 1);
+ if (Indx2Units[i = Units2Indx[sz-1]] != sz)
+ {
+ int k = sz - Indx2Units[--i];
+ InsertNode(Base + p + (sz - k) * UNIT_SIZE, k - 1);
+ }
+ InsertNode(Base + p, i);
+ }
+ }
+ void* AllocUnitsRare(int indx)
+ {
+ if ( !GlueCount )
+ {
+ GlueCount = 255;
+ GlueFreeBlocks();
+ if (FreeList[indx] != 0)
+ return RemoveNode(indx);
+ }
+ int i = indx;
+ do
+ {
+ if (++i == static_cast< int >( N_INDEXES) )
+ {
+ GlueCount--;
+ i = U2B(Indx2Units[indx]);
+ return (UnitsStart - pText > i) ? (UnitsStart -= i) : (NULL);
+ }
+ } while (FreeList[i] == 0);
+ void* RetVal = RemoveNode(i);
+ SplitBlock(RetVal, i, indx);
+ return RetVal;
+ }
+
+ void* AllocUnits(int NU)
+ {
+ int indx = Units2Indx[NU - 1];
+ if (FreeList[indx] != 0)
+ return RemoveNode(indx);
+ void* RetVal = LoUnit;
+ LoUnit += U2B(Indx2Units[indx]);
+ if (LoUnit <= HiUnit)
+ return RetVal;
+ LoUnit -= U2B(Indx2Units[indx]);
+ return AllocUnitsRare(indx);
+ }
+
+ void* AllocContext()
+ {
+ if (HiUnit != LoUnit)
+ return (HiUnit -= UNIT_SIZE);
+ if (FreeList[0] != 0)
+ return RemoveNode(0);
+ return AllocUnitsRare(0);
+ }
+
+ void* ExpandUnits(void* oldPtr, int oldNU)
+ {
+ int i0=Units2Indx[oldNU - 1], i1=Units2Indx[oldNU - 1 + 1];
+ if (i0 == i1)
+ return oldPtr;
+ void* ptr = AllocUnits(oldNU + 1);
+ if (ptr)
+ {
+ memcpy(ptr, oldPtr, U2B(oldNU));
+ InsertNode(oldPtr, i0);
+ }
+ return ptr;
+ }
+
+ void* ShrinkUnits(void* oldPtr, int oldNU, int newNU)
+ {
+ int i0 = Units2Indx[oldNU - 1], i1 = Units2Indx[newNU - 1];
+ if (i0 == i1)
+ return oldPtr;
+ if (FreeList[i1] != 0)
+ {
+ void* ptr = RemoveNode(i1);
+ memcpy(ptr, oldPtr, U2B(newNU));
+ InsertNode(oldPtr,i0);
+ return ptr;
+ }
+ else
+ {
+ SplitBlock(oldPtr, i0, i1);
+ return oldPtr;
+ }
+ }
+
+ void FreeUnits(void* ptr, int oldNU)
+ {
+ InsertNode(ptr, Units2Indx[oldNU - 1]);
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdType.h b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdType.h
new file mode 100644
index 000000000..e4b0203c0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdType.h
@@ -0,0 +1,14 @@
+// PpmdType.h
+// 2009-05-30 : Igor Pavlov : Public domain
+// This code is based on Dmitry Shkarin's PPMdH code (public domain)
+
+#ifndef __COMPRESS_PPMD_TYPE_H
+#define __COMPRESS_PPMD_TYPE_H
+
+const int kMaxOrderCompress = 32;
+const int MAX_O = 255; /* maximum allowed model order */
+
+template <class T>
+inline void _PPMD_SWAP(T& t1,T& t2) { T tmp = t1; t1 = t2; t2 = tmp; }
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdZip.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdZip.cpp
new file mode 100644
index 000000000..e83d979c3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdZip.cpp
@@ -0,0 +1,223 @@
+// PpmdZip.cpp
+// 2010-03-24 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "PpmdZip.h"
+
+namespace NCompress {
+namespace NPpmdZip {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+CDecoder::CDecoder(bool fullFileMode):
+ _fullFileMode(fullFileMode)
+{
+ _ppmd.Stream.In = &_inStream.p;
+ Ppmd8_Construct(&_ppmd);
+}
+
+CDecoder::~CDecoder()
+{
+ Ppmd8_Free(&_ppmd, &g_BigAlloc);
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (!_outStream.Alloc())
+ return E_OUTOFMEMORY;
+ if (!_inStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+
+ _inStream.Stream = inStream;
+ _inStream.Init();
+
+ {
+ Byte buf[2];
+ for (int i = 0; i < 2; i++)
+ buf[i] = _inStream.ReadByte();
+ if (_inStream.Extra)
+ return S_FALSE;
+
+ UInt32 val = GetUi16(buf);
+ UInt32 order = (val & 0xF) + 1;
+ UInt32 mem = ((val >> 4) & 0xFF) + 1;
+ UInt32 restor = (val >> 12);
+ if (order < 2 || restor > 2)
+ return S_FALSE;
+
+ #ifndef PPMD8_FREEZE_SUPPORT
+ if (restor == 2)
+ return E_NOTIMPL;
+ #endif
+
+ if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ if (!Ppmd8_RangeDec_Init(&_ppmd))
+ return S_FALSE;
+ Ppmd8_Init(&_ppmd, order, restor);
+ }
+
+ bool wasFinished = false;
+ UInt64 processedSize = 0;
+ while (!outSize || processedSize < *outSize)
+ {
+ size_t size = kBufSize;
+ if (outSize != NULL)
+ {
+ const UInt64 rem = *outSize - processedSize;
+ if (size > rem)
+ size = (size_t)rem;
+ }
+ Byte *data = _outStream.Buf;
+ size_t i = 0;
+ int sym = 0;
+ do
+ {
+ sym = Ppmd8_DecodeSymbol(&_ppmd);
+ if (_inStream.Extra || sym < 0)
+ break;
+ data[i] = (Byte)sym;
+ }
+ while (++i != size);
+ processedSize += i;
+
+ RINOK(WriteStream(outStream, _outStream.Buf, i));
+
+ RINOK(_inStream.Res);
+ if (_inStream.Extra)
+ return S_FALSE;
+
+ if (sym < 0)
+ {
+ if (sym != -1)
+ return S_FALSE;
+ wasFinished = true;
+ break;
+ }
+ if (progress)
+ {
+ UInt64 inSize = _inStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&inSize, &processedSize));
+ }
+ }
+ RINOK(_inStream.Res);
+ if (_fullFileMode)
+ {
+ if (!wasFinished)
+ {
+ int res = Ppmd8_DecodeSymbol(&_ppmd);
+ RINOK(_inStream.Res);
+ if (_inStream.Extra || res != -1)
+ return S_FALSE;
+ }
+ if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd))
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+
+// ---------- Encoder ----------
+
+CEncoder::~CEncoder()
+{
+ Ppmd8_Free(&_ppmd, &g_BigAlloc);
+}
+
+HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = (UInt32)prop.ulVal;
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kAlgorithm:
+ if (v > 1)
+ return E_INVALIDARG;
+ _restor = v;
+ break;
+ case NCoderPropID::kUsedMemorySize:
+ if (v < (1 << 20) || v > (1 << 28))
+ return E_INVALIDARG;
+ _usedMemInMB = v >> 20;
+ break;
+ case NCoderPropID::kOrder:
+ if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER)
+ return E_INVALIDARG;
+ _order = (Byte)v;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+CEncoder::CEncoder():
+ _usedMemInMB(16),
+ _order(6),
+ _restor(PPMD8_RESTORE_METHOD_RESTART)
+{
+ _ppmd.Stream.Out = &_outStream.p;
+ Ppmd8_Construct(&_ppmd);
+}
+
+HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ if (!_inStream.Alloc())
+ return E_OUTOFMEMORY;
+ if (!_outStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd8_Alloc(&_ppmd, _usedMemInMB << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ _outStream.Stream = outStream;
+ _outStream.Init();
+
+ Ppmd8_RangeEnc_Init(&_ppmd);
+ Ppmd8_Init(&_ppmd, _order, _restor);
+
+ UInt32 val = (UInt32)((_order - 1) + ((_usedMemInMB - 1) << 4) + (_restor << 12));
+ _outStream.WriteByte((Byte)(val & 0xFF));
+ _outStream.WriteByte((Byte)(val >> 8));
+ RINOK(_outStream.Res);
+
+ UInt64 processed = 0;
+ for (;;)
+ {
+ UInt32 size;
+ RINOK(inStream->Read(_inStream.Buf, kBufSize, &size));
+ if (size == 0)
+ {
+ Ppmd8_EncodeSymbol(&_ppmd, -1);
+ Ppmd8_RangeEnc_FlushData(&_ppmd);
+ return _outStream.Flush();
+ }
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Ppmd8_EncodeSymbol(&_ppmd, _inStream.Buf[i]);
+ RINOK(_outStream.Res);
+ }
+ processed += size;
+ if (progress != NULL)
+ {
+ UInt64 outSize = _outStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&processed, &outSize));
+ }
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/PpmdZip.h b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdZip.h
new file mode 100644
index 000000000..c2288b5af
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/PpmdZip.h
@@ -0,0 +1,72 @@
+// PpmdZip.h
+// 2010-03-11 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_PPMD_ZIP_H
+#define __COMPRESS_PPMD_ZIP_H
+
+#include "../../../C/Alloc.h"
+#include "../../../C/Ppmd8.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../Common/CWrappers.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NPpmdZip {
+
+static const UInt32 kBufSize = (1 << 20);
+
+struct CBuf
+{
+ Byte *Buf;
+
+ CBuf(): Buf(0) {}
+ ~CBuf() { ::MidFree(Buf); }
+ bool Alloc()
+ {
+ if (!Buf)
+ Buf = (Byte *)::MidAlloc(kBufSize);
+ return (Buf != 0);
+ }
+};
+
+class CDecoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CByteInBufWrap _inStream;
+ CBuf _outStream;
+ CPpmd8 _ppmd;
+ bool _fullFileMode;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ CDecoder(bool fullFileMode);
+ ~CDecoder();
+};
+
+class CEncoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CByteOutBufWrap _outStream;
+ CBuf _inStream;
+ CPpmd8 _ppmd;
+ UInt32 _usedMemInMB;
+ unsigned _order;
+ unsigned _restor;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ CEncoder();
+ ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/QuantumDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/QuantumDecoder.cpp
new file mode 100644
index 000000000..501bd0e1f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/QuantumDecoder.cpp
@@ -0,0 +1,175 @@
+// QuantumDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+
+#include "QuantumDecoder.h"
+
+namespace NCompress {
+namespace NQuantum {
+
+static const int kLenIdNeedInit = -2;
+
+static const unsigned kNumLenSymbols = 27;
+static const unsigned kMatchMinLen = 3;
+static const unsigned kNumSimplePosSlots = 4;
+static const unsigned kNumSimpleLenSlots = 6;
+
+void CDecoder::Init()
+{
+ m_Selector.Init(kNumSelectors);
+ unsigned i;
+ for (i = 0; i < kNumLitSelectors; i++)
+ m_Literals[i].Init(kNumLitSymbols);
+ unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1));
+ const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 };
+ for (i = 0; i < kNumMatchSelectors; i++)
+ m_PosSlot[i].Init(MyMin(numItems, kNumPosSymbolsMax[i]));
+ m_LenSlot.Init(kNumLenSymbols);
+}
+
+HRESULT CDecoder::CodeSpec(UInt32 curSize)
+{
+ if (_remainLen == kLenIdNeedInit)
+ {
+ if (!_keepHistory)
+ {
+ if (!_outWindowStream.Create((UInt32)1 << _numDictBits))
+ return E_OUTOFMEMORY;
+ Init();
+ }
+ if (!_rangeDecoder.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ _rangeDecoder.Init();
+ _remainLen = 0;
+ }
+ if (curSize == 0)
+ return S_OK;
+
+ while (_remainLen > 0 && curSize > 0)
+ {
+ _remainLen--;
+ Byte b = _outWindowStream.GetByte(_rep0);
+ _outWindowStream.PutByte(b);
+ curSize--;
+ }
+
+ while (curSize > 0)
+ {
+ if (_rangeDecoder.Stream.WasFinished())
+ return S_FALSE;
+
+ unsigned selector = m_Selector.Decode(&_rangeDecoder);
+ if (selector < kNumLitSelectors)
+ {
+ Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder));
+ _outWindowStream.PutByte(b);
+ curSize--;
+ }
+ else
+ {
+ selector -= kNumLitSelectors;
+ unsigned len = selector + kMatchMinLen;
+ if (selector == 2)
+ {
+ unsigned lenSlot = m_LenSlot.Decode(&_rangeDecoder);
+ if (lenSlot >= kNumSimpleLenSlots)
+ {
+ lenSlot -= 2;
+ int numDirectBits = (int)(lenSlot >> 2);
+ len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
+ if (numDirectBits < 6)
+ len += _rangeDecoder.Stream.ReadBits(numDirectBits);
+ }
+ else
+ len += lenSlot;
+ }
+ UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder);
+ if (rep0 >= kNumSimplePosSlots)
+ {
+ int numDirectBits = (int)((rep0 >> 1) - 1);
+ rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits);
+ }
+ unsigned locLen = len;
+ if (len > curSize)
+ locLen = (unsigned)curSize;
+ if (!_outWindowStream.CopyBlock(rep0, locLen))
+ return S_FALSE;
+ curSize -= locLen;
+ len -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (int)len;
+ _rep0 = rep0;
+ break;
+ }
+ }
+ }
+ return _rangeDecoder.Stream.WasFinished() ? S_FALSE : S_OK;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+ UInt64 size = *outSize;
+
+ SetInStream(inStream);
+ _outWindowStream.SetStream(outStream);
+ SetOutStreamSize(outSize);
+ CDecoderFlusher flusher(this);
+
+ const UInt64 start = _outWindowStream.GetProcessedSize();
+ for (;;)
+ {
+ UInt32 curSize = 1 << 18;
+ UInt64 rem = size - (_outWindowStream.GetProcessedSize() - start);
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ if (curSize == 0)
+ break;
+ RINOK(CodeSpec(curSize));
+ if (progress != NULL)
+ {
+ UInt64 inSize = _rangeDecoder.GetProcessedSize();
+ UInt64 nowPos64 = _outWindowStream.GetProcessedSize() - start;
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+ }
+ }
+ flusher.NeedFlush = false;
+ return Flush();
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
+{
+ _rangeDecoder.SetStream(inStream);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::ReleaseInStream()
+{
+ _rangeDecoder.ReleaseStream();
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ if (outSize == NULL)
+ return E_FAIL;
+ _remainLen = kLenIdNeedInit;
+ _outWindowStream.Init(_keepHistory);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/QuantumDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/QuantumDecoder.h
new file mode 100644
index 000000000..e9ab023ba
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/QuantumDecoder.h
@@ -0,0 +1,264 @@
+// QuantumDecoder.h
+
+#ifndef __COMPRESS_QUANTUM_DECODER_H
+#define __COMPRESS_QUANTUM_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NQuantum {
+
+class CStreamBitDecoder
+{
+ UInt32 Value;
+ CInBuffer Stream;
+public:
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ void Finish() { Value = 0x10000; }
+
+ void Init()
+ {
+ Stream.Init();
+ Value = 0x10000;
+ }
+
+ UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
+ bool WasFinished() const { return Stream.WasFinished(); }
+
+ UInt32 ReadBit()
+ {
+ if (Value >= 0x10000)
+ Value = 0x100 | Stream.ReadByte();
+ UInt32 res = (Value >> 7) & 1;
+ Value <<= 1;
+ return res;
+ }
+
+ UInt32 ReadBits(int numBits) // numBits > 0
+ {
+ UInt32 res = 0;
+ do
+ res = (res << 1) | ReadBit();
+ while (--numBits != 0);
+ return res;
+ }
+};
+
+const unsigned kNumLitSelectorBits = 2;
+const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits);
+const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
+const unsigned kNumMatchSelectors = 3;
+const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
+const unsigned kNumSymbolsMax = kNumLitSymbols; // 64
+
+namespace NRangeCoder {
+
+class CDecoder
+{
+ UInt32 Low;
+ UInt32 Range;
+ UInt32 Code;
+public:
+ CStreamBitDecoder Stream;
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ void Init()
+ {
+ Stream.Init();
+ Low = 0;
+ Range = 0x10000;
+ Code = Stream.ReadBits(16);
+ }
+
+ void Finish()
+ {
+ // we need these extra two Bit_reads
+ Stream.ReadBit();
+ Stream.ReadBit();
+ Stream.Finish();
+ }
+
+ UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
+
+ UInt32 GetThreshold(UInt32 total) const
+ {
+ return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
+ }
+
+ void Decode(UInt32 start, UInt32 end, UInt32 total)
+ {
+ UInt32 high = Low + end * Range / total - 1;
+ UInt32 offset = start * Range / total;
+ Code -= offset;
+ Low += offset;
+ for (;;)
+ {
+ if ((Low & 0x8000) != (high & 0x8000))
+ {
+ if ((Low & 0x4000) == 0 || (high & 0x4000) != 0)
+ break;
+ Low &= 0x3FFF;
+ high |= 0x4000;
+ }
+ Low = (Low << 1) & 0xFFFF;
+ high = ((high << 1) | 1) & 0xFFFF;
+ Code = ((Code << 1) | Stream.ReadBit());
+ }
+ Range = high - Low + 1;
+ }
+};
+
+const UInt16 kUpdateStep = 8;
+const UInt16 kFreqSumMax = 3800;
+const UInt16 kReorderCountStart = 4;
+const UInt16 kReorderCount = 50;
+
+class CModelDecoder
+{
+ unsigned NumItems;
+ unsigned ReorderCount;
+ UInt16 Freqs[kNumSymbolsMax + 1];
+ Byte Values[kNumSymbolsMax];
+public:
+ void Init(unsigned numItems)
+ {
+ NumItems = numItems;
+ ReorderCount = kReorderCountStart;
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ Freqs[i] = (UInt16)(numItems - i);
+ Values[i] = (Byte)i;
+ }
+ Freqs[numItems] = 0;
+ }
+
+ unsigned Decode(CDecoder *rangeDecoder)
+ {
+ UInt32 threshold = rangeDecoder->GetThreshold(Freqs[0]);
+ unsigned i;
+ for (i = 1; Freqs[i] > threshold; i++);
+ rangeDecoder->Decode(Freqs[i], Freqs[i - 1], Freqs[0]);
+ unsigned res = Values[--i];
+ do
+ Freqs[i] += kUpdateStep;
+ while (i-- != 0);
+
+ if (Freqs[0] > kFreqSumMax)
+ {
+ if (--ReorderCount == 0)
+ {
+ ReorderCount = kReorderCount;
+ for (i = 0; i < NumItems; i++)
+ Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1);
+ for (i = 0; i < NumItems - 1; i++)
+ for (unsigned j = i + 1; j < NumItems; j++)
+ if (Freqs[i] < Freqs[j])
+ {
+ UInt16 tmpFreq = Freqs[i];
+ Byte tmpVal = Values[i];
+ Freqs[i] = Freqs[j];
+ Values[i] = Values[j];
+ Freqs[j] = tmpFreq;
+ Values[j] = tmpVal;
+ }
+ do
+ Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]);
+ while (i-- != 0);
+ }
+ else
+ {
+ i = NumItems - 1;
+ do
+ {
+ Freqs[i] >>= 1;
+ if (Freqs[i] <= Freqs[i + 1])
+ Freqs[i] = (UInt16)(Freqs[i + 1] + 1);
+ }
+ while (i-- != 0);
+ }
+ }
+ return res;
+ }
+};
+
+}
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public CMyUnknownImp
+{
+ CLzOutWindow _outWindowStream;
+ NRangeCoder::CDecoder _rangeDecoder;
+
+ UInt64 _outSize;
+ int _remainLen; // -1 means end of stream. // -2 means need Init
+ UInt32 _rep0;
+
+ int _numDictBits;
+ bool _keepHistory;
+
+ NRangeCoder::CModelDecoder m_Selector;
+ NRangeCoder::CModelDecoder m_Literals[kNumLitSelectors];
+ NRangeCoder::CModelDecoder m_PosSlot[kNumMatchSelectors];
+ NRangeCoder::CModelDecoder m_LenSlot;
+ void Init();
+ HRESULT CodeSpec(UInt32 size);
+public:
+ MY_UNKNOWN_IMP2(
+ ICompressSetInStream,
+ ICompressSetOutStreamSize)
+
+ void ReleaseStreams()
+ {
+ _outWindowStream.ReleaseStream();
+ ReleaseInStream();
+ }
+
+ class CDecoderFlusher
+ {
+ CDecoder *_decoder;
+ public:
+ bool NeedFlush;
+ CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ _decoder->Flush();
+ _decoder->ReleaseStreams();
+ }
+ };
+
+ HRESULT Flush() { return _outWindowStream.Flush(); }
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ void SetParams(int numDictBits) { _numDictBits = numDictBits; }
+ void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+ CDecoder(): _keepHistory(false) {}
+ virtual ~CDecoder() {}
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/RangeCoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/RangeCoder.h
new file mode 100644
index 000000000..1eb2a6d47
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/RangeCoder.h
@@ -0,0 +1,205 @@
+// Compress/RangeCoder.h
+// 2009-05-30 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_RANGE_CODER_H
+#define __COMPRESS_RANGE_CODER_H
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const int kNumTopBits = 24;
+const UInt32 kTopValue = (1 << kNumTopBits);
+
+class CEncoder
+{
+ UInt32 _cacheSize;
+ Byte _cache;
+public:
+ UInt64 Low;
+ UInt32 Range;
+ COutBuffer Stream;
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+
+ void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); }
+ void Init()
+ {
+ Stream.Init();
+ Low = 0;
+ Range = 0xFFFFFFFF;
+ _cacheSize = 1;
+ _cache = 0;
+ }
+
+ void FlushData()
+ {
+ // Low += 1;
+ for(int i = 0; i < 5; i++)
+ ShiftLow();
+ }
+
+ HRESULT FlushStream() { return Stream.Flush(); }
+
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ void Encode(UInt32 start, UInt32 size, UInt32 total)
+ {
+ Low += start * (Range /= total);
+ Range *= size;
+ while (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+
+ void ShiftLow()
+ {
+ if ((UInt32)Low < (UInt32)0xFF000000 || (int)(Low >> 32) != 0)
+ {
+ Byte temp = _cache;
+ do
+ {
+ Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32)));
+ temp = 0xFF;
+ }
+ while(--_cacheSize != 0);
+ _cache = (Byte)((UInt32)Low >> 24);
+ }
+ _cacheSize++;
+ Low = (UInt32)Low << 8;
+ }
+
+ void EncodeDirectBits(UInt32 value, int numBits)
+ {
+ for (numBits--; numBits >= 0; numBits--)
+ {
+ Range >>= 1;
+ Low += Range & (0 - ((value >> numBits) & 1));
+ if (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+ }
+
+ void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol)
+ {
+ UInt32 newBound = (Range >> numTotalBits) * size0;
+ if (symbol == 0)
+ Range = newBound;
+ else
+ {
+ Low += newBound;
+ Range -= newBound;
+ }
+ while (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+
+ UInt64 GetProcessedSize() { return Stream.GetProcessedSize() + _cacheSize + 4; }
+};
+
+class CDecoder
+{
+public:
+ CInBuffer Stream;
+ UInt32 Range;
+ UInt32 Code;
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+
+ void Normalize()
+ {
+ while (Range < kTopValue)
+ {
+ Code = (Code << 8) | Stream.ReadByte();
+ Range <<= 8;
+ }
+ }
+
+ void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+ void Init()
+ {
+ Stream.Init();
+ Code = 0;
+ Range = 0xFFFFFFFF;
+ for(int i = 0; i < 5; i++)
+ Code = (Code << 8) | Stream.ReadByte();
+ }
+
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ UInt32 GetThreshold(UInt32 total)
+ {
+ return (Code) / ( Range /= total);
+ }
+
+ void Decode(UInt32 start, UInt32 size)
+ {
+ Code -= start * Range;
+ Range *= size;
+ Normalize();
+ }
+
+ UInt32 DecodeDirectBits(int numTotalBits)
+ {
+ UInt32 range = Range;
+ UInt32 code = Code;
+ UInt32 result = 0;
+ for (int i = numTotalBits; i != 0; i--)
+ {
+ range >>= 1;
+ /*
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ */
+ UInt32 t = (code - range) >> 31;
+ code -= range & (t - 1);
+ result = (result << 1) | (1 - t);
+
+ if (range < kTopValue)
+ {
+ code = (code << 8) | Stream.ReadByte();
+ range <<= 8;
+ }
+ }
+ Range = range;
+ Code = code;
+ return result;
+ }
+
+ UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits)
+ {
+ UInt32 newBound = (Range >> numTotalBits) * size0;
+ UInt32 symbol;
+ if (Code < newBound)
+ {
+ symbol = 0;
+ Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ Code -= newBound;
+ Range -= newBound;
+ }
+ Normalize();
+ return symbol;
+ }
+
+ UInt64 GetProcessedSize() {return Stream.GetProcessedSize(); }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/RangeCoderBit.h b/src/libs/7zip/unix/CPP/7zip/Compress/RangeCoderBit.h
new file mode 100644
index 000000000..b5a1830d6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/RangeCoderBit.h
@@ -0,0 +1,114 @@
+// Compress/RangeCoderBit.h
+// 2009-05-30 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_RANGE_CODER_BIT_H
+#define __COMPRESS_RANGE_CODER_BIT_H
+
+#include "RangeCoder.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const int kNumBitModelTotalBits = 11;
+const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits);
+
+const int kNumMoveReducingBits = 4;
+
+const int kNumBitPriceShiftBits = 4;
+const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits;
+
+extern UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+
+template <int numMoveBits>
+class CBitModel
+{
+public:
+ UInt32 Prob;
+ void UpdateModel(UInt32 symbol)
+ {
+ /*
+ Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits;
+ Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits);
+ */
+ if (symbol == 0)
+ Prob += (kBitModelTotal - Prob) >> numMoveBits;
+ else
+ Prob -= (Prob) >> numMoveBits;
+ }
+public:
+ void Init() { Prob = kBitModelTotal / 2; }
+};
+
+template <int numMoveBits>
+class CBitEncoder: public CBitModel<numMoveBits>
+{
+public:
+ void Encode(CEncoder *encoder, UInt32 symbol)
+ {
+ /*
+ encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol);
+ this->UpdateModel(symbol);
+ */
+ UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob;
+ if (symbol == 0)
+ {
+ encoder->Range = newBound;
+ this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+ }
+ else
+ {
+ encoder->Low += newBound;
+ encoder->Range -= newBound;
+ this->Prob -= (this->Prob) >> numMoveBits;
+ }
+ if (encoder->Range < kTopValue)
+ {
+ encoder->Range <<= 8;
+ encoder->ShiftLow();
+ }
+ }
+ UInt32 GetPrice(UInt32 symbol) const
+ {
+ return ProbPrices[(this->Prob ^ ((-(int)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
+ }
+ UInt32 GetPrice0() const { return ProbPrices[this->Prob >> kNumMoveReducingBits]; }
+ UInt32 GetPrice1() const { return ProbPrices[(this->Prob ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]; }
+};
+
+
+template <int numMoveBits>
+class CBitDecoder: public CBitModel<numMoveBits>
+{
+public:
+ UInt32 Decode(CDecoder *decoder)
+ {
+ UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob;
+ if (decoder->Code < newBound)
+ {
+ decoder->Range = newBound;
+ this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+ if (decoder->Range < kTopValue)
+ {
+ decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+ decoder->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ decoder->Range -= newBound;
+ decoder->Code -= newBound;
+ this->Prob -= (this->Prob) >> numMoveBits;
+ if (decoder->Range < kTopValue)
+ {
+ decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+ decoder->Range <<= 8;
+ }
+ return 1;
+ }
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp
new file mode 100644
index 000000000..eadca7b3d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp
@@ -0,0 +1,480 @@
+// Rar1Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+#include "Rar1Decoder.h"
+
+namespace NCompress {
+namespace NRar1 {
+
+static UInt32 PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32, 256};
+static UInt32 PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36, 256};
+static UInt32 PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33, 257};
+static UInt32 PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127, 257};
+static UInt32 PosHf2[]={0,0,0,0,0,0,2,7,53,117,233, 257,0};
+static UInt32 PosHf3[]={0,0,0,0,0,0,0,2,16,218,251, 257,0};
+static UInt32 PosHf4[]={0,0,0,0,0,0,0,0,0,255, 257,0,0};
+
+static const UInt32 kHistorySize = (1 << 16);
+
+class CCoderReleaser
+{
+ CDecoder *m_Coder;
+public:
+ CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
+};
+
+CDecoder::CDecoder(): m_IsSolid(false) { }
+
+void CDecoder::InitStructures()
+{
+ for(int i = 0; i < kNumRepDists; i++)
+ m_RepDists[i] = 0;
+ m_RepDistPtr = 0;
+ LastLength = 0;
+ LastDist = 0;
+}
+
+UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
+
+HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len)
+{
+ if (len == 0)
+ return S_FALSE;
+ m_UnpackSize -= len;
+ return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE;
+}
+
+
+UInt32 CDecoder::DecodeNum(const UInt32 *posTab)
+{
+ UInt32 startPos = 2;
+ UInt32 num = m_InBitStream.GetValue(12);
+ for (;;)
+ {
+ UInt32 cur = (posTab[startPos + 1] - posTab[startPos]) << (12 - startPos);
+ if (num < cur)
+ break;
+ startPos++;
+ num -= cur;
+ }
+ m_InBitStream.MovePos(startPos);
+ return((num >> (12 - startPos)) + posTab[startPos]);
+}
+
+static Byte kShortLen1[] = {1,3,4,4,5,6,7,8,8,4,4,5,6,6 };
+static Byte kShortLen1a[] = {1,4,4,4,5,6,7,8,8,4,4,5,6,6,4 };
+static Byte kShortLen2[] = {2,3,3,3,4,4,5,6,6,4,4,5,6,6 };
+static Byte kShortLen2a[] = {2,3,3,4,4,4,5,6,6,4,4,5,6,6,4 };
+static UInt32 kShortXor1[] = {0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0};
+static UInt32 kShortXor2[] = {0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0};
+
+HRESULT CDecoder::ShortLZ()
+{
+ UInt32 len, saveLen, dist;
+ int distancePlace;
+ Byte *kShortLen;
+ const UInt32 *kShortXor;
+ NumHuf = 0;
+
+ if (LCount == 2)
+ {
+ if (ReadBits(1))
+ return CopyBlock(LastDist, LastLength);
+ LCount = 0;
+ }
+
+ UInt32 bitField = m_InBitStream.GetValue(8);
+
+ if (AvrLn1 < 37)
+ {
+ kShortLen = Buf60 ? kShortLen1a : kShortLen1;
+ kShortXor = kShortXor1;
+ }
+ else
+ {
+ kShortLen = Buf60 ? kShortLen2a : kShortLen2;
+ kShortXor = kShortXor2;
+ }
+
+ for (len = 0; ((bitField ^ kShortXor[len]) & (~(0xff >> kShortLen[len]))) != 0; len++);
+ m_InBitStream.MovePos(kShortLen[len]);
+
+ if (len >= 9)
+ {
+ if (len == 9)
+ {
+ LCount++;
+ return CopyBlock(LastDist, LastLength);
+ }
+ if (len == 14)
+ {
+ LCount = 0;
+ len = DecodeNum(PosL2) + 5;
+ dist = 0x8000 + ReadBits(15) - 1;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+ }
+
+ LCount = 0;
+ saveLen = len;
+ dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3];
+ len = DecodeNum(PosL1) + 2;
+ if (len == 0x101 && saveLen == 10)
+ {
+ Buf60 ^= 1;
+ return S_OK;
+ }
+ if (dist >= 256)
+ len++;
+ if (dist >= MaxDist3 - 1)
+ len++;
+ }
+ else
+ {
+ LCount = 0;
+ AvrLn1 += len;
+ AvrLn1 -= AvrLn1 >> 4;
+
+ distancePlace = DecodeNum(PosHf2) & 0xff;
+ dist = ChSetA[distancePlace];
+ if (--distancePlace != -1)
+ {
+ PlaceA[dist]--;
+ UInt32 lastDistance = ChSetA[distancePlace];
+ PlaceA[lastDistance]++;
+ ChSetA[distancePlace + 1] = lastDistance;
+ ChSetA[distancePlace] = dist;
+ }
+ len += 2;
+ }
+ m_RepDists[m_RepDistPtr++] = dist;
+ m_RepDistPtr &= 3;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+}
+
+
+HRESULT CDecoder::LongLZ()
+{
+ UInt32 len;
+ UInt32 dist;
+ UInt32 distancePlace, newDistancePlace;
+ UInt32 oldAvr2, oldAvr3;
+
+ NumHuf = 0;
+ Nlzb += 16;
+ if (Nlzb > 0xff)
+ {
+ Nlzb = 0x90;
+ Nhfb >>= 1;
+ }
+ oldAvr2=AvrLn2;
+
+ if (AvrLn2 >= 122)
+ len = DecodeNum(PosL2);
+ else if (AvrLn2 >= 64)
+ len = DecodeNum(PosL1);
+ else
+ {
+ UInt32 bitField = m_InBitStream.GetValue(16);
+ if (bitField < 0x100)
+ {
+ len = bitField;
+ m_InBitStream.MovePos(16);
+ }
+ else
+ {
+ for (len = 0; ((bitField << len) & 0x8000) == 0; len++)
+ ;
+ m_InBitStream.MovePos(len + 1);
+ }
+ }
+
+ AvrLn2 += len;
+ AvrLn2 -= AvrLn2 >> 5;
+
+ if (AvrPlcB > 0x28ff)
+ distancePlace = DecodeNum(PosHf2);
+ else if (AvrPlcB > 0x6ff)
+ distancePlace = DecodeNum(PosHf1);
+ else
+ distancePlace = DecodeNum(PosHf0);
+
+ AvrPlcB += distancePlace;
+ AvrPlcB -= AvrPlcB >> 8;
+ for (;;)
+ {
+ dist = ChSetB[distancePlace & 0xff];
+ newDistancePlace = NToPlB[dist++ & 0xff]++;
+ if (!(dist & 0xff))
+ CorrHuff(ChSetB,NToPlB);
+ else
+ break;
+ }
+
+ ChSetB[distancePlace] = ChSetB[newDistancePlace];
+ ChSetB[newDistancePlace] = dist;
+
+ dist = ((dist & 0xff00) >> 1) | ReadBits(7);
+
+ oldAvr3 = AvrLn3;
+ if (len != 1 && len != 4)
+ if (len == 0 && dist <= MaxDist3)
+ {
+ AvrLn3++;
+ AvrLn3 -= AvrLn3 >> 8;
+ }
+ else
+ if (AvrLn3 > 0)
+ AvrLn3--;
+ len += 3;
+ if (dist >= MaxDist3)
+ len++;
+ if (dist <= 256)
+ len += 8;
+ if (oldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && oldAvr2 < 0x40)
+ MaxDist3 = 0x7f00;
+ else
+ MaxDist3 = 0x2001;
+ m_RepDists[m_RepDistPtr++] = --dist;
+ m_RepDistPtr &= 3;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+}
+
+
+HRESULT CDecoder::HuffDecode()
+{
+ UInt32 curByte, newBytePlace;
+ UInt32 len;
+ UInt32 dist;
+ int bytePlace;
+
+ if (AvrPlc > 0x75ff) bytePlace = DecodeNum(PosHf4);
+ else if (AvrPlc > 0x5dff) bytePlace = DecodeNum(PosHf3);
+ else if (AvrPlc > 0x35ff) bytePlace = DecodeNum(PosHf2);
+ else if (AvrPlc > 0x0dff) bytePlace = DecodeNum(PosHf1);
+ else bytePlace = DecodeNum(PosHf0);
+ if (StMode)
+ {
+ if (--bytePlace == -1)
+ {
+ if (ReadBits(1))
+ {
+ NumHuf = StMode = 0;
+ return S_OK;
+ }
+ else
+ {
+ len = (ReadBits(1)) ? 4 : 3;
+ dist = DecodeNum(PosHf2);
+ dist = (dist << 5) | ReadBits(5);
+ return CopyBlock(dist - 1, len);
+ }
+ }
+ }
+ else if (NumHuf++ >= 16 && FlagsCnt == 0)
+ StMode = 1;
+ bytePlace &= 0xff;
+ AvrPlc += bytePlace;
+ AvrPlc -= AvrPlc >> 8;
+ Nhfb+=16;
+ if (Nhfb > 0xff)
+ {
+ Nhfb=0x90;
+ Nlzb >>= 1;
+ }
+
+ m_UnpackSize --;
+ m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8));
+
+ for (;;)
+ {
+ curByte = ChSet[bytePlace];
+ newBytePlace = NToPl[curByte++ & 0xff]++;
+ if ((curByte & 0xff) > 0xa1)
+ CorrHuff(ChSet, NToPl);
+ else
+ break;
+ }
+
+ ChSet[bytePlace] = ChSet[newBytePlace];
+ ChSet[newBytePlace] = curByte;
+ return S_OK;
+}
+
+
+void CDecoder::GetFlagsBuf()
+{
+ UInt32 flags, newFlagsPlace;
+ UInt32 flagsPlace = DecodeNum(PosHf2);
+
+ for (;;)
+ {
+ flags = ChSetC[flagsPlace];
+ FlagBuf = flags >> 8;
+ newFlagsPlace = NToPlC[flags++ & 0xff]++;
+ if ((flags & 0xff) != 0)
+ break;
+ CorrHuff(ChSetC, NToPlC);
+ }
+
+ ChSetC[flagsPlace] = ChSetC[newFlagsPlace];
+ ChSetC[newFlagsPlace] = flags;
+}
+
+void CDecoder::InitData()
+{
+ if (!m_IsSolid)
+ {
+ AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0;
+ AvrPlc = 0x3500;
+ MaxDist3 = 0x2001;
+ Nhfb = Nlzb = 0x80;
+ }
+ FlagsCnt = 0;
+ FlagBuf = 0;
+ StMode = 0;
+ LCount = 0;
+}
+
+void CDecoder::CorrHuff(UInt32 *CharSet,UInt32 *NumToPlace)
+{
+ int i;
+ for (i = 7; i >= 0; i--)
+ for (int j = 0; j < 32; j++, CharSet++)
+ *CharSet = (*CharSet & ~0xff) | i;
+ memset(NumToPlace, 0, sizeof(NToPl));
+ for (i = 6; i >= 0; i--)
+ NumToPlace[i] = (7 - i) * 32;
+}
+
+void CDecoder::InitHuff()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ Place[i] = PlaceA[i] = PlaceB[i] = i;
+ PlaceC[i] = (~i + 1) & 0xff;
+ ChSet[i] = ChSetB[i] = i << 8;
+ ChSetA[i] = i;
+ ChSetC[i] = ((~i + 1) & 0xff) << 8;
+ }
+ memset(NToPl, 0, sizeof(NToPl));
+ memset(NToPlB, 0, sizeof(NToPlB));
+ memset(NToPlC, 0, sizeof(NToPlC));
+ CorrHuff(ChSetB, NToPlB);
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */)
+{
+ if (inSize == NULL || outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ m_UnpackSize = (Int64)*outSize;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(m_IsSolid);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+ InitData();
+ if (!m_IsSolid)
+ {
+ InitStructures();
+ InitHuff();
+ }
+ if (m_UnpackSize > 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 8;
+ }
+
+ while (m_UnpackSize > 0)
+ {
+ if (StMode)
+ {
+ RINOK(HuffDecode());
+ continue;
+ }
+
+ if (--FlagsCnt < 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt=7;
+ }
+
+ if (FlagBuf & 0x80)
+ {
+ FlagBuf <<= 1;
+ if (Nlzb > Nhfb)
+ {
+ RINOK(LongLZ());
+ }
+ else
+ {
+ RINOK(HuffDecode());
+ }
+ }
+ else
+ {
+ FlagBuf <<= 1;
+ if (--FlagsCnt < 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 7;
+ }
+ if (FlagBuf & 0x80)
+ {
+ FlagBuf <<= 1;
+ if (Nlzb > Nhfb)
+ {
+ RINOK(HuffDecode());
+ }
+ else
+ {
+ RINOK(LongLZ());
+ }
+ }
+ else
+ {
+ FlagBuf <<= 1;
+ RINOK(ShortLZ());
+ }
+ }
+ }
+ if (m_UnpackSize < 0)
+ return S_FALSE;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ m_IsSolid = (data[0] != 0);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.h
new file mode 100644
index 000000000..f7c08b386
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.h
@@ -0,0 +1,88 @@
+// Rar1Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef __COMPRESS_RAR1_DECODER_H
+#define __COMPRESS_RAR1_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NRar1 {
+
+const UInt32 kNumRepDists = 4;
+
+typedef NBitm::CDecoder<CInBuffer> CBitDecoder;
+
+class CDecoder :
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+public:
+ CLzOutWindow m_OutWindowStream;
+ CBitDecoder m_InBitStream;
+
+ UInt32 m_RepDists[kNumRepDists];
+ UInt32 m_RepDistPtr;
+
+ UInt32 LastDist;
+ UInt32 LastLength;
+
+ Int64 m_UnpackSize;
+ bool m_IsSolid;
+
+ UInt32 ReadBits(int numBits);
+ HRESULT CopyBlock(UInt32 distance, UInt32 len);
+
+ UInt32 DecodeNum(const UInt32 *posTab);
+ HRESULT ShortLZ();
+ HRESULT LongLZ();
+ HRESULT HuffDecode();
+ void GetFlagsBuf();
+ void InitData();
+ void InitHuff();
+ void CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace);
+ void OldUnpWriteBuf();
+
+ UInt32 ChSet[256],ChSetA[256],ChSetB[256],ChSetC[256];
+ UInt32 Place[256],PlaceA[256],PlaceB[256],PlaceC[256];
+ UInt32 NToPl[256],NToPlB[256],NToPlC[256];
+ UInt32 FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3;
+ int Buf60,NumHuf,StMode,LCount,FlagsCnt;
+ UInt32 Nhfb,Nlzb,MaxDist3;
+
+ void InitStructures();
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+public:
+ CDecoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar2Decoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Rar2Decoder.cpp
new file mode 100644
index 000000000..4e669bd64
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar2Decoder.cpp
@@ -0,0 +1,391 @@
+// Rar2Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+#include "Rar2Decoder.h"
+
+namespace NCompress {
+namespace NRar2 {
+
+namespace NMultimedia {
+
+Byte CFilter::Decode(int &channelDelta, Byte deltaByte)
+{
+ D4 = D3;
+ D3 = D2;
+ D2 = LastDelta - D1;
+ D1 = LastDelta;
+ int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3);
+
+ Byte realValue = (Byte)(predictedValue - deltaByte);
+ int i = ((int)(signed char)deltaByte) << 3;
+
+ Dif[0] += abs(i);
+ Dif[1] += abs(i - D1);
+ Dif[2] += abs(i + D1);
+ Dif[3] += abs(i - D2);
+ Dif[4] += abs(i + D2);
+ Dif[5] += abs(i - D3);
+ Dif[6] += abs(i + D3);
+ Dif[7] += abs(i - D4);
+ Dif[8] += abs(i + D4);
+ Dif[9] += abs(i - channelDelta);
+ Dif[10] += abs(i + channelDelta);
+
+ channelDelta = LastDelta = (signed char)(realValue - LastChar);
+ LastChar = realValue;
+
+ if (((++ByteCount) & 0x1F) == 0)
+ {
+ UInt32 minDif = Dif[0];
+ UInt32 numMinDif = 0;
+ Dif[0] = 0;
+ for (i = 1; i < sizeof(Dif) / sizeof(Dif[0]); i++)
+ {
+ if (Dif[i] < minDif)
+ {
+ minDif = Dif[i];
+ numMinDif = i;
+ }
+ Dif[i] = 0;
+ }
+ switch(numMinDif)
+ {
+ case 1: if (K1 >= -16) K1--; break;
+ case 2: if (K1 < 16) K1++; break;
+ case 3: if (K2 >= -16) K2--; break;
+ case 4: if (K2 < 16) K2++; break;
+ case 5: if (K3 >= -16) K3--; break;
+ case 6: if (K3 < 16) K3++; break;
+ case 7: if (K4 >= -16) K4--; break;
+ case 8: if (K4 < 16) K4++; break;
+ case 9: if (K5 >= -16) K5--; break;
+ case 10:if (K5 < 16) K5++; break;
+ }
+ }
+ return realValue;
+}
+}
+
+static const char *kNumberErrorMessage = "Number error";
+
+static const UInt32 kHistorySize = 1 << 20;
+
+static const int kNumStats = 11;
+
+static const UInt32 kWindowReservSize = (1 << 22) + 256;
+
+CDecoder::CDecoder():
+ m_IsSolid(false)
+{
+}
+
+void CDecoder::InitStructures()
+{
+ m_MmFilter.Init();
+ for(int i = 0; i < kNumRepDists; i++)
+ m_RepDists[i] = 0;
+ m_RepDistPtr = 0;
+ m_LastLength = 0;
+ memset(m_LastLevels, 0, kMaxTableSize);
+}
+
+UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CDecoder::ReadTables(void)
+{
+ Byte levelLevels[kLevelTableSize];
+ Byte newLevels[kMaxTableSize];
+ m_AudioMode = (ReadBits(1) == 1);
+
+ if (ReadBits(1) == 0)
+ memset(m_LastLevels, 0, kMaxTableSize);
+ int numLevels;
+ if (m_AudioMode)
+ {
+ m_NumChannels = ReadBits(2) + 1;
+ if (m_MmFilter.CurrentChannel >= m_NumChannels)
+ m_MmFilter.CurrentChannel = 0;
+ numLevels = m_NumChannels * kMMTableSize;
+ }
+ else
+ numLevels = kHeapTablesSizesSum;
+
+ int i;
+ for (i = 0; i < kLevelTableSize; i++)
+ levelLevels[i] = (Byte)ReadBits(4);
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+ i = 0;
+ while (i < numLevels)
+ {
+ UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < kTableDirectLevels)
+ {
+ newLevels[i] = (Byte)((number + m_LastLevels[i]) & kLevelMask);
+ i++;
+ }
+ else
+ {
+ if (number == kTableLevelRepNumber)
+ {
+ int t = ReadBits(2) + 3;
+ for (int reps = t; reps > 0 && i < numLevels ; reps--, i++)
+ newLevels[i] = newLevels[i - 1];
+ }
+ else
+ {
+ int num;
+ if (number == kTableLevel0Number)
+ num = ReadBits(3) + 3;
+ else if (number == kTableLevel0Number2)
+ num = ReadBits(7) + 11;
+ else
+ return false;
+ for (;num > 0 && i < numLevels; num--)
+ newLevels[i++] = 0;
+ }
+ }
+ }
+ if (m_AudioMode)
+ for (i = 0; i < m_NumChannels; i++)
+ {
+ RIF(m_MMDecoders[i].SetCodeLengths(&newLevels[i * kMMTableSize]));
+ }
+ else
+ {
+ RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
+ RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
+ RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
+ }
+ memcpy(m_LastLevels, newLevels, kMaxTableSize);
+ return true;
+}
+
+bool CDecoder::ReadLastTables()
+{
+ // it differs a little from pure RAR sources;
+ // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2;
+ // + 2 works for: return 0xFF; in CInBuffer::ReadByte.
+ if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect;
+ // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
+ if (m_AudioMode)
+ {
+ UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
+ if (symbol == 256)
+ return ReadTables();
+ if (symbol >= kMMTableSize)
+ return false;
+ }
+ else
+ {
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ if (number == kReadTableNumber)
+ return ReadTables();
+ if (number >= kMainTableSize)
+ return false;
+ }
+ return true;
+}
+
+class CCoderReleaser
+{
+ CDecoder *m_Coder;
+public:
+ CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser()
+ {
+ m_Coder->ReleaseStreams();
+ }
+};
+
+bool CDecoder::DecodeMm(UInt32 pos)
+{
+ while (pos-- > 0)
+ {
+ UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
+ if (symbol == 256)
+ return true;
+ if (symbol >= kMMTableSize)
+ return false;
+ /*
+ Byte byPredict = m_Predictor.Predict();
+ Byte byReal = (Byte)(byPredict - (Byte)symbol);
+ m_Predictor.Update(byReal, byPredict);
+ */
+ Byte byReal = m_MmFilter.Decode((Byte)symbol);
+ m_OutWindowStream.PutByte(byReal);
+ if (++m_MmFilter.CurrentChannel == m_NumChannels)
+ m_MmFilter.CurrentChannel = 0;
+ }
+ return true;
+}
+
+bool CDecoder::DecodeLz(Int32 pos)
+{
+ while (pos > 0)
+ {
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ UInt32 length, distance;
+ if (number < 256)
+ {
+ m_OutWindowStream.PutByte(Byte(number));
+ pos--;
+ continue;
+ }
+ else if (number >= kMatchNumber)
+ {
+ number -= kMatchNumber;
+ length = kNormalMatchMinLen + UInt32(kLenStart[number]) +
+ m_InBitStream.ReadBits(kLenDirectBits[number]);
+ number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
+ if (number >= kDistTableSize)
+ return false;
+ distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
+ if (distance >= kDistLimit3)
+ {
+ length += 2 - ((distance - kDistLimit4) >> 31);
+ // length++;
+ // if (distance >= kDistLimit4)
+ // length++;
+ }
+ }
+ else if (number == kRepBothNumber)
+ {
+ length = m_LastLength;
+ if (length == 0)
+ return false;
+ distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
+ }
+ else if (number < kLen2Number)
+ {
+ distance = m_RepDists[(m_RepDistPtr - (number - kRepNumber + 1)) & 3];
+ number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
+ if (number >= kLenTableSize)
+ return false;
+ length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
+ if (distance >= kDistLimit2)
+ {
+ length++;
+ if (distance >= kDistLimit3)
+ {
+ length += 2 - ((distance - kDistLimit4) >> 31);
+ // length++;
+ // if (distance >= kDistLimit4)
+ // length++;
+ }
+ }
+ }
+ else if (number < kReadTableNumber)
+ {
+ number -= kLen2Number;
+ distance = kLen2DistStarts[number] +
+ m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
+ length = 2;
+ }
+ else if (number == kReadTableNumber)
+ return true;
+ else
+ return false;
+ m_RepDists[m_RepDistPtr++ & 3] = distance;
+ m_LastLength = length;
+ if (!m_OutWindowStream.CopyBlock(distance, length))
+ return false;
+ pos -= length;
+ }
+ return true;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (inSize == NULL || outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ m_PackSize = *inSize;
+
+ UInt64 pos = 0, unPackSize = *outSize;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(m_IsSolid);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+ if (!m_IsSolid)
+ {
+ InitStructures();
+ if (unPackSize == 0)
+ {
+ if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
+ if (!ReadTables())
+ return S_FALSE;
+ return S_OK;
+ }
+ if (!ReadTables())
+ return S_FALSE;
+ }
+
+ UInt64 startPos = m_OutWindowStream.GetProcessedSize();
+ while(pos < unPackSize)
+ {
+ UInt32 blockSize = 1 << 20;
+ if (blockSize > unPackSize - pos)
+ blockSize = (UInt32)(unPackSize - pos);
+ UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize();
+ if (m_AudioMode)
+ {
+ if (!DecodeMm(blockSize))
+ return S_FALSE;
+ }
+ else
+ {
+ if (!DecodeLz((Int32)blockSize))
+ return S_FALSE;
+ }
+ UInt64 globalPos = m_OutWindowStream.GetProcessedSize();
+ pos = globalPos - blockStartPos;
+ if (pos < blockSize)
+ if (!ReadTables())
+ return S_FALSE;
+ pos = globalPos - startPos;
+ if (progress != 0)
+ {
+ UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ }
+ }
+ if (pos > unPackSize)
+ return S_FALSE;
+
+ if (!ReadLastTables())
+ return S_FALSE;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ m_IsSolid = (data[0] != 0);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar2Decoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/Rar2Decoder.h
new file mode 100644
index 000000000..61a8b4dab
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar2Decoder.h
@@ -0,0 +1,174 @@
+// Rar2Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef __COMPRESS_RAR2_DECODER_H
+#define __COMPRESS_RAR2_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NRar2 {
+
+const UInt32 kNumRepDists = 4;
+const UInt32 kDistTableSize = 48;
+
+const int kMMTableSize = 256 + 1;
+
+const UInt32 kMainTableSize = 298;
+const UInt32 kLenTableSize = 28;
+
+const UInt32 kDistTableStart = kMainTableSize;
+const UInt32 kLenTableStart = kDistTableStart + kDistTableSize;
+
+const UInt32 kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize;
+
+const UInt32 kLevelTableSize = 19;
+
+const UInt32 kMMTablesSizesSum = kMMTableSize * 4;
+
+const UInt32 kMaxTableSize = kMMTablesSizesSum;
+
+const UInt32 kTableDirectLevels = 16;
+const UInt32 kTableLevelRepNumber = kTableDirectLevels;
+const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1;
+const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1;
+
+const UInt32 kLevelMask = 0xF;
+
+
+const UInt32 kRepBothNumber = 256;
+const UInt32 kRepNumber = kRepBothNumber + 1;
+const UInt32 kLen2Number = kRepNumber + 4;
+
+const UInt32 kLen2NumNumbers = 8;
+const UInt32 kReadTableNumber = kLen2Number + kLen2NumNumbers;
+const UInt32 kMatchNumber = kReadTableNumber + 1;
+
+const Byte kLenStart[kLenTableSize] = {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};
+const Byte kLenDirectBits[kLenTableSize] = {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};
+
+const UInt32 kDistStart[kDistTableSize] = {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
+const Byte kDistDirectBits[kDistTableSize] = {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, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
+
+const Byte kLevelDirectBits[kLevelTableSize] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
+
+const Byte kLen2DistStarts[kLen2NumNumbers]={0,4,8,16,32,64,128,192};
+const Byte kLen2DistDirectBits[kLen2NumNumbers]={2,2,3, 4, 5, 6, 6, 6};
+
+const UInt32 kDistLimit2 = 0x101 - 1;
+const UInt32 kDistLimit3 = 0x2000 - 1;
+const UInt32 kDistLimit4 = 0x40000 - 1;
+
+const UInt32 kMatchMaxLen = 255 + 2;
+const UInt32 kMatchMaxLenMax = 255 + 5;
+const UInt32 kNormalMatchMinLen = 3;
+
+namespace NMultimedia {
+
+struct CFilter
+{
+ int K1,K2,K3,K4,K5;
+ int D1,D2,D3,D4;
+ int LastDelta;
+ UInt32 Dif[11];
+ UInt32 ByteCount;
+ int LastChar;
+
+ Byte Decode(int &channelDelta, Byte delta);
+
+ void Init() { memset(this, 0, sizeof(*this)); }
+
+};
+
+const int kNumChanelsMax = 4;
+
+class CFilter2
+{
+public:
+ CFilter m_Filters[kNumChanelsMax];
+ int m_ChannelDelta;
+ int CurrentChannel;
+
+ void Init() { memset(this, 0, sizeof(*this)); }
+ Byte Decode(Byte delta)
+ {
+ return m_Filters[CurrentChannel].Decode(m_ChannelDelta, delta);
+ }
+
+};
+
+}
+
+typedef NBitm::CDecoder<CInBuffer> CBitDecoder;
+
+const int kNumHuffmanBits = 15;
+
+class CDecoder :
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ CBitDecoder m_InBitStream;
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kMMTableSize> m_MMDecoders[NMultimedia::kNumChanelsMax];
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ bool m_AudioMode;
+
+ NMultimedia::CFilter2 m_MmFilter;
+ int m_NumChannels;
+
+ UInt32 m_RepDists[kNumRepDists];
+ UInt32 m_RepDistPtr;
+
+ UInt32 m_LastLength;
+
+ Byte m_LastLevels[kMaxTableSize];
+
+ UInt64 m_PackSize;
+ bool m_IsSolid;
+
+ void InitStructures();
+ UInt32 ReadBits(int numBits);
+ bool ReadTables();
+ bool ReadLastTables();
+
+ bool DecodeMm(UInt32 pos);
+ bool DecodeLz(Int32 pos);
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+public:
+ CDecoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Decoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Decoder.cpp
new file mode 100644
index 000000000..dde7c6de3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Decoder.cpp
@@ -0,0 +1,897 @@
+// Rar3Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Rar3Decoder.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static const UInt32 kNumAlignReps = 15;
+
+static const UInt32 kSymbolReadTable = 256;
+static const UInt32 kSymbolRep = 259;
+static const UInt32 kSymbolLen2 = kSymbolRep + kNumReps;
+
+static const Byte kLenStart[kLenTableSize] = {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};
+static const Byte kLenDirectBits[kLenTableSize] = {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};
+
+static const Byte kDistDirectBits[kDistTableSize] =
+ {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,15,15,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 18,18,18,18,18,18,18,18,18,18,18,18};
+
+static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192};
+static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6};
+
+static const UInt32 kDistLimit3 = 0x2000 - 2;
+static const UInt32 kDistLimit4 = 0x40000 - 2;
+
+static const UInt32 kNormalMatchMinLen = 3;
+
+static const UInt32 kVmDataSizeMax = 1 << 16;
+static const UInt32 kVmCodeSizeMax = 1 << 16;
+
+extern "C" {
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ return p->Code / (p->Range /= total);
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ start *= p->Range;
+ p->Low += start;
+ p->Code -= start;
+ p->Range *= size;
+ p->Normalize();
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ if (p->Code / (p->Range >>= 14) < size0)
+ {
+ Range_Decode(p, 0, size0);
+ return 0;
+ }
+ else
+ {
+ Range_Decode(p, size0, (1 << 14) - size0);
+ return 1;
+ }
+}
+
+}
+
+CRangeDecoder::CRangeDecoder()
+{
+ s.GetThreshold = Range_GetThreshold;
+ s.Decode = Range_Decode;
+ s.DecodeBit = Range_DecodeBit;
+}
+
+CDecoder::CDecoder():
+ _window(0),
+ _winPos(0),
+ _wrPtr(0),
+ _lzSize(0),
+ _writtenFileSize(0),
+ _vmData(0),
+ _vmCode(0),
+ m_IsSolid(false)
+{
+ Ppmd7_Construct(&_ppmd);
+}
+
+CDecoder::~CDecoder()
+{
+ InitFilters();
+ ::MidFree(_vmData);
+ ::MidFree(_window);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
+{
+ return WriteStream(_outStream, data, size);
+}
+
+HRESULT CDecoder::WriteData(const Byte *data, UInt32 size)
+{
+ HRESULT res = S_OK;
+ if (_writtenFileSize < _unpackSize)
+ {
+ UInt32 curSize = size;
+ UInt64 remain = _unpackSize - _writtenFileSize;
+ if (remain < curSize)
+ curSize = (UInt32)remain;
+ res = WriteDataToStream(data, curSize);
+ }
+ _writtenFileSize += size;
+ return res;
+}
+
+HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr)
+{
+ if (startPtr <= endPtr)
+ return WriteData(_window + startPtr, endPtr - startPtr);
+ RINOK(WriteData(_window + startPtr, kWindowSize - startPtr));
+ return WriteData(_window, endPtr);
+}
+
+void CDecoder::ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef)
+{
+ CTempFilter *tempFilter = _tempFilters[tempFilterIndex];
+ tempFilter->InitR[6] = (UInt32)_writtenFileSize;
+ NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize);
+ NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32));
+ CFilter *filter = _filters[tempFilter->FilterIndex];
+ _vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData);
+ delete tempFilter;
+ _tempFilters[tempFilterIndex] = 0;
+}
+
+HRESULT CDecoder::WriteBuf()
+{
+ UInt32 writtenBorder = _wrPtr;
+ UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask;
+ for (int i = 0; i < _tempFilters.Size(); i++)
+ {
+ CTempFilter *filter = _tempFilters[i];
+ if (filter == NULL)
+ continue;
+ if (filter->NextWindow)
+ {
+ filter->NextWindow = false;
+ continue;
+ }
+ UInt32 blockStart = filter->BlockStart;
+ UInt32 blockSize = filter->BlockSize;
+ if (((blockStart - writtenBorder) & kWindowMask) < writeSize)
+ {
+ if (writtenBorder != blockStart)
+ {
+ RINOK(WriteArea(writtenBorder, blockStart));
+ writtenBorder = blockStart;
+ writeSize = (_winPos - writtenBorder) & kWindowMask;
+ }
+ if (blockSize <= writeSize)
+ {
+ UInt32 blockEnd = (blockStart + blockSize) & kWindowMask;
+ if (blockStart < blockEnd || blockEnd == 0)
+ _vm.SetMemory(0, _window + blockStart, blockSize);
+ else
+ {
+ UInt32 tailSize = kWindowSize - blockStart;
+ _vm.SetMemory(0, _window + blockStart, tailSize);
+ _vm.SetMemory(tailSize, _window, blockEnd);
+ }
+ NVm::CBlockRef outBlockRef;
+ ExecuteFilter(i, outBlockRef);
+ while (i + 1 < _tempFilters.Size())
+ {
+ CTempFilter *nextFilter = _tempFilters[i + 1];
+ if (nextFilter == NULL || nextFilter->BlockStart != blockStart ||
+ nextFilter->BlockSize != outBlockRef.Size || nextFilter->NextWindow)
+ break;
+ _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
+ ExecuteFilter(++i, outBlockRef);
+ }
+ WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
+ _writtenFileSize += outBlockRef.Size;
+ writtenBorder = blockEnd;
+ writeSize = (_winPos - writtenBorder) & kWindowMask;
+ }
+ else
+ {
+ for (int j = i; j < _tempFilters.Size(); j++)
+ {
+ CTempFilter *filter = _tempFilters[j];
+ if (filter != NULL && filter->NextWindow)
+ filter->NextWindow = false;
+ }
+ _wrPtr = writtenBorder;
+ return S_OK; // check it
+ }
+ }
+ }
+
+ _wrPtr = _winPos;
+ return WriteArea(writtenBorder, _winPos);
+}
+
+void CDecoder::InitFilters()
+{
+ _lastFilter = 0;
+ int i;
+ for (i = 0; i < _tempFilters.Size(); i++)
+ delete _tempFilters[i];
+ _tempFilters.Clear();
+ for (i = 0; i < _filters.Size(); i++)
+ delete _filters[i];
+ _filters.Clear();
+}
+
+bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
+{
+ CMemBitDecoder inp;
+ inp.Init(_vmData, codeSize);
+
+ UInt32 filterIndex;
+ if (firstByte & 0x80)
+ {
+ filterIndex = NVm::ReadEncodedUInt32(inp);
+ if (filterIndex == 0)
+ InitFilters();
+ else
+ filterIndex--;
+ }
+ else
+ filterIndex = _lastFilter;
+ if (filterIndex > (UInt32)_filters.Size())
+ return false;
+ _lastFilter = filterIndex;
+ bool newFilter = (filterIndex == (UInt32)_filters.Size());
+
+ CFilter *filter;
+ if (newFilter)
+ {
+ // check if too many filters
+ if (filterIndex > 1024)
+ return false;
+ filter = new CFilter;
+ _filters.Add(filter);
+ }
+ else
+ {
+ filter = _filters[filterIndex];
+ filter->ExecCount++;
+ }
+
+ int numEmptyItems = 0;
+ int i;
+ for (i = 0; i < _tempFilters.Size(); i++)
+ {
+ _tempFilters[i - numEmptyItems] = _tempFilters[i];
+ if (_tempFilters[i] == NULL)
+ numEmptyItems++;
+ if (numEmptyItems > 0)
+ _tempFilters[i] = NULL;
+ }
+ if (numEmptyItems == 0)
+ {
+ _tempFilters.Add(NULL);
+ numEmptyItems = 1;
+ }
+ CTempFilter *tempFilter = new CTempFilter;
+ _tempFilters[_tempFilters.Size() - numEmptyItems] = tempFilter;
+ tempFilter->FilterIndex = filterIndex;
+ tempFilter->ExecCount = filter->ExecCount;
+
+ UInt32 blockStart = NVm::ReadEncodedUInt32(inp);
+ if (firstByte & 0x40)
+ blockStart += 258;
+ tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask;
+ if (firstByte & 0x20)
+ filter->BlockSize = NVm::ReadEncodedUInt32(inp);
+ tempFilter->BlockSize = filter->BlockSize;
+ tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart;
+
+ memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR));
+ tempFilter->InitR[3] = NVm::kGlobalOffset;
+ tempFilter->InitR[4] = tempFilter->BlockSize;
+ tempFilter->InitR[5] = tempFilter->ExecCount;
+ if (firstByte & 0x10)
+ {
+ UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs);
+ for (int i = 0; i < NVm::kNumGpRegs; i++)
+ if (initMask & (1 << i))
+ tempFilter->InitR[i] = NVm::ReadEncodedUInt32(inp);
+ }
+ if (newFilter)
+ {
+ UInt32 vmCodeSize = NVm::ReadEncodedUInt32(inp);
+ if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0)
+ return false;
+ for (UInt32 i = 0; i < vmCodeSize; i++)
+ _vmCode[i] = (Byte)inp.ReadBits(8);
+ _vm.PrepareProgram(_vmCode, vmCodeSize, filter);
+ }
+
+ tempFilter->AllocateEmptyFixedGlobal();
+
+ Byte *globalData = &tempFilter->GlobalData[0];
+ for (i = 0; i < NVm::kNumGpRegs; i++)
+ NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]);
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize);
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why?
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], tempFilter->ExecCount);
+
+ if (firstByte & 8)
+ {
+ UInt32 dataSize = NVm::ReadEncodedUInt32(inp);
+ if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize)
+ return false;
+ CRecordVector<Byte> &globalData = tempFilter->GlobalData;
+ int requredSize = (int)(dataSize + NVm::kFixedGlobalSize);
+ if (globalData.Size() < requredSize)
+ {
+ globalData.Reserve(requredSize);
+ for (; globalData.Size() < requredSize; i++)
+ globalData.Add(0);
+ }
+ for (UInt32 i = 0; i < dataSize; i++)
+ globalData[NVm::kFixedGlobalSize + i] = (Byte)inp.ReadBits(8);
+ }
+ return true;
+}
+
+bool CDecoder::ReadVmCodeLZ()
+{
+ UInt32 firstByte = ReadBits(8);
+ UInt32 length = (firstByte & 7) + 1;
+ if (length == 7)
+ length = ReadBits(8) + 7;
+ else if (length == 8)
+ length = ReadBits(16);
+ if (length > kVmDataSizeMax)
+ return false;
+ for (UInt32 i = 0; i < length; i++)
+ _vmData[i] = (Byte)ReadBits(8);
+ return AddVmCode(firstByte, length);
+}
+
+bool CDecoder::ReadVmCodePPM()
+{
+ int firstByte = DecodePpmSymbol();
+ if (firstByte < 0)
+ return false;
+ UInt32 length = (firstByte & 7) + 1;
+ if (length == 7)
+ {
+ int b1 = DecodePpmSymbol();
+ if (b1 < 0)
+ return false;
+ length = b1 + 7;
+ }
+ else if (length == 8)
+ {
+ int b1 = DecodePpmSymbol();
+ if (b1 < 0)
+ return false;
+ int b2 = DecodePpmSymbol();
+ if (b2 < 0)
+ return false;
+ length = b1 * 256 + b2;
+ }
+ if (length > kVmDataSizeMax)
+ return false;
+ for (UInt32 i = 0; i < length; i++)
+ {
+ int b = DecodePpmSymbol();
+ if (b < 0)
+ return false;
+ _vmData[i] = (Byte)b;
+ }
+ return AddVmCode(firstByte, length);
+}
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.bitDecoder.ReadBits(numBits); }
+
+/////////////////////////////////////////////////
+// PPM
+
+HRESULT CDecoder::InitPPM()
+{
+ Byte maxOrder = (Byte)ReadBits(7);
+
+ bool reset = ((maxOrder & 0x20) != 0);
+ int maxMB = 0;
+ if (reset)
+ maxMB = (Byte)ReadBits(8);
+ else
+ {
+ if (PpmError || !Ppmd7_WasAllocated(&_ppmd))
+ return S_FALSE;
+ }
+ if (maxOrder & 0x40)
+ PpmEscChar = (Byte)ReadBits(8);
+ m_InBitStream.InitRangeCoder();
+ /*
+ if (m_InBitStream.m_BitPos != 0)
+ return S_FALSE;
+ */
+ if (reset)
+ {
+ PpmError = true;
+ maxOrder = (maxOrder & 0x1F) + 1;
+ if (maxOrder > 16)
+ maxOrder = 16 + (maxOrder - 16) * 3;
+ if (maxOrder == 1)
+ {
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+ return S_FALSE;
+ }
+ if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+ Ppmd7_Init(&_ppmd, maxOrder);
+ PpmError = false;
+ }
+ return S_OK;
+}
+
+int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.s); }
+
+HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
+{
+ keepDecompressing = false;
+ if (PpmError)
+ return S_FALSE;
+ do
+ {
+ if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
+ {
+ RINOK(WriteBuf());
+ if (_writtenFileSize > _unpackSize)
+ {
+ keepDecompressing = false;
+ return S_OK;
+ }
+ }
+ int c = DecodePpmSymbol();
+ if (c < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ if (c == PpmEscChar)
+ {
+ int nextCh = DecodePpmSymbol();
+ if (nextCh < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ if (nextCh == 0)
+ return ReadTables(keepDecompressing);
+ if (nextCh == 2 || nextCh == -1)
+ return S_OK;
+ if (nextCh == 3)
+ {
+ if (!ReadVmCodePPM())
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ continue;
+ }
+ if (nextCh == 4 || nextCh == 5)
+ {
+ UInt32 distance = 0;
+ UInt32 length = 4;
+ if (nextCh == 4)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ int c = DecodePpmSymbol();
+ if (c < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ distance = (distance << 8) + (Byte)c;
+ }
+ distance++;
+ length += 28;
+ }
+ int c = DecodePpmSymbol();
+ if (c < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ length += c;
+ if (distance >= _lzSize)
+ return S_FALSE;
+ CopyBlock(distance, length);
+ num -= (Int32)length;
+ continue;
+ }
+ }
+ PutByte((Byte)c);
+ num--;
+ }
+ while (num >= 0);
+ keepDecompressing = true;
+ return S_OK;
+}
+
+/////////////////////////////////////////////////
+// LZ
+
+HRESULT CDecoder::ReadTables(bool &keepDecompressing)
+{
+ keepDecompressing = true;
+ ReadBits((8 - m_InBitStream.bitDecoder.GetBitPosition()) & 7);
+ if (ReadBits(1) != 0)
+ {
+ _lzMode = false;
+ return InitPPM();
+ }
+
+ _lzMode = true;
+ PrevAlignBits = 0;
+ PrevAlignCount = 0;
+
+ Byte levelLevels[kLevelTableSize];
+ Byte newLevels[kTablesSizesSum];
+
+ if (ReadBits(1) == 0)
+ memset(m_LastLevels, 0, kTablesSizesSum);
+
+ int i;
+ for (i = 0; i < kLevelTableSize; i++)
+ {
+ UInt32 length = ReadBits(4);
+ if (length == 15)
+ {
+ UInt32 zeroCount = ReadBits(4);
+ if (zeroCount != 0)
+ {
+ zeroCount += 2;
+ while (zeroCount-- > 0 && i < kLevelTableSize)
+ levelLevels[i++]=0;
+ i--;
+ continue;
+ }
+ }
+ levelLevels[i] = (Byte)length;
+ }
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+ i = 0;
+ while (i < kTablesSizesSum)
+ {
+ UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number < 16)
+ {
+ newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
+ i++;
+ }
+ else if (number > kLevelTableSize)
+ return S_FALSE;
+ else
+ {
+ int num;
+ if (((number - 16) & 1) == 0)
+ num = ReadBits(3) + 3;
+ else
+ num = ReadBits(7) + 11;
+ if (number < 18)
+ {
+ if (i == 0)
+ return S_FALSE;
+ for (; num > 0 && i < kTablesSizesSum; num--, i++)
+ newLevels[i] = newLevels[i - 1];
+ }
+ else
+ {
+ for (; num > 0 && i < kTablesSizesSum; num--)
+ newLevels[i++] = 0;
+ }
+ }
+ }
+ TablesRead = true;
+
+ // original code has check here:
+ /*
+ if (InAddr > ReadTop)
+ {
+ keepDecompressing = false;
+ return true;
+ }
+ */
+
+ RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
+ RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
+ RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
+ RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
+
+ memcpy(m_LastLevels, newLevels, kTablesSizesSum);
+ return S_OK;
+}
+
+class CCoderReleaser
+{
+ CDecoder *m_Coder;
+public:
+ CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser()
+ {
+ m_Coder->ReleaseStreams();
+ }
+};
+
+HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
+{
+ if (ReadBits(1) != 0)
+ {
+ // old file
+ TablesRead = false;
+ return ReadTables(keepDecompressing);
+ }
+ // new file
+ keepDecompressing = false;
+ TablesRead = (ReadBits(1) == 0);
+ return S_OK;
+}
+
+UInt32 kDistStart[kDistTableSize];
+
+class CDistInit
+{
+public:
+ CDistInit() { Init(); }
+ void Init()
+ {
+ UInt32 start = 0;
+ for (UInt32 i = 0; i < kDistTableSize; i++)
+ {
+ kDistStart[i] = start;
+ start += (1 << kDistDirectBits[i]);
+ }
+ }
+} g_DistInit;
+
+HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
+{
+ UInt32 rep0 = _reps[0];
+ UInt32 rep1 = _reps[1];
+ UInt32 rep2 = _reps[2];
+ UInt32 rep3 = _reps[3];
+ UInt32 length = _lastLength;
+ for (;;)
+ {
+ if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
+ {
+ RINOK(WriteBuf());
+ if (_writtenFileSize > _unpackSize)
+ {
+ keepDecompressing = false;
+ return S_OK;
+ }
+ }
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number < 256)
+ {
+ PutByte((Byte)number);
+ continue;
+ }
+ else if (number == kSymbolReadTable)
+ {
+ RINOK(ReadEndOfBlock(keepDecompressing));
+ break;
+ }
+ else if (number == 257)
+ {
+ if (!ReadVmCodeLZ())
+ return S_FALSE;
+ continue;
+ }
+ else if (number == 258)
+ {
+ if (length == 0)
+ return S_FALSE;
+ }
+ else if (number < kSymbolRep + 4)
+ {
+ if (number != kSymbolRep)
+ {
+ UInt32 distance;
+ if (number == kSymbolRep + 1)
+ distance = rep1;
+ else
+ {
+ if (number == kSymbolRep + 2)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+
+ UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number >= kLenTableSize)
+ return S_FALSE;
+ length = 2 + kLenStart[number] + m_InBitStream.bitDecoder.ReadBits(kLenDirectBits[number]);
+ }
+ else
+ {
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ if (number < 271)
+ {
+ number -= 263;
+ rep0 = kLen2DistStarts[number] + m_InBitStream.bitDecoder.ReadBits(kLen2DistDirectBits[number]);
+ length = 2;
+ }
+ else if (number < 299)
+ {
+ number -= 271;
+ length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.bitDecoder.ReadBits(kLenDirectBits[number]);
+ UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number >= kDistTableSize)
+ return S_FALSE;
+ rep0 = kDistStart[number];
+ int numBits = kDistDirectBits[number];
+ if (number >= (kNumAlignBits * 2) + 2)
+ {
+ if (numBits > kNumAlignBits)
+ rep0 += (m_InBitStream.bitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
+ if (PrevAlignCount > 0)
+ {
+ PrevAlignCount--;
+ rep0 += PrevAlignBits;
+ }
+ else
+ {
+ UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number < (1 << kNumAlignBits))
+ {
+ rep0 += number;
+ PrevAlignBits = number;
+ }
+ else if (number == (1 << kNumAlignBits))
+ {
+ PrevAlignCount = kNumAlignReps;
+ rep0 += PrevAlignBits;
+ }
+ else
+ return S_FALSE;
+ }
+ }
+ else
+ rep0 += m_InBitStream.bitDecoder.ReadBits(numBits);
+ length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
+ }
+ else
+ return S_FALSE;
+ }
+ if (rep0 >= _lzSize)
+ return S_FALSE;
+ CopyBlock(rep0, length);
+ }
+ _reps[0] = rep0;
+ _reps[1] = rep1;
+ _reps[2] = rep2;
+ _reps[3] = rep3;
+ _lastLength = length;
+
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
+{
+ _writtenFileSize = 0;
+ if (!m_IsSolid)
+ {
+ _lzSize = 0;
+ _winPos = 0;
+ _wrPtr = 0;
+ for (int i = 0; i < kNumReps; i++)
+ _reps[i] = 0;
+ _lastLength = 0;
+ memset(m_LastLevels, 0, kTablesSizesSum);
+ TablesRead = false;
+ PpmEscChar = 2;
+ PpmError = true;
+ InitFilters();
+ }
+ if (!m_IsSolid || !TablesRead)
+ {
+ bool keepDecompressing;
+ RINOK(ReadTables(keepDecompressing));
+ if (!keepDecompressing)
+ return S_OK;
+ }
+
+ for (;;)
+ {
+ bool keepDecompressing;
+ if (_lzMode)
+ {
+ RINOK(DecodeLZ(keepDecompressing))
+ }
+ else
+ {
+ RINOK(DecodePPM(1 << 18, keepDecompressing))
+ }
+ UInt64 packSize = m_InBitStream.bitDecoder.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
+ if (!keepDecompressing)
+ break;
+ }
+ RINOK(WriteBuf());
+ UInt64 packSize = m_InBitStream.bitDecoder.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
+ if (_writtenFileSize < _unpackSize)
+ return S_FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try
+ {
+ if (inSize == NULL || outSize == NULL)
+ return E_INVALIDARG;
+
+ if (_vmData == 0)
+ {
+ _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
+ if (_vmData == 0)
+ return E_OUTOFMEMORY;
+ _vmCode = _vmData + kVmDataSizeMax;
+ }
+
+ if (_window == 0)
+ {
+ _window = (Byte *)::MidAlloc(kWindowSize);
+ if (_window == 0)
+ return E_OUTOFMEMORY;
+ }
+ if (!m_InBitStream.bitDecoder.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!_vm.Create())
+ return E_OUTOFMEMORY;
+
+
+ m_InBitStream.bitDecoder.SetStream(inStream);
+ m_InBitStream.bitDecoder.Init();
+ _outStream = outStream;
+
+ CCoderReleaser coderReleaser(this);
+ _unpackSize = *outSize;
+ return CodeReal(progress);
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+ // CNewException is possible here. But probably CNewException is caused
+ // by error in data stream.
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ m_IsSolid = (data[0] != 0);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Decoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Decoder.h
new file mode 100644
index 000000000..99b647dc7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Decoder.h
@@ -0,0 +1,267 @@
+// Rar3Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#ifndef __COMPRESS_RAR3_DECODER_H
+#define __COMPRESS_RAR3_DECODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "Rar3Vm.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+const UInt32 kWindowSize = 1 << 22;
+const UInt32 kWindowMask = (kWindowSize - 1);
+
+const UInt32 kNumReps = 4;
+const UInt32 kNumLen2Symbols = 8;
+const UInt32 kLenTableSize = 28;
+const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize;
+const UInt32 kDistTableSize = 60;
+
+const int kNumAlignBits = 4;
+const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1;
+
+const UInt32 kLevelTableSize = 20;
+
+const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
+
+class CBitDecoder
+{
+ UInt32 m_Value;
+ unsigned m_BitPos;
+public:
+ CInBuffer m_Stream;
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);}
+ void ReleaseStream() { m_Stream.ReleaseStream();}
+
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = 0;
+ m_Value = 0;
+ }
+
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - (m_BitPos) / 8; }
+ UInt32 GetBitPosition() const { return ((8 - m_BitPos) & 7); }
+
+ UInt32 GetValue(unsigned numBits)
+ {
+ if (m_BitPos < numBits)
+ {
+ m_BitPos += 8;
+ m_Value = (m_Value << 8) | m_Stream.ReadByte();
+ if (m_BitPos < numBits)
+ {
+ m_BitPos += 8;
+ m_Value = (m_Value << 8) | m_Stream.ReadByte();
+ }
+ }
+ return m_Value >> (m_BitPos - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ m_BitPos -= numBits;
+ m_Value = m_Value & ((1 << m_BitPos) - 1);
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ MovePos(numBits);
+ return res;
+ }
+};
+
+const UInt32 kTopValue = (1 << 24);
+const UInt32 kBot = (1 << 15);
+
+struct CRangeDecoder
+{
+ IPpmd7_RangeDec s;
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ CBitDecoder bitDecoder;
+ SRes Res;
+
+public:
+ void InitRangeCoder()
+ {
+ Code = 0;
+ Low = 0;
+ Range = 0xFFFFFFFF;
+ for (int i = 0; i < 4; i++)
+ Code = (Code << 8) | bitDecoder.ReadBits(8);
+ }
+
+ void Normalize()
+ {
+ while ((Low ^ (Low + Range)) < kTopValue ||
+ Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1))
+ {
+ Code = (Code << 8) | bitDecoder.m_Stream.ReadByte();
+ Range <<= 8;
+ Low <<= 8;
+ }
+ }
+
+ CRangeDecoder();
+};
+
+struct CFilter: public NVm::CProgram
+{
+ CRecordVector<Byte> GlobalData;
+ UInt32 BlockStart;
+ UInt32 BlockSize;
+ UInt32 ExecCount;
+ CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {}
+};
+
+struct CTempFilter: public NVm::CProgramInitState
+{
+ UInt32 BlockStart;
+ UInt32 BlockSize;
+ UInt32 ExecCount;
+ bool NextWindow;
+
+ UInt32 FilterIndex;
+};
+
+const int kNumHuffmanBits = 15;
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ CRangeDecoder m_InBitStream;
+ Byte *_window;
+ UInt32 _winPos;
+ UInt32 _wrPtr;
+ UInt64 _lzSize;
+ UInt64 _unpackSize;
+ UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written
+ CMyComPtr<ISequentialOutStream> _outStream;
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ UInt32 _reps[kNumReps];
+ UInt32 _lastLength;
+
+ Byte m_LastLevels[kTablesSizesSum];
+
+ Byte *_vmData;
+ Byte *_vmCode;
+ NVm::CVm _vm;
+ CRecordVector<CFilter *> _filters;
+ CRecordVector<CTempFilter *> _tempFilters;
+ UInt32 _lastFilter;
+
+ bool m_IsSolid;
+
+ bool _lzMode;
+
+ UInt32 PrevAlignBits;
+ UInt32 PrevAlignCount;
+
+ bool TablesRead;
+
+ CPpmd7 _ppmd;
+ int PpmEscChar;
+ bool PpmError;
+
+ HRESULT WriteDataToStream(const Byte *data, UInt32 size);
+ HRESULT WriteData(const Byte *data, UInt32 size);
+ HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr);
+ void ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef);
+ HRESULT WriteBuf();
+
+ void InitFilters();
+ bool AddVmCode(UInt32 firstByte, UInt32 codeSize);
+ bool ReadVmCodeLZ();
+ bool ReadVmCodePPM();
+
+ UInt32 ReadBits(int numBits);
+
+ HRESULT InitPPM();
+ int DecodePpmSymbol();
+ HRESULT DecodePPM(Int32 num, bool &keepDecompressing);
+
+ HRESULT ReadTables(bool &keepDecompressing);
+ HRESULT ReadEndOfBlock(bool &keepDecompressing);
+ HRESULT DecodeLZ(bool &keepDecompressing);
+ HRESULT CodeReal(ICompressProgressInfo *progress);
+public:
+ CDecoder();
+ ~CDecoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ void ReleaseStreams()
+ {
+ _outStream.Release();
+ m_InBitStream.bitDecoder.ReleaseStream();
+ }
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+ void CopyBlock(UInt32 distance, UInt32 len)
+ {
+ _lzSize += len;
+ UInt32 pos = (_winPos - distance - 1) & kWindowMask;
+ Byte *window = _window;
+ UInt32 winPos = _winPos;
+ if (kWindowSize - winPos > len && kWindowSize - pos > len)
+ {
+ const Byte *src = window + pos;
+ Byte *dest = window + winPos;
+ _winPos += len;
+ do
+ *dest++ = *src++;
+ while(--len != 0);
+ return;
+ }
+ do
+ {
+ window[winPos] = window[pos];
+ winPos = (winPos + 1) & kWindowMask;
+ pos = (pos + 1) & kWindowMask;
+ }
+ while(--len != 0);
+ _winPos = winPos;
+ }
+
+ void PutByte(Byte b)
+ {
+ _window[_winPos] = b;
+ _winPos = (_winPos + 1) & kWindowMask;
+ _lzSize++;
+ }
+
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Vm.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Vm.cpp
new file mode 100644
index 000000000..74051dd79
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Vm.cpp
@@ -0,0 +1,1091 @@
+// Rar3Vm.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/*
+Note:
+ Due to performance considerations Rar VM may set Flags C incorrectly
+ for some operands (SHL x, 0, ... ).
+ Check implementation of concrete VM command
+ to see if it sets flags right.
+*/
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/Alloc.h"
+
+#include "Rar3Vm.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+UInt32 CMemBitDecoder::ReadBits(int numBits)
+{
+ UInt32 res = 0;
+ for (;;)
+ {
+ Byte b = _bitPos < _bitSize ? _data[_bitPos >> 3] : 0;
+ int avail = (int)(8 - (_bitPos & 7));
+ if (numBits <= avail)
+ {
+ _bitPos += numBits;
+ return res | (b >> (avail - numBits)) & ((1 << numBits) - 1);
+ }
+ numBits -= avail;
+ res |= (UInt32)(b & ((1 << avail) - 1)) << numBits;
+ _bitPos += avail;
+ }
+}
+
+UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }
+
+namespace NVm {
+
+static const UInt32 kStackRegIndex = kNumRegs - 1;
+
+static const UInt32 FLAG_C = 1;
+static const UInt32 FLAG_Z = 2;
+static const UInt32 FLAG_S = 0x80000000;
+
+static const Byte CF_OP0 = 0;
+static const Byte CF_OP1 = 1;
+static const Byte CF_OP2 = 2;
+static const Byte CF_OPMASK = 3;
+static const Byte CF_BYTEMODE = 4;
+static const Byte CF_JUMP = 8;
+static const Byte CF_PROC = 16;
+static const Byte CF_USEFLAGS = 32;
+static const Byte CF_CHFLAGS = 64;
+
+static Byte kCmdFlags[]=
+{
+ /* CMD_MOV */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JMP */ CF_OP1 | CF_JUMP,
+ /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_PUSH */ CF_OP1,
+ /* CMD_POP */ CF_OP1,
+ /* CMD_CALL */ CF_OP1 | CF_PROC,
+ /* CMD_RET */ CF_OP0 | CF_PROC,
+ /* CMD_NOT */ CF_OP1 | CF_BYTEMODE,
+ /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_PUSHA */ CF_OP0,
+ /* CMD_POPA */ CF_OP0,
+ /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS,
+ /* CMD_POPF */ CF_OP0 | CF_CHFLAGS,
+ /* CMD_MOVZX */ CF_OP2,
+ /* CMD_MOVSX */ CF_OP2,
+ /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_MUL */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_DIV */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
+ /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
+ /* CMD_PRINT */ CF_OP0
+};
+
+CVm::CVm(): Mem(NULL) {}
+
+bool CVm::Create()
+{
+ if (Mem == NULL)
+ Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
+ return (Mem != NULL);
+}
+
+CVm::~CVm()
+{
+ ::MyFree(Mem);
+}
+
+// CVm::Execute can change CProgram object: it clears progarm if VM returns error.
+
+bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
+ CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData)
+{
+ memcpy(R, initState->InitR, sizeof(initState->InitR));
+ R[kStackRegIndex] = kSpaceSize;
+ R[kNumRegs] = 0;
+ Flags = 0;
+
+ UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize);
+ if (globalSize != 0)
+ memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize);
+ UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize);
+ if (staticSize != 0)
+ memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);
+
+ bool res = true;
+ #ifdef RARVM_STANDARD_FILTERS
+ if (prg->StandardFilterIndex >= 0)
+ ExecuteStandardFilter(prg->StandardFilterIndex);
+ else
+ #endif
+ {
+ res = ExecuteCode(prg);
+ if (!res)
+ prg->Commands[0].OpCode = CMD_RET;
+ }
+ UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
+ UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
+ if (newBlockPos + newBlockSize >= kSpaceSize)
+ newBlockPos = newBlockSize = 0;
+ outBlockRef.Offset = newBlockPos;
+ outBlockRef.Size = newBlockSize;
+
+ outGlobalData.Clear();
+ UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize);
+ dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize);
+ if (dataSize != 0)
+ {
+ dataSize += kFixedGlobalSize;
+ outGlobalData.Reserve(dataSize);
+ for (UInt32 i = 0; i < dataSize; i++)
+ outGlobalData.Add(Mem[kGlobalOffset + i]);
+ }
+ return res;
+}
+
+
+#define SET_IP(IP) \
+ if ((IP) >= numCommands) return true; \
+ if (--maxOpCount <= 0) return false; \
+ cmd = commands + (IP);
+
+#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0)
+#define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); }
+#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S
+#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)
+
+UInt32 CVm::GetOperand32(const COperand *op) const
+{
+ switch(op->Type)
+ {
+ case OP_TYPE_REG: return R[op->Data];
+ case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
+ default: return op->Data;
+ }
+}
+
+void CVm::SetOperand32(const COperand *op, UInt32 val)
+{
+ switch(op->Type)
+ {
+ case OP_TYPE_REG: R[op->Data] = val; return;
+ case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
+ }
+}
+
+Byte CVm::GetOperand8(const COperand *op) const
+{
+ switch(op->Type)
+ {
+ case OP_TYPE_REG: return (Byte)R[op->Data];
+ case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];;
+ default: return (Byte)op->Data;
+ }
+}
+
+void CVm::SetOperand8(const COperand *op, Byte val)
+{
+ switch(op->Type)
+ {
+ case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
+ case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
+ }
+}
+
+UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
+{
+ if (byteMode)
+ return GetOperand8(op);
+ return GetOperand32(op);
+}
+
+void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val)
+{
+ if (byteMode)
+ SetOperand8(op, (Byte)(val & 0xFF));
+ else
+ SetOperand32(op, val);
+}
+
+bool CVm::ExecuteCode(const CProgram *prg)
+{
+ Int32 maxOpCount = 25000000;
+ const CCommand *commands = &prg->Commands[0];
+ const CCommand *cmd = commands;
+ UInt32 numCommands = prg->Commands.Size();
+ for (;;)
+ {
+ switch(cmd->OpCode)
+ {
+ #ifndef RARVM_NO_VM
+
+ case CMD_MOV:
+ SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
+ break;
+ case CMD_MOVB:
+ SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2));
+ break;
+ case CMD_CMP:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ UInt32 res = v1 - GetOperand32(&cmd->Op2);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_CMPB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ Byte res = v1 - GetOperand8(&cmd->Op2);
+ res &= 0xFF;
+ Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res);
+ }
+ break;
+ case CMD_ADD:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ UInt32 res = v1 + GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_ADDB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ Byte res = v1 + GetOperand8(&cmd->Op2);
+ res &= 0xFF;
+ SetOperand8(&cmd->Op1, (Byte)res);
+ Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res));
+ }
+ break;
+ case CMD_ADC:
+ {
+ UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ UInt32 FC = (Flags & FLAG_C);
+ UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC;
+ if (cmd->ByteMode)
+ res &= 0xFF;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_SUB:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ UInt32 res = v1 - GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_SUBB:
+ {
+ UInt32 v1 = GetOperand8(&cmd->Op1);
+ UInt32 res = v1 - GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, (Byte)res);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_SBB:
+ {
+ UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ UInt32 FC = (Flags & FLAG_C);
+ UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC;
+ // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S);
+ if (cmd->ByteMode)
+ res &= 0xFF;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_INC:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) + 1;
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_INCB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) + 1;
+ SetOperand8(&cmd->Op1, res);;
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_DEC:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) - 1;
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_DECB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) - 1;
+ SetOperand8(&cmd->Op1, res);;
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_XOR:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_XORB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_AND:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_ANDB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_OR:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_ORB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_TEST:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_TESTB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_NOT:
+ SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1));
+ break;
+ case CMD_NEG:
+ {
+ UInt32 res = 0 - GetOperand32(&cmd->Op1);
+ SetOperand32(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S);
+ }
+ break;
+ case CMD_NEGB:
+ {
+ Byte res = (Byte)(0 - GetOperand8(&cmd->Op1));
+ SetOperand8(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res);
+ }
+ break;
+
+ case CMD_SHL:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ int v2 = (int)GetOperand32(&cmd->Op2);
+ UInt32 res = v1 << v2;
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0);
+ }
+ break;
+ case CMD_SHLB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ int v2 = (int)GetOperand8(&cmd->Op2);
+ Byte res = (Byte)(v1 << v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0);
+ }
+ break;
+ case CMD_SHR:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ int v2 = (int)GetOperand32(&cmd->Op2);
+ UInt32 res = v1 >> v2;
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SHRB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ int v2 = (int)GetOperand8(&cmd->Op2);
+ Byte res = (Byte)(v1 >> v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SAR:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ int v2 = (int)GetOperand32(&cmd->Op2);
+ UInt32 res = UInt32(((Int32)v1) >> v2);
+ SetOperand32(&cmd->Op1, res);
+ Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SARB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ int v2 = (int)GetOperand8(&cmd->Op2);
+ Byte res = (Byte)(((signed char)v1) >> v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+
+ case CMD_JMP:
+ SET_IP_OP1;
+ continue;
+ case CMD_JZ:
+ if ((Flags & FLAG_Z) != 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JNZ:
+ if ((Flags & FLAG_Z) == 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JS:
+ if ((Flags & FLAG_S) != 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JNS:
+ if ((Flags & FLAG_S) == 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JB:
+ if ((Flags & FLAG_C) != 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JBE:
+ if ((Flags & (FLAG_C | FLAG_Z)) != 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JA:
+ if ((Flags & (FLAG_C | FLAG_Z)) == 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JAE:
+ if ((Flags & FLAG_C) == 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+
+ case CMD_PUSH:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1));
+ break;
+ case CMD_POP:
+ SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]));
+ R[kStackRegIndex] += 4;
+ break;
+ case CMD_CALL:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1));
+ SET_IP_OP1;
+ continue;
+
+ case CMD_PUSHA:
+ {
+ for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4)
+ SetValue32(&Mem[SP & kSpaceMask], R[i]);
+ R[kStackRegIndex] -= kNumRegs * 4;
+ }
+ break;
+ case CMD_POPA:
+ {
+ for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4)
+ R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]);
+ }
+ break;
+ case CMD_PUSHF:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags);
+ break;
+ case CMD_POPF:
+ Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
+ R[kStackRegIndex] += 4;
+ break;
+
+ case CMD_MOVZX:
+ SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2));
+ break;
+ case CMD_MOVSX:
+ SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2));
+ break;
+ case CMD_XCHG:
+ {
+ UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2));
+ SetOperand(cmd->ByteMode, &cmd->Op2, v1);
+ }
+ break;
+ case CMD_MUL:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ }
+ break;
+ case CMD_MULB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, res);
+ }
+ break;
+ case CMD_DIV:
+ {
+ UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2);
+ if (divider != 0)
+ {
+ UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ }
+ }
+ break;
+
+ #endif
+
+ case CMD_RET:
+ {
+ if (R[kStackRegIndex] >= kSpaceSize)
+ return true;
+ UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
+ SET_IP(ip);
+ R[kStackRegIndex] += 4;
+ continue;
+ }
+ case CMD_PRINT:
+ break;
+ }
+ cmd++;
+ --maxOpCount;
+ }
+}
+
+
+//////////////////////////////////////////////////////
+// Read program
+
+UInt32 ReadEncodedUInt32(CMemBitDecoder &inp)
+{
+ switch(inp.ReadBits(2))
+ {
+ case 0:
+ return inp.ReadBits(4);
+ case 1:
+ {
+ UInt32 v = inp.ReadBits(4);
+ if (v == 0)
+ return 0xFFFFFF00 | inp.ReadBits(8);
+ else
+ return (v << 4) | inp.ReadBits(4);
+ }
+ case 2:
+ return inp.ReadBits(16);
+ default:
+ return inp.ReadBits(32);
+ }
+}
+
+void CVm::DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode)
+{
+ if (inp.ReadBit())
+ {
+ op.Type = OP_TYPE_REG;
+ op.Data = inp.ReadBits(kNumRegBits);
+ }
+ else if (inp.ReadBit() == 0)
+ {
+ op.Type = OP_TYPE_INT;
+ if (byteMode)
+ op.Data = inp.ReadBits(8);
+ else
+ op.Data = ReadEncodedUInt32(inp);
+ }
+ else
+ {
+ op.Type = OP_TYPE_REGMEM;
+ if (inp.ReadBit() == 0)
+ {
+ op.Data = inp.ReadBits(kNumRegBits);
+ op.Base = 0;
+ }
+ else
+ {
+ if (inp.ReadBit() == 0)
+ op.Data = inp.ReadBits(kNumRegBits);
+ else
+ op.Data = kNumRegs;
+ op.Base = ReadEncodedUInt32(inp);
+ }
+ }
+}
+
+void CVm::ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
+{
+ CMemBitDecoder inp;
+ inp.Init(code, codeSize);
+
+ prg->StaticData.Clear();
+ if (inp.ReadBit())
+ {
+ UInt32 dataSize = ReadEncodedUInt32(inp) + 1;
+ for (UInt32 i = 0; inp.Avail() && i < dataSize; i++)
+ prg->StaticData.Add((Byte)inp.ReadBits(8));
+ }
+ while (inp.Avail())
+ {
+ prg->Commands.Add(CCommand());
+ CCommand *cmd = &prg->Commands.Back();
+ if (inp.ReadBit() == 0)
+ cmd->OpCode = (ECommand)inp.ReadBits(3);
+ else
+ cmd->OpCode = (ECommand)(8 + inp.ReadBits(5));
+ if (kCmdFlags[cmd->OpCode] & CF_BYTEMODE)
+ cmd->ByteMode = (inp.ReadBit()) ? true : false;
+ else
+ cmd->ByteMode = 0;
+ int opNum = (kCmdFlags[cmd->OpCode] & CF_OPMASK);
+ if (opNum > 0)
+ {
+ DecodeArg(inp, cmd->Op1, cmd->ByteMode);
+ if (opNum == 2)
+ DecodeArg(inp, cmd->Op2, cmd->ByteMode);
+ else
+ {
+ if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[cmd->OpCode] & (CF_JUMP | CF_PROC)))
+ {
+ int Distance = cmd->Op1.Data;
+ if (Distance >= 256)
+ Distance -= 256;
+ else
+ {
+ if (Distance >= 136)
+ Distance -= 264;
+ else if (Distance >= 16)
+ Distance -= 8;
+ else if (Distance >= 8)
+ Distance -= 16;
+ Distance += prg->Commands.Size() - 1;
+ }
+ cmd->Op1.Data = Distance;
+ }
+ }
+ }
+ if (cmd->ByteMode)
+ {
+ switch (cmd->OpCode)
+ {
+ case CMD_MOV: cmd->OpCode = CMD_MOVB; break;
+ case CMD_CMP: cmd->OpCode = CMD_CMPB; break;
+ case CMD_ADD: cmd->OpCode = CMD_ADDB; break;
+ case CMD_SUB: cmd->OpCode = CMD_SUBB; break;
+ case CMD_INC: cmd->OpCode = CMD_INCB; break;
+ case CMD_DEC: cmd->OpCode = CMD_DECB; break;
+ case CMD_XOR: cmd->OpCode = CMD_XORB; break;
+ case CMD_AND: cmd->OpCode = CMD_ANDB; break;
+ case CMD_OR: cmd->OpCode = CMD_ORB; break;
+ case CMD_TEST: cmd->OpCode = CMD_TESTB; break;
+ case CMD_NEG: cmd->OpCode = CMD_NEGB; break;
+ case CMD_SHL: cmd->OpCode = CMD_SHLB; break;
+ case CMD_SHR: cmd->OpCode = CMD_SHRB; break;
+ case CMD_SAR: cmd->OpCode = CMD_SARB; break;
+ case CMD_MUL: cmd->OpCode = CMD_MULB; break;
+ }
+ }
+ }
+}
+
+#ifdef RARVM_STANDARD_FILTERS
+
+enum EStandardFilter
+{
+ SF_E8,
+ SF_E8E9,
+ SF_ITANIUM,
+ SF_RGB,
+ SF_AUDIO,
+ SF_DELTA,
+ SF_UPCASE
+};
+
+struct StandardFilterSignature
+{
+ UInt32 Length;
+ UInt32 CRC;
+ EStandardFilter Type;
+}
+kStdFilters[]=
+{
+ { 53, 0xad576887, SF_E8 },
+ { 57, 0x3cd7e57e, SF_E8E9 },
+ { 120, 0x3769893f, SF_ITANIUM },
+ { 29, 0x0e06077d, SF_DELTA },
+ { 149, 0x1c2c5dc8, SF_RGB },
+ { 216, 0xbc85e701, SF_AUDIO },
+ { 40, 0x46b9c560, SF_UPCASE }
+};
+
+static int FindStandardFilter(const Byte *code, UInt32 codeSize)
+{
+ UInt32 crc = CrcCalc(code, codeSize);
+ for (int i = 0; i < sizeof(kStdFilters) / sizeof(kStdFilters[0]); i++)
+ {
+ StandardFilterSignature &sfs = kStdFilters[i];
+ if (sfs.CRC == crc && sfs.Length == codeSize)
+ return i;
+ }
+ return -1;
+}
+
+#endif
+
+void CVm::PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
+{
+ Byte xorSum = 0;
+ for (UInt32 i = 1; i < codeSize; i++)
+ xorSum ^= code[i];
+
+ prg->Commands.Clear();
+ #ifdef RARVM_STANDARD_FILTERS
+ prg->StandardFilterIndex = -1;
+ #endif
+
+ if (xorSum == code[0] && codeSize > 0)
+ {
+ #ifdef RARVM_STANDARD_FILTERS
+ prg->StandardFilterIndex = FindStandardFilter(code, codeSize);
+ if (prg->StandardFilterIndex >= 0)
+ return;
+ #endif
+ // 1 byte for checksum
+ ReadVmProgram(code + 1, codeSize - 1, prg);
+ }
+ prg->Commands.Add(CCommand());
+ CCommand *cmd = &prg->Commands.Back();
+ cmd->OpCode = CMD_RET;
+}
+
+void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize)
+{
+ if (pos < kSpaceSize && data != Mem + pos)
+ memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos));
+}
+
+#ifdef RARVM_STANDARD_FILTERS
+
+static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
+{
+ if (dataSize <= 4)
+ return;
+ dataSize -= 4;
+ const UInt32 kFileSize = 0x1000000;
+ Byte cmpByte2 = (e9 ? 0xE9 : 0xE8);
+ for (UInt32 curPos = 0; curPos < dataSize;)
+ {
+ Byte curByte = *(data++);
+ curPos++;
+ if (curByte == 0xE8 || curByte == cmpByte2)
+ {
+ UInt32 offset = curPos + fileOffset;
+ UInt32 addr = (Int32)GetValue32(data);
+ if (addr < kFileSize)
+ SetValue32(data, addr - offset);
+ else if ((Int32)addr < 0 && (Int32)(addr + offset) >= 0)
+ SetValue32(data, addr + kFileSize);
+ data += 4;
+ curPos += 4;
+ }
+ }
+}
+
+static inline UInt32 ItaniumGetOpType(const Byte *data, int bitPos)
+{
+ return (data[(unsigned int)bitPos >> 3] >> (bitPos & 7)) & 0xF;
+}
+
+
+static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
+{
+ UInt32 curPos = 0;
+ fileOffset >>= 4;
+ while (curPos < dataSize - 21)
+ {
+ int b = (data[0] & 0x1F) - 0x10;
+ if (b >= 0)
+ {
+ static Byte kCmdMasks[16] = {4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
+ Byte cmdMask = kCmdMasks[b];
+ if (cmdMask != 0)
+ for (int i = 0; i < 3; i++)
+ if (cmdMask & (1 << i))
+ {
+ int startPos = i * 41 + 18;
+ if (ItaniumGetOpType(data, startPos + 24) == 5)
+ {
+ const UInt32 kMask = 0xFFFFF;
+ Byte *p = data + ((unsigned int)startPos >> 3);
+ UInt32 bitField = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
+ int inBit = (startPos & 7);
+ UInt32 offset = (bitField >> inBit) & kMask;
+ UInt32 andMask = ~(kMask << inBit);
+ bitField = ((offset - fileOffset) & kMask) << inBit;
+ for (int j = 0; j < 3; j++)
+ {
+ p[j] &= andMask;
+ p[j] |= bitField;
+ andMask >>= 8;
+ bitField >>= 8;
+ }
+ }
+ }
+ }
+ data += 16;
+ curPos += 16;
+ fileOffset++;
+ }
+}
+
+static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels)
+{
+ UInt32 srcPos = 0;
+ UInt32 border = dataSize * 2;
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ Byte prevByte = 0;
+ for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels)
+ data[destPos] = (prevByte = prevByte - data[srcPos++]);
+ }
+}
+
+static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR)
+{
+ Byte *destData = srcData + dataSize;
+ const UInt32 numChannels = 3;
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ Byte prevByte = 0;
+
+ for (UInt32 i = curChannel; i < dataSize; i+= numChannels)
+ {
+ unsigned int predicted;
+ if (i < width)
+ predicted = prevByte;
+ else
+ {
+ unsigned int upperLeftByte = destData[i - width];
+ unsigned int upperByte = destData[i - width + 3];
+ predicted = prevByte + upperByte - upperLeftByte;
+ int pa = abs((int)(predicted - prevByte));
+ int pb = abs((int)(predicted - upperByte));
+ int pc = abs((int)(predicted - upperLeftByte));
+ if (pa <= pb && pa <= pc)
+ predicted = prevByte;
+ else
+ if (pb <= pc)
+ predicted = upperByte;
+ else
+ predicted = upperLeftByte;
+ }
+ destData[i] = prevByte = (Byte)(predicted - *(srcData++));
+ }
+ }
+ if (dataSize < 3)
+ return;
+ for (UInt32 i = posR, border = dataSize - 2; i < border; i += 3)
+ {
+ Byte g = destData[i + 1];
+ destData[i] = destData[i] + g;
+ destData[i + 2] = destData[i + 2] + g;
+ }
+}
+
+static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels)
+{
+ Byte *destData = srcData + dataSize;
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ UInt32 prevByte = 0, prevDelta = 0, dif[7];
+ Int32 D1 = 0, D2 = 0, D3;
+ Int32 K1 = 0, K2 = 0, K3 = 0;
+ memset(dif, 0, sizeof(dif));
+
+ for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++)
+ {
+ D3 = D2;
+ D2 = prevDelta - D1;
+ D1 = prevDelta;
+
+ UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3;
+ predicted = (predicted >> 3) & 0xFF;
+
+ UInt32 curByte = *(srcData++);
+
+ predicted -= curByte;
+ destData[i] = (Byte)predicted;
+ prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte);
+ prevByte = predicted;
+
+ Int32 D = ((Int32)(signed char)curByte) << 3;
+
+ dif[0] += abs(D);
+ dif[1] += abs(D - D1);
+ dif[2] += abs(D + D1);
+ dif[3] += abs(D - D2);
+ dif[4] += abs(D + D2);
+ dif[5] += abs(D - D3);
+ dif[6] += abs(D + D3);
+
+ if ((byteCount & 0x1F) == 0)
+ {
+ UInt32 minDif = dif[0], numMinDif = 0;
+ dif[0] = 0;
+ for (int j = 1; j < sizeof(dif) / sizeof(dif[0]); j++)
+ {
+ if (dif[j] < minDif)
+ {
+ minDif = dif[j];
+ numMinDif = j;
+ }
+ dif[j] = 0;
+ }
+ switch (numMinDif)
+ {
+ case 1: if (K1 >= -16) K1--; break;
+ case 2: if (K1 < 16) K1++; break;
+ case 3: if (K2 >= -16) K2--; break;
+ case 4: if (K2 < 16) K2++; break;
+ case 5: if (K3 >= -16) K3--; break;
+ case 6: if (K3 < 16) K3++; break;
+ }
+ }
+ }
+ }
+}
+
+static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
+{
+ UInt32 srcPos = 0, destPos = dataSize;
+ while (srcPos < dataSize)
+ {
+ Byte curByte = data[srcPos++];
+ if (curByte == 2 && (curByte = data[srcPos++]) != 2)
+ curByte -= 32;
+ data[destPos++] = curByte;
+ }
+ return destPos - dataSize;
+}
+
+void CVm::ExecuteStandardFilter(int filterIndex)
+{
+ UInt32 dataSize = R[4];
+ if (dataSize >= kGlobalOffset)
+ return;
+ EStandardFilter filterType = kStdFilters[filterIndex].Type;
+
+ switch (filterType)
+ {
+ case SF_E8:
+ case SF_E8E9:
+ E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9));
+ break;
+ case SF_ITANIUM:
+ ItaniumDecode(Mem, dataSize, R[6]);
+ break;
+ case SF_DELTA:
+ if (dataSize >= kGlobalOffset / 2)
+ break;
+ SetBlockPos(dataSize);
+ DeltaDecode(Mem, dataSize, R[0]);
+ break;
+ case SF_RGB:
+ if (dataSize >= kGlobalOffset / 2)
+ break;
+ {
+ UInt32 width = R[0];
+ if (width <= 3)
+ break;
+ SetBlockPos(dataSize);
+ RgbDecode(Mem, dataSize, width, R[1]);
+ }
+ break;
+ case SF_AUDIO:
+ if (dataSize >= kGlobalOffset / 2)
+ break;
+ SetBlockPos(dataSize);
+ AudioDecode(Mem, dataSize, R[0]);
+ break;
+ case SF_UPCASE:
+ if (dataSize >= kGlobalOffset / 2)
+ break;
+ UInt32 destSize = UpCaseDecode(Mem, dataSize);
+ SetBlockSize(destSize);
+ SetBlockPos(dataSize);
+ break;
+ }
+}
+
+#endif
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Vm.h b/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Vm.h
new file mode 100644
index 000000000..c02534c61
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar3Vm.h
@@ -0,0 +1,179 @@
+// Rar3Vm.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef __COMPRESS_RAR3_VM_H
+#define __COMPRESS_RAR3_VM_H
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/MyVector.h"
+#include "Common/Types.h"
+
+#define RARVM_STANDARD_FILTERS
+
+namespace NCompress {
+namespace NRar3 {
+
+class CMemBitDecoder
+{
+ const Byte *_data;
+ UInt32 _bitSize;
+ UInt32 _bitPos;
+public:
+ void Init(const Byte *data, UInt32 byteSize)
+ {
+ _data = data;
+ _bitSize = (byteSize << 3);
+ _bitPos = 0;
+ }
+ UInt32 ReadBits(int numBits);
+ UInt32 ReadBit();
+ bool Avail() const { return (_bitPos < _bitSize); }
+};
+
+namespace NVm {
+
+inline UInt32 GetValue32(const void *addr) { return GetUi32(addr); }
+inline void SetValue32(void *addr, UInt32 value) { SetUi32(addr, value); }
+
+UInt32 ReadEncodedUInt32(CMemBitDecoder &inp);
+
+const int kNumRegBits = 3;
+const UInt32 kNumRegs = 1 << kNumRegBits;
+const UInt32 kNumGpRegs = kNumRegs - 1;
+
+const UInt32 kSpaceSize = 0x40000;
+const UInt32 kSpaceMask = kSpaceSize -1;
+const UInt32 kGlobalOffset = 0x3C000;
+const UInt32 kGlobalSize = 0x2000;
+const UInt32 kFixedGlobalSize = 64;
+
+namespace NGlobalOffset
+{
+ const UInt32 kBlockSize = 0x1C;
+ const UInt32 kBlockPos = 0x20;
+ const UInt32 kExecCount = 0x2C;
+ const UInt32 kGlobalMemOutSize = 0x30;
+}
+
+enum ECommand
+{
+ CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC,
+ CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB,
+ CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT,
+ CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF,
+ CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT,
+
+ CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB,
+ CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB,
+ CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB
+};
+
+enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE};
+
+// Addr in COperand object can link (point) to CVm object!!!
+
+struct COperand
+{
+ EOpType Type;
+ UInt32 Data;
+ UInt32 Base;
+ COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {}
+};
+
+struct CCommand
+{
+ ECommand OpCode;
+ bool ByteMode;
+ COperand Op1, Op2;
+};
+
+struct CBlockRef
+{
+ UInt32 Offset;
+ UInt32 Size;
+};
+
+struct CProgram
+{
+ CRecordVector<CCommand> Commands;
+ #ifdef RARVM_STANDARD_FILTERS
+ int StandardFilterIndex;
+ #endif
+ CRecordVector<Byte> StaticData;
+};
+
+struct CProgramInitState
+{
+ UInt32 InitR[kNumGpRegs];
+ CRecordVector<Byte> GlobalData;
+
+ void AllocateEmptyFixedGlobal()
+ {
+ GlobalData.Clear();
+ GlobalData.Reserve(NVm::kFixedGlobalSize);
+ for (UInt32 i = 0; i < NVm::kFixedGlobalSize; i++)
+ GlobalData.Add(0);
+ }
+};
+
+class CVm
+{
+ static UInt32 GetValue(bool byteMode, const void *addr)
+ {
+ if (byteMode)
+ return(*(const Byte *)addr);
+ else
+ return GetUi32(addr);
+ }
+
+ static void SetValue(bool byteMode, void *addr, UInt32 value)
+ {
+ if (byteMode)
+ *(Byte *)addr = (Byte)value;
+ else
+ SetUi32(addr, value);
+ }
+
+ UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); }
+
+ void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); }
+ void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); }
+public:
+ static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); }
+private:
+ UInt32 GetOperand32(const COperand *op) const;
+ void SetOperand32(const COperand *op, UInt32 val);
+ Byte GetOperand8(const COperand *op) const;
+ void SetOperand8(const COperand *op, Byte val);
+ UInt32 GetOperand(bool byteMode, const COperand *op) const;
+ void SetOperand(bool byteMode, const COperand *op, UInt32 val);
+
+ void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode);
+
+ bool ExecuteCode(const CProgram *prg);
+
+ #ifdef RARVM_STANDARD_FILTERS
+ void ExecuteStandardFilter(int filterIndex);
+ #endif
+
+ Byte *Mem;
+ UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization)
+ UInt32 Flags;
+ void ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg);
+public:
+ CVm();
+ ~CVm();
+ bool Create();
+ void PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg);
+ void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize);
+ bool Execute(CProgram *prg, const CProgramInitState *initState,
+ CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData);
+ const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; }
+
+};
+
+#endif
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/RarCodecsRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/RarCodecsRegister.cpp
new file mode 100644
index 000000000..e3f6a05c4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/RarCodecsRegister.cpp
@@ -0,0 +1,26 @@
+// RarCodecsRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Rar1Decoder.h"
+#include "Rar2Decoder.h"
+#include "Rar3Decoder.h"
+
+#define CREATE_CODEC(x) static void *CreateCodec ## x() { return (void *)(ICompressCoder *)(new NCompress::NRar ## x::CDecoder); }
+
+CREATE_CODEC(1)
+CREATE_CODEC(2)
+CREATE_CODEC(3)
+
+#define RAR_CODEC(x, name) { CreateCodec ## x, 0, 0x040300 + x, L"Rar" name, 1, false }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ RAR_CODEC(1, L"1"),
+ RAR_CODEC(2, L"2"),
+ RAR_CODEC(3, L"3"),
+};
+
+REGISTER_CODECS(Rar)
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ShrinkDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ShrinkDecoder.cpp
new file mode 100644
index 000000000..a89d323c6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ShrinkDecoder.cpp
@@ -0,0 +1,145 @@
+// ShrinkDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "BitlDecoder.h"
+#include "ShrinkDecoder.h"
+
+namespace NCompress {
+namespace NShrink {
+
+static const UInt32 kBufferSize = (1 << 20);
+static const int kNumMinBits = 9;
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ NBitl::CBaseDecoder<CInBuffer> inBuffer;
+ COutBuffer outBuffer;
+
+ if (!inBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ inBuffer.SetStream(inStream);
+ inBuffer.Init();
+
+ if (!outBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ outBuffer.SetStream(outStream);
+ outBuffer.Init();
+
+ UInt64 prevPos = 0;
+ int numBits = kNumMinBits;
+ UInt32 head = 257;
+ bool needPrev = false;
+ UInt32 lastSymbol = 0;
+
+ int i;
+ for (i = 0; i < kNumItems; i++)
+ _parents[i] = 0;
+ for (i = 0; i < kNumItems; i++)
+ _suffixes[i] = 0;
+ for (i = 0; i < 257; i++)
+ _isFree[i] = false;
+ for (; i < kNumItems; i++)
+ _isFree[i] = true;
+
+ for (;;)
+ {
+ UInt32 symbol = inBuffer.ReadBits(numBits);
+ if (inBuffer.ExtraBitsWereRead())
+ break;
+ if (_isFree[symbol])
+ return S_FALSE;
+ if (symbol == 256)
+ {
+ UInt32 symbol = inBuffer.ReadBits(numBits);
+ if (symbol == 1)
+ {
+ if (numBits < kNumMaxBits)
+ numBits++;
+ }
+ else if (symbol == 2)
+ {
+ if (needPrev)
+ _isFree[head - 1] = true;
+ for (i = 257; i < kNumItems; i++)
+ _isParent[i] = false;
+ for (i = 257; i < kNumItems; i++)
+ if (!_isFree[i])
+ _isParent[_parents[i]] = true;
+ for (i = 257; i < kNumItems; i++)
+ if (!_isParent[i])
+ _isFree[i] = true;
+ head = 257;
+ while (head < kNumItems && !_isFree[head])
+ head++;
+ if (head < kNumItems)
+ {
+ needPrev = true;
+ _isFree[head] = false;
+ _parents[head] = (UInt16)lastSymbol;
+ head++;
+ }
+ }
+ else
+ return S_FALSE;
+ continue;
+ }
+ UInt32 cur = symbol;
+ i = 0;
+ int corectionIndex = -1;
+ while (cur >= 256)
+ {
+ if (cur == head - 1)
+ corectionIndex = i;
+ _stack[i++] = _suffixes[cur];
+ cur = _parents[cur];
+ }
+ _stack[i++] = (Byte)cur;
+ if (needPrev)
+ {
+ _suffixes[head - 1] = (Byte)cur;
+ if (corectionIndex >= 0)
+ _stack[corectionIndex] = (Byte)cur;
+ }
+ while (i > 0)
+ outBuffer.WriteByte((_stack[--i]));
+ while (head < kNumItems && !_isFree[head])
+ head++;
+ if (head < kNumItems)
+ {
+ needPrev = true;
+ _isFree[head] = false;
+ _parents[head] = (UInt16)symbol;
+ head++;
+ }
+ else
+ needPrev = false;
+ lastSymbol = symbol;
+
+ UInt64 nowPos = outBuffer.GetProcessedSize();
+ if (progress != NULL && nowPos - prevPos > (1 << 18))
+ {
+ prevPos = nowPos;
+ UInt64 packSize = inBuffer.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &nowPos));
+ }
+ }
+ return outBuffer.Flush();
+}
+
+STDMETHODIMP CDecoder ::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ShrinkDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/ShrinkDecoder.h
new file mode 100644
index 000000000..9bbecd41b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ShrinkDecoder.h
@@ -0,0 +1,38 @@
+// ShrinkDecoder.h
+
+#ifndef __COMPRESS_SHRINK_DECODER_H
+#define __COMPRESS_SHRINK_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NShrink {
+
+const int kNumMaxBits = 13;
+const UInt32 kNumItems = 1 << kNumMaxBits;
+
+class CDecoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ UInt16 _parents[kNumItems];
+ Byte _suffixes[kNumItems];
+ Byte _stack[kNumItems];
+ bool _isFree[kNumItems];
+ bool _isParent[kNumItems];
+
+public:
+ MY_UNKNOWN_IMP
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ZDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ZDecoder.cpp
new file mode 100644
index 000000000..e28c64518
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ZDecoder.cpp
@@ -0,0 +1,159 @@
+// ZDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "ZDecoder.h"
+
+namespace NCompress {
+namespace NZ {
+
+static const UInt32 kBufferSize = (1 << 20);
+static const Byte kNumBitsMask = 0x1F;
+static const Byte kBlockModeMask = 0x80;
+static const int kNumMinBits = 9;
+static const int kNumMaxBits = 16;
+
+void CDecoder::Free()
+{
+ MyFree(_parents); _parents = 0;
+ MyFree(_suffixes); _suffixes = 0;
+ MyFree(_stack); _stack = 0;
+}
+
+CDecoder::~CDecoder() { Free(); }
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CInBuffer inBuffer;
+ COutBuffer outBuffer;
+
+ if (!inBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ inBuffer.SetStream(inStream);
+ inBuffer.Init();
+
+ if (!outBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ outBuffer.SetStream(outStream);
+ outBuffer.Init();
+
+ int maxbits = _properties & kNumBitsMask;
+ if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
+ return S_FALSE;
+ UInt32 numItems = 1 << maxbits;
+ bool blockMode = ((_properties & kBlockModeMask) != 0);
+
+ if (maxbits != _numMaxBits || _parents == 0 || _suffixes == 0 || _stack == 0)
+ {
+ Free();
+ _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (_parents == 0) return E_OUTOFMEMORY;
+ _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_suffixes == 0) return E_OUTOFMEMORY;
+ _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_stack == 0) return E_OUTOFMEMORY;
+ _numMaxBits = maxbits;
+ }
+
+ UInt64 prevPos = 0;
+ int numBits = kNumMinBits;
+ UInt32 head = blockMode ? 257 : 256;
+
+ bool needPrev = false;
+
+ unsigned bitPos = 0;
+ unsigned numBufBits = 0;
+
+ Byte buf[kNumMaxBits + 4];
+
+ _parents[256] = 0; // virus protection
+ _suffixes[256] = 0;
+
+ for (;;)
+ {
+ if (numBufBits == bitPos)
+ {
+ numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8;
+ bitPos = 0;
+ UInt64 nowPos = outBuffer.GetProcessedSize();
+ if (progress != NULL && nowPos - prevPos >= (1 << 18))
+ {
+ prevPos = nowPos;
+ UInt64 packSize = inBuffer.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &nowPos));
+ }
+ }
+ unsigned bytePos = bitPos >> 3;
+ UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16);
+ symbol >>= (bitPos & 7);
+ symbol &= (1 << numBits) - 1;
+ bitPos += numBits;
+ if (bitPos > numBufBits)
+ break;
+ if (symbol >= head)
+ return S_FALSE;
+ if (blockMode && symbol == 256)
+ {
+ numBufBits = bitPos = 0;
+ numBits = kNumMinBits;
+ head = 257;
+ needPrev = false;
+ continue;
+ }
+ UInt32 cur = symbol;
+ int i = 0;
+ while (cur >= 256)
+ {
+ _stack[i++] = _suffixes[cur];
+ cur = _parents[cur];
+ }
+ _stack[i++] = (Byte)cur;
+ if (needPrev)
+ {
+ _suffixes[head - 1] = (Byte)cur;
+ if (symbol == head - 1)
+ _stack[0] = (Byte)cur;
+ }
+ do
+ outBuffer.WriteByte((_stack[--i]));
+ while (i > 0);
+ if (head < numItems)
+ {
+ needPrev = true;
+ _parents[head++] = (UInt16)symbol;
+ if (head > ((UInt32)1 << numBits))
+ {
+ if (numBits < maxbits)
+ {
+ numBufBits = bitPos = 0;
+ numBits++;
+ }
+ }
+ }
+ else
+ needPrev = false;
+ }
+ return outBuffer.Flush();
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ _properties = data[0];
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ZDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/ZDecoder.h
new file mode 100644
index 000000000..2bd83a177
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ZDecoder.h
@@ -0,0 +1,42 @@
+// ZDecoder.h
+
+#ifndef __COMPRESS_Z_DECODER_H
+#define __COMPRESS_Z_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NZ {
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ UInt16 *_parents;
+ Byte *_suffixes;
+ Byte *_stack;
+ Byte _properties;
+ int _numMaxBits;
+
+public:
+ CDecoder(): _parents(0), _suffixes(0), _stack(0), _properties(0), _numMaxBits(0) {};
+ ~CDecoder();
+ void Free();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ZlibDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ZlibDecoder.cpp
new file mode 100644
index 000000000..90d6715db
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ZlibDecoder.cpp
@@ -0,0 +1,89 @@
+// ZlibDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "ZlibDecoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } catch(...) { return S_FALSE; }
+
+#define ADLER_MOD 65521
+#define ADLER_LOOP_MAX 5550
+
+UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size)
+{
+ UInt32 a = adler & 0xFFFF;
+ UInt32 b = (adler >> 16) & 0xFFFF;
+ while (size > 0)
+ {
+ unsigned curSize = (size > ADLER_LOOP_MAX) ? ADLER_LOOP_MAX : (unsigned )size;
+ unsigned i;
+ for (i = 0; i < curSize; i++)
+ {
+ a += buf[i];
+ b += a;
+ }
+ buf += curSize;
+ size -= curSize;
+ a %= ADLER_MOD;
+ b %= ADLER_MOD;
+ }
+ return (b << 16) + a;
+}
+
+STDMETHODIMP COutStreamWithAdler::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = _stream->Write(data, size, &size);
+ _adler = Adler32_Update(_adler, (const Byte *)data, size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ DEFLATE_TRY_BEGIN
+ if (!AdlerStream)
+ AdlerStream = AdlerSpec = new COutStreamWithAdler;
+ if (!DeflateDecoder)
+ {
+ DeflateDecoderSpec = new NDeflate::NDecoder::CCOMCoder;
+ DeflateDecoderSpec->ZlibMode = true;
+ DeflateDecoder = DeflateDecoderSpec;
+ }
+
+ Byte buf[2];
+ RINOK(ReadStream_FALSE(inStream, buf, 2));
+ int method = buf[0] & 0xF;
+ if (method != 8)
+ return S_FALSE;
+ // int dicSize = buf[0] >> 4;
+ if ((((UInt32)buf[0] << 8) + buf[1]) % 31 != 0)
+ return S_FALSE;
+ if ((buf[1] & 0x20) != 0) // dictPresent
+ return S_FALSE;
+ // int level = (buf[1] >> 6);
+
+ AdlerSpec->SetStream(outStream);
+ AdlerSpec->Init();
+ HRESULT res = DeflateDecoder->Code(inStream, AdlerStream, inSize, outSize, progress);
+ AdlerSpec->ReleaseStream();
+
+ if (res == S_OK)
+ {
+ const Byte *p = DeflateDecoderSpec->ZlibFooter;
+ UInt32 adler = ((UInt32)p[0] << 24) | ((UInt32)p[1] << 16) | ((UInt32)p[2] << 8) | p[3];
+ if (adler != AdlerSpec->GetAdler())
+ return S_FALSE;
+ }
+ return res;
+ DEFLATE_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ZlibDecoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/ZlibDecoder.h
new file mode 100644
index 000000000..95c110022
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ZlibDecoder.h
@@ -0,0 +1,48 @@
+// ZlibDecoder.h
+
+#ifndef __ZLIB_DECODER_H
+#define __ZLIB_DECODER_H
+
+#include "DeflateDecoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+const UInt32 ADLER_INIT_VAL = 1;
+
+class COutStreamWithAdler:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt32 _adler;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _adler = ADLER_INIT_VAL; }
+ UInt32 GetAdler() const { return _adler; }
+};
+
+class CDecoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ COutStreamWithAdler *AdlerSpec;
+ CMyComPtr<ISequentialOutStream> AdlerStream;
+
+ NCompress::NDeflate::NDecoder::CCOMCoder *DeflateDecoderSpec;
+ CMyComPtr<ICompressCoder> DeflateDecoder;
+public:
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ UInt64 GetInputProcessedSize() const { return DeflateDecoderSpec->GetInputProcessedSize() + 2; }
+
+ MY_UNKNOWN_IMP
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ZlibEncoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/ZlibEncoder.cpp
new file mode 100644
index 000000000..09235c337
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ZlibEncoder.cpp
@@ -0,0 +1,61 @@
+// ZlibEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "ZlibEncoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } catch(...) { return S_FALSE; }
+
+UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size);
+
+STDMETHODIMP CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = _stream->Read(data, size, &size);
+ _adler = Adler32_Update(_adler, (const Byte *)data, size);
+ _size += size;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
+
+void CEncoder::Create()
+{
+ if (!DeflateEncoder)
+ DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder;
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ DEFLATE_TRY_BEGIN
+ if (!AdlerStream)
+ AdlerStream = AdlerSpec = new CInStreamWithAdler;
+ Create();
+
+ {
+ Byte buf[2] = { 0x78, 0xDA };
+ RINOK(WriteStream(outStream, buf, 2));
+ }
+
+ AdlerSpec->SetStream(inStream);
+ AdlerSpec->Init();
+ HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress);
+ AdlerSpec->ReleaseStream();
+
+ RINOK(res);
+
+ {
+ UInt32 a = AdlerSpec->GetAdler();
+ Byte buf[4] = { (Byte)(a >> 24), (Byte)(a >> 16), (Byte)(a >> 8), (Byte)(a) };
+ return WriteStream(outStream, buf, 4);
+ }
+ DEFLATE_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/ZlibEncoder.h b/src/libs/7zip/unix/CPP/7zip/Compress/ZlibEncoder.h
new file mode 100644
index 000000000..621cc1d08
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/ZlibEncoder.h
@@ -0,0 +1,48 @@
+// ZlibEncoder.h
+
+#ifndef __ZLIB_ENCODER_H
+#define __ZLIB_ENCODER_H
+
+#include "DeflateEncoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+class CInStreamWithAdler:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt32 _adler;
+ UInt64 _size;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _adler = 1; _size = 0; } // ADLER_INIT_VAL
+ UInt32 GetAdler() const { return _adler; }
+ UInt64 GetSize() const { return _size; }
+};
+
+class CEncoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CInStreamWithAdler *AdlerSpec;
+ CMyComPtr<ISequentialInStream> AdlerStream;
+ CMyComPtr<ICompressCoder> DeflateEncoder;
+public:
+ NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec;
+
+ void Create();
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); }
+
+ MY_UNKNOWN_IMP
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.cpp
new file mode 100644
index 000000000..b686fb61f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.cpp
@@ -0,0 +1,244 @@
+// 7zAes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Sha256.h"
+
+#include "Windows/Synchronization.h"
+
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "7zAes.h"
+#include "MyAes.h"
+
+#ifndef EXTRACT_ONLY
+#include "RandGen.h"
+#endif
+
+using namespace NWindows;
+
+namespace NCrypto {
+namespace NSevenZ {
+
+bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
+{
+ if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
+ return false;
+ for (UInt32 i = 0; i < SaltSize; i++)
+ if (Salt[i] != a.Salt[i])
+ return false;
+ return (Password == a.Password);
+}
+
+void CKeyInfo::CalculateDigest()
+{
+ if (NumCyclesPower == 0x3F)
+ {
+ UInt32 pos;
+ for (pos = 0; pos < SaltSize; pos++)
+ Key[pos] = Salt[pos];
+ for (UInt32 i = 0; i < Password.GetCapacity() && pos < kKeySize; i++)
+ Key[pos++] = Password[i];
+ for (; pos < kKeySize; pos++)
+ Key[pos] = 0;
+ }
+ else
+ {
+ CSha256 sha;
+ Sha256_Init(&sha);
+ const UInt64 numRounds = (UInt64)1 << NumCyclesPower;
+ Byte temp[8] = { 0,0,0,0,0,0,0,0 };
+ for (UInt64 round = 0; round < numRounds; round++)
+ {
+ Sha256_Update(&sha, Salt, (size_t)SaltSize);
+ Sha256_Update(&sha, Password, Password.GetCapacity());
+ Sha256_Update(&sha, temp, 8);
+ for (int i = 0; i < 8; i++)
+ if (++(temp[i]) != 0)
+ break;
+ }
+ Sha256_Final(&sha, Key);
+ }
+}
+
+bool CKeyInfoCache::Find(CKeyInfo &key)
+{
+ for (int i = 0; i < Keys.Size(); i++)
+ {
+ const CKeyInfo &cached = Keys[i];
+ if (key.IsEqualTo(cached))
+ {
+ for (int j = 0; j < kKeySize; j++)
+ key.Key[j] = cached.Key[j];
+ if (i != 0)
+ {
+ Keys.Insert(0, cached);
+ Keys.Delete(i+1);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void CKeyInfoCache::Add(CKeyInfo &key)
+{
+ if (Find(key))
+ return;
+ if (Keys.Size() >= Size)
+ Keys.DeleteBack();
+ Keys.Insert(0, key);
+}
+
+static CKeyInfoCache g_GlobalKeyCache(32);
+static NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
+
+CBase::CBase():
+ _cachedKeys(16),
+ _ivSize(0)
+{
+ for (int i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+}
+
+void CBase::CalculateDigest()
+{
+ NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
+ if (_cachedKeys.Find(_key))
+ g_GlobalKeyCache.Add(_key);
+ else
+ {
+ if (!g_GlobalKeyCache.Find(_key))
+ {
+ _key.CalculateDigest();
+ g_GlobalKeyCache.Add(_key);
+ }
+ _cachedKeys.Add(_key);
+ }
+}
+
+#ifndef EXTRACT_ONLY
+
+/*
+STDMETHODIMP CEncoder::ResetSalt()
+{
+ _key.SaltSize = 4;
+ g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
+ return S_OK;
+}
+*/
+
+STDMETHODIMP CEncoder::ResetInitVector()
+{
+ _ivSize = 8;
+ g_RandomGenerator.Generate(_iv, (unsigned)_ivSize);
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ // _key.Init();
+ for (UInt32 i = _ivSize; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+
+ UInt32 ivSize = _ivSize;
+
+ // _key.NumCyclesPower = 0x3F;
+ _key.NumCyclesPower = 19;
+
+ Byte firstByte = (Byte)(_key.NumCyclesPower |
+ (((_key.SaltSize == 0) ? 0 : 1) << 7) |
+ (((ivSize == 0) ? 0 : 1) << 6));
+ RINOK(outStream->Write(&firstByte, 1, NULL));
+ if (_key.SaltSize == 0 && ivSize == 0)
+ return S_OK;
+ Byte saltSizeSpec = (Byte)((_key.SaltSize == 0) ? 0 : (_key.SaltSize - 1));
+ Byte ivSizeSpec = (Byte)((ivSize == 0) ? 0 : (ivSize - 1));
+ Byte secondByte = (Byte)(((saltSizeSpec) << 4) | ivSizeSpec);
+ RINOK(outStream->Write(&secondByte, 1, NULL));
+ if (_key.SaltSize > 0)
+ {
+ RINOK(WriteStream(outStream, _key.Salt, _key.SaltSize));
+ }
+ if (ivSize > 0)
+ {
+ RINOK(WriteStream(outStream, _iv, ivSize));
+ }
+ return S_OK;
+}
+
+HRESULT CEncoder::CreateFilter()
+{
+ _aesFilter = new CAesCbcEncoder;
+ return S_OK;
+}
+
+#endif
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ _key.Init();
+ UInt32 i;
+ for (i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+ if (size == 0)
+ return S_OK;
+ UInt32 pos = 0;
+ Byte firstByte = data[pos++];
+
+ _key.NumCyclesPower = firstByte & 0x3F;
+ if ((firstByte & 0xC0) == 0)
+ return S_OK;
+ _key.SaltSize = (firstByte >> 7) & 1;
+ UInt32 ivSize = (firstByte >> 6) & 1;
+
+ if (pos >= size)
+ return E_INVALIDARG;
+ Byte secondByte = data[pos++];
+
+ _key.SaltSize += (secondByte >> 4);
+ ivSize += (secondByte & 0x0F);
+
+ if (pos + _key.SaltSize + ivSize > size)
+ return E_INVALIDARG;
+ for (i = 0; i < _key.SaltSize; i++)
+ _key.Salt[i] = data[pos++];
+ for (i = 0; i < ivSize; i++)
+ _iv[i] = data[pos++];
+ return (_key.NumCyclesPower <= 24) ? S_OK : E_NOTIMPL;
+}
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _key.Password.SetCapacity((size_t)size);
+ memcpy(_key.Password, data, (size_t)size);
+ return S_OK;
+}
+
+STDMETHODIMP CBaseCoder::Init()
+{
+ CalculateDigest();
+ if (_aesFilter == 0)
+ {
+ RINOK(CreateFilter());
+ }
+ CMyComPtr<ICryptoProperties> cp;
+ RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
+ RINOK(cp->SetKey(_key.Key, sizeof(_key.Key)));
+ RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
+{
+ return _aesFilter->Filter(data, size);
+}
+
+HRESULT CDecoder::CreateFilter()
+{
+ _aesFilter = new CAesCbcDecoder;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.h b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.h
new file mode 100644
index 000000000..79d723fae
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAes.h
@@ -0,0 +1,117 @@
+// 7zAes.h
+
+#ifndef __CRYPTO_7Z_AES_H
+#define __CRYPTO_7Z_AES_H
+
+#include "Common/Buffer.h"
+#include "Common/MyCom.h"
+#include "Common/MyVector.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NSevenZ {
+
+const int kKeySize = 32;
+
+class CKeyInfo
+{
+public:
+ int NumCyclesPower;
+ UInt32 SaltSize;
+ Byte Salt[16];
+ CByteBuffer Password;
+ Byte Key[kKeySize];
+
+ bool IsEqualTo(const CKeyInfo &a) const;
+ void CalculateDigest();
+
+ CKeyInfo() { Init(); }
+ void Init()
+ {
+ NumCyclesPower = 0;
+ SaltSize = 0;
+ for (int i = 0; i < sizeof(Salt); i++)
+ Salt[i] = 0;
+ }
+};
+
+class CKeyInfoCache
+{
+ int Size;
+ CObjectVector<CKeyInfo> Keys;
+public:
+ CKeyInfoCache(int size): Size(size) {}
+ bool Find(CKeyInfo &key);
+ // HRESULT Calculate(CKeyInfo &key);
+ void Add(CKeyInfo &key);
+};
+
+class CBase
+{
+ CKeyInfoCache _cachedKeys;
+protected:
+ CKeyInfo _key;
+ Byte _iv[16];
+ UInt32 _ivSize;
+ void CalculateDigest();
+ CBase();
+};
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp,
+ public CBase
+{
+protected:
+ CMyComPtr<ICompressFilter> _aesFilter;
+
+ virtual HRESULT CreateFilter() = 0;
+ #ifndef CRYPTO_AES
+ HRESULT CreateFilterFromDLL(REFCLSID clsID);
+ #endif
+public:
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+#ifndef EXTRACT_ONLY
+
+class CEncoder:
+ public CBaseCoder,
+ public ICompressWriteCoderProperties,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector
+{
+ virtual HRESULT CreateFilter();
+public:
+ MY_UNKNOWN_IMP3(
+ ICryptoSetPassword,
+ ICompressWriteCoderProperties,
+ // ICryptoResetSalt,
+ ICryptoResetInitVector)
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+ // STDMETHOD(ResetSalt)();
+ STDMETHOD(ResetInitVector)();
+};
+#endif
+
+class CDecoder:
+ public CBaseCoder,
+ public ICompressSetDecoderProperties2
+{
+ virtual HRESULT CreateFilter();
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/7zAesRegister.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAesRegister.cpp
new file mode 100644
index 000000000..5e57748f5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/7zAesRegister.cpp
@@ -0,0 +1,18 @@
+// 7zAesRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+#include "7zAes.h"
+
+static void *CreateCodec() { return (void *)(ICompressFilter *)(new NCrypto::NSevenZ::CDecoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new NCrypto::NSevenZ::CEncoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x06F10701, L"7zAES", 1, true };
+
+REGISTER_CODEC(7zAES)
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.cpp
new file mode 100644
index 000000000..a66d62711
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.cpp
@@ -0,0 +1,109 @@
+// HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void CHmac::SetKey(const Byte *key, size_t keySize)
+{
+ Byte keyTemp[kBlockSize];
+ size_t i;
+ for (i = 0; i < kBlockSize; i++)
+ keyTemp[i] = 0;
+ if(keySize > kBlockSize)
+ {
+ _sha.Init();
+ _sha.Update(key, keySize);
+ _sha.Final(keyTemp);
+ keySize = kDigestSize;
+ }
+ else
+ for (i = 0; i < keySize; i++)
+ keyTemp[i] = key[i];
+ for (i = 0; i < kBlockSize; i++)
+ keyTemp[i] ^= 0x36;
+ _sha.Init();
+ _sha.Update(keyTemp, kBlockSize);
+ for (i = 0; i < kBlockSize; i++)
+ keyTemp[i] ^= 0x36 ^ 0x5C;
+ _sha2.Init();
+ _sha2.Update(keyTemp, kBlockSize);
+}
+
+void CHmac::Final(Byte *mac, size_t macSize)
+{
+ Byte digest[kDigestSize];
+ _sha.Final(digest);
+ _sha2.Update(digest, kDigestSize);
+ _sha2.Final(digest);
+ for(size_t i = 0; i < macSize; i++)
+ mac[i] = digest[i];
+}
+
+
+void CHmac32::SetKey(const Byte *key, size_t keySize)
+{
+ UInt32 keyTemp[kBlockSizeInWords];
+ size_t i;
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] = 0;
+ if(keySize > kBlockSize)
+ {
+ CContext sha;
+ sha.Init();
+ sha.Update(key, keySize);
+ Byte digest[kDigestSize];
+ sha.Final(digest);
+
+ for (int i = 0 ; i < kDigestSizeInWords; i++)
+ keyTemp[i] =
+ ((UInt32)(digest[i * 4 + 0]) << 24) |
+ ((UInt32)(digest[i * 4 + 1]) << 16) |
+ ((UInt32)(digest[i * 4 + 2]) << 8) |
+ ((UInt32)(digest[i * 4 + 3]));
+ keySize = kDigestSizeInWords;
+ }
+ else
+ for (size_t i = 0; i < keySize; i++)
+ keyTemp[i / 4] |= (key[i] << (24 - 8 * (i & 3)));
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] ^= 0x36363636;
+ _sha.Init();
+ _sha.Update(keyTemp, kBlockSizeInWords);
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] ^= 0x36363636 ^ 0x5C5C5C5C;
+ _sha2.Init();
+ _sha2.Update(keyTemp, kBlockSizeInWords);
+}
+
+void CHmac32::Final(UInt32 *mac, size_t macSize)
+{
+ UInt32 digest[kDigestSizeInWords];
+ _sha.Final(digest);
+ _sha2.Update(digest, kDigestSizeInWords);
+ _sha2.Final(digest);
+ for(size_t i = 0; i < macSize; i++)
+ mac[i] = digest[i];
+}
+
+void CHmac32::GetLoopXorDigest(UInt32 *mac, UInt32 numIteration)
+{
+ UInt32 block[kBlockSizeInWords];
+ UInt32 block2[kBlockSizeInWords];
+ _sha.PrepareBlock(block, kDigestSizeInWords);
+ _sha2.PrepareBlock(block2, kDigestSizeInWords);
+ for(unsigned int s = 0; s < kDigestSizeInWords; s++)
+ block[s] = mac[s];
+ for(UInt32 i = 0; i < numIteration; i++)
+ {
+ _sha.GetBlockDigest(block, block2);
+ _sha2.GetBlockDigest(block2, block);
+ for (unsigned int s = 0; s < kDigestSizeInWords; s++)
+ mac[s] ^= block[s];
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.h b/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.h
new file mode 100644
index 000000000..d7181329c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/HmacSha1.h
@@ -0,0 +1,39 @@
+// HmacSha1.h
+// Implements HMAC-SHA-1 (RFC2104, FIPS-198)
+
+#ifndef __CRYPTO_HMAC_SHA1_H
+#define __CRYPTO_HMAC_SHA1_H
+
+#include "Sha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+// Use: SetKey(key, keySize); for () Update(data, size); Final(mac, macSize);
+
+class CHmac
+{
+ CContext _sha;
+ CContext _sha2;
+public:
+ void SetKey(const Byte *key, size_t keySize);
+ void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); }
+ void Final(Byte *mac, size_t macSize = kDigestSize);
+};
+
+class CHmac32
+{
+ CContext32 _sha;
+ CContext32 _sha2;
+public:
+ void SetKey(const Byte *key, size_t keySize);
+ void Update(const UInt32 *data, size_t dataSize) { _sha.Update(data, dataSize); }
+ void Final(UInt32 *mac, size_t macSize = kDigestSizeInWords);
+
+ // It'sa for hmac function. in,out: mac[kDigestSizeInWords].
+ void GetLoopXorDigest(UInt32 *mac, UInt32 numIteration);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.cpp
new file mode 100644
index 000000000..70a7dccff
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.cpp
@@ -0,0 +1,48 @@
+// Crypto/MyAes.cpp
+
+#include "StdAfx.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+
+struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;
+
+CAesCbcCoder::CAesCbcCoder()
+{
+ _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32);
+}
+
+STDMETHODIMP CAesCbcCoder::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CAesCbcCoder::Filter(Byte *data, UInt32 size)
+{
+ if (size == 0)
+ return 0;
+ if (size < AES_BLOCK_SIZE)
+ return AES_BLOCK_SIZE;
+ size >>= 4;
+ _codeFunc(_aes + _offset, data, size);
+ return size << 4;
+}
+
+STDMETHODIMP CAesCbcCoder::SetKey(const Byte *data, UInt32 size)
+{
+ if ((size & 0x7) != 0 || size < 16 || size > 32)
+ return E_INVALIDARG;
+ _setKeyFunc(_aes + _offset + 4, data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CAesCbcCoder::SetInitVector(const Byte *data, UInt32 size)
+{
+ if (size != AES_BLOCK_SIZE)
+ return E_INVALIDARG;
+ AesCbc_Init(_aes + _offset, data);
+ return S_OK;
+}
+
+CAesCbcEncoder::CAesCbcEncoder() { _codeFunc = g_AesCbc_Encode; _setKeyFunc = Aes_SetKey_Enc; }
+CAesCbcDecoder::CAesCbcDecoder() { _codeFunc = g_AesCbc_Decode; _setKeyFunc = Aes_SetKey_Dec; }
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.h b/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.h
new file mode 100644
index 000000000..60b13845f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/MyAes.h
@@ -0,0 +1,38 @@
+// Crypto/MyAes.h
+
+#ifndef __CRYPTO_MY_AES_H
+#define __CRYPTO_MY_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCrypto {
+
+class CAesCbcCoder:
+ public ICompressFilter,
+ public ICryptoProperties,
+ public CMyUnknownImp
+{
+protected:
+ AES_CODE_FUNC _codeFunc;
+ AES_SET_KEY_FUNC _setKeyFunc;
+ unsigned _offset;
+ UInt32 _aes[AES_NUM_IVMRK_WORDS + 3];
+public:
+ CAesCbcCoder();
+ MY_UNKNOWN_IMP1(ICryptoProperties)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetKey)(const Byte *data, UInt32 size);
+ STDMETHOD(SetInitVector)(const Byte *data, UInt32 size);
+};
+
+struct CAesCbcEncoder: public CAesCbcCoder { CAesCbcEncoder(); };
+struct CAesCbcDecoder: public CAesCbcCoder { CAesCbcDecoder(); };
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
new file mode 100644
index 000000000..cbbdec89d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
@@ -0,0 +1,83 @@
+// Pbkdf2HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSize,
+ UInt32 numIterations, Byte *key, size_t keySize)
+{
+ CHmac baseCtx;
+ baseCtx.SetKey(pwd, pwdSize);
+ for (UInt32 i = 1; keySize > 0; i++)
+ {
+ CHmac ctx = baseCtx;
+ ctx.Update(salt, saltSize);
+ Byte u[kDigestSize] = { (Byte)(i >> 24), (Byte)(i >> 16), (Byte)(i >> 8), (Byte)(i) };
+ const unsigned int curSize = (keySize < kDigestSize) ? (unsigned int)keySize : kDigestSize;
+ ctx.Update(u, 4);
+ ctx.Final(u, kDigestSize);
+
+ unsigned int s;
+ for (s = 0; s < curSize; s++)
+ key[s] = u[s];
+
+ for (UInt32 j = numIterations; j > 1; j--)
+ {
+ ctx = baseCtx;
+ ctx.Update(u, kDigestSize);
+ ctx.Final(u, kDigestSize);
+ for (s = 0; s < curSize; s++)
+ key[s] ^= u[s];
+ }
+
+ key += curSize;
+ keySize -= curSize;
+ }
+}
+
+void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t saltSize,
+ UInt32 numIterations, UInt32 *key, size_t keySize)
+{
+ CHmac32 baseCtx;
+ baseCtx.SetKey(pwd, pwdSize);
+ for (UInt32 i = 1; keySize > 0; i++)
+ {
+ CHmac32 ctx = baseCtx;
+ ctx.Update(salt, saltSize);
+ UInt32 u[kDigestSizeInWords] = { i };
+ const unsigned int curSize = (keySize < kDigestSizeInWords) ? (unsigned int)keySize : kDigestSizeInWords;
+ ctx.Update(u, 1);
+ ctx.Final(u, kDigestSizeInWords);
+
+ // Speed-optimized code start
+ ctx = baseCtx;
+ ctx.GetLoopXorDigest(u, numIterations - 1);
+ // Speed-optimized code end
+
+ unsigned int s;
+ for (s = 0; s < curSize; s++)
+ key[s] = u[s];
+
+ /*
+ // Default code start
+ for (UInt32 j = numIterations; j > 1; j--)
+ {
+ ctx = baseCtx;
+ ctx.Update(u, kDigestSizeInWords);
+ ctx.Final(u, kDigestSizeInWords);
+ for (s = 0; s < curSize; s++)
+ key[s] ^= u[s];
+ }
+ // Default code end
+ */
+
+ key += curSize;
+ keySize -= curSize;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.h b/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
new file mode 100644
index 000000000..bb90e1214
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
@@ -0,0 +1,21 @@
+// Pbkdf2HmacSha1.h
+// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1
+
+#ifndef __CRYPTO_PBKDF2_HMAC_SHA1_H
+#define __CRYPTO_PBKDF2_HMAC_SHA1_H
+
+#include <stddef.h>
+#include "../../Common/Types.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSize,
+ UInt32 numIterations, Byte *key, size_t keySize);
+
+void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t saltSize,
+ UInt32 numIterations, UInt32 *key, size_t keySize);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.cpp
new file mode 100644
index 000000000..e0e2e3abd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.cpp
@@ -0,0 +1,107 @@
+// RandGen.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+#include "Windows/Synchronization.h"
+#include "RandGen.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#endif
+#endif
+
+// This is not very good random number generator.
+// Please use it only for salt.
+// First generated data block depends from timer and processID.
+// Other generated data blocks depend from previous state
+// Maybe it's possible to restore original timer value from generated value.
+
+void CRandomGenerator::Init()
+{
+ NCrypto::NSha1::CContext hash;
+ hash.Init();
+
+ #ifdef _WIN32
+ DWORD w = ::GetCurrentProcessId();
+ hash.Update((const Byte *)&w, sizeof(w));
+ w = ::GetCurrentThreadId();
+ hash.Update((const Byte *)&w, sizeof(w));
+ #else
+ pid_t pid = getpid();
+ hash.Update((const Byte *)&pid, sizeof(pid));
+ pid = getppid();
+ hash.Update((const Byte *)&pid, sizeof(pid));
+ #endif
+
+ for (int i = 0; i < 1000; i++)
+ {
+ #ifdef _WIN32
+ LARGE_INTEGER v;
+ if (::QueryPerformanceCounter(&v))
+ hash.Update((const Byte *)&v.QuadPart, sizeof(v.QuadPart));
+ #endif
+
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ timeval v;
+ if (gettimeofday(&v, 0) == 0)
+ {
+ hash.Update((const Byte *)&v.tv_sec, sizeof(v.tv_sec));
+ hash.Update((const Byte *)&v.tv_usec, sizeof(v.tv_usec));
+ }
+ #endif
+ time_t v2 = time(NULL);
+ hash.Update((const Byte *)&v2, sizeof(v2));
+ #endif
+
+ DWORD tickCount = ::GetTickCount();
+ hash.Update((const Byte *)&tickCount, sizeof(tickCount));
+
+ for (int j = 0; j < 100; j++)
+ {
+ hash.Final(_buff);
+ hash.Init();
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ }
+ }
+ hash.Final(_buff);
+ _needInit = false;
+}
+
+static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
+
+void CRandomGenerator::Generate(Byte *data, unsigned int size)
+{
+ g_CriticalSection.Enter();
+ if (_needInit)
+ Init();
+ while (size > 0)
+ {
+ NCrypto::NSha1::CContext hash;
+
+ hash.Init();
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ hash.Final(_buff);
+
+ hash.Init();
+ UInt32 salt = 0xF672ABD1;
+ hash.Update((const Byte *)&salt, sizeof(salt));
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ Byte buff[NCrypto::NSha1::kDigestSize];
+ hash.Final(buff);
+ for (unsigned int i = 0; i < NCrypto::NSha1::kDigestSize && size > 0; i++, size--)
+ *data++ = buff[i];
+ }
+ g_CriticalSection.Leave();
+}
+
+CRandomGenerator g_RandomGenerator;
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.h b/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.h
new file mode 100644
index 000000000..209445c43
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/RandGen.h
@@ -0,0 +1,21 @@
+// RandGen.h
+
+#ifndef __CRYPTO_RAND_GEN_H
+#define __CRYPTO_RAND_GEN_H
+
+#include "Sha1.h"
+
+class CRandomGenerator
+{
+ Byte _buff[NCrypto::NSha1::kDigestSize];
+ bool _needInit;
+
+ void Init();
+public:
+ CRandomGenerator(): _needInit(true) {};
+ void Generate(Byte *data, unsigned size);
+};
+
+extern CRandomGenerator g_RandomGenerator;
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.cpp
new file mode 100644
index 000000000..c2df0e527
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.cpp
@@ -0,0 +1,133 @@
+// Crypto/Rar20Crypto.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/RotateDefs.h"
+
+#include "Rar20Crypto.h"
+
+namespace NCrypto {
+namespace NRar20 {
+
+static const int kNumRounds = 32;
+
+static const Byte InitSubstTable[256] = {
+ 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
+ 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
+ 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
+ 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
+ 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
+ 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
+ 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
+ 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
+ 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
+ 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
+ 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
+ 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
+ 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
+ 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
+ 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
+ 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
+};
+
+void CData::UpdateKeys(const Byte *data)
+{
+ for (int i = 0; i < 16; i += 4)
+ for (int j = 0; j < 4; j++)
+ Keys[j] ^= g_CrcTable[data[i + j]];
+}
+
+static void Swap(Byte *b1, Byte *b2)
+{
+ Byte b = *b1;
+ *b1 = *b2;
+ *b2 = b;
+}
+
+void CData::SetPassword(const Byte *password, UInt32 passwordLen)
+{
+ Keys[0] = 0xD3A3B879L;
+ Keys[1] = 0x3F6D12F7L;
+ Keys[2] = 0x7515A235L;
+ Keys[3] = 0xA4E7F123L;
+
+ Byte psw[256];
+ memset(psw, 0, sizeof(psw));
+ memcpy(psw, password, passwordLen);
+ memcpy(SubstTable, InitSubstTable, sizeof(SubstTable));
+
+ for (UInt32 j = 0; j < 256; j++)
+ for (UInt32 i = 0; i < passwordLen; i += 2)
+ {
+ UInt32 n2 = (Byte)g_CrcTable[(psw[i + 1] + j) & 0xFF];
+ UInt32 n1 = (Byte)g_CrcTable[(psw[i] - j) & 0xFF];
+ for (UInt32 k = 1; (n1 & 0xFF) != n2; n1++, k++)
+ Swap(&SubstTable[n1 & 0xFF], &SubstTable[(n1 + i + k) & 0xFF]);
+ }
+ for (UInt32 i = 0; i < passwordLen; i+= 16)
+ EncryptBlock(&psw[i]);
+}
+
+void CData::CryptBlock(Byte *buf, bool encrypt)
+{
+ Byte inBuf[16];
+ UInt32 A, B, C, D, T, TA, TB;
+
+ A = GetUi32(buf + 0) ^ Keys[0];
+ B = GetUi32(buf + 4) ^ Keys[1];
+ C = GetUi32(buf + 8) ^ Keys[2];
+ D = GetUi32(buf + 12) ^ Keys[3];
+
+ if (!encrypt)
+ memcpy(inBuf, buf, sizeof(inBuf));
+
+ for (int i = 0; i < kNumRounds; i++)
+ {
+ UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3];
+ T = ((C + rotlFixed(D, 11)) ^ key);
+ TA = A ^ SubstLong(T);
+ T = ((D ^ rotlFixed(C, 17)) + key);
+ TB = B ^ SubstLong(T);
+ A = C;
+ B = D;
+ C = TA;
+ D = TB;
+ }
+
+ SetUi32(buf + 0, C ^ Keys[0]);
+ SetUi32(buf + 4, D ^ Keys[1]);
+ SetUi32(buf + 8, A ^ Keys[2]);
+ SetUi32(buf + 12, B ^ Keys[3]);
+
+ UpdateKeys(encrypt ? buf : inBuf);
+}
+
+STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _cipher.SetPassword(data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Init()
+{
+ return S_OK;
+}
+
+static const UInt32 kBlockSize = 16;
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ if (size == 0)
+ return 0;
+ if (size < kBlockSize)
+ return kBlockSize;
+ UInt32 i;
+ size -= kBlockSize;
+ for (i = 0; i <= size; i += kBlockSize)
+ _cipher.DecryptBlock(data + i);
+ return i;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.h b/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.h
new file mode 100644
index 000000000..b9648f59d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Rar20Crypto.h
@@ -0,0 +1,50 @@
+// Crypto/Rar20Crypto.h
+
+#ifndef __CRYPTO_RAR20_CRYPTO_H
+#define __CRYPTO_RAR20_CRYPTO_H
+
+#include "Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NRar20 {
+
+class CData
+{
+ Byte SubstTable[256];
+ UInt32 Keys[4];
+
+ UInt32 SubstLong(UInt32 t)
+ {
+ return (UInt32)SubstTable[(int)t & 255] |
+ ((UInt32)SubstTable[(int)(t >> 8) & 255] << 8) |
+ ((UInt32)SubstTable[(int)(t >> 16) & 255] << 16) |
+ ((UInt32)SubstTable[(int)(t >> 24) & 255] << 24);
+ }
+ void UpdateKeys(const Byte *data);
+ void CryptBlock(Byte *buf, bool encrypt);
+public:
+ void EncryptBlock(Byte *buf) { CryptBlock(buf, true); }
+ void DecryptBlock(Byte *buf) { CryptBlock(buf, false); }
+ void SetPassword(const Byte *password, UInt32 passwordLen);
+};
+
+class CDecoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+ CData _cipher;
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.cpp
new file mode 100644
index 000000000..b0f00ea85
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.cpp
@@ -0,0 +1,134 @@
+// Crypto/RarAes.cpp
+// Note: you must include MyAes.cpp to project to initialize AES tables
+
+#include "StdAfx.h"
+
+#include "RarAes.h"
+#include "Sha1.h"
+
+namespace NCrypto {
+namespace NRar29 {
+
+CDecoder::CDecoder():
+ _thereIsSalt(false),
+ _needCalculate(true),
+ _rar350Mode(false)
+{
+ for (int i = 0; i < sizeof(_salt); i++)
+ _salt[i] = 0;
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ bool thereIsSaltPrev = _thereIsSalt;
+ _thereIsSalt = false;
+ if (size == 0)
+ return S_OK;
+ if (size < 8)
+ return E_INVALIDARG;
+ _thereIsSalt = true;
+ bool same = false;
+ if (_thereIsSalt == thereIsSaltPrev)
+ {
+ same = true;
+ if (_thereIsSalt)
+ {
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ if (_salt[i] != data[i])
+ {
+ same = false;
+ break;
+ }
+ }
+ }
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ _salt[i] = data[i];
+ if (!_needCalculate && !same)
+ _needCalculate = true;
+ return S_OK;
+}
+
+static const unsigned kMaxPasswordLength = 127 * 2;
+
+STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ if (size > kMaxPasswordLength)
+ size = kMaxPasswordLength;
+ bool same = false;
+ if (size == buffer.GetCapacity())
+ {
+ same = true;
+ for (UInt32 i = 0; i < size; i++)
+ if (data[i] != buffer[i])
+ {
+ same = false;
+ break;
+ }
+ }
+ if (!_needCalculate && !same)
+ _needCalculate = true;
+ buffer.SetCapacity(size);
+ memcpy(buffer, data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Init()
+{
+ Calculate();
+ SetKey(aesKey, kRarAesKeySize);
+ AesCbc_Init(_aes + _offset, _aesInit);
+ return S_OK;
+}
+
+void CDecoder::Calculate()
+{
+ if (_needCalculate)
+ {
+ const unsigned kSaltSize = 8;
+
+ Byte rawPassword[kMaxPasswordLength + kSaltSize];
+
+ memcpy(rawPassword, buffer, buffer.GetCapacity());
+
+ size_t rawLength = buffer.GetCapacity();
+
+ if (_thereIsSalt)
+ {
+ memcpy(rawPassword + rawLength, _salt, kSaltSize);
+ rawLength += kSaltSize;
+ }
+
+ NSha1::CContext sha;
+ sha.Init();
+
+ // rar reverts hash for sha.
+ const unsigned kNumRounds = (1 << 18);
+ unsigned i;
+ for (i = 0; i < kNumRounds; i++)
+ {
+ sha.UpdateRar(rawPassword, rawLength, _rar350Mode);
+ Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
+ sha.UpdateRar(pswNum, 3, _rar350Mode);
+ if (i % (kNumRounds / 16) == 0)
+ {
+ NSha1::CContext shaTemp = sha;
+ Byte digest[NSha1::kDigestSize];
+ shaTemp.Final(digest);
+ _aesInit[i / (kNumRounds / 16)] = (Byte)digest[4 * 4 + 3];
+ }
+ }
+ /*
+ // it's test message for sha
+ const char *message = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+ sha.Update((const Byte *)message, strlen(message));
+ */
+ Byte digest[20];
+ sha.Final(digest);
+ for (i = 0; i < 4; i++)
+ for (unsigned j = 0; j < 4; j++)
+ aesKey[i * 4 + j] = (digest[i * 4 + 3 - j]);
+ }
+ _needCalculate = false;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.h b/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.h
new file mode 100644
index 000000000..119cc2336
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/RarAes.h
@@ -0,0 +1,47 @@
+// Crypto/RarAes.h
+
+#ifndef __CRYPTO_RAR_AES_H
+#define __CRYPTO_RAR_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "Common/Buffer.h"
+
+#include "../IPassword.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NRar29 {
+
+const UInt32 kRarAesKeySize = 16;
+
+class CDecoder:
+ public CAesCbcDecoder,
+ public ICompressSetDecoderProperties2,
+ public ICryptoSetPassword
+{
+ Byte _salt[8];
+ bool _thereIsSalt;
+ CByteBuffer buffer;
+ Byte aesKey[kRarAesKeySize];
+ Byte _aesInit[AES_BLOCK_SIZE];
+ bool _needCalculate;
+ bool _rar350Mode;
+
+ void Calculate();
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD(Init)();
+ STDMETHOD(CryptoSetPassword)(const Byte *aData, UInt32 aSize);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+ CDecoder();
+ void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.cpp
new file mode 100644
index 000000000..82ca986c7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.cpp
@@ -0,0 +1,229 @@
+// Crypto/Sha1.cpp
+// This file is based on public domain
+// Steve Reid and Wei Dai's code from Crypto++
+
+#include "StdAfx.h"
+
+#include "../../../C/RotateDefs.h"
+
+#include "Sha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+// define it for speed optimization
+// #define _SHA1_UNROLL
+
+static const unsigned kNumW =
+ #ifdef _SHA1_UNROLL
+ 16;
+ #else
+ 80;
+ #endif
+
+
+#define w0(i) (W[(i)] = data[(i)])
+
+#ifdef _SHA1_UNROLL
+#define w1(i) (W[(i)&15] = rotlFixed(W[((i)-3)&15] ^ W[((i)-8)&15] ^ W[((i)-14)&15] ^ W[((i)-16)&15], 1))
+#else
+#define w1(i) (W[(i)] = rotlFixed(W[(i)-3] ^ W[(i)-8] ^ W[(i)-14] ^ W[(i)-16], 1))
+#endif
+
+#define f1(x,y,z) (z^(x&(y^z)))
+#define f2(x,y,z) (x^y^z)
+#define f3(x,y,z) ((x&y)|(z&(x|y)))
+#define f4(x,y,z) (x^y^z)
+
+#define RK1(a,b,c,d,e,i, f, w, k) e += f(b,c,d) + w(i) + k + rotlFixed(a,5); b = rotlFixed(b,30);
+
+#define R0(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f1, w0, 0x5A827999)
+#define R1(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f1, w1, 0x5A827999)
+#define R2(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f2, w1, 0x6ED9EBA1)
+#define R3(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f3, w1, 0x8F1BBCDC)
+#define R4(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f4, w1, 0xCA62C1D6)
+
+#define RX_1_4(rx1, rx4, i) rx1(a,b,c,d,e,i); rx4(e,a,b,c,d,i+1); rx4(d,e,a,b,c,i+2); rx4(c,d,e,a,b,i+3); rx4(b,c,d,e,a,i+4);
+#define RX_5(rx, i) RX_1_4(rx, rx, i);
+
+void CContextBase::Init()
+{
+ _state[0] = 0x67452301;
+ _state[1] = 0xEFCDAB89;
+ _state[2] = 0x98BADCFE;
+ _state[3] = 0x10325476;
+ _state[4] = 0xC3D2E1F0;
+ _count = 0;
+}
+
+void CContextBase::GetBlockDigest(UInt32 *data, UInt32 *destDigest, bool returnRes)
+{
+ UInt32 a, b, c, d, e;
+ UInt32 W[kNumW];
+
+ a = _state[0];
+ b = _state[1];
+ c = _state[2];
+ d = _state[3];
+ e = _state[4];
+ #ifdef _SHA1_UNROLL
+ RX_5(R0, 0); RX_5(R0, 5); RX_5(R0, 10);
+ #else
+ int i;
+ for (i = 0; i < 15; i += 5) { RX_5(R0, i); }
+ #endif
+
+ RX_1_4(R0, R1, 15);
+
+
+ #ifdef _SHA1_UNROLL
+ RX_5(R2, 20); RX_5(R2, 25); RX_5(R2, 30); RX_5(R2, 35);
+ RX_5(R3, 40); RX_5(R3, 45); RX_5(R3, 50); RX_5(R3, 55);
+ RX_5(R4, 60); RX_5(R4, 65); RX_5(R4, 70); RX_5(R4, 75);
+ #else
+ i = 20;
+ for (; i < 40; i += 5) { RX_5(R2, i); }
+ for (; i < 60; i += 5) { RX_5(R3, i); }
+ for (; i < 80; i += 5) { RX_5(R4, i); }
+ #endif
+
+ destDigest[0] = _state[0] + a;
+ destDigest[1] = _state[1] + b;
+ destDigest[2] = _state[2] + c;
+ destDigest[3] = _state[3] + d;
+ destDigest[4] = _state[4] + e;
+
+ if (returnRes)
+ for (int i = 0 ; i < 16; i++)
+ data[i] = W[kNumW - 16 + i];
+
+ // Wipe variables
+ // a = b = c = d = e = 0;
+}
+
+void CContextBase::PrepareBlock(UInt32 *block, unsigned size) const
+{
+ unsigned curBufferPos = size & 0xF;
+ block[curBufferPos++] = 0x80000000;
+ while (curBufferPos != (16 - 2))
+ block[curBufferPos++] = 0;
+ const UInt64 lenInBits = (_count << 9) + ((UInt64)size << 5);
+ block[curBufferPos++] = (UInt32)(lenInBits >> 32);
+ block[curBufferPos++] = (UInt32)(lenInBits);
+}
+
+void CContext::Update(const Byte *data, size_t size)
+{
+ unsigned curBufferPos = _count2;
+ while (size--)
+ {
+ int pos = (int)(curBufferPos & 3);
+ if (pos == 0)
+ _buffer[curBufferPos >> 2] = 0;
+ _buffer[curBufferPos >> 2] |= ((UInt32)*data++) << (8 * (3 - pos));
+ if (++curBufferPos == kBlockSize)
+ {
+ curBufferPos = 0;
+ CContextBase::UpdateBlock(_buffer, false);
+ }
+ }
+ _count2 = curBufferPos;
+}
+
+void CContext::UpdateRar(Byte *data, size_t size, bool rar350Mode)
+{
+ bool returnRes = false;
+ unsigned curBufferPos = _count2;
+ while (size--)
+ {
+ int pos = (int)(curBufferPos & 3);
+ if (pos == 0)
+ _buffer[curBufferPos >> 2] = 0;
+ _buffer[curBufferPos >> 2] |= ((UInt32)*data++) << (8 * (3 - pos));
+ if (++curBufferPos == kBlockSize)
+ {
+ curBufferPos = 0;
+ CContextBase::UpdateBlock(_buffer, returnRes);
+ if (returnRes)
+ for (int i = 0; i < kBlockSizeInWords; i++)
+ {
+ UInt32 d = _buffer[i];
+ data[i * 4 + 0 - kBlockSize] = (Byte)(d);
+ data[i * 4 + 1 - kBlockSize] = (Byte)(d >> 8);
+ data[i * 4 + 2 - kBlockSize] = (Byte)(d >> 16);
+ data[i * 4 + 3 - kBlockSize] = (Byte)(d >> 24);
+ }
+ returnRes = rar350Mode;
+ }
+ }
+ _count2 = curBufferPos;
+}
+
+void CContext::Final(Byte *digest)
+{
+ const UInt64 lenInBits = (_count << 9) + ((UInt64)_count2 << 3);
+ unsigned curBufferPos = _count2;
+ int pos = (int)(curBufferPos & 3);
+ curBufferPos >>= 2;
+ if (pos == 0)
+ _buffer[curBufferPos] = 0;
+ _buffer[curBufferPos++] |= ((UInt32)0x80) << (8 * (3 - pos));
+
+ while (curBufferPos != (16 - 2))
+ {
+ curBufferPos &= 0xF;
+ if (curBufferPos == 0)
+ UpdateBlock();
+ _buffer[curBufferPos++] = 0;
+ }
+ _buffer[curBufferPos++] = (UInt32)(lenInBits >> 32);
+ _buffer[curBufferPos++] = (UInt32)(lenInBits);
+ UpdateBlock();
+
+ int i;
+ for (i = 0; i < kDigestSizeInWords; i++)
+ {
+ UInt32 state = _state[i] & 0xFFFFFFFF;
+ *digest++ = (Byte)(state >> 24);
+ *digest++ = (Byte)(state >> 16);
+ *digest++ = (Byte)(state >> 8);
+ *digest++ = (Byte)(state);
+ }
+ Init();
+}
+
+///////////////////////////
+// Words version
+
+void CContext32::Update(const UInt32 *data, size_t size)
+{
+ while (size--)
+ {
+ _buffer[_count2++] = *data++;
+ if (_count2 == kBlockSizeInWords)
+ {
+ _count2 = 0;
+ UpdateBlock();
+ }
+ }
+}
+
+void CContext32::Final(UInt32 *digest)
+{
+ const UInt64 lenInBits = (_count << 9) + ((UInt64)_count2 << 5);
+ unsigned curBufferPos = _count2;
+ _buffer[curBufferPos++] = 0x80000000;
+ while (curBufferPos != (16 - 2))
+ {
+ curBufferPos &= 0xF;
+ if (curBufferPos == 0)
+ UpdateBlock();
+ _buffer[curBufferPos++] = 0;
+ }
+ _buffer[curBufferPos++] = (UInt32)(lenInBits >> 32);
+ _buffer[curBufferPos++] = (UInt32)(lenInBits);
+ GetBlockDigest(_buffer, digest);
+ Init();
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.h b/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.h
new file mode 100644
index 000000000..1bad1f91f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/Sha1.h
@@ -0,0 +1,68 @@
+// Crypto/Sha1.h
+// This file is based on public domain
+// Steve Reid and Wei Dai's code from Crypto++
+
+#ifndef __CRYPTO_SHA1_H
+#define __CRYPTO_SHA1_H
+
+#include <stddef.h>
+#include "../../Common/Types.h"
+
+// Sha1 implementation in RAR before version 3.60 has bug:
+// it changes data bytes in some cases.
+// So this class supports both versions: normal_SHA and rar3Mode
+
+namespace NCrypto {
+namespace NSha1 {
+
+const unsigned kBlockSize = 64;
+const unsigned kDigestSize = 20;
+
+const unsigned kBlockSizeInWords = (kBlockSize >> 2);
+const unsigned kDigestSizeInWords = (kDigestSize >> 2);
+
+class CContextBase
+{
+protected:
+ UInt32 _state[5];
+ UInt64 _count;
+ void UpdateBlock(UInt32 *data, bool returnRes = false)
+ {
+ GetBlockDigest(data, _state, returnRes);
+ _count++;
+ }
+public:
+ void Init();
+ void GetBlockDigest(UInt32 *blockData, UInt32 *destDigest, bool returnRes = false);
+ // PrepareBlock can be used only when size <= 13. size in Words
+ void PrepareBlock(UInt32 *block, unsigned int size) const;
+};
+
+class CContextBase2: public CContextBase
+{
+protected:
+ unsigned _count2;
+ UInt32 _buffer[kBlockSizeInWords];
+ void UpdateBlock() { CContextBase::UpdateBlock(_buffer); }
+public:
+ void Init() { CContextBase::Init(); _count2 = 0; }
+};
+
+class CContext: public CContextBase2
+{
+public:
+ void Update(const Byte *data, size_t size);
+ void UpdateRar(Byte *data, size_t size, bool rar350Mode);
+ void Final(Byte *digest);
+};
+
+class CContext32: public CContextBase2
+{
+public:
+ void Update(const UInt32 *data, size_t size);
+ void Final(UInt32 *digest);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.cpp
new file mode 100644
index 000000000..08a1818c0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.cpp
@@ -0,0 +1,221 @@
+// Crypto/WzAes.cpp
+/*
+This code implements Brian Gladman's scheme
+specified in password Based File Encryption Utility.
+
+Note: you must include MyAes.cpp to project to initialize AES tables
+*/
+
+#include "StdAfx.h"
+
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "Pbkdf2HmacSha1.h"
+#include "RandGen.h"
+#include "WzAes.h"
+
+// define it if you don't want to use speed-optimized version of Pbkdf2HmacSha1
+// #define _NO_WZAES_OPTIMIZATIONS
+
+namespace NCrypto {
+namespace NWzAes {
+
+const unsigned kAesKeySizeMax = 32;
+
+static const UInt32 kNumKeyGenIterations = 1000;
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ if(size > kPasswordSizeMax)
+ return E_INVALIDARG;
+ _key.Password.SetCapacity(size);
+ memcpy(_key.Password, data, size);
+ return S_OK;
+}
+
+#ifndef _NO_WZAES_OPTIMIZATIONS
+
+static void BytesToBeUInt32s(const Byte *src, UInt32 *dest, unsigned destSize)
+{
+ for (unsigned i = 0; i < destSize; i++)
+ dest[i] =
+ ((UInt32)(src[i * 4 + 0]) << 24) |
+ ((UInt32)(src[i * 4 + 1]) << 16) |
+ ((UInt32)(src[i * 4 + 2]) << 8) |
+ ((UInt32)(src[i * 4 + 3]));
+}
+
+#endif
+
+STDMETHODIMP CBaseCoder::Init()
+{
+ UInt32 keySize = _key.GetKeySize();
+ UInt32 keysTotalSize = 2 * keySize + kPwdVerifCodeSize;
+ Byte buf[2 * kAesKeySizeMax + kPwdVerifCodeSize];
+
+ // for (unsigned ii = 0; ii < 1000; ii++)
+ {
+ #ifdef _NO_WZAES_OPTIMIZATIONS
+
+ NSha1::Pbkdf2Hmac(
+ _key.Password, _key.Password.GetCapacity(),
+ _key.Salt, _key.GetSaltSize(),
+ kNumKeyGenIterations,
+ buf, keysTotalSize);
+
+ #else
+
+ UInt32 buf32[(2 * kAesKeySizeMax + kPwdVerifCodeSize + 3) / 4];
+ UInt32 key32SizeTotal = (keysTotalSize + 3) / 4;
+ UInt32 salt[kSaltSizeMax * 4];
+ UInt32 saltSizeInWords = _key.GetSaltSize() / 4;
+ BytesToBeUInt32s(_key.Salt, salt, saltSizeInWords);
+ NSha1::Pbkdf2Hmac32(
+ _key.Password, _key.Password.GetCapacity(),
+ salt, saltSizeInWords,
+ kNumKeyGenIterations,
+ buf32, key32SizeTotal);
+ for (UInt32 j = 0; j < keysTotalSize; j++)
+ buf[j] = (Byte)(buf32[j / 4] >> (24 - 8 * (j & 3)));
+
+ #endif
+ }
+
+ _hmac.SetKey(buf + keySize, keySize);
+ memcpy(_key.PwdVerifComputed, buf + 2 * keySize, kPwdVerifCodeSize);
+
+ AesCtr2_Init(&_aes);
+ Aes_SetKey_Enc(_aes.aes + _aes.offset + 8, buf, keySize);
+ return S_OK;
+}
+
+HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
+{
+ UInt32 saltSize = _key.GetSaltSize();
+ g_RandomGenerator.Generate(_key.Salt, saltSize);
+ Init();
+ RINOK(WriteStream(outStream, _key.Salt, saltSize));
+ return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifCodeSize);
+}
+
+HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
+{
+ Byte mac[kMacSize];
+ _hmac.Final(mac, kMacSize);
+ return WriteStream(outStream, mac, kMacSize);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size != 1)
+ return E_INVALIDARG;
+ _key.Init();
+ return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
+{
+ UInt32 saltSize = _key.GetSaltSize();
+ UInt32 extraSize = saltSize + kPwdVerifCodeSize;
+ Byte temp[kSaltSizeMax + kPwdVerifCodeSize];
+ RINOK(ReadStream_FAIL(inStream, temp, extraSize));
+ UInt32 i;
+ for (i = 0; i < saltSize; i++)
+ _key.Salt[i] = temp[i];
+ for (i = 0; i < kPwdVerifCodeSize; i++)
+ _pwdVerifFromArchive[i] = temp[saltSize + i];
+ return S_OK;
+}
+
+static bool CompareArrays(const Byte *p1, const Byte *p2, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ if (p1[i] != p2[i])
+ return false;
+ return true;
+}
+
+bool CDecoder::CheckPasswordVerifyCode()
+{
+ return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifCodeSize);
+}
+
+HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
+{
+ isOK = false;
+ Byte mac1[kMacSize];
+ RINOK(ReadStream_FAIL(inStream, mac1, kMacSize));
+ Byte mac2[kMacSize];
+ _hmac.Final(mac2, kMacSize);
+ isOK = CompareArrays(mac1, mac2, kMacSize);
+ return S_OK;
+}
+
+CAesCtr2::CAesCtr2()
+{
+ offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32);
+}
+
+void AesCtr2_Init(CAesCtr2 *p)
+{
+ UInt32 *ctr = p->aes + p->offset + 4;
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ ctr[i] = 0;
+ p->pos = AES_BLOCK_SIZE;
+}
+
+void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
+{
+ unsigned pos = p->pos;
+ UInt32 *buf32 = p->aes + p->offset;
+ if (size == 0)
+ return;
+ if (pos != AES_BLOCK_SIZE)
+ {
+ const Byte *buf = (const Byte *)buf32;
+ do
+ *data++ ^= buf[pos++];
+ while (--size != 0 && pos != AES_BLOCK_SIZE);
+ }
+ if (size >= 16)
+ {
+ SizeT size2 = size >> 4;
+ g_AesCtr_Code(buf32 + 4, data, size2);
+ size2 <<= 4;
+ data += size2;
+ size -= size2;
+ pos = AES_BLOCK_SIZE;
+ }
+ if (size != 0)
+ {
+ unsigned j;
+ const Byte *buf;
+ for (j = 0; j < 4; j++)
+ buf32[j] = 0;
+ g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1);
+ buf = (const Byte *)buf32;
+ pos = 0;
+ do
+ *data++ ^= buf[pos++];
+ while (--size != 0 && pos != AES_BLOCK_SIZE);
+ }
+ p->pos = pos;
+}
+
+STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
+{
+ AesCtr2_Code(&_aes, data, size);
+ _hmac.Update(data, size);
+ return size;
+}
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ _hmac.Update(data, size);
+ AesCtr2_Code(&_aes, data, size);
+ return size;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.h b/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.h
new file mode 100644
index 000000000..f37fe6440
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/WzAes.h
@@ -0,0 +1,125 @@
+// Crypto/WzAes.h
+/*
+This code implements Brian Gladman's scheme
+specified in password Based File Encryption Utility:
+ - AES encryption (128,192,256-bit) in Counter (CTR) mode.
+ - HMAC-SHA1 authentication for encrypted data (10 bytes)
+ - Keys are derived by PPKDF2(RFC2898)-HMAC-SHA1 from ASCII password and
+ Salt (saltSize = aesKeySize / 2).
+ - 2 bytes contain Password Verifier's Code
+*/
+
+#ifndef __CRYPTO_WZ_AES_H
+#define __CRYPTO_WZ_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "Common/Buffer.h"
+#include "Common/MyCom.h"
+#include "Common/MyVector.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NWzAes {
+
+const unsigned kSaltSizeMax = 16;
+const unsigned kMacSize = 10;
+
+const UInt32 kPasswordSizeMax = 99; // 128;
+
+// Password Verification Code Size
+const unsigned kPwdVerifCodeSize = 2;
+
+enum EKeySizeMode
+{
+ kKeySizeMode_AES128 = 1,
+ kKeySizeMode_AES192 = 2,
+ kKeySizeMode_AES256 = 3
+};
+
+class CKeyInfo
+{
+public:
+ EKeySizeMode KeySizeMode;
+ Byte Salt[kSaltSizeMax];
+ Byte PwdVerifComputed[kPwdVerifCodeSize];
+
+ CByteBuffer Password;
+
+ UInt32 GetKeySize() const { return (8 * (KeySizeMode & 3) + 8); }
+ UInt32 GetSaltSize() const { return (4 * (KeySizeMode & 3) + 4); }
+
+ CKeyInfo() { Init(); }
+ void Init() { KeySizeMode = kKeySizeMode_AES256; }
+};
+
+struct CAesCtr2
+{
+ unsigned pos;
+ unsigned offset;
+ UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3];
+ CAesCtr2();
+};
+
+void AesCtr2_Init(CAesCtr2 *p);
+void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size);
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+protected:
+ CKeyInfo _key;
+ NSha1::CHmac _hmac;
+ Byte _pwdVerifFromArchive[kPwdVerifCodeSize];
+ CAesCtr2 _aes;
+
+public:
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) = 0;
+
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+
+ UInt32 GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifCodeSize; }
+ bool SetKeyMode(unsigned mode)
+ {
+ if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256)
+ return false;
+ _key.KeySizeMode = (EKeySizeMode)mode;
+ return true;
+ }
+};
+
+class CEncoder:
+ public CBaseCoder
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ HRESULT WriteHeader(ISequentialOutStream *outStream);
+ HRESULT WriteFooter(ISequentialOutStream *outStream);
+};
+
+class CDecoder:
+ public CBaseCoder,
+ public ICompressSetDecoderProperties2
+{
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ HRESULT ReadHeader(ISequentialInStream *inStream);
+ bool CheckPasswordVerifyCode();
+ HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.cpp
new file mode 100644
index 000000000..baaaf98e3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.cpp
@@ -0,0 +1,88 @@
+// Crypto/ZipCrypto.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "RandGen.h"
+#include "ZipCrypto.h"
+
+namespace NCrypto {
+namespace NZip {
+
+void CCipher::UpdateKeys(Byte b)
+{
+ Keys[0] = CRC_UPDATE_BYTE(Keys[0], b);
+ Keys[1] = (Keys[1] + (Keys[0] & 0xFF)) * 0x8088405 + 1;
+ Keys[2] = CRC_UPDATE_BYTE(Keys[2], (Byte)(Keys[1] >> 24));
+}
+
+STDMETHODIMP CCipher::CryptoSetPassword(const Byte *password, UInt32 passwordLen)
+{
+ Keys[0] = 0x12345678;
+ Keys[1] = 0x23456789;
+ Keys[2] = 0x34567890;
+ UInt32 i;
+ for (i = 0; i < passwordLen; i++)
+ UpdateKeys(password[i]);
+ for (i = 0; i < 3; i++)
+ Keys2[i] = Keys[i];
+ return S_OK;
+}
+
+STDMETHODIMP CCipher::Init()
+{
+ return S_OK;
+}
+
+Byte CCipher::DecryptByteSpec()
+{
+ UInt32 temp = Keys[2] | 2;
+ return (Byte)((temp * (temp ^ 1)) >> 8);
+}
+
+HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream, UInt32 crc)
+{
+ Byte h[kHeaderSize];
+ g_RandomGenerator.Generate(h, kHeaderSize - 2);
+ h[kHeaderSize - 1] = (Byte)(crc >> 24);
+ h[kHeaderSize - 2] = (Byte)(crc >> 16);
+ RestoreKeys();
+ Filter(h, kHeaderSize);
+ return WriteStream(outStream, h, kHeaderSize);
+}
+
+STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte b = data[i];
+ data[i] = (Byte)(b ^ DecryptByteSpec());;
+ UpdateKeys(b);
+ }
+ return size;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
+{
+ Byte h[kHeaderSize];
+ RINOK(ReadStream_FAIL(inStream, h, kHeaderSize));
+ RestoreKeys();
+ Filter(h, kHeaderSize);
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte c = (Byte)(data[i] ^ DecryptByteSpec());
+ UpdateKeys(c);
+ data[i] = c;
+ }
+ return size;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.h b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.h
new file mode 100644
index 000000000..6f104beb4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipCrypto.h
@@ -0,0 +1,56 @@
+// Crypto/ZipCrypto.h
+
+#ifndef __CRYPTO_ZIP_CRYPTO_H
+#define __CRYPTO_ZIP_CRYPTO_H
+
+#include "Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NZip {
+
+const unsigned kHeaderSize = 12;
+
+class CCipher:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+ UInt32 Keys[3];
+ UInt32 Keys2[3];
+
+protected:
+ void UpdateKeys(Byte b);
+ Byte DecryptByteSpec();
+ void RestoreKeys()
+ {
+ for (int i = 0; i < 3; i++)
+ Keys[i] = Keys2[i];
+ }
+
+public:
+ STDMETHOD(Init)();
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+class CEncoder: public CCipher
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ HRESULT WriteHeader(ISequentialOutStream *outStream, UInt32 crc);
+};
+
+class CDecoder: public CCipher
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ HRESULT ReadHeader(ISequentialInStream *inStream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.cpp b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.cpp
new file mode 100644
index 000000000..1554b3489
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.cpp
@@ -0,0 +1,164 @@
+// Crypto/ZipStrong.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "MyAes.h"
+#include "Sha1.h"
+#include "ZipStrong.h"
+
+namespace NCrypto {
+namespace NZipStrong {
+
+static const UInt16 kAES128 = 0x660E;
+
+// DeriveKey* function is similar to CryptDeriveKey() from Windows.
+// But MSDN tells that we need such scheme only if
+// "the required key length is longer than the hash value"
+// but ZipStrong uses it always.
+
+static void DeriveKey2(const Byte *digest, Byte c, Byte *dest)
+{
+ Byte buf[64];
+ memset(buf, c, 64);
+ for (unsigned i = 0; i < NSha1::kDigestSize; i++)
+ buf[i] ^= digest[i];
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(buf, 64);
+ sha.Final(dest);
+}
+
+static void DeriveKey(NSha1::CContext &sha, Byte *key)
+{
+ Byte digest[NSha1::kDigestSize];
+ sha.Final(digest);
+ Byte temp[NSha1::kDigestSize * 2];
+ DeriveKey2(digest, 0x36, temp);
+ DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize);
+ memcpy(key, temp, 32);
+}
+
+void CKeyInfo::SetPassword(const Byte *data, UInt32 size)
+{
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(data, size);
+ DeriveKey(sha, MasterKey);
+}
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _key.SetPassword(data, size);
+ return S_OK;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 /* crc */, UInt64 /* unpackSize */)
+{
+ Byte temp[4];
+ RINOK(ReadStream_FALSE(inStream, temp, 2));
+ _ivSize = GetUi16(temp);
+ if (_ivSize == 0)
+ {
+ return E_NOTIMPL;
+ /*
+ SetUi32(_iv, crc);
+ for (int i = 0; i < 8; i++)
+ _iv[4 + i] = (Byte)(unpackSize >> (8 * i));
+ SetUi32(_iv + 12, 0);
+ */
+ }
+ else if (_ivSize == 16)
+ {
+ RINOK(ReadStream_FALSE(inStream, _iv, _ivSize));
+ }
+ else
+ return E_NOTIMPL;
+ RINOK(ReadStream_FALSE(inStream, temp, 4));
+ _remSize = GetUi32(temp);
+ const UInt32 kAlign = 16;
+ if (_remSize < 16 || _remSize > (1 << 18))
+ return E_NOTIMPL;
+ if (_remSize + kAlign > _buf.GetCapacity())
+ {
+ _buf.Free();
+ _buf.SetCapacity(_remSize + kAlign);
+ _bufAligned = (Byte *)((ptrdiff_t)((Byte *)_buf + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
+ }
+ return ReadStream_FALSE(inStream, _bufAligned, _remSize);
+}
+
+HRESULT CDecoder::CheckPassword(bool &passwOK)
+{
+ passwOK = false;
+ if (_remSize < 16)
+ return E_NOTIMPL;
+ Byte *p = _bufAligned;
+ UInt16 format = GetUi16(p);
+ if (format != 3)
+ return E_NOTIMPL;
+ UInt16 algId = GetUi16(p + 2);
+ if (algId < kAES128)
+ return E_NOTIMPL;
+ algId -= kAES128;
+ if (algId > 2)
+ return E_NOTIMPL;
+ UInt16 bitLen = GetUi16(p + 4);
+ UInt16 flags = GetUi16(p + 6);
+ if (algId * 64 + 128 != bitLen)
+ return E_NOTIMPL;
+ _key.KeySize = 16 + algId * 8;
+ if ((flags & 1) == 0)
+ return E_NOTIMPL;
+ if ((flags & 0x4000) != 0)
+ {
+ // Use 3DES
+ return E_NOTIMPL;
+ }
+
+ UInt32 rdSize = GetUi16(p + 8);
+ if ((rdSize & 0xF) != 0 || rdSize + 16 > _remSize)
+ return E_NOTIMPL;
+ memmove(p, p + 10, rdSize);
+ Byte *validData = p + rdSize + 16;
+ if (GetUi32(validData - 6) != 0) // reserved
+ return E_NOTIMPL;
+ UInt32 validSize = GetUi16(validData - 2);
+ if ((validSize & 0xF) != 0 || 16 + rdSize + validSize != _remSize)
+ return E_NOTIMPL;
+
+
+ {
+ RINOK(SetKey(_key.MasterKey, _key.KeySize));
+ RINOK(SetInitVector(_iv, 16));
+ Init();
+ Filter(p, rdSize);
+ }
+
+ Byte fileKey[32];
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(_iv, 16);
+ sha.Update(p, rdSize - 16); // we don't use last 16 bytes (PAD bytes)
+ DeriveKey(sha, fileKey);
+
+ RINOK(SetKey(fileKey, _key.KeySize));
+ RINOK(SetInitVector(_iv, 16));
+ Init();
+ Filter(validData, validSize);
+
+ if (validSize < 4)
+ return E_NOTIMPL;
+ validSize -= 4;
+ if (GetUi32(validData + validSize) != CrcCalc(validData, validSize))
+ return S_OK;
+ passwOK = true;
+ Init();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.h b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.h
new file mode 100644
index 000000000..151677ea6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Crypto/ZipStrong.h
@@ -0,0 +1,47 @@
+// Crypto/ZipStrong.h
+
+#ifndef __CRYPTO_ZIP_STRONG_H
+#define __CRYPTO_ZIP_STRONG_H
+
+#include "Common/Buffer.h"
+
+#include "../IPassword.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NZipStrong {
+
+struct CKeyInfo
+{
+ Byte MasterKey[32];
+ UInt32 KeySize;
+ void SetPassword(const Byte *data, UInt32 size);
+};
+
+class CBaseCoder:
+ public CAesCbcDecoder,
+ public ICryptoSetPassword
+{
+protected:
+ CKeyInfo _key;
+ CByteBuffer _buf;
+ Byte *_bufAligned;
+public:
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+class CDecoder: public CBaseCoder
+{
+ UInt32 _ivSize;
+ Byte _iv[16];
+ UInt32 _remSize;
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize);
+ HRESULT CheckPassword(bool &passwOK);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/Guid.txt b/src/libs/7zip/unix/CPP/7zip/Guid.txt
new file mode 100644
index 000000000..59a743b96
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Guid.txt
@@ -0,0 +1,170 @@
+{23170F69-40C1-278A-0000-00yy00xx0000}
+
+00 IProgress.h
+
+ 05 IProgress
+
+01 IFolderArchive.h
+
+ 05 IArchiveFolder
+ // 06 IInFolderArchive // old
+ 07 IFileExtractCallback.h::IFolderArchiveExtractCallback
+ 0A IOutFolderArchive
+ 0B IFolderArchiveUpdateCallback
+ 0C Agent.h::IArchiveFolderInternal
+ 0D
+ 0E IInFolderArchive
+
+03 IStream.h
+
+ 01 ISequentialInStream
+ 02 ISequentialOutStream
+ 03 IInStream
+ 04 IOutStream
+ 06 IStreamGetSize
+ 07 IOutStreamFlush
+
+
+04 ICoder.h
+
+ 04 ICompressProgressInfo
+ 05 ICompressCoder
+ 18 ICompressCoder2
+ 20 ICompressSetCoderProperties
+ 21 ICompressSetDecoderProperties //
+ 22 ICompressSetDecoderProperties2
+ 23 ICompressWriteCoderProperties
+ 24 ICompressGetInStreamProcessedSize
+ 25 ICompressSetCoderMt
+ 30 ICompressGetSubStreamSize
+ 31 ICompressSetInStream
+ 32 ICompressSetOutStream
+ 33 ICompressSetInStreamSize
+ 34 ICompressSetOutStreamSize
+ 35 ICompressSetBufSize
+ 40 ICompressFilter
+ 60 ICompressCodecsInfo
+ 61 ISetCompressCodecsInfo
+ 80 ICryptoProperties
+ 88 ICryptoResetSalt
+ 8C ICryptoResetInitVector
+ 90 ICryptoSetPassword
+ A0 ICryptoSetCRC
+
+
+05 IPassword.h
+
+ 10 ICryptoGetTextPassword
+ 11 ICryptoGetTextPassword2
+
+
+06 IArchive.h
+
+ 03 ISetProperties
+
+ 10 IArchiveOpenCallback
+ 20 IArchiveExtractCallback
+ 30 IArchiveOpenVolumeCallback
+ 40 IInArchiveGetStream
+ 50 IArchiveOpenSetSubArchiveName
+ 60 IInArchive
+ 61 IArchiveOpenSeq
+
+ 80 IArchiveUpdateCallback
+ 82 IArchiveUpdateCallback2
+ A0 IOutArchive
+
+
+
+08 IFolder.h
+
+ 00 IFolderFolder
+ 01 IEnumProperties
+ 02 IFolderGetTypeID
+ 03 IFolderGetPath
+ 04 IFolderWasChanged
+ 05 // IFolderReload
+ 06 IFolderOperations
+ 07 IFolderGetSystemIconIndex
+ 08 IFolderGetItemFullSize
+ 09 IFolderClone
+ 0A IFolderSetFlatMode
+ 0B IFolderOperationsExtractCallback
+ 0C //
+ 0D //
+ 0E IFolderProperties
+ 0F
+ 10 IFolderArcProps
+ 11 IGetFolderArcProps
+
+
+09 IFolder.h :: FOLDER_MANAGER_INTERFACE
+
+ 00 - 04 // old IFolderManager
+ 05 IFolderManager
+
+
+// 0A PluginInterface.h
+ 00 IInitContextMenu
+ 01 IPluginOptionsCallback
+ 02 IPluginOptions
+
+
+Handler GUIDs:
+
+{23170F69-40C1-278A-1000-000110xx0000}
+
+ 01 Zip
+ 02 BZip2
+ 03 Rar
+ 04 Arj
+ 05 Z
+ 06 Lzh
+ 07 7z
+ 08 Cab
+ 09 Nsis
+ 0A lzma
+ 0B lzma86
+ 0C xz
+ 0D ppmd
+
+ D2 SquashFS
+ D3 CramFS
+ D4 APM
+ D5 Mslz
+ D6 Flv
+ D7 Swf
+ D8 Swfc
+ D9 Ntfs
+ DA Fat
+ DB Mbr
+ DC Vhd
+ DD Pe
+ DE Elf
+ DF Mach-O
+ E0 Udf
+ E1 Xar
+ E2 Mub
+ E3 Hfs
+ E4 Dmg
+ E5 Compound
+ E6 Wim
+ E7 Iso
+ E8 Bkf
+ E9 Chm
+ EA Split
+ EB Rpm
+ EC Deb
+ ED Cpio
+ EE Tar
+ EF GZip
+
+{23170F69-40C1-278A-1000-000100030000} CAgentArchiveHandle
+{23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu
+
+{23170F69-40C1-278B- old codecs clsids
+
+{23170F69-40C1-278D-1000-000100020000} OptionsDialog.h::CLSID_CSevenZipOptions
+
+{23170F69-40C1-2790-id} Codec Decoders
+{23170F69-40C1-2791-id} Codec Encoders
diff --git a/src/libs/7zip/unix/CPP/7zip/ICoder.h b/src/libs/7zip/unix/CPP/7zip/ICoder.h
new file mode 100644
index 000000000..a518de463
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/ICoder.h
@@ -0,0 +1,186 @@
+// ICoder.h
+
+#ifndef __ICODER_H
+#define __ICODER_H
+
+#include "IStream.h"
+
+#define CODER_INTERFACE(i, x) DECL_INTERFACE(i, 4, x)
+
+CODER_INTERFACE(ICompressProgressInfo, 0x04)
+{
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE;
+};
+
+CODER_INTERFACE(ICompressCoder, 0x05)
+{
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress) PURE;
+};
+
+CODER_INTERFACE(ICompressCoder2, 0x18)
+{
+ STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress) PURE;
+};
+
+namespace NCoderPropID
+{
+ enum EEnum
+ {
+ kDefaultProp = 0,
+ kDictionarySize,
+ kUsedMemorySize,
+ kOrder,
+ kBlockSize,
+ kPosStateBits,
+ kLitContextBits,
+ kLitPosBits,
+ kNumFastBytes,
+ kMatchFinder,
+ kMatchFinderCycles,
+ kNumPasses,
+ kAlgorithm,
+ kNumThreads,
+ kEndMarker
+ };
+}
+
+CODER_INTERFACE(ICompressSetCoderProperties, 0x20)
+{
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) PURE;
+};
+
+/*
+CODER_INTERFACE(ICompressSetCoderProperties, 0x21)
+{
+ STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE;
+};
+*/
+
+CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22)
+{
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICompressWriteCoderProperties, 0x23)
+{
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream) PURE;
+};
+
+CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24)
+{
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE;
+};
+
+CODER_INTERFACE(ICompressSetCoderMt, 0x25)
+{
+ STDMETHOD(SetNumberOfThreads)(UInt32 numThreads) PURE;
+};
+
+CODER_INTERFACE(ICompressGetSubStreamSize, 0x30)
+{
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE;
+};
+
+CODER_INTERFACE(ICompressSetInStream, 0x31)
+{
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE;
+ STDMETHOD(ReleaseInStream)() PURE;
+};
+
+CODER_INTERFACE(ICompressSetOutStream, 0x32)
+{
+ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE;
+ STDMETHOD(ReleaseOutStream)() PURE;
+};
+
+CODER_INTERFACE(ICompressSetInStreamSize, 0x33)
+{
+ STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE;
+};
+
+CODER_INTERFACE(ICompressSetOutStreamSize, 0x34)
+{
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE;
+};
+
+CODER_INTERFACE(ICompressSetBufSize, 0x35)
+{
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size) PURE;
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICompressFilter, 0x40)
+{
+ STDMETHOD(Init)() PURE;
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) PURE;
+ // Filter converts as most as possible bytes
+ // Filter return outSize (UInt32)
+ // if (outSize <= size): Filter have converted outSize bytes
+ // if (outSize > size): Filter have not converted anything.
+ // and it needs at least outSize bytes to convert one block
+ // (it's for crypto block algorithms).
+};
+
+CODER_INTERFACE(ICompressCodecsInfo, 0x60)
+{
+ STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods) PURE;
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE;
+ STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder) PURE;
+ STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder) PURE;
+};
+CODER_INTERFACE(ISetCompressCodecsInfo, 0x61)
+{
+ STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo) PURE;
+};
+
+CODER_INTERFACE(ICryptoProperties, 0x80)
+{
+ STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE;
+ STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE;
+};
+
+/*
+CODER_INTERFACE(ICryptoResetSalt, 0x88)
+{
+ STDMETHOD(ResetSalt)() PURE;
+};
+*/
+
+CODER_INTERFACE(ICryptoResetInitVector, 0x8C)
+{
+ STDMETHOD(ResetInitVector)() PURE;
+};
+
+CODER_INTERFACE(ICryptoSetPassword, 0x90)
+{
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICryptoSetCRC, 0xA0)
+{
+ STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE;
+};
+
+//////////////////////
+// It's for DLL file
+namespace NMethodPropID
+{
+ enum EEnum
+ {
+ kID,
+ kName,
+ kDecoder,
+ kEncoder,
+ kInStreams,
+ kOutStreams,
+ kDescription,
+ kDecoderIsAssigned,
+ kEncoderIsAssigned
+ };
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/IDecl.h b/src/libs/7zip/unix/CPP/7zip/IDecl.h
new file mode 100644
index 000000000..8316eb3ac
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/IDecl.h
@@ -0,0 +1,15 @@
+// IDecl.h
+
+#ifndef __IDECL_H
+#define __IDECL_H
+
+#include "../Common/MyUnknown.h"
+
+#define DECL_INTERFACE_SUB(i, base, groupId, subId) \
+DEFINE_GUID(IID_ ## i, \
+0x23170F69, 0x40C1, 0x278A, 0, 0, 0, (groupId), 0, (subId), 0, 0); \
+struct i: public base
+
+#define DECL_INTERFACE(i, groupId, subId) DECL_INTERFACE_SUB(i, IUnknown, groupId, subId)
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/IPassword.h b/src/libs/7zip/unix/CPP/7zip/IPassword.h
new file mode 100644
index 000000000..3ca7b090e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/IPassword.h
@@ -0,0 +1,24 @@
+// IPassword.h
+
+#ifndef __IPASSWORD_H
+#define __IPASSWORD_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+#define PASSWORD_INTERFACE(i, x) DECL_INTERFACE(i, 5, x)
+
+PASSWORD_INTERFACE(ICryptoGetTextPassword, 0x10)
+{
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE;
+};
+
+PASSWORD_INTERFACE(ICryptoGetTextPassword2, 0x11)
+{
+ STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password) PURE;
+};
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/7zip/IProgress.h b/src/libs/7zip/unix/CPP/7zip/IProgress.h
new file mode 100644
index 000000000..d6093f173
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/IProgress.h
@@ -0,0 +1,33 @@
+// Interface/IProgress.h
+
+#ifndef __IPROGRESS_H
+#define __IPROGRESS_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+#define INTERFACE_IProgress(x) \
+ STDMETHOD(SetTotal)(UInt64 total) x; \
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue) x; \
+
+DECL_INTERFACE(IProgress, 0, 5)
+{
+ INTERFACE_IProgress(PURE)
+};
+
+/*
+// {23170F69-40C1-278A-0000-000000050002}
+DEFINE_GUID(IID_IProgress2,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050002")
+IProgress2: public IUnknown
+{
+public:
+ STDMETHOD(SetTotal)(const UInt64 *total) PURE;
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE;
+};
+*/
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/IStream.h b/src/libs/7zip/unix/CPP/7zip/IStream.h
new file mode 100644
index 000000000..165e8baad
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/IStream.h
@@ -0,0 +1,58 @@
+// IStream.h
+
+#ifndef __ISTREAM_H
+#define __ISTREAM_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+#define STREAM_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 3, x)
+#define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x)
+
+STREAM_INTERFACE(ISequentialInStream, 0x01)
+{
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE;
+ /*
+ Out: if size != 0, return_value = S_OK and (*processedSize == 0),
+ then there are no more bytes in stream.
+ if (size > 0) && there are bytes in stream,
+ this function must read at least 1 byte.
+ This function is allowed to read less than number of remaining bytes in stream.
+ You must call Read function in loop, if you need exact amount of data
+ */
+};
+
+STREAM_INTERFACE(ISequentialOutStream, 0x02)
+{
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE;
+ /*
+ if (size > 0) this function must write at least 1 byte.
+ This function is allowed to write less than "size".
+ You must call Write function in loop, if you need to write exact amount of data
+ */
+};
+
+STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03)
+{
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
+};
+
+STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04)
+{
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
+ STDMETHOD(SetSize)(UInt64 newSize) PURE;
+};
+
+STREAM_INTERFACE(IStreamGetSize, 0x06)
+{
+ STDMETHOD(GetSize)(UInt64 *size) PURE;
+};
+
+STREAM_INTERFACE(IOutStreamFlush, 0x07)
+{
+ STDMETHOD(Flush)() PURE;
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/MyVersion.h b/src/libs/7zip/unix/CPP/7zip/MyVersion.h
new file mode 100644
index 000000000..3acfb833f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/MyVersion.h
@@ -0,0 +1,11 @@
+#define MY_VER_MAJOR 9
+#define MY_VER_MINOR 20
+#define MY_VER_BUILD 0
+#define MY_VERSION "9.20"
+#define MY_7ZIP_VERSION "7-Zip 9.20"
+#define MY_DATE "2010-11-18"
+#define MY_COPYRIGHT "Copyright (c) 1999-2010 Igor Pavlov"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " " MY_DATE
+
+#define P7ZIP_VERSION "9.20"
+
diff --git a/src/libs/7zip/unix/CPP/7zip/PropID.h b/src/libs/7zip/unix/CPP/7zip/PropID.h
new file mode 100644
index 000000000..8f8885263
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/PropID.h
@@ -0,0 +1,76 @@
+// PropID.h
+
+#ifndef __7ZIP_PROPID_H
+#define __7ZIP_PROPID_H
+
+enum
+{
+ kpidNoProperty = 0,
+ kpidMainSubfile = 1,
+ kpidHandlerItemIndex = 2,
+ kpidPath,
+ kpidName,
+ kpidExtension,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidAttrib,
+ kpidCTime,
+ kpidATime,
+ kpidMTime,
+ kpidSolid,
+ kpidCommented,
+ kpidEncrypted,
+ kpidSplitBefore,
+ kpidSplitAfter,
+ kpidDictionarySize,
+ kpidCRC,
+ kpidType,
+ kpidIsAnti,
+ kpidMethod,
+ kpidHostOS,
+ kpidFileSystem,
+ kpidUser,
+ kpidGroup,
+ kpidBlock,
+ kpidComment,
+ kpidPosition,
+ kpidPrefix,
+ kpidNumSubDirs,
+ kpidNumSubFiles,
+ kpidUnpackVer,
+ kpidVolume,
+ kpidIsVolume,
+ kpidOffset,
+ kpidLinks,
+ kpidNumBlocks,
+ kpidNumVolumes,
+ kpidTimeType,
+ kpidBit64,
+ kpidBigEndian,
+ kpidCpu,
+ kpidPhySize,
+ kpidHeadersSize,
+ kpidChecksum,
+ kpidCharacts,
+ kpidVa,
+ kpidId,
+ kpidShortName,
+ kpidCreatorApp,
+ kpidSectorSize,
+ kpidPosixAttrib,
+ kpidLink,
+ kpidError,
+
+ kpidTotalSize = 0x1100,
+ kpidFreeSpace,
+ kpidClusterSize,
+ kpidVolumeName,
+
+ kpidLocalName = 0x1200,
+ kpidProvider,
+
+ kpidUserDefined = 0x10000
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
new file mode 100644
index 000000000..d954129f3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -0,0 +1,1010 @@
+// ArchiveCommandLine.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+#include <io.h>
+#endif
+#endif
+#include <stdio.h>
+
+#include "Common/ListFileUtils.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileName.h"
+#ifdef _WIN32
+#include "Windows/FileMapping.h"
+#include "Windows/Synchronization.h"
+#else
+#include "myPrivate.h"
+#endif
+
+#include "ArchiveCommandLine.h"
+#include "EnumDirItems.h"
+#include "SortUtils.h"
+#include "Update.h"
+#include "UpdateAction.h"
+
+extern bool g_CaseSensitive;
+
+#ifdef UNDER_CE
+
+#define MY_IS_TERMINAL(x) false;
+
+#else
+
+#if _MSC_VER >= 1400
+#define MY_isatty_fileno(x) _isatty(_fileno(x))
+#else
+#define MY_isatty_fileno(x) isatty(fileno(x))
+#endif
+
+#define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
+
+#endif
+
+using namespace NCommandLineParser;
+using namespace NWindows;
+using namespace NFile;
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kHelp3,
+ kDisableHeaders,
+ kDisablePercents,
+ kArchiveType,
+ kYes,
+ #ifndef _NO_CRYPTO
+ kPassword,
+ #endif
+ kProperty,
+ kOutputDir,
+ kWorkingDir,
+ kInclude,
+ kExclude,
+ kArInclude,
+ kArExclude,
+ kNoArName,
+ kUpdate,
+ kVolume,
+ kRecursed,
+ kSfx,
+ kStdIn,
+ kStdOut,
+ kOverwrite,
+ kEmail,
+ kShowDialog,
+ kLargePages,
+ kUseLStat,
+ kTechMode,
+ kCaseSensitive,
+ kCalcCrc
+};
+
+}
+
+
+static const wchar_t kRecursedIDChar = 'R';
+static const wchar_t *kRecursedPostCharSet = L"0-";
+
+namespace NRecursedPostCharIndex {
+ enum EEnum
+ {
+ kWildCardRecursionOnly = 0,
+ kNoRecursion = 1
+ };
+}
+
+static const char kImmediateNameID = '!';
+static const char kMapNameID = '#';
+static const char kFileListID = '@';
+
+static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
+static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
+
+static const wchar_t *kOverwritePostCharSet = L"asut";
+
+NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
+{
+ NExtract::NOverwriteMode::kWithoutPrompt,
+ NExtract::NOverwriteMode::kSkipExisting,
+ NExtract::NOverwriteMode::kAutoRename,
+ NExtract::NOverwriteMode::kAutoRenameExisting
+};
+
+static const CSwitchForm kSwitchForms[] =
+ {
+ { L"?", NSwitchType::kSimple, false },
+ { L"H", NSwitchType::kSimple, false },
+ { L"-HELP", NSwitchType::kSimple, false },
+ { L"BA", NSwitchType::kSimple, false },
+ { L"BD", NSwitchType::kSimple, false },
+ { L"T", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"Y", NSwitchType::kSimple, false },
+ #ifndef _NO_CRYPTO
+ { L"P", NSwitchType::kUnLimitedPostString, false, 0 },
+ #endif
+ { L"M", NSwitchType::kUnLimitedPostString, true, 1 },
+ { L"O", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"W", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"I", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"X", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AI", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AX", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AN", NSwitchType::kSimple, false },
+ { L"U", NSwitchType::kUnLimitedPostString, true, 1},
+ { L"V", NSwitchType::kUnLimitedPostString, true, 1},
+ { L"R", NSwitchType::kPostChar, false, 0, 0, kRecursedPostCharSet },
+ { L"SFX", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"SI", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"SO", NSwitchType::kSimple, false, 0 },
+ { L"AO", NSwitchType::kPostChar, false, 1, 1, kOverwritePostCharSet},
+ { L"SEML", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"AD", NSwitchType::kSimple, false },
+ { L"SLP", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"L", NSwitchType::kSimple, false },
+ { L"SLT", NSwitchType::kSimple, false },
+ { L"SSC", NSwitchType::kPostChar, false, 0, 0, L"-" },
+ { L"SCRC", NSwitchType::kSimple, false }
+ };
+
+static const CCommandForm g_CommandForms[] =
+{
+ { L"A", false },
+ { L"U", false },
+ { L"D", false },
+ { L"T", false },
+ { L"E", false },
+ { L"X", false },
+ { L"L", false },
+ { L"B", false },
+ { L"I", false }
+};
+
+static const int kNumCommandForms = sizeof(g_CommandForms) / sizeof(g_CommandForms[0]);
+
+static const wchar_t *kUniversalWildcard = L"*";
+static const int kMinNonSwitchWords = 1;
+static const int kCommandIndex = 0;
+
+// ---------------------------
+// exception messages
+
+static const char *kUserErrorMessage = "Incorrect command line";
+static const char *kCannotFindListFile = "Cannot find listfile";
+static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
+static const char *kIncorrectWildCardInListFile = "Incorrect wildcard in listfile";
+static const char *kIncorrectWildCardInCommandLine = "Incorrect wildcard in command line";
+static const char *kTerminalOutError = "I won't write compressed data to a terminal";
+static const char *kSameTerminalError = "I won't write data and program's messages to same terminal";
+static const char *kEmptyFilePath = "Empty file path";
+
+static void ThrowException(const char *errorMessage)
+{
+ throw CArchiveCommandLineException(errorMessage);
+}
+
+static void ThrowUserErrorException()
+{
+ ThrowException(kUserErrorMessage);
+}
+
+// ---------------------------
+
+bool CArchiveCommand::IsFromExtractGroup() const
+{
+ switch(CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kExtract:
+ case NCommandType::kFullExtract:
+ return true;
+ default:
+ return false;
+ }
+}
+
+NExtract::NPathMode::EEnum CArchiveCommand::GetPathMode() const
+{
+ switch(CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kFullExtract:
+ return NExtract::NPathMode::kFullPathnames;
+ default:
+ return NExtract::NPathMode::kNoPathnames;
+ }
+}
+
+bool CArchiveCommand::IsFromUpdateGroup() const
+{
+ return (CommandType == NCommandType::kAdd ||
+ CommandType == NCommandType::kUpdate ||
+ CommandType == NCommandType::kDelete);
+}
+
+static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
+{
+ switch (index)
+ {
+ case NRecursedPostCharIndex::kWildCardRecursionOnly:
+ return NRecursedType::kWildCardOnlyRecursed;
+ case NRecursedPostCharIndex::kNoRecursion:
+ return NRecursedType::kNonRecursed;
+ default:
+ return NRecursedType::kRecursed;
+ }
+}
+
+static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command)
+{
+ UString commandStringUpper = commandString;
+ commandStringUpper.MakeUpper();
+ UString postString;
+ int commandIndex = ParseCommand(kNumCommandForms, g_CommandForms, commandStringUpper,
+ postString) ;
+ if (commandIndex < 0)
+ return false;
+ command.CommandType = (NCommandType::EEnum)commandIndex;
+ return true;
+}
+
+// ------------------------------------------------------------------
+// filenames functions
+
+static void AddNameToCensor(NWildcard::CCensor &wildcardCensor,
+ const UString &name, bool include, NRecursedType::EEnum type)
+{
+ bool recursed = false;
+
+ switch (type)
+ {
+ case NRecursedType::kWildCardOnlyRecursed:
+ recursed = DoesNameContainWildCard(name);
+ break;
+ case NRecursedType::kRecursed:
+ recursed = true;
+ break;
+ }
+ wildcardCensor.AddItem(include, name, recursed);
+}
+
+static void AddToCensorFromListFile(NWildcard::CCensor &wildcardCensor,
+ LPCWSTR fileName, bool include, NRecursedType::EEnum type, UINT codePage)
+{
+ UStringVector names;
+ if (!NFind::DoesFileExist(fileName))
+ throw kCannotFindListFile;
+ if (!ReadNamesFromListFile(fileName, names, codePage))
+ throw kIncorrectListFile;
+ for (int i = 0; i < names.Size(); i++)
+ AddNameToCensor(wildcardCensor, names[i], include, type);
+}
+
+static void AddToCensorFromNonSwitchesStrings(
+ int startIndex,
+ NWildcard::CCensor &wildcardCensor,
+ const UStringVector &nonSwitchStrings, NRecursedType::EEnum type,
+ bool thereAreSwitchIncludes, UINT codePage)
+{
+ if (nonSwitchStrings.Size() == startIndex && (!thereAreSwitchIncludes))
+ AddNameToCensor(wildcardCensor, kUniversalWildcard, true, type);
+ for (int i = startIndex; i < nonSwitchStrings.Size(); i++)
+ {
+ const UString &s = nonSwitchStrings[i];
+ if (s.IsEmpty())
+ throw kEmptyFilePath;
+ if (s[0] == kFileListID)
+ AddToCensorFromListFile(wildcardCensor, s.Mid(1), true, type, codePage);
+ else
+ AddNameToCensor(wildcardCensor, s, true, type);
+ }
+}
+
+#ifdef _WIN32
+static void ParseMapWithPaths(NWildcard::CCensor &wildcardCensor,
+ const UString &switchParam, bool include,
+ NRecursedType::EEnum commonRecursedType)
+{
+ int splitPos = switchParam.Find(L':');
+ if (splitPos < 0)
+ ThrowUserErrorException();
+ UString mappingName = switchParam.Left(splitPos);
+
+ UString switchParam2 = switchParam.Mid(splitPos + 1);
+ splitPos = switchParam2.Find(L':');
+ if (splitPos < 0)
+ ThrowUserErrorException();
+
+ UString mappingSize = switchParam2.Left(splitPos);
+ UString eventName = switchParam2.Mid(splitPos + 1);
+
+ UInt64 dataSize64 = ConvertStringToUInt64(mappingSize, NULL);
+ UInt32 dataSize = (UInt32)dataSize64;
+ {
+ CFileMapping fileMapping;
+ if (fileMapping.Open(FILE_MAP_READ, GetSystemString(mappingName)) != 0)
+ ThrowException("Can not open mapping");
+ LPVOID data = fileMapping.Map(FILE_MAP_READ, 0, dataSize);
+ if (data == NULL)
+ ThrowException("MapViewOfFile error");
+ try
+ {
+ const wchar_t *curData = (const wchar_t *)data;
+ if (*curData != 0)
+ ThrowException("Incorrect mapping data");
+ UInt32 numChars = dataSize / sizeof(wchar_t);
+ UString name;
+ for (UInt32 i = 1; i < numChars; i++)
+ {
+ wchar_t c = curData[i];
+ if (c == L'\0')
+ {
+ AddNameToCensor(wildcardCensor, name, include, commonRecursedType);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ if (!name.IsEmpty())
+ ThrowException("data error");
+ }
+ catch(...)
+ {
+ UnmapViewOfFile(data);
+ throw;
+ }
+ UnmapViewOfFile(data);
+ }
+
+ {
+ NSynchronization::CManualResetEvent event;
+ if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(eventName)) == S_OK)
+ event.Set();
+ }
+}
+#endif
+
+static void AddSwitchWildCardsToCensor(NWildcard::CCensor &wildcardCensor,
+ const UStringVector &strings, bool include,
+ NRecursedType::EEnum commonRecursedType, UINT codePage)
+{
+ for (int i = 0; i < strings.Size(); i++)
+ {
+ const UString &name = strings[i];
+ NRecursedType::EEnum recursedType;
+ int pos = 0;
+ if (name.Length() < kSomeCludePostStringMinSize)
+ ThrowUserErrorException();
+ if (::MyCharUpper(name[pos]) == kRecursedIDChar)
+ {
+ pos++;
+ int index = UString(kRecursedPostCharSet).Find(name[pos]);
+ recursedType = GetRecursedTypeFromIndex(index);
+ if (index >= 0)
+ pos++;
+ }
+ else
+ recursedType = commonRecursedType;
+ if (name.Length() < pos + kSomeCludeAfterRecursedPostStringMinSize)
+ ThrowUserErrorException();
+ UString tail = name.Mid(pos + 1);
+ if (name[pos] == kImmediateNameID)
+ AddNameToCensor(wildcardCensor, tail, include, recursedType);
+ else if (name[pos] == kFileListID)
+ AddToCensorFromListFile(wildcardCensor, tail, include, recursedType, codePage);
+ #ifdef _WIN32
+ else if (name[pos] == kMapNameID)
+ ParseMapWithPaths(wildcardCensor, tail, include, recursedType);
+ #endif
+ else
+ ThrowUserErrorException();
+ }
+}
+
+#ifdef _WIN32
+
+// This code converts all short file names to long file names.
+
+static void ConvertToLongName(const UString &prefix, UString &name)
+{
+ if (name.IsEmpty() || DoesNameContainWildCard(name))
+ return;
+ NFind::CFileInfoW fi;
+ if (fi.Find(prefix + name))
+ name = fi.Name;
+}
+
+static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::CItem> &items)
+{
+ for (int i = 0; i < items.Size(); i++)
+ {
+ NWildcard::CItem &item = items[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ continue;
+ ConvertToLongName(prefix, item.PathParts.Front());
+ }
+}
+
+static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node)
+{
+ ConvertToLongNames(prefix, node.IncludeItems);
+ ConvertToLongNames(prefix, node.ExcludeItems);
+ int i;
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ ConvertToLongName(prefix, node.SubNodes[i].Name);
+ // mix folders with same name
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ NWildcard::CCensorNode &nextNode1 = node.SubNodes[i];
+ for (int j = i + 1; j < node.SubNodes.Size();)
+ {
+ const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j];
+ if (nextNode1.Name.CompareNoCase(nextNode2.Name) == 0)
+ {
+ nextNode1.IncludeItems += nextNode2.IncludeItems;
+ nextNode1.ExcludeItems += nextNode2.ExcludeItems;
+ node.SubNodes.Delete(j);
+ }
+ else
+ j++;
+ }
+ }
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ NWildcard::CCensorNode &nextNode = node.SubNodes[i];
+ ConvertToLongNames(prefix + nextNode.Name + wchar_t(NFile::NName::kDirDelimiter), nextNode);
+ }
+}
+
+static void ConvertToLongNames(NWildcard::CCensor &censor)
+{
+ for (int i = 0; i < censor.Pairs.Size(); i++)
+ {
+ NWildcard::CPair &pair = censor.Pairs[i];
+ ConvertToLongNames(pair.Prefix, pair.Head);
+ }
+}
+
+#endif
+
+static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
+{
+ switch(i)
+ {
+ case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
+ case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
+ case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
+ case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
+ }
+ throw 98111603;
+}
+
+const UString kUpdatePairStateIDSet = L"PQRXYZW";
+const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
+
+const UString kUpdatePairActionIDSet = L"0123"; //Ignore, Copy, Compress, Create Anti
+
+const wchar_t *kUpdateIgnoreItselfPostStringID = L"-";
+const wchar_t kUpdateNewArchivePostCharID = '!';
+
+
+static bool ParseUpdateCommandString2(const UString &command,
+ NUpdateArchive::CActionSet &actionSet, UString &postString)
+{
+ for (int i = 0; i < command.Length();)
+ {
+ wchar_t c = MyCharUpper(command[i]);
+ int statePos = kUpdatePairStateIDSet.Find(c);
+ if (statePos < 0)
+ {
+ postString = command.Mid(i);
+ return true;
+ }
+ i++;
+ if (i >= command.Length())
+ return false;
+ int actionPos = kUpdatePairActionIDSet.Find(::MyCharUpper(command[i]));
+ if (actionPos < 0)
+ return false;
+ actionSet.StateActions[statePos] = GetUpdatePairActionType(actionPos);
+ if (kUpdatePairStateNotSupportedActions[statePos] == actionPos)
+ return false;
+ i++;
+ }
+ postString.Empty();
+ return true;
+}
+
+static void ParseUpdateCommandString(CUpdateOptions &options,
+ const UStringVector &updatePostStrings,
+ const NUpdateArchive::CActionSet &defaultActionSet)
+{
+ for (int i = 0; i < updatePostStrings.Size(); i++)
+ {
+ const UString &updateString = updatePostStrings[i];
+ if (updateString.CompareNoCase(kUpdateIgnoreItselfPostStringID) == 0)
+ {
+ if (options.UpdateArchiveItself)
+ {
+ options.UpdateArchiveItself = false;
+ options.Commands.Delete(0);
+ }
+ }
+ else
+ {
+ NUpdateArchive::CActionSet actionSet = defaultActionSet;
+
+ UString postString;
+ if (!ParseUpdateCommandString2(updateString, actionSet, postString))
+ ThrowUserErrorException();
+ if (postString.IsEmpty())
+ {
+ if (options.UpdateArchiveItself)
+ options.Commands[0].ActionSet = actionSet;
+ }
+ else
+ {
+ if (MyCharUpper(postString[0]) != kUpdateNewArchivePostCharID)
+ ThrowUserErrorException();
+ CUpdateArchiveCommand uc;
+ UString archivePath = postString.Mid(1);
+ if (archivePath.IsEmpty())
+ ThrowUserErrorException();
+ uc.UserArchivePath = archivePath;
+ uc.ActionSet = actionSet;
+ options.Commands.Add(uc);
+ }
+ }
+ }
+}
+
+static const char kByteSymbol = 'B';
+static const char kKiloSymbol = 'K';
+static const char kMegaSymbol = 'M';
+static const char kGigaSymbol = 'G';
+
+static bool ParseComplexSize(const UString &src, UInt64 &result)
+{
+ UString s = src;
+ s.MakeUpper();
+
+ const wchar_t *start = s;
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(start, &end);
+ int numDigits = (int)(end - start);
+ if (numDigits == 0 || s.Length() > numDigits + 1)
+ return false;
+ if (s.Length() == numDigits)
+ {
+ result = number;
+ return true;
+ }
+ int numBits;
+ switch (s[numDigits])
+ {
+ case kByteSymbol:
+ result = number;
+ return true;
+ case kKiloSymbol:
+ numBits = 10;
+ break;
+ case kMegaSymbol:
+ numBits = 20;
+ break;
+ case kGigaSymbol:
+ numBits = 30;
+ break;
+ default:
+ return false;
+ }
+ if (number >= ((UInt64)1 << (64 - numBits)))
+ return false;
+ result = number << numBits;
+ return true;
+}
+
+static void SetAddCommandOptions(
+ NCommandType::EEnum commandType,
+ const CParser &parser,
+ CUpdateOptions &options)
+{
+ NUpdateArchive::CActionSet defaultActionSet;
+ switch(commandType)
+ {
+ case NCommandType::kAdd:
+ defaultActionSet = NUpdateArchive::kAddActionSet;
+ break;
+ case NCommandType::kDelete:
+ defaultActionSet = NUpdateArchive::kDeleteActionSet;
+ break;
+ default:
+ defaultActionSet = NUpdateArchive::kUpdateActionSet;
+ }
+
+ options.UpdateArchiveItself = true;
+
+ options.Commands.Clear();
+ CUpdateArchiveCommand updateMainCommand;
+ updateMainCommand.ActionSet = defaultActionSet;
+ options.Commands.Add(updateMainCommand);
+ if (parser[NKey::kUpdate].ThereIs)
+ ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
+ defaultActionSet);
+ if (parser[NKey::kWorkingDir].ThereIs)
+ {
+ const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
+ if (postString.IsEmpty())
+ NDirectory::MyGetTempPath(options.WorkingDir);
+ else
+ options.WorkingDir = postString;
+ }
+ options.SfxMode = parser[NKey::kSfx].ThereIs;
+ if (options.SfxMode)
+ options.SfxModule = parser[NKey::kSfx].PostStrings[0];
+
+ if (parser[NKey::kVolume].ThereIs)
+ {
+ const UStringVector &sv = parser[NKey::kVolume].PostStrings;
+ for (int i = 0; i < sv.Size(); i++)
+ {
+ UInt64 size;
+ if (!ParseComplexSize(sv[i], size))
+ ThrowException("Incorrect volume size");
+ options.VolumesSizes.Add(size);
+ }
+ }
+}
+
+static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
+{
+ if (parser[NKey::kProperty].ThereIs)
+ {
+ // options.MethodMode.Properties.Clear();
+ for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++)
+ {
+ CProperty property;
+ const UString &postString = parser[NKey::kProperty].PostStrings[i];
+ int index = postString.Find(L'=');
+ if (index < 0)
+ property.Name = postString;
+ else
+ {
+ property.Name = postString.Left(index);
+ property.Value = postString.Mid(index + 1);
+ }
+ properties.Add(property);
+ }
+ }
+}
+
+CArchiveCommandLineParser::CArchiveCommandLineParser():
+ parser(sizeof(kSwitchForms) / sizeof(kSwitchForms[0])) {}
+
+void CArchiveCommandLineParser::Parse1(const UStringVector &commandStrings,
+ CArchiveCommandLineOptions &options)
+{
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ }
+ catch(...)
+ {
+ ThrowUserErrorException();
+ }
+
+ options.IsInTerminal = MY_IS_TERMINAL(stdin);
+ options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
+ options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
+ options.StdInMode = parser[NKey::kStdIn].ThereIs;
+ options.StdOutMode = parser[NKey::kStdOut].ThereIs;
+ options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
+ options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs;
+
+ #ifdef _7ZIP_LARGE_PAGES
+ options.LargePages = false;
+ if (parser[NKey::kLargePages].ThereIs)
+ {
+ const UString &postString = parser[NKey::kLargePages].PostStrings.Front();
+ if (postString.IsEmpty())
+ options.LargePages = true;
+ }
+ #endif
+}
+
+static bool ConvertStringToUInt32(const wchar_t *s, UInt32 &v)
+{
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(s, &end);
+ if (*end != 0)
+ return false;
+ if (number > (UInt32)0xFFFFFFFF)
+ return false;
+ v = (UInt32)number;
+ return true;
+}
+
+void CArchiveCommandLineParser::Parse2(CArchiveCommandLineOptions &options)
+{
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+ int numNonSwitchStrings = nonSwitchStrings.Size();
+ if (numNonSwitchStrings < kMinNonSwitchWords)
+ ThrowUserErrorException();
+
+ if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
+ ThrowUserErrorException();
+
+ options.TechMode = parser[NKey::kTechMode].ThereIs;
+ options.CalcCrc = parser[NKey::kCalcCrc].ThereIs;
+
+ if (parser[NKey::kCaseSensitive].ThereIs)
+ g_CaseSensitive = (parser[NKey::kCaseSensitive].PostCharIndex < 0);
+
+ NRecursedType::EEnum recursedType;
+ if (parser[NKey::kRecursed].ThereIs)
+ recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
+ else
+ recursedType = NRecursedType::kNonRecursed;
+
+ UINT codePage = CP_ACP;
+
+ bool thereAreSwitchIncludes = false;
+ if (parser[NKey::kInclude].ThereIs)
+ {
+ thereAreSwitchIncludes = true;
+ AddSwitchWildCardsToCensor(options.WildcardCensor,
+ parser[NKey::kInclude].PostStrings, true, recursedType, codePage);
+ }
+ if (parser[NKey::kExclude].ThereIs)
+ AddSwitchWildCardsToCensor(options.WildcardCensor,
+ parser[NKey::kExclude].PostStrings, false, recursedType, codePage);
+
+ int curCommandIndex = kCommandIndex + 1;
+ bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
+ options.Command.CommandType != NCommandType::kBenchmark &&
+ options.Command.CommandType != NCommandType::kInfo;
+
+ bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+ bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
+
+ if (isExtractOrList && options.StdInMode)
+ thereIsArchiveName = false;
+
+ if (thereIsArchiveName)
+ {
+ if (curCommandIndex >= numNonSwitchStrings)
+ ThrowUserErrorException();
+ options.ArchiveName = nonSwitchStrings[curCommandIndex++];
+ if (options.ArchiveName.IsEmpty())
+ ThrowUserErrorException();
+ }
+
+ AddToCensorFromNonSwitchesStrings(
+ curCommandIndex, options.WildcardCensor,
+ nonSwitchStrings, recursedType, thereAreSwitchIncludes, codePage);
+
+ options.YesToAll = parser[NKey::kYes].ThereIs;
+
+#ifdef ENV_HAVE_LSTAT
+ global_use_lstat = !parser[NKey::kUseLStat].ThereIs;
+#endif
+
+ #ifndef _NO_CRYPTO
+ options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
+ if (options.PasswordEnabled)
+ options.Password = parser[NKey::kPassword].PostStrings[0];
+ #endif
+
+ options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
+
+ if (parser[NKey::kArchiveType].ThereIs)
+ options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
+
+ if (isExtractOrList)
+ {
+ if (!options.WildcardCensor.AllAreRelative())
+ ThrowException("Cannot use absolute pathnames for this command");
+
+ NWildcard::CCensor archiveWildcardCensor;
+
+ if (parser[NKey::kArInclude].ThereIs)
+ AddSwitchWildCardsToCensor(archiveWildcardCensor,
+ parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, codePage);
+ if (parser[NKey::kArExclude].ThereIs)
+ AddSwitchWildCardsToCensor(archiveWildcardCensor,
+ parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, codePage);
+
+ bool directlyAddArchiveName = false;
+ if (thereIsArchiveName) {
+ if ((options.ArchiveName.Find(kUniversalWildcard) == -1) && (options.ArchiveName.Find(L"?") == -1)) {
+ // no wildcard => no need to scan
+ directlyAddArchiveName = true;
+ } else {
+ AddNameToCensor(archiveWildcardCensor, options.ArchiveName, true, NRecursedType::kNonRecursed);
+ }
+ }
+
+ #ifdef _WIN32
+ ConvertToLongNames(archiveWildcardCensor);
+ #endif
+
+ archiveWildcardCensor.ExtendExclude();
+
+ if (options.StdInMode)
+ {
+ UString arcName = parser[NKey::kStdIn].PostStrings.Front();
+ options.ArchivePathsSorted.Add(arcName);
+ options.ArchivePathsFullSorted.Add(arcName);
+ }
+ else
+ {
+
+ UStringVector archivePaths;
+
+ {
+ CDirItems dirItems;
+ {
+ UStringVector errorPaths;
+ CRecordVector<DWORD> errorCodes;
+ HRESULT res = EnumerateItems(archiveWildcardCensor, dirItems, NULL, errorPaths, errorCodes);
+ if (res != S_OK || errorPaths.Size() > 0)
+ throw "cannot find archive";
+ }
+ for (int i = 0; i < dirItems.Items.Size(); i++)
+ {
+ const CDirItem &dirItem = dirItems.Items[i];
+ if (!dirItem.IsDir())
+ archivePaths.Add(dirItems.GetPhyPath(i));
+ }
+ }
+
+ // Because the pathname of archive can be a symbolic link
+ // do not use "AddCommandLineWildCardToCensr(archiveWildcardCensor, options.ArchiveName"
+ if (directlyAddArchiveName)
+ archivePaths.Add(options.ArchiveName);
+
+ if (archivePaths.Size() == 0)
+ throw "there is no such archive";
+
+ UStringVector archivePathsFull;
+
+ int i;
+ for (i = 0; i < archivePaths.Size(); i++)
+ {
+ UString fullPath;
+ NFile::NDirectory::MyGetFullPathName(archivePaths[i], fullPath);
+ archivePathsFull.Add(fullPath);
+ }
+ CIntVector indices;
+ SortFileNames(archivePathsFull, indices);
+ options.ArchivePathsSorted.Reserve(indices.Size());
+ options.ArchivePathsFullSorted.Reserve(indices.Size());
+ for (i = 0; i < indices.Size(); i++)
+ {
+ options.ArchivePathsSorted.Add(archivePaths[indices[i]]);
+ options.ArchivePathsFullSorted.Add(archivePathsFull[indices[i]]);
+ }
+
+ }
+
+ if (isExtractGroupCommand)
+ {
+ SetMethodOptions(parser, options.ExtractProperties);
+ if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal)
+ throw kSameTerminalError;
+ if (parser[NKey::kOutputDir].ThereIs)
+ {
+ options.OutputDir = parser[NKey::kOutputDir].PostStrings[0];
+ NFile::NName::NormalizeDirPathPrefix(options.OutputDir);
+ }
+
+ options.OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
+ if (parser[NKey::kOverwrite].ThereIs)
+ options.OverwriteMode = k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex];
+ else if (options.YesToAll)
+ options.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
+ }
+ }
+ else if (options.Command.IsFromUpdateGroup())
+ {
+ CUpdateOptions &updateOptions = options.UpdateOptions;
+
+ SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
+
+ SetMethodOptions(parser, updateOptions.MethodMode.Properties);
+
+ options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs;
+
+ if (options.EnablePercents)
+ {
+ if ((options.StdOutMode && !options.IsStdErrTerminal) ||
+ (!options.StdOutMode && !options.IsStdOutTerminal))
+ options.EnablePercents = false;
+ }
+
+ updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
+ if (updateOptions.EMailMode)
+ {
+ updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
+ if (updateOptions.EMailAddress.Length() > 0)
+ if (updateOptions.EMailAddress[0] == L'.')
+ {
+ updateOptions.EMailRemoveAfter = true;
+ updateOptions.EMailAddress.Delete(0);
+ }
+ }
+
+ updateOptions.StdOutMode = options.StdOutMode;
+ updateOptions.StdInMode = options.StdInMode;
+
+ if (updateOptions.StdOutMode && updateOptions.EMailMode)
+ throw "stdout mode and email mode cannot be combined";
+ if (updateOptions.StdOutMode && options.IsStdOutTerminal)
+ throw kTerminalOutError;
+ if (updateOptions.StdInMode)
+ updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
+
+ #ifdef _WIN32
+ ConvertToLongNames(options.WildcardCensor);
+ #endif
+ }
+ else if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ options.NumThreads = (UInt32)-1;
+ options.DictionarySize = (UInt32)-1;
+ options.NumIterations = 1;
+ if (curCommandIndex < numNonSwitchStrings)
+ {
+ if (!ConvertStringToUInt32(nonSwitchStrings[curCommandIndex++], options.NumIterations))
+ ThrowUserErrorException();
+ }
+ for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++)
+ {
+ UString postString = parser[NKey::kProperty].PostStrings[i];
+ postString.MakeUpper();
+ if (postString.Length() < 2)
+ ThrowUserErrorException();
+ if (postString[0] == 'D')
+ {
+ int pos = 1;
+ if (postString[pos] == '=')
+ pos++;
+ UInt32 logSize;
+ if (!ConvertStringToUInt32((const wchar_t *)postString + pos, logSize))
+ ThrowUserErrorException();
+ if (logSize > 31)
+ ThrowUserErrorException();
+ options.DictionarySize = 1 << logSize;
+ }
+ else if (postString[0] == 'M' && postString[1] == 'T' )
+ {
+ int pos = 2;
+ if (postString[pos] == '=')
+ pos++;
+ if (postString[pos] != 0)
+ if (!ConvertStringToUInt32((const wchar_t *)postString + pos, options.NumThreads))
+ ThrowUserErrorException();
+ }
+ else if (postString[0] == 'M' && postString[1] == '=' )
+ {
+ int pos = 2;
+ if (postString[pos] != 0)
+ options.Method = postString.Mid(2);
+ }
+ else
+ ThrowUserErrorException();
+ }
+ }
+ else if (options.Command.CommandType == NCommandType::kInfo)
+ {
+ }
+ else
+ ThrowUserErrorException();
+ options.WildcardCensor.ExtendExclude();
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.h
new file mode 100644
index 000000000..bc7a99b0d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveCommandLine.h
@@ -0,0 +1,111 @@
+// ArchiveCommandLine.h
+
+#ifndef __ARCHIVE_COMMAND_LINE_H
+#define __ARCHIVE_COMMAND_LINE_H
+
+#include "Common/CommandLineParser.h"
+#include "Common/Wildcard.h"
+
+#include "Extract.h"
+#include "Update.h"
+
+struct CArchiveCommandLineException: public AString
+{
+ CArchiveCommandLineException(const char *errorMessage): AString(errorMessage) {}
+};
+
+namespace NCommandType { enum EEnum
+{
+ kAdd = 0,
+ kUpdate,
+ kDelete,
+ kTest,
+ kExtract,
+ kFullExtract,
+ kList,
+ kBenchmark,
+ kInfo
+};}
+
+namespace NRecursedType { enum EEnum
+{
+ kRecursed,
+ kWildCardOnlyRecursed,
+ kNonRecursed
+};}
+
+struct CArchiveCommand
+{
+ NCommandType::EEnum CommandType;
+ bool IsFromExtractGroup() const;
+ bool IsFromUpdateGroup() const;
+ bool IsTestMode() const { return CommandType == NCommandType::kTest; }
+ NExtract::NPathMode::EEnum GetPathMode() const;
+};
+
+struct CArchiveCommandLineOptions
+{
+ bool HelpMode;
+
+ #ifdef _7ZIP_LARGE_PAGES
+ bool LargePages;
+ #endif
+
+ bool IsInTerminal;
+ bool IsStdOutTerminal;
+ bool IsStdErrTerminal;
+ bool StdInMode;
+ bool StdOutMode;
+ bool EnableHeaders;
+
+ bool YesToAll;
+ bool ShowDialog;
+ // NWildcard::CCensor ArchiveWildcardCensor;
+ NWildcard::CCensor WildcardCensor;
+
+ CArchiveCommand Command;
+ UString ArchiveName;
+
+ #ifndef _NO_CRYPTO
+ bool PasswordEnabled;
+ UString Password;
+ #endif
+
+ bool TechMode;
+ // Extract
+ bool CalcCrc;
+ bool AppendName;
+ UString OutputDir;
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+ UStringVector ArchivePathsSorted;
+ UStringVector ArchivePathsFullSorted;
+ CObjectVector<CProperty> ExtractProperties;
+
+ CUpdateOptions UpdateOptions;
+ UString ArcType;
+ bool EnablePercents;
+
+ // Benchmark
+ UInt32 NumIterations;
+ UInt32 NumThreads;
+ UInt32 DictionarySize;
+ UString Method;
+
+
+ CArchiveCommandLineOptions(): StdInMode(false), StdOutMode(false) {};
+};
+
+class CArchiveCommandLineParser
+{
+ NCommandLineParser::CParser parser;
+public:
+ CArchiveCommandLineParser();
+ void Parse1(const UStringVector &commandStrings, CArchiveCommandLineOptions &options);
+ void Parse2(CArchiveCommandLineOptions &options);
+};
+
+void EnumerateDirItemsAndSort(NWildcard::CCensor &wildcardCensor,
+ UStringVector &sortedPaths,
+ UStringVector &sortedFullPaths);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
new file mode 100644
index 000000000..4c0cc90b5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -0,0 +1,488 @@
+// ArchiveExtractCallback.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "ArchiveExtractCallback.h"
+
+using namespace NWindows;
+
+static const wchar_t *kCantAutoRename = L"ERROR: Can not create file with auto name";
+static const wchar_t *kCantRenameFile = L"ERROR: Can not rename existing file ";
+static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file ";
+
+void CArchiveExtractCallback::Init(
+ const NWildcard::CCensorNode *wildcardCensor,
+ const CArc *arc,
+ IFolderArchiveExtractCallback *extractCallback2,
+ bool stdOutMode, bool testMode, bool crcMode,
+ const UString &directoryPath,
+ const UStringVector &removePathParts,
+ UInt64 packSize)
+{
+ _wildcardCensor = wildcardCensor;
+
+ _stdOutMode = stdOutMode;
+ _testMode = testMode;
+ _crcMode = crcMode;
+ _unpTotal = 1;
+ _packTotal = packSize;
+
+ _extractCallback2 = extractCallback2;
+ _compressProgress.Release();
+ _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
+
+ LocalProgressSpec->Init(extractCallback2, true);
+ LocalProgressSpec->SendProgress = false;
+
+
+ _removePathParts = removePathParts;
+ _arc = arc;
+ _directoryPath = directoryPath;
+ NFile::NName::NormalizeDirPathPrefix(_directoryPath);
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
+{
+ COM_TRY_BEGIN
+ _unpTotal = size;
+ if (!_multiArchives && _extractCallback2)
+ return _extractCallback2->SetTotal(size);
+ return S_OK;
+ COM_TRY_END
+}
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ const UInt64 kMax = (UInt64)1 << 31;
+ while (v1 > kMax)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)
+{
+ NormalizeVals(packTotal, unpTotal);
+ NormalizeVals(unpCur, unpTotal);
+ if (unpTotal == 0)
+ unpTotal = 1;
+ return unpCur * packTotal / unpTotal;
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
+{
+ COM_TRY_BEGIN
+ if (!_extractCallback2)
+ return S_OK;
+
+ if (_multiArchives)
+ {
+ if (completeValue != NULL)
+ {
+ UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal);
+ return _extractCallback2->SetCompleted(&packCur);
+ }
+ }
+ return _extractCallback2->SetCompleted(completeValue);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ COM_TRY_BEGIN
+ return _localProgress->SetRatioInfo(inSize, outSize);
+ COM_TRY_END
+}
+
+void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath)
+{
+ fullPath = _directoryPath;
+ for (int i = 0; i < dirPathParts.Size(); i++)
+ {
+ if (i > 0)
+ fullPath += wchar_t(NFile::NName::kDirDelimiter);
+ fullPath += dirPathParts[i];
+ NFile::NDirectory::MyCreateDirectory(fullPath);
+ }
+}
+
+HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
+{
+ filetimeIsDefined = false;
+ NCOM::CPropVariant prop;
+ RINOK(_arc->Archive->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ {
+ filetime = prop.filetime;
+ filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT CArchiveExtractCallback::GetUnpackSize()
+{
+ NCOM::CPropVariant prop;
+ RINOK(_arc->Archive->GetProperty(_index, kpidSize, &prop));
+ _curSizeDefined = (prop.vt != VT_EMPTY);
+ if (_curSizeDefined)
+ _curSize = ConvertPropVariantToUInt64(prop);
+ return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
+{
+ COM_TRY_BEGIN
+ _crcStream.Release();
+ *outStream = 0;
+ _outFileStream.Release();
+
+ _encrypted = false;
+ _isSplit = false;
+ _curSize = 0;
+ _curSizeDefined = false;
+ _index = index;
+
+ UString fullPath;
+
+ IInArchive *archive = _arc->Archive;
+ RINOK(_arc->GetItemPath(index, fullPath));
+ RINOK(IsArchiveItemFolder(archive, index, _fi.IsDir));
+
+ _filePath = fullPath;
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidPosition, &prop));
+ if (prop.vt != VT_EMPTY)
+ {
+ if (prop.vt != VT_UI8)
+ return E_FAIL;
+ _position = prop.uhVal.QuadPart;
+ _isSplit = true;
+ }
+ }
+
+ RINOK(GetArchiveItemBoolProp(archive, index, kpidEncrypted, _encrypted));
+
+ RINOK(GetUnpackSize());
+
+ if (_wildcardCensor)
+ {
+ if (!_wildcardCensor->CheckPath(fullPath, !_fi.IsDir))
+ return S_OK;
+ }
+
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
+ {
+ if (_stdOutMode)
+ {
+ CMyComPtr<ISequentialOutStream> outStreamLoc = new CStdOutFileStream;
+ *outStream = outStreamLoc.Detach();
+ return S_OK;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidAttrib, &prop));
+ if (prop.vt == VT_UI4)
+ {
+ _fi.Attrib = prop.ulVal;
+ _fi.AttribDefined = true;
+ }
+ else if (prop.vt == VT_EMPTY)
+ _fi.AttribDefined = false;
+ else
+ return E_FAIL;
+ }
+
+ RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined));
+ RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined));
+ RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined));
+
+ bool isAnti = false;
+ RINOK(_arc->IsItemAnti(index, isAnti));
+
+ UStringVector pathParts;
+ SplitPathToParts(fullPath, pathParts);
+
+ if (pathParts.IsEmpty())
+ return E_FAIL;
+ int numRemovePathParts = 0;
+ switch(_pathMode)
+ {
+ case NExtract::NPathMode::kFullPathnames:
+ break;
+ case NExtract::NPathMode::kCurrentPathnames:
+ {
+ numRemovePathParts = _removePathParts.Size();
+ if (pathParts.Size() <= numRemovePathParts)
+ return E_FAIL;
+ for (int i = 0; i < numRemovePathParts; i++)
+ if (_removePathParts[i].CompareNoCase(pathParts[i]) != 0)
+ return E_FAIL;
+ break;
+ }
+ case NExtract::NPathMode::kNoPathnames:
+ {
+ numRemovePathParts = pathParts.Size() - 1;
+ break;
+ }
+ }
+ pathParts.Delete(0, numRemovePathParts);
+ MakeCorrectPath(pathParts);
+ UString processedPath = MakePathNameFromParts(pathParts);
+ if (!isAnti)
+ {
+ if (!_fi.IsDir)
+ {
+ if (!pathParts.IsEmpty())
+ pathParts.DeleteBack();
+ }
+
+ if (!pathParts.IsEmpty())
+ {
+ UString fullPathNew;
+ CreateComplexDirectory(pathParts, fullPathNew);
+ if (_fi.IsDir)
+ NFile::NDirectory::SetDirTime(fullPathNew,
+ (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
+ (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
+ (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ }
+ }
+
+
+ UString fullProcessedPath = _directoryPath + processedPath;
+
+ if (_fi.IsDir)
+ {
+ _diskFilePath = fullProcessedPath;
+ if (isAnti)
+ NFile::NDirectory::MyRemoveDirectory(_diskFilePath);
+ return S_OK;
+ }
+
+ if (!_isSplit)
+ {
+ NFile::NFind::CFileInfoW fileInfo;
+ if (fileInfo.Find(fullProcessedPath))
+ {
+ switch(_overwriteMode)
+ {
+ case NExtract::NOverwriteMode::kSkipExisting:
+ return S_OK;
+ case NExtract::NOverwriteMode::kAskBefore:
+ {
+ Int32 overwiteResult;
+ RINOK(_extractCallback2->AskOverwrite(
+ fullProcessedPath, &fileInfo.MTime, &fileInfo.Size, fullPath,
+ _fi.MTimeDefined ? &_fi.MTime : NULL,
+ _curSizeDefined ? &_curSize : NULL,
+ &overwiteResult))
+
+ switch(overwiteResult)
+ {
+ case NOverwriteAnswer::kCancel:
+ return E_ABORT;
+ case NOverwriteAnswer::kNo:
+ return S_OK;
+ case NOverwriteAnswer::kNoToAll:
+ _overwriteMode = NExtract::NOverwriteMode::kSkipExisting;
+ return S_OK;
+ case NOverwriteAnswer::kYesToAll:
+ _overwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
+ break;
+ case NOverwriteAnswer::kYes:
+ break;
+ case NOverwriteAnswer::kAutoRename:
+ _overwriteMode = NExtract::NOverwriteMode::kAutoRename;
+ break;
+ default:
+ return E_FAIL;
+ }
+ }
+ }
+ if (_overwriteMode == NExtract::NOverwriteMode::kAutoRename)
+ {
+ if (!AutoRenamePath(fullProcessedPath))
+ {
+ UString message = UString(kCantAutoRename) + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ }
+ else if (_overwriteMode == NExtract::NOverwriteMode::kAutoRenameExisting)
+ {
+ UString existPath = fullProcessedPath;
+ if (!AutoRenamePath(existPath))
+ {
+ UString message = kCantAutoRename + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ if (!NFile::NDirectory::MyMoveFile(fullProcessedPath, existPath))
+ {
+ UString message = UString(kCantRenameFile) + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ }
+ else
+ if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath))
+ {
+ UString message = UString(kCantDeleteOutputFile) + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return S_OK;
+ // return E_FAIL;
+ }
+ }
+ }
+ if (!isAnti)
+ {
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+ if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+ {
+ // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
+ {
+ UString message = L"can not open output file " + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return S_OK;
+ }
+ }
+ if (_isSplit)
+ {
+ RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
+ }
+ _outFileStream = outStreamLoc;
+ *outStream = outStreamLoc.Detach();
+ }
+ _diskFilePath = fullProcessedPath;
+ }
+ else
+ {
+ *outStream = NULL;
+ }
+ if (_crcMode)
+ {
+ _crcStreamSpec = new COutStreamWithCRC;
+ _crcStream = _crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> crcStream = _crcStreamSpec;
+ _crcStreamSpec->SetStream(*outStream);
+ if (*outStream)
+ (*outStream)->Release();
+ *outStream = crcStream.Detach();
+ _crcStreamSpec->Init(true);
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
+{
+ COM_TRY_BEGIN
+ _extractMode = false;
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract:
+ if (_testMode)
+ askExtractMode = NArchive::NExtract::NAskMode::kTest;
+ else
+ _extractMode = true;
+ break;
+ };
+ return _extractCallback2->PrepareOperation(_filePath, _fi.IsDir,
+ askExtractMode, _isSplit ? &_position: 0);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
+{
+ COM_TRY_BEGIN
+ switch(operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ case NArchive::NExtract::NOperationResult::kDataError:
+ break;
+ default:
+ _outFileStream.Release();
+ return E_FAIL;
+ }
+ if (_crcStream)
+ {
+ CrcSum += _crcStreamSpec->GetCRC();
+ _curSize = _crcStreamSpec->GetSize();
+ _curSizeDefined = true;
+ _crcStream.Release();
+ }
+ if (_outFileStream)
+ {
+ _outFileStreamSpec->SetTime(
+ (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
+ (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
+ (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ _curSize = _outFileStreamSpec->ProcessedSize;
+ _curSizeDefined = true;
+ RINOK(_outFileStreamSpec->Close());
+ _outFileStream.Release();
+ }
+ if (!_curSizeDefined)
+ GetUnpackSize();
+ if (_curSizeDefined)
+ UnpackSize += _curSize;
+ if (_fi.IsDir)
+ NumFolders++;
+ else
+ NumFiles++;
+
+ if (_extractMode && _fi.AttribDefined)
+ NFile::NDirectory::MySetFileAttributes(_diskFilePath, _fi.Attrib);
+ RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted));
+ return S_OK;
+ COM_TRY_END
+}
+
+/*
+STDMETHODIMP CArchiveExtractCallback::GetInStream(
+ const wchar_t *name, ISequentialInStream **inStream)
+{
+ COM_TRY_BEGIN
+ CInFileStream *inFile = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamTemp = inFile;
+ if (!inFile->Open(_srcDirectoryPrefix + name))
+ return ::GetLastError();
+ *inStream = inStreamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+*/
+
+STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ if (!_cryptoGetTextPassword)
+ {
+ RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,
+ &_cryptoGetTextPassword));
+ }
+ return _cryptoGetTextPassword->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.h
new file mode 100644
index 000000000..367e4b07d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -0,0 +1,143 @@
+// ArchiveExtractCallback.h
+
+#ifndef __ARCHIVE_EXTRACT_CALLBACK_H
+#define __ARCHIVE_EXTRACT_CALLBACK_H
+
+#include "Common/MyCom.h"
+#include "Common/Wildcard.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../../Archive/Common/OutStreamWithCRC.h"
+
+#include "ExtractMode.h"
+#include "IFileExtractCallback.h"
+#include "OpenArchive.h"
+
+class CArchiveExtractCallback:
+ public IArchiveExtractCallback,
+ // public IArchiveVolumeExtractCallback,
+ public ICryptoGetTextPassword,
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ const CArc *_arc;
+ const NWildcard::CCensorNode *_wildcardCensor;
+ CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
+ CMyComPtr<ICompressProgressInfo> _compressProgress;
+ CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
+ UString _directoryPath;
+ NExtract::NPathMode::EEnum _pathMode;
+ NExtract::NOverwriteMode::EEnum _overwriteMode;
+
+ UString _diskFilePath;
+ UString _filePath;
+ UInt64 _position;
+ bool _isSplit;
+
+ bool _extractMode;
+
+ bool WriteCTime;
+ bool WriteATime;
+ bool WriteMTime;
+
+ bool _encrypted;
+
+ struct CProcessedFileInfo
+ {
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ UInt32 Attrib;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+ bool AttribDefined;
+
+ bool IsDir;
+ } _fi;
+
+ UInt32 _index;
+ UInt64 _curSize;
+ bool _curSizeDefined;
+ COutFileStream *_outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outFileStream;
+
+ COutStreamWithCRC *_crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> _crcStream;
+
+ UStringVector _removePathParts;
+
+ bool _stdOutMode;
+ bool _testMode;
+ bool _crcMode;
+ bool _multiArchives;
+
+ CMyComPtr<ICompressProgressInfo> _localProgress;
+ UInt64 _packTotal;
+ UInt64 _unpTotal;
+
+ void CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath);
+ HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
+ HRESULT GetUnpackSize();
+
+public:
+
+ CLocalProgress *LocalProgressSpec;
+
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+ UInt64 UnpackSize;
+ UInt32 CrcSum;
+
+ MY_UNKNOWN_IMP2(ICryptoGetTextPassword, ICompressProgressInfo)
+ // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback)
+
+ INTERFACE_IArchiveExtractCallback(;)
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+
+ // IArchiveVolumeExtractCallback
+ // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream);
+
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+ CArchiveExtractCallback():
+ WriteCTime(true),
+ WriteATime(true),
+ WriteMTime(true),
+ _multiArchives(false)
+ {
+ LocalProgressSpec = new CLocalProgress();
+ _localProgress = LocalProgressSpec;
+ }
+
+ void InitForMulti(bool multiArchives,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode)
+ {
+ _multiArchives = multiArchives;
+ _pathMode = pathMode;
+ _overwriteMode = overwriteMode;
+ NumFolders = NumFiles = UnpackSize = 0;
+ CrcSum = 0;
+ }
+
+ void Init(
+ const NWildcard::CCensorNode *wildcardCensor,
+ const CArc *arc,
+ IFolderArchiveExtractCallback *extractCallback2,
+ bool stdOutMode, bool testMode, bool crcMode,
+ const UString &directoryPath,
+ const UStringVector &removePathParts,
+ UInt64 packSize);
+
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveName.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveName.cpp
new file mode 100644
index 000000000..c3684def8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveName.cpp
@@ -0,0 +1,54 @@
+// ArchiveName.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+
+#include "ExtractingFilePath.h"
+
+using namespace NWindows;
+
+static UString CreateArchiveName2(const UString &srcName, bool fromPrev, bool keepName)
+{
+ UString resultName = L"Archive";
+ if (fromPrev)
+ {
+ UString dirPrefix;
+ if (NFile::NDirectory::GetOnlyDirPrefix(srcName, dirPrefix))
+ {
+ if (dirPrefix.Length() > 0)
+ if (dirPrefix[dirPrefix.Length() - 1] == WCHAR_PATH_SEPARATOR)
+ {
+ dirPrefix.Delete(dirPrefix.Length() - 1);
+ NFile::NFind::CFileInfoW fileInfo;
+ if (fileInfo.Find(dirPrefix))
+ resultName = fileInfo.Name;
+ }
+ }
+ }
+ else
+ {
+ NFile::NFind::CFileInfoW fileInfo;
+ if (!fileInfo.Find(srcName))
+ // return resultName;
+ return srcName;
+ resultName = fileInfo.Name;
+ if (!fileInfo.IsDir() && !keepName)
+ {
+ int dotPos = resultName.ReverseFind('.');
+ if (dotPos > 0)
+ {
+ UString archiveName2 = resultName.Left(dotPos);
+ if (archiveName2.ReverseFind('.') < 0)
+ resultName = archiveName2;
+ }
+ }
+ }
+ return resultName;
+}
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName)
+{
+ return GetCorrectFsPath(CreateArchiveName2(srcName, fromPrev, keepName));
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveName.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveName.h
new file mode 100644
index 000000000..9513fb2ba
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveName.h
@@ -0,0 +1,10 @@
+// ArchiveName.h
+
+#ifndef __ARCHIVENAME_H
+#define __ARCHIVENAME_H
+
+#include "Common/MyString.h"
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
new file mode 100644
index 000000000..e7e617131
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
@@ -0,0 +1,133 @@
+// ArchiveOpenCallback.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StringConvert.h"
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "ArchiveOpenCallback.h"
+
+using namespace NWindows;
+
+STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ return ReOpenCallback->SetTotal(files, bytes);
+ if (!Callback)
+ return S_OK;
+ return Callback->Open_SetTotal(files, bytes);
+ COM_TRY_END
+}
+
+STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ return ReOpenCallback->SetCompleted(files, bytes);
+ if (!Callback)
+ return S_OK;
+ return Callback->Open_SetCompleted(files, bytes);
+ COM_TRY_END
+}
+
+STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (_subArchiveMode)
+ switch(propID)
+ {
+ case kpidName: prop = _subArchiveName; break;
+ }
+ else
+ switch(propID)
+ {
+ case kpidName: prop = _fileInfo.Name; break;
+ case kpidIsDir: prop = _fileInfo.IsDir(); break;
+ case kpidSize: prop = _fileInfo.Size; break;
+ case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break;
+ case kpidCTime: prop = _fileInfo.CTime; break;
+ case kpidATime: prop = _fileInfo.ATime; break;
+ case kpidMTime: prop = _fileInfo.MTime; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+int COpenCallbackImp::FindName(const UString &name)
+{
+ for (int i = 0; i < FileNames.Size(); i++)
+ if (name.CompareNoCase(FileNames[i]) == 0)
+ return i;
+ return -1;
+}
+
+struct CInFileStreamVol: public CInFileStream
+{
+ UString Name;
+ COpenCallbackImp *OpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
+ ~CInFileStreamVol()
+ {
+ if (OpenCallbackRef)
+ {
+ int index = OpenCallbackImp->FindName(Name);
+ if (index >= 0)
+ OpenCallbackImp->FileNames.Delete(index);
+ }
+ }
+};
+
+STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)
+{
+ COM_TRY_BEGIN
+ if (_subArchiveMode)
+ return S_FALSE;
+ if (Callback)
+ {
+ RINOK(Callback->Open_CheckBreak());
+ }
+ *inStream = NULL;
+ UString fullPath = _folderPrefix + name;
+ if (!_fileInfo.Find(fullPath))
+ return S_FALSE;
+ if (_fileInfo.IsDir())
+ return S_FALSE;
+ CInFileStreamVol *inFile = new CInFileStreamVol;
+ CMyComPtr<IInStream> inStreamTemp = inFile;
+ if (!inFile->Open(fullPath))
+ return ::GetLastError();
+ *inStream = inStreamTemp.Detach();
+ inFile->Name = name;
+ inFile->OpenCallbackImp = this;
+ inFile->OpenCallbackRef = this;
+ FileNames.Add(name);
+ TotalSize += _fileInfo.Size;
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifndef _NO_CRYPTO
+STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ {
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ if (getTextPassword)
+ return getTextPassword->CryptoGetTextPassword(password);
+ }
+ if (!Callback)
+ return E_NOTIMPL;
+ return Callback->Open_CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.h
new file mode 100644
index 000000000..c6651e8f9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ArchiveOpenCallback.h
@@ -0,0 +1,103 @@
+// ArchiveOpenCallback.h
+
+#ifndef __ARCHIVE_OPEN_CALLBACK_H
+#define __ARCHIVE_OPEN_CALLBACK_H
+
+#include "Common/MyCom.h"
+#include "Common/MyString.h"
+
+#include "Windows/FileFind.h"
+
+#ifndef _NO_CRYPTO
+#include "../../IPassword.h"
+#endif
+#include "../../Archive/IArchive.h"
+
+#ifdef _NO_CRYPTO
+
+#define INTERFACE_IOpenCallbackUI_Crypto(x)
+
+#else
+
+#define INTERFACE_IOpenCallbackUI_Crypto(x) \
+ virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x; \
+ virtual HRESULT Open_GetPasswordIfAny(UString &password) x; \
+ virtual bool Open_WasPasswordAsked() x; \
+ virtual void Open_ClearPasswordWasAskedFlag() x; \
+
+#endif
+
+#define INTERFACE_IOpenCallbackUI(x) \
+ virtual HRESULT Open_CheckBreak() x; \
+ virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x; \
+ virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x; \
+ INTERFACE_IOpenCallbackUI_Crypto(x)
+
+struct IOpenCallbackUI
+{
+ INTERFACE_IOpenCallbackUI(=0)
+};
+
+class COpenCallbackImp:
+ public IArchiveOpenCallback,
+ public IArchiveOpenVolumeCallback,
+ public IArchiveOpenSetSubArchiveName,
+ #ifndef _NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ #ifndef _NO_CRYPTO
+ MY_UNKNOWN_IMP3(
+ IArchiveOpenVolumeCallback,
+ ICryptoGetTextPassword,
+ IArchiveOpenSetSubArchiveName
+ )
+ #else
+ MY_UNKNOWN_IMP2(
+ IArchiveOpenVolumeCallback,
+ IArchiveOpenSetSubArchiveName
+ )
+ #endif
+
+ INTERFACE_IArchiveOpenCallback(;)
+ INTERFACE_IArchiveOpenVolumeCallback(;)
+
+ #ifndef _NO_CRYPTO
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+ #endif
+
+ STDMETHOD(SetSubArchiveName(const wchar_t *name))
+ {
+ _subArchiveMode = true;
+ _subArchiveName = name;
+ TotalSize = 0;
+ return S_OK;
+ }
+
+private:
+ UString _folderPrefix;
+ NWindows::NFile::NFind::CFileInfoW _fileInfo;
+ bool _subArchiveMode;
+ UString _subArchiveName;
+public:
+ UStringVector FileNames;
+ IOpenCallbackUI *Callback;
+ CMyComPtr<IArchiveOpenCallback> ReOpenCallback;
+ UInt64 TotalSize;
+
+ COpenCallbackImp(): Callback(NULL) {}
+ void Init(const UString &folderPrefix, const UString &fileName)
+ {
+ _folderPrefix = folderPrefix;
+ if (!_fileInfo.Find(_folderPrefix + fileName))
+ throw 1;
+ FileNames.Clear();
+ _subArchiveMode = false;
+ TotalSize = 0;
+ }
+ int FindName(const UString &name);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/Bench.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/Bench.cpp
new file mode 100644
index 000000000..282f405f1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/Bench.cpp
@@ -0,0 +1,1028 @@
+// Bench.cpp
+
+#include "StdAfx.h"
+
+#include "Bench.h"
+
+#ifndef _WIN32
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#endif
+#endif
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/Alloc.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/Thread.h"
+#endif
+
+#include "../../../Windows/PropVariant.h"
+
+static const UInt32 kUncompressMinBlockSize =
+#ifdef UNDER_CE
+1 << 24;
+#else
+1 << 26;
+#endif
+
+static const UInt32 kCrcBlockSize =
+#ifdef UNDER_CE
+1 << 25;
+#else
+1 << 30;
+#endif
+
+static const UInt32 kAdditionalSize = (1 << 16);
+static const UInt32 kCompressedAdditionalSize = (1 << 10);
+static const UInt32 kMaxLzmaPropSize = 5;
+
+class CBaseRandomGenerator
+{
+ UInt32 A1;
+ UInt32 A2;
+public:
+ CBaseRandomGenerator() { Init(); }
+ void Init() { A1 = 362436069; A2 = 521288629;}
+ UInt32 GetRnd()
+ {
+ return
+ ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
+ ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
+ }
+};
+
+class CBenchBuffer
+{
+public:
+ size_t BufferSize;
+ Byte *Buffer;
+ CBenchBuffer(): Buffer(0) {}
+ virtual ~CBenchBuffer() { Free(); }
+ void Free()
+ {
+ ::MidFree(Buffer);
+ Buffer = 0;
+ }
+ bool Alloc(size_t bufferSize)
+ {
+ if (Buffer != 0 && BufferSize == bufferSize)
+ return true;
+ Free();
+ Buffer = (Byte *)::MidAlloc(bufferSize);
+ BufferSize = bufferSize;
+ return (Buffer != 0);
+ }
+};
+
+class CBenchRandomGenerator: public CBenchBuffer
+{
+ CBaseRandomGenerator *RG;
+public:
+ void Set(CBaseRandomGenerator *rg) { RG = rg; }
+ UInt32 GetVal(UInt32 &res, int numBits)
+ {
+ UInt32 val = res & (((UInt32)1 << numBits) - 1);
+ res >>= numBits;
+ return val;
+ }
+ UInt32 GetLen(UInt32 &res)
+ {
+ UInt32 len = GetVal(res, 2);
+ return GetVal(res, 1 + len);
+ }
+ void Generate()
+ {
+ UInt32 pos = 0;
+ UInt32 rep0 = 1;
+ while (pos < BufferSize)
+ {
+ UInt32 res = RG->GetRnd();
+ res >>= 1;
+ if (GetVal(res, 1) == 0 || pos < 1024)
+ Buffer[pos++] = (Byte)(res & 0xFF);
+ else
+ {
+ UInt32 len;
+ len = 1 + GetLen(res);
+ if (GetVal(res, 3) != 0)
+ {
+ len += GetLen(res);
+ do
+ {
+ UInt32 ppp = GetVal(res, 5) + 6;
+ res = RG->GetRnd();
+ if (ppp > 30)
+ continue;
+ rep0 = /* (1 << ppp) +*/ GetVal(res, ppp);
+ res = RG->GetRnd();
+ }
+ while (rep0 >= pos);
+ rep0++;
+ }
+
+ for (UInt32 i = 0; i < len && pos < BufferSize; i++, pos++)
+ Buffer[pos] = Buffer[pos - rep0];
+ }
+ }
+ }
+};
+
+
+class CBenchmarkInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ const Byte *Data;
+ size_t Pos;
+ size_t Size;
+public:
+ MY_UNKNOWN_IMP
+ void Init(const Byte *data, size_t size)
+ {
+ Data = data;
+ Size = size;
+ Pos = 0;
+ }
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t remain = Size - Pos;
+ UInt32 kMaxBlockSize = (1 << 20);
+ if (size > kMaxBlockSize)
+ size = kMaxBlockSize;
+ if (size > remain)
+ size = (UInt32)remain;
+ for (UInt32 i = 0; i < size; i++)
+ ((Byte *)data)[i] = Data[Pos + i];
+ Pos += size;
+ if(processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+class CBenchmarkOutStream:
+ public ISequentialOutStream,
+ public CBenchBuffer,
+ public CMyUnknownImp
+{
+ // bool _overflow;
+public:
+ UInt32 Pos;
+ // CBenchmarkOutStream(): _overflow(false) {}
+ void Init()
+ {
+ // _overflow = false;
+ Pos = 0;
+ }
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t curSize = BufferSize - Pos;
+ if (curSize > size)
+ curSize = size;
+ memcpy(Buffer + Pos, data, curSize);
+ Pos += (UInt32)curSize;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)curSize;
+ if (curSize != size)
+ {
+ // _overflow = true;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+class CCrcOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ UInt32 Crc;
+ MY_UNKNOWN_IMP
+ void Init() { Crc = CRC_INIT_VAL; }
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ Crc = CrcUpdate(Crc, data, size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+static UInt64 GetTimeCount()
+{
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ timeval v;
+ if (gettimeofday(&v, 0) == 0)
+ return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec;
+ return (UInt64)time(NULL) * 1000000;
+ #else
+ return time(NULL);
+ #endif
+ #else
+ /*
+ LARGE_INTEGER value;
+ if (::QueryPerformanceCounter(&value))
+ return value.QuadPart;
+ */
+ return GetTickCount();
+ #endif
+}
+
+static UInt64 GetFreq()
+{
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ return 1000000;
+ #else
+ return 1;
+ #endif
+ #else
+ /*
+ LARGE_INTEGER value;
+ if (::QueryPerformanceFrequency(&value))
+ return value.QuadPart;
+ */
+ return 1000;
+ #endif
+}
+
+#ifndef USE_POSIX_TIME
+static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
+#endif
+
+static UInt64 GetUserTime()
+{
+ #ifdef USE_POSIX_TIME
+ return clock();
+ #else
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ if (
+ #ifdef UNDER_CE
+ ::GetThreadTimes(::GetCurrentThread()
+ #else
+ ::GetProcessTimes(::GetCurrentProcess()
+ #endif
+ , &creationTime, &exitTime, &kernelTime, &userTime) != 0)
+ return GetTime64(userTime) + GetTime64(kernelTime);
+ return (UInt64)GetTickCount() * 10000;
+ #endif
+}
+
+static UInt64 GetUserFreq()
+{
+ #ifdef USE_POSIX_TIME
+ return CLOCKS_PER_SEC;
+ #else
+ return 10000000;
+ #endif
+}
+
+class CBenchProgressStatus
+{
+ #ifndef _7ZIP_ST
+ NWindows::NSynchronization::CCriticalSection CS;
+ #endif
+public:
+ HRESULT Res;
+ bool EncodeMode;
+ void SetResult(HRESULT res)
+ {
+ #ifndef _7ZIP_ST
+ NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+ #endif
+ Res = res;
+ }
+ HRESULT GetResult()
+ {
+ #ifndef _7ZIP_ST
+ NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+ #endif
+ return Res;
+ }
+};
+
+class CBenchProgressInfo:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ CBenchProgressStatus *Status;
+ CBenchInfo BenchInfo;
+ HRESULT Res;
+ IBenchCallback *callback;
+ CBenchProgressInfo(): callback(0) {}
+ MY_UNKNOWN_IMP
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+static void SetStartTime(CBenchInfo &bi)
+{
+ bi.GlobalFreq = GetFreq();
+ bi.UserFreq = GetUserFreq();
+ bi.GlobalTime = ::GetTimeCount();
+ bi.UserTime = ::GetUserTime();
+}
+
+static void SetFinishTime(const CBenchInfo &biStart, CBenchInfo &dest)
+{
+ dest.GlobalFreq = GetFreq();
+ dest.UserFreq = GetUserFreq();
+ dest.GlobalTime = ::GetTimeCount() - biStart.GlobalTime;
+ dest.UserTime = ::GetUserTime() - biStart.UserTime;
+}
+
+STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ HRESULT res = Status->GetResult();
+ if (res != S_OK)
+ return res;
+ if (!callback)
+ return res;
+ CBenchInfo info = BenchInfo;
+ SetFinishTime(BenchInfo, info);
+ if (Status->EncodeMode)
+ {
+ info.UnpackSize = *inSize;
+ info.PackSize = *outSize;
+ res = callback->SetEncodeResult(info, false);
+ }
+ else
+ {
+ info.PackSize = BenchInfo.PackSize + *inSize;
+ info.UnpackSize = BenchInfo.UnpackSize + *outSize;
+ res = callback->SetDecodeResult(info, false);
+ }
+ if (res != S_OK)
+ Status->SetResult(res);
+ return res;
+}
+
+static const int kSubBits = 8;
+
+static UInt32 GetLogSize(UInt32 size)
+{
+ for (int i = kSubBits; i < 32; i++)
+ for (UInt32 j = 0; j < (1 << kSubBits); j++)
+ if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
+ return (i << kSubBits) + j;
+ return (32 << kSubBits);
+}
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ while (v1 > 1000000)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+UInt64 GetUsage(const CBenchInfo &info)
+{
+ UInt64 userTime = info.UserTime;
+ UInt64 userFreq = info.UserFreq;
+ UInt64 globalTime = info.GlobalTime;
+ UInt64 globalFreq = info.GlobalFreq;
+ NormalizeVals(userTime, userFreq);
+ NormalizeVals(globalFreq, globalTime);
+ if (userFreq == 0)
+ userFreq = 1;
+ if (globalTime == 0)
+ globalTime = 1;
+ return userTime * globalFreq * 1000000 / userFreq / globalTime;
+}
+
+UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating)
+{
+ UInt64 userTime = info.UserTime;
+ UInt64 userFreq = info.UserFreq;
+ UInt64 globalTime = info.GlobalTime;
+ UInt64 globalFreq = info.GlobalFreq;
+ NormalizeVals(userFreq, userTime);
+ NormalizeVals(globalTime, globalFreq);
+ if (globalFreq == 0)
+ globalFreq = 1;
+ if (userTime == 0)
+ userTime = 1;
+ return userFreq * globalTime / globalFreq * rating / userTime;
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
+{
+ UInt64 elTime = elapsedTime;
+ NormalizeVals(freq, elTime);
+ if (elTime == 0)
+ elTime = 1;
+ return value * freq / elTime;
+}
+
+UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
+{
+ UInt64 t = GetLogSize(dictionarySize) - (kBenchMinDicLogSize << kSubBits);
+ UInt64 numCommandsForOne = 870 + ((t * t * 5) >> (2 * kSubBits));
+ UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
+ return MyMultDiv64(numCommands, elapsedTime, freq);
+}
+
+UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations)
+{
+ UInt64 numCommands = (inSize * 200 + outSize * 4) * numIterations;
+ return MyMultDiv64(numCommands, elapsedTime, freq);
+}
+
+struct CEncoderInfo;
+
+struct CEncoderInfo
+{
+ #ifndef _7ZIP_ST
+ NWindows::CThread thread[2];
+ #endif
+ CMyComPtr<ICompressCoder> encoder;
+ CBenchProgressInfo *progressInfoSpec[2];
+ CMyComPtr<ICompressProgressInfo> progressInfo[2];
+ UInt32 NumIterations;
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+
+ struct CDecoderInfo
+ {
+ CEncoderInfo *Encoder;
+ UInt32 DecoderIndex;
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+ bool CallbackMode;
+ };
+ CDecoderInfo decodersInfo[2];
+
+ CMyComPtr<ICompressCoder> decoders[2];
+ HRESULT Results[2];
+ CBenchmarkOutStream *outStreamSpec;
+ CMyComPtr<ISequentialOutStream> outStream;
+ IBenchCallback *callback;
+ UInt32 crc;
+ UInt32 kBufferSize;
+ UInt32 compressedSize;
+ CBenchRandomGenerator rg;
+ CBenchmarkOutStream *propStreamSpec;
+ CMyComPtr<ISequentialOutStream> propStream;
+ HRESULT Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rg);
+ HRESULT Encode();
+ HRESULT Decode(UInt32 decoderIndex);
+
+ CEncoderInfo(): outStreamSpec(0), callback(0), propStreamSpec(0) {}
+
+ #ifndef _7ZIP_ST
+ static THREAD_FUNC_DECL EncodeThreadFunction(void *param)
+ {
+ CEncoderInfo *encoder = (CEncoderInfo *)param;
+ #ifdef USE_ALLOCA
+ alloca(encoder->AllocaSize);
+ #endif
+ HRESULT res = encoder->Encode();
+ encoder->Results[0] = res;
+ if (res != S_OK)
+ encoder->progressInfoSpec[0]->Status->SetResult(res);
+
+ return 0;
+ }
+ static THREAD_FUNC_DECL DecodeThreadFunction(void *param)
+ {
+ CDecoderInfo *decoder = (CDecoderInfo *)param;
+ #ifdef USE_ALLOCA
+ alloca(decoder->AllocaSize);
+ #endif
+ CEncoderInfo *encoder = decoder->Encoder;
+ encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);
+ return 0;
+ }
+
+ HRESULT CreateEncoderThread()
+ {
+ return thread[0].Create(EncodeThreadFunction, this);
+ }
+
+ HRESULT CreateDecoderThread(int index, bool callbackMode
+ #ifdef USE_ALLOCA
+ , size_t allocaSize
+ #endif
+ )
+ {
+ CDecoderInfo &decoder = decodersInfo[index];
+ decoder.DecoderIndex = index;
+ decoder.Encoder = this;
+ #ifdef USE_ALLOCA
+ decoder.AllocaSize = allocaSize;
+ #endif
+ decoder.CallbackMode = callbackMode;
+ return thread[index].Create(DecodeThreadFunction, &decoder);
+ }
+ #endif
+};
+
+HRESULT CEncoderInfo::Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rgLoc)
+{
+ rg.Set(rgLoc);
+ kBufferSize = dictionarySize + kAdditionalSize;
+ UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
+ if (!rg.Alloc(kBufferSize))
+ return E_OUTOFMEMORY;
+ rg.Generate();
+ crc = CrcCalc(rg.Buffer, rg.BufferSize);
+
+ outStreamSpec = new CBenchmarkOutStream;
+ if (!outStreamSpec->Alloc(kCompressedBufferSize))
+ return E_OUTOFMEMORY;
+
+ outStream = outStreamSpec;
+
+ propStreamSpec = 0;
+ if (!propStream)
+ {
+ propStreamSpec = new CBenchmarkOutStream;
+ propStream = propStreamSpec;
+ }
+ if (!propStreamSpec->Alloc(kMaxLzmaPropSize))
+ return E_OUTOFMEMORY;
+ propStreamSpec->Init();
+
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumThreads
+ };
+ const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ PROPVARIANT props[kNumProps];
+ props[0].vt = VT_UI4;
+ props[0].ulVal = dictionarySize;
+
+ props[1].vt = VT_UI4;
+ props[1].ulVal = numThreads;
+
+ {
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ RINOK(encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties));
+ if (!setCoderProperties)
+ return E_FAIL;
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, kNumProps));
+
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+ encoder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProperties);
+ if (writeCoderProperties)
+ {
+ RINOK(writeCoderProperties->WriteCoderProperties(propStream));
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CEncoderInfo::Encode()
+{
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ inStreamSpec->Init(rg.Buffer, rg.BufferSize);
+ outStreamSpec->Init();
+
+ RINOK(encoder->Code(inStream, outStream, 0, 0, progressInfo[0]));
+ compressedSize = outStreamSpec->Pos;
+ encoder.Release();
+ return S_OK;
+}
+
+HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)
+{
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ CMyComPtr<ICompressCoder> &decoder = decoders[decoderIndex];
+
+ CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
+ decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &compressSetDecoderProperties);
+ if (!compressSetDecoderProperties)
+ return E_FAIL;
+
+ CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
+ CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
+
+ CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
+ pi->BenchInfo.UnpackSize = 0;
+ pi->BenchInfo.PackSize = 0;
+
+ for (UInt32 j = 0; j < NumIterations; j++)
+ {
+ inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
+ crcOutStreamSpec->Init();
+
+ RINOK(compressSetDecoderProperties->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos));
+ UInt64 outSize = kBufferSize;
+ RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex]));
+ if (CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc)
+ return S_FALSE;
+ pi->BenchInfo.UnpackSize += kBufferSize;
+ pi->BenchInfo.PackSize += compressedSize;
+ }
+ decoder.Release();
+ return S_OK;
+}
+
+static const UInt32 kNumThreadsMax = (1 << 16);
+
+struct CBenchEncoders
+{
+ CEncoderInfo *encoders;
+ CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; }
+ ~CBenchEncoders() { delete []encoders; }
+};
+
+HRESULT LzmaBench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback)
+{
+ UInt32 numEncoderThreads =
+ #ifndef _7ZIP_ST
+ (numThreads > 1 ? numThreads / 2 : 1);
+ #else
+ 1;
+ #endif
+ UInt32 numSubDecoderThreads =
+ #ifndef _7ZIP_ST
+ (numThreads > 1 ? 2 : 1);
+ #else
+ 1;
+ #endif
+ if (dictionarySize < (1 << kBenchMinDicLogSize) || numThreads < 1 || numEncoderThreads > kNumThreadsMax)
+ {
+ return E_INVALIDARG;
+ }
+
+ CBenchEncoders encodersSpec(numEncoderThreads);
+ CEncoderInfo *encoders = encodersSpec.encoders;
+
+
+ UInt32 i;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.callback = (i == 0) ? callback : 0;
+
+ const UInt32 kLzmaId = 0x030101;
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS kLzmaId, encoder.encoder, true));
+ if (!encoder.encoder)
+ return E_NOTIMPL;
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS kLzmaId, encoder.decoders[j], false));
+ if (!encoder.decoders[j])
+ return E_NOTIMPL;
+ }
+ }
+
+ CBaseRandomGenerator rg;
+ rg.Init();
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ RINOK(encoders[i].Init(dictionarySize, numThreads, &rg));
+ }
+
+ CBenchProgressStatus status;
+ status.Res = S_OK;
+ status.EncodeMode = true;
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ for (int j = 0; j < 2; j++)
+ {
+ encoder.progressInfo[j] = encoder.progressInfoSpec[j] = new CBenchProgressInfo;
+ encoder.progressInfoSpec[j]->Status = &status;
+ }
+ if (i == 0)
+ {
+ encoder.progressInfoSpec[0]->callback = callback;
+ encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numEncoderThreads;
+ SetStartTime(encoder.progressInfoSpec[0]->BenchInfo);
+ }
+
+ #ifndef _7ZIP_ST
+ if (numEncoderThreads > 1)
+ {
+ #ifdef USE_ALLOCA
+ encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
+ #endif
+ RINOK(encoder.CreateEncoderThread())
+ }
+ else
+ #endif
+ {
+ RINOK(encoder.Encode());
+ }
+ }
+ #ifndef _7ZIP_ST
+ if (numEncoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ encoders[i].thread[0].Wait();
+ #endif
+
+ RINOK(status.Res);
+
+ CBenchInfo info;
+
+ SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info);
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = 1; // progressInfoSpec->NumIterations;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ info.UnpackSize += encoder.kBufferSize;
+ info.PackSize += encoder.compressedSize;
+ }
+ RINOK(callback->SetEncodeResult(info, true));
+
+
+ status.Res = S_OK;
+ status.EncodeMode = false;
+
+ UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.NumIterations = 2 + kUncompressMinBlockSize / encoder.kBufferSize;
+
+ if (i == 0)
+ {
+ encoder.progressInfoSpec[0]->callback = callback;
+ encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numDecoderThreads;
+ SetStartTime(encoder.progressInfoSpec[0]->BenchInfo);
+ }
+
+ #ifndef _7ZIP_ST
+ if (numDecoderThreads > 1)
+ {
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
+ #ifdef USE_ALLOCA
+ , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
+ #endif
+ );
+ RINOK(res);
+ }
+ }
+ else
+ #endif
+ {
+ RINOK(encoder.Decode(0));
+ }
+ }
+ #ifndef _7ZIP_ST
+ HRESULT res = S_OK;
+ if (numDecoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.thread[j].Wait();
+ if (encoder.Results[j] != S_OK)
+ res = encoder.Results[j];
+ }
+ RINOK(res);
+ #endif
+ RINOK(status.Res);
+ SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info);
+ #ifndef _7ZIP_ST
+ #ifdef UNDER_CE
+ if (numDecoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0)
+ info.UserTime += GetTime64(userTime) + GetTime64(kernelTime);
+ }
+ #endif
+ #endif
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ info.UnpackSize += encoder.kBufferSize;
+ info.PackSize += encoder.compressedSize;
+ }
+ RINOK(callback->SetDecodeResult(info, false));
+ RINOK(callback->SetDecodeResult(info, true));
+ return S_OK;
+}
+
+
+inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)
+{
+ UInt32 hs = dictionary - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ hs |= 0xFFFF;
+ if (hs > (1 << 24))
+ hs >>= 1;
+ hs++;
+ return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 +
+ (1 << 20) + (multiThread ? (6 << 20) : 0);
+}
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary)
+{
+ const UInt32 kBufferSize = dictionary;
+ const UInt32 kCompressedBufferSize = (kBufferSize / 2);
+ UInt32 numSubThreads = (numThreads > 1) ? 2 : 1;
+ UInt32 numBigThreads = numThreads / numSubThreads;
+ return (kBufferSize + kCompressedBufferSize +
+ GetLZMAUsage((numThreads > 1), dictionary) + (2 << 20)) * numBigThreads;
+}
+
+static bool CrcBig(const void *data, UInt32 size, UInt32 numCycles, UInt32 crcBase)
+{
+ for (UInt32 i = 0; i < numCycles; i++)
+ if (CrcCalc(data, size) != crcBase)
+ return false;
+ return true;
+}
+
+#ifndef _7ZIP_ST
+struct CCrcInfo
+{
+ NWindows::CThread Thread;
+ const Byte *Data;
+ UInt32 Size;
+ UInt32 NumCycles;
+ UInt32 Crc;
+ bool Res;
+ void Wait()
+ {
+ Thread.Wait();
+ Thread.Close();
+ }
+};
+
+static THREAD_FUNC_DECL CrcThreadFunction(void *param)
+{
+ CCrcInfo *p = (CCrcInfo *)param;
+ p->Res = CrcBig(p->Data, p->Size, p->NumCycles, p->Crc);
+ return 0;
+}
+
+struct CCrcThreads
+{
+ UInt32 NumThreads;
+ CCrcInfo *Items;
+ CCrcThreads(): Items(0), NumThreads(0) {}
+ void WaitAll()
+ {
+ for (UInt32 i = 0; i < NumThreads; i++)
+ Items[i].Wait();
+ NumThreads = 0;
+ }
+ ~CCrcThreads()
+ {
+ WaitAll();
+ delete []Items;
+ }
+};
+#endif
+
+static UInt32 CrcCalc1(const Byte *buf, UInt32 size)
+{
+ UInt32 crc = CRC_INIT_VAL;;
+ for (UInt32 i = 0; i < size; i++)
+ crc = CRC_UPDATE_BYTE(crc, buf[i]);
+ return CRC_GET_DIGEST(crc);
+}
+
+static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+ for (UInt32 i = 0; i < size; i++)
+ buf[i] = (Byte)RG.GetRnd();
+}
+
+static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+ RandGen(buf, size, RG);
+ return CrcCalc1(buf, size);
+}
+
+bool CrcInternalTest()
+{
+ CBenchBuffer buffer;
+ const UInt32 kBufferSize0 = (1 << 8);
+ const UInt32 kBufferSize1 = (1 << 10);
+ const UInt32 kCheckSize = (1 << 5);
+ if (!buffer.Alloc(kBufferSize0 + kBufferSize1))
+ return false;
+ Byte *buf = buffer.Buffer;
+ UInt32 i;
+ for (i = 0; i < kBufferSize0; i++)
+ buf[i] = (Byte)i;
+ UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
+ if (crc1 != 0x29058C73)
+ return false;
+ CBaseRandomGenerator RG;
+ RandGen(buf + kBufferSize0, kBufferSize1, RG);
+ for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
+ for (UInt32 j = 0; j < kCheckSize; j++)
+ if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
+ return false;
+ return true;
+}
+
+HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed)
+{
+ if (numThreads == 0)
+ numThreads = 1;
+
+ CBenchBuffer buffer;
+ size_t totalSize = (size_t)bufferSize * numThreads;
+ if (totalSize / numThreads != bufferSize)
+ return E_OUTOFMEMORY;
+ if (!buffer.Alloc(totalSize))
+ return E_OUTOFMEMORY;
+
+ Byte *buf = buffer.Buffer;
+ CBaseRandomGenerator RG;
+ UInt32 numCycles = (kCrcBlockSize) / ((bufferSize >> 2) + 1) + 1;
+
+ UInt64 timeVal;
+ #ifndef _7ZIP_ST
+ CCrcThreads threads;
+ if (numThreads > 1)
+ {
+ threads.Items = new CCrcInfo[numThreads];
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &info = threads.Items[i];
+ Byte *data = buf + (size_t)bufferSize * i;
+ info.Data = data;
+ info.NumCycles = numCycles;
+ info.Size = bufferSize;
+ info.Crc = RandGenCrc(data, bufferSize, RG);
+ }
+ timeVal = GetTimeCount();
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &info = threads.Items[i];
+ RINOK(info.Thread.Create(CrcThreadFunction, &info));
+ threads.NumThreads++;
+ }
+ threads.WaitAll();
+ for (i = 0; i < numThreads; i++)
+ if (!threads.Items[i].Res)
+ return S_FALSE;
+ }
+ else
+ #endif
+ {
+ UInt32 crc = RandGenCrc(buf, bufferSize, RG);
+ timeVal = GetTimeCount();
+ if (!CrcBig(buf, bufferSize, numCycles, crc))
+ return S_FALSE;
+ }
+ timeVal = GetTimeCount() - timeVal;
+ if (timeVal == 0)
+ timeVal = 1;
+
+ UInt64 size = (UInt64)numCycles * totalSize;
+ speed = MyMultDiv64(size, timeVal, GetFreq());
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/Bench.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/Bench.h
new file mode 100644
index 000000000..a8d02a19b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/Bench.h
@@ -0,0 +1,42 @@
+// Bench.h
+
+#ifndef __7ZIP_BENCH_H
+#define __7ZIP_BENCH_H
+
+#include "../../Common/CreateCoder.h"
+
+struct CBenchInfo
+{
+ UInt64 GlobalTime;
+ UInt64 GlobalFreq;
+ UInt64 UserTime;
+ UInt64 UserFreq;
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt32 NumIterations;
+ CBenchInfo(): NumIterations(0) {}
+};
+
+struct IBenchCallback
+{
+ virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0;
+ virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0;
+};
+
+UInt64 GetUsage(const CBenchInfo &benchOnfo);
+UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating);
+UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
+UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations);
+
+HRESULT LzmaBench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback);
+
+const int kBenchMinDicLogSize = 18;
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary);
+
+bool CrcInternalTest();
+HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/CompressCall.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/CompressCall.cpp
new file mode 100644
index 000000000..fdc6c66f1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/CompressCall.cpp
@@ -0,0 +1,470 @@
+// CompressCall.cpp
+
+#include "StdAfx.h"
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#undef _WIN32
+
+#include "CompressCall.h"
+
+// FIXME #include "Common/Random.h"
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Synchronization.h"
+// FIXME #include "Windows/FileMapping.h"
+#include "Windows/FileDir.h"
+
+#include "../FileManager/ProgramLocation.h"
+#include "../FileManager/RegistryUtils.h"
+
+#define NEED_NAME_WINDOWS_TO_UNIX
+#include "myPrivate.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif // _UNICODE
+
+using namespace NWindows;
+
+static LPCWSTR kShowDialogSwitch = L" -ad";
+static LPCWSTR kEmailSwitch = L" -seml.";
+static LPCWSTR kMapSwitch = L" -i#";
+static LPCWSTR kArchiveNoNameSwitch = L" -an";
+static LPCWSTR kArchiveTypeSwitch = L" -t";
+static LPCWSTR kArchiveMapSwitch = L" -ai#";
+static LPCWSTR kStopSwitchParsing = L" --";
+static LPCWSTR kLargePagesDisable = L" -slp-";
+
+static void AddLagePagesSwitch(UString &params)
+{
+#ifdef _WIN32
+ if (!ReadLockMemoryEnable())
+ params += kLargePagesDisable;
+#endif
+}
+
+HRESULT MyCreateProcess(const UString &params,
+ LPCWSTR curDir, bool waitFinish,
+ NWindows::NSynchronization::CBaseEvent *event)
+{
+ printf("MyCreateProcess: waitFinish=%d event=%p\n",(unsigned)waitFinish,event);
+ printf("\tparams : %ls\n",(const wchar_t*)params);
+ printf("\tcurDir : %ls\n",(const wchar_t*)curDir);
+
+ wxString cmd(params);
+ wxString memoCurDir = wxGetCwd();
+
+ if (curDir) { // FIXME
+ wxSetWorkingDirectory(wxString(curDir));
+
+
+ // under MacOSX, a bundle does not keep the current directory
+ // between 7zFM and 7zG ...
+ // So, try to use the environment variable P7ZIP_CURRENT_DIR
+
+ char p7zip_current_dir[MAX_PATH];
+
+ AString aCurPath = GetAnsiString(curDir);
+
+ const char *dir2 = nameWindowToUnix((const char *)aCurPath);
+
+ snprintf(p7zip_current_dir,sizeof(p7zip_current_dir),"P7ZIP_CURRENT_DIR=%s/",dir2);
+
+ p7zip_current_dir[sizeof(p7zip_current_dir)-1] = 0;
+
+ putenv(p7zip_current_dir);
+
+ printf("putenv(%s)\n",p7zip_current_dir);
+
+ }
+
+
+ printf("MyCreateProcess: cmd='%ls'\n",(const wchar_t *)cmd);
+ long pid = 0;
+ if (waitFinish) pid = wxExecute(cmd, wxEXEC_SYNC); // FIXME process never ends and stays zombie ...
+ else pid = wxExecute(cmd, wxEXEC_ASYNC);
+
+ if (curDir) wxSetWorkingDirectory(memoCurDir);
+
+
+ // FIXME if (pid == 0) return E_FAIL;
+
+ return S_OK;
+#ifdef _WIN32 // FIXME
+ const UString params2 = params;
+ BOOL result;
+ {
+ STARTUPINFOW startupInfo;
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpReserved = 0;
+ startupInfo.lpDesktop = 0;
+ startupInfo.lpTitle = 0;
+ startupInfo.dwFlags = 0;
+ startupInfo.cbReserved2 = 0;
+ startupInfo.lpReserved2 = 0;
+
+ result = ::CreateProcessW(NULL, (LPWSTR)(LPCWSTR)params,
+ NULL, NULL, FALSE, 0, NULL,
+ curDir,
+ &startupInfo, &processInformation);
+ }
+ if (result == 0)
+ return ::GetLastError();
+ else
+ {
+ ::CloseHandle(processInformation.hThread);
+ if (waitFinish)
+ WaitForSingleObject(processInformation.hProcess, INFINITE);
+ else if (event != NULL)
+ {
+ HANDLE handles[] = {processInformation.hProcess, *event };
+ ::WaitForMultipleObjects(sizeof(handles) / sizeof(handles[0]),
+ handles, FALSE, INFINITE);
+ }
+ ::CloseHandle(processInformation.hProcess);
+ }
+ return S_OK;
+#endif
+}
+
+UString GetQuotedString(const UString &s)
+{
+ return UString(L"\"") + s + UString(L"\"");
+}
+
+static UString Get7zGuiPath()
+{
+ UString path;
+ UString folder;
+ if (GetProgramFolderPath(folder))
+ path += folder;
+#ifdef _WIN32
+ path += L"7zG.exe";
+#else
+ path += L"7zG";
+#endif
+ return GetQuotedString(path);
+}
+
+#ifdef _WIN32
+static HRESULT CreateTempEvent(const wchar_t *name,
+ NSynchronization::CManualResetEvent &event, UString &eventName)
+{
+ CRandom random;
+ random.Init(GetTickCount());
+ for (;;)
+ {
+ int number = random.Generate();
+ wchar_t temp[32];
+ ConvertUInt64ToString((UInt32)number, temp);
+ eventName = name;
+ eventName += temp;
+ RINOK(event.CreateWithName(false, GetSystemString(eventName)));
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ return S_OK;
+ event.Close();
+ }
+}
+
+static HRESULT CreateMap(const UStringVector &names,
+ const UString &id,
+ CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event,
+ UString &params)
+{
+ UInt32 extraSize = 2;
+ UInt32 dataSize = 0;
+ for (int i = 0; i < names.Size(); i++)
+ dataSize += (names[i].Length() + 1) * sizeof(wchar_t);
+ UInt32 totalSize = extraSize + dataSize;
+
+ UString mappingName;
+
+ CRandom random;
+ random.Init(GetTickCount());
+ for (;;)
+ {
+ int number = random.Generate();
+ wchar_t temp[32];
+ ConvertUInt64ToString(UInt32(number), temp);
+ mappingName = id;
+ mappingName += L"Mapping";
+ mappingName += temp;
+ if (!fileMapping.Create(INVALID_HANDLE_VALUE, NULL,
+ PAGE_READWRITE, totalSize, GetSystemString(mappingName)))
+ return E_FAIL;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ break;
+ fileMapping.Close();
+ }
+
+ UString eventName;
+ RINOK(CreateTempEvent(id + L"MappingEndEvent", event, eventName));
+
+ params += mappingName;
+ params += L":";
+ wchar_t string[10];
+ ConvertUInt64ToString(totalSize, string);
+ params += string;
+
+ params += L":";
+ params += eventName;
+
+ LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_WRITE, 0, totalSize);
+ if (data == NULL)
+ return E_FAIL;
+ {
+ wchar_t *curData = (wchar_t *)data;
+ *curData = 0;
+ curData++;
+ for (int i = 0; i < names.Size(); i++)
+ {
+ const UString &s = names[i];
+ memcpy(curData, (const wchar_t *)s, s.Length() * sizeof(wchar_t));
+ curData += s.Length();
+ *curData++ = L'\0';
+ }
+ }
+ return S_OK;
+}
+#endif
+
+HRESULT CompressFiles(
+ const UString &curDir,
+ const UString &archiveName,
+ const UString &archiveType,
+ const UStringVector &names,
+ // const UString &outFolder,
+ bool email,
+ bool showDialog,
+ bool waitFinish)
+{
+ /*
+ UString curDir;
+ if (names.Size() > 0)
+ {
+ NFile::NDirectory::GetOnlyDirPrefix(names[0], curDir);
+ }
+ */
+ UString params;
+ params = Get7zGuiPath();
+ params += L" a";
+#ifdef _WIN32
+ params += kMapSwitch;
+ // params += _fileNames[0];
+
+ UInt32 extraSize = 2;
+ UInt32 dataSize = 0;
+ for (int i = 0; i < names.Size(); i++)
+ dataSize += (names[i].Length() + 1) * sizeof(wchar_t);
+ UInt32 totalSize = extraSize + dataSize;
+
+ UString mappingName;
+
+ CFileMapping fileMapping;
+ CRandom random;
+ random.Init(GetTickCount());
+ for (;;)
+ {
+ int number = random.Generate();
+ wchar_t temp[32];
+ ConvertUInt64ToString(UInt32(number), temp);
+ mappingName = L"7zCompressMapping";
+ mappingName += temp;
+ if (!fileMapping.Create(INVALID_HANDLE_VALUE, NULL,
+ PAGE_READWRITE, totalSize, GetSystemString(mappingName)))
+ {
+ // MyMessageBox(IDS_ERROR, 0x02000605);
+ return E_FAIL;
+ }
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ break;
+ fileMapping.Close();
+ }
+
+ NSynchronization::CManualResetEvent event;
+ UString eventName;
+ RINOK(CreateTempEvent(L"7zCompressMappingEndEvent", event, eventName));
+
+ params += mappingName;
+ params += L":";
+ wchar_t string[10];
+ ConvertUInt64ToString(totalSize, string);
+ params += string;
+
+ params += L":";
+ params += eventName;
+#else
+ char tempFile[256];
+ static int count = 1000;
+
+ sprintf(tempFile,"/tmp/7zCompress_%d_%d.tmp",(int)getpid(),count++);
+
+ FILE * file = fopen(tempFile,"w");
+ if (file)
+ {
+ for (int i = 0; i < names.Size(); i++) {
+ fprintf(file,"%ls\n",(const wchar_t *)names[i]);
+ printf(" TMP_%d : '%ls'\n",i,(const wchar_t *)names[i]);
+ }
+
+ fclose(file);
+ }
+ params += L" -i@";
+ params += GetUnicodeString(tempFile);
+#endif
+
+ if (!archiveType.IsEmpty())
+ {
+ params += kArchiveTypeSwitch;
+ params += archiveType;
+ }
+
+ if (email)
+ params += kEmailSwitch;
+
+ if (showDialog)
+ params += kShowDialogSwitch;
+
+ AddLagePagesSwitch(params);
+
+ params += kStopSwitchParsing;
+ params += L" ";
+
+ params += GetQuotedString(archiveName);
+
+#ifdef _WIN32
+ LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_WRITE, 0, totalSize);
+ if (data == NULL)
+ {
+ // MyMessageBox(IDS_ERROR, 0x02000605);
+ return E_FAIL;
+ }
+ try
+ {
+ wchar_t *curData = (wchar_t *)data;
+ *curData = 0;
+ curData++;
+ for (int i = 0; i < names.Size(); i++)
+ {
+ const UString &unicodeString = names[i];
+ memcpy(curData, (const wchar_t *)unicodeString ,
+ unicodeString .Length() * sizeof(wchar_t));
+ curData += unicodeString.Length();
+ *curData++ = L'\0';
+ }
+ // MessageBox(0, params, 0, 0);
+ RINOK(MyCreateProcess(params,
+ (curDir.IsEmpty()? 0: (LPCWSTR)curDir),
+ waitFinish, &event));
+ }
+ catch(...)
+ {
+ UnmapViewOfFile(data);
+ throw;
+ }
+ UnmapViewOfFile(data);
+
+
+ /*
+ CThreadCompressMain *compressor = new CThreadCompressMain();;
+ compressor->FileNames = _fileNames;
+ CThread thread;
+ if (!thread.Create(CThreadCompressMain::MyThreadFunction, compressor))
+ throw 271824;
+ */
+#else
+ printf("CompressFiles : -%ls-\n",(const wchar_t *)params);
+ HRESULT res = MyCreateProcess(params,
+ (curDir.IsEmpty()? 0: (LPCWSTR)curDir),
+ true, /* &event FIXME */ 0);
+ printf("CompressFiles : END\n");
+
+ remove(tempFile);
+#endif
+ return S_OK;
+}
+
+static HRESULT ExtractGroupCommand(const UStringVector &archivePaths,
+ const UString &params)
+{
+ UString params2 = params;
+ AddLagePagesSwitch(params2);
+ params2 += kArchiveNoNameSwitch;
+#ifdef _WIN32
+ params2 += kArchiveMapSwitch;
+ CFileMapping fileMapping;
+ NSynchronization::CManualResetEvent event;
+ RINOK(CreateMap(archivePaths, L"7zExtract", fileMapping, event, params2));
+ return MyCreateProcess(params2, 0, false, &event);
+#else
+ char tempFile[256];
+ static int count = 1000;
+
+ sprintf(tempFile,"/tmp/7zExtract_%d_%d.tmp",(int)getpid(),count++);
+
+ FILE * file = fopen(tempFile,"w");
+ if (file)
+ {
+ for (int i = 0; i < archivePaths.Size(); i++) {
+ fprintf(file,"%ls\n",(const wchar_t *)archivePaths[i]);
+ printf(" TMP_%d : '%ls'\n",i,(const wchar_t *)archivePaths[i]);
+ }
+
+ fclose(file);
+ }
+ params2 += L" -ai@";
+ params2 += GetUnicodeString(tempFile);
+ printf("ExtractGroupCommand : -%ls-\n",(const wchar_t *)params2);
+ HRESULT res = MyCreateProcess(params2, 0, true, /* &event FIXME */ 0);
+ printf("ExtractGroupCommand : END\n");
+
+ remove(tempFile);
+
+ return res;
+#endif
+}
+
+HRESULT ExtractArchives(const UStringVector &archivePaths,
+ const UString &outFolder, bool showDialog)
+{
+ UString params;
+ params = Get7zGuiPath();
+ params += L" x";
+ if (!outFolder.IsEmpty())
+ {
+ params += L" \"-o";
+ params += outFolder;
+ params += L"\"";
+ }
+ if (showDialog)
+ params += kShowDialogSwitch;
+ return ExtractGroupCommand(archivePaths, params);
+}
+
+HRESULT TestArchives(const UStringVector &archivePaths)
+{
+ UString params;
+ params = Get7zGuiPath();
+ params += L" t";
+ return ExtractGroupCommand(archivePaths, params);
+}
+
+HRESULT Benchmark()
+{
+ UString params;
+ params = Get7zGuiPath();
+ params += L" b";
+ return MyCreateProcess(params, 0, false, NULL);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/CompressCall.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/CompressCall.h
new file mode 100644
index 000000000..fc18df57c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/CompressCall.h
@@ -0,0 +1,24 @@
+// CompressCall.h
+
+#ifndef __COMPRESS_CALL_H
+#define __COMPRESS_CALL_H
+
+#include "Common/MyString.h"
+
+UString GetQuotedString(const UString &s);
+
+extern HWND g_HWND;
+UString HResultToMessage(HRESULT errorCode);
+
+HRESULT CompressFiles(
+ const UString &arcPathPrefix,
+ const UString &arcName,
+ const UString &arcType,
+ const UStringVector &names,
+ bool email, bool showDialog, bool waitFinish);
+
+HRESULT ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog);
+HRESULT TestArchives(const UStringVector &arcPaths);
+HRESULT Benchmark();
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.cpp
new file mode 100644
index 000000000..4335e2731
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.cpp
@@ -0,0 +1,35 @@
+// DefaultName.cpp
+
+#include "StdAfx.h"
+
+#include "DefaultName.h"
+
+static UString GetDefaultName3(const UString &fileName,
+ const UString &extension, const UString &addSubExtension)
+{
+ int extLength = extension.Length();
+ int fileNameLength = fileName.Length();
+ if (fileNameLength > extLength + 1)
+ {
+ int dotPos = fileNameLength - (extLength + 1);
+ if (fileName[dotPos] == '.')
+ if (extension.CompareNoCase(fileName.Mid(dotPos + 1)) == 0)
+ return fileName.Left(dotPos) + addSubExtension;
+ }
+ int dotPos = fileName.ReverseFind(L'.');
+ if (dotPos > 0)
+ return fileName.Left(dotPos) + addSubExtension;
+
+ if (addSubExtension.IsEmpty())
+ return fileName + L"~";
+ else
+ return fileName + addSubExtension;
+}
+
+UString GetDefaultName2(const UString &fileName,
+ const UString &extension, const UString &addSubExtension)
+{
+ UString name = GetDefaultName3(fileName, extension, addSubExtension);
+ name.TrimRight();
+ return name;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.h
new file mode 100644
index 000000000..9764ff871
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/DefaultName.h
@@ -0,0 +1,11 @@
+// DefaultName.h
+
+#ifndef __DEFAULTNAME_H
+#define __DEFAULTNAME_H
+
+#include "Common/MyString.h"
+
+UString GetDefaultName2(const UString &fileName,
+ const UString &extension, const UString &addSubExtension);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/DirItem.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/DirItem.h
new file mode 100644
index 000000000..29cc60d93
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/DirItem.h
@@ -0,0 +1,69 @@
+// DirItem.h
+
+#ifndef __DIR_ITEM_H
+#define __DIR_ITEM_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+#include "../../Archive/IArchive.h"
+
+struct CDirItem
+{
+ UInt64 Size;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ UString Name;
+ UInt32 Attrib;
+ int PhyParent;
+ int LogParent;
+
+ CDirItem(): PhyParent(-1), LogParent(-1) {}
+ bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
+};
+
+class CDirItems
+{
+ UStringVector Prefixes;
+ CIntVector PhyParents;
+ CIntVector LogParents;
+
+ UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const;
+public:
+ CObjectVector<CDirItem> Items;
+
+ int GetNumFolders() const { return Prefixes.Size(); }
+ UString GetPhyPath(int index) const;
+ UString GetLogPath(int index) const;
+
+ int AddPrefix(int phyParent, int logParent, const UString &prefix);
+ void DeleteLastPrefix();
+
+ void EnumerateDirectory(int phyParent, int logParent, const UString &phyPrefix,
+ UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes);
+
+ void EnumerateDirItems2(
+ const UString &phyPrefix,
+ const UString &logPrefix,
+ const UStringVector &filePaths,
+ UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes);
+
+ void ReserveDown();
+};
+
+struct CArcItem
+{
+ UInt64 Size;
+ FILETIME MTime;
+ UString Name;
+ bool IsDir;
+ bool SizeDefined;
+ bool MTimeDefined;
+ bool Censored;
+ UInt32 IndexInServer;
+ int TimeType;
+
+ CArcItem(): IsDir(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {}
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.cpp
new file mode 100644
index 000000000..ba03ea35c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -0,0 +1,361 @@
+// EnumDirItems.cpp
+
+#include "StdAfx.h"
+
+#include "EnumDirItems.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+void AddDirFileInfo(int phyParent, int logParent,
+ const NFind::CFileInfoW &fi, CObjectVector<CDirItem> &dirItems)
+{
+ CDirItem di;
+ di.Size = fi.Size;
+ di.CTime = fi.CTime;
+ di.ATime = fi.ATime;
+ di.MTime = fi.MTime;
+ di.Attrib = fi.Attrib;
+ di.PhyParent = phyParent;
+ di.LogParent = logParent;
+ di.Name = fi.Name;
+ dirItems.Add(di);
+}
+
+UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
+{
+ UString path;
+ int len = name.Length();
+ int i;
+ for (i = index; i >= 0; i = parents[i])
+ len += Prefixes[i].Length();
+ int totalLen = len;
+ wchar_t *p = path.GetBuffer(len);
+ p[len] = 0;
+ len -= name.Length();
+ memcpy(p + len, (const wchar_t *)name, name.Length() * sizeof(wchar_t));
+ for (i = index; i >= 0; i = parents[i])
+ {
+ const UString &s = Prefixes[i];
+ len -= s.Length();
+ memcpy(p + len, (const wchar_t *)s, s.Length() * sizeof(wchar_t));
+ }
+ path.ReleaseBuffer(totalLen);
+ return path;
+}
+
+UString CDirItems::GetPhyPath(int index) const
+{
+ const CDirItem &di = Items[index];
+ return GetPrefixesPath(PhyParents, di.PhyParent, di.Name);
+}
+
+UString CDirItems::GetLogPath(int index) const
+{
+ const CDirItem &di = Items[index];
+ return GetPrefixesPath(LogParents, di.LogParent, di.Name);
+}
+
+void CDirItems::ReserveDown()
+{
+ Prefixes.ReserveDown();
+ PhyParents.ReserveDown();
+ LogParents.ReserveDown();
+ Items.ReserveDown();
+}
+
+int CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)
+{
+ PhyParents.Add(phyParent);
+ LogParents.Add(logParent);
+ return Prefixes.Add(prefix);
+}
+
+void CDirItems::DeleteLastPrefix()
+{
+ PhyParents.DeleteBack();
+ LogParents.DeleteBack();
+ Prefixes.DeleteBack();
+}
+
+void CDirItems::EnumerateDirectory(int phyParent, int logParent, const UString &phyPrefix,
+ UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes)
+{
+ NFind::CEnumeratorW enumerator(phyPrefix + (wchar_t)kAnyStringWildcard);
+ for (;;)
+ {
+ NFind::CFileInfoW fi;
+ bool found;
+ if (!enumerator.Next(fi, found))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(phyPrefix);
+ return;
+ }
+ if (!found)
+ break;
+ AddDirFileInfo(phyParent, logParent, fi, Items);
+ if (fi.IsDir())
+ {
+ const UString name2 = fi.Name + (wchar_t)kDirDelimiter;
+ int parent = AddPrefix(phyParent, logParent, name2);
+ EnumerateDirectory(parent, parent, phyPrefix + name2, errorPaths, errorCodes);
+ }
+ }
+}
+
+void CDirItems::EnumerateDirItems2(const UString &phyPrefix, const UString &logPrefix,
+ const UStringVector &filePaths, UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes)
+{
+ int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, phyPrefix);
+ int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);
+
+ for (int i = 0; i < filePaths.Size(); i++)
+ {
+ const UString &filePath = filePaths[i];
+ NFind::CFileInfoW fi;
+ const UString phyPath = phyPrefix + filePath;
+ if (!fi.Find(phyPath))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(phyPath);
+ continue;
+ }
+ int delimiter = filePath.ReverseFind((wchar_t)kDirDelimiter);
+ UString phyPrefixCur;
+ int phyParentCur = phyParent;
+ if (delimiter >= 0)
+ {
+ phyPrefixCur = filePath.Left(delimiter + 1);
+ phyParentCur = AddPrefix(phyParent, logParent, phyPrefixCur);
+ }
+ AddDirFileInfo(phyParentCur, logParent, fi, Items);
+ if (fi.IsDir())
+ {
+ const UString name2 = fi.Name + (wchar_t)kDirDelimiter;
+ int parent = AddPrefix(phyParentCur, logParent, name2);
+ EnumerateDirectory(parent, parent, phyPrefix + phyPrefixCur + name2, errorPaths, errorCodes);
+ }
+ }
+ ReserveDown();
+}
+
+static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const UString &phyPrefix,
+ const UStringVector &addArchivePrefix,
+ CDirItems &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes);
+
+static HRESULT EnumerateDirItems_Spec(const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const UString &curFolderName,
+ const UString &phyPrefix,
+ const UStringVector &addArchivePrefix,
+ CDirItems &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+
+{
+ const UString name2 = curFolderName + (wchar_t)kDirDelimiter;
+ int parent = dirItems.AddPrefix(phyParent, logParent, name2);
+ int numItems = dirItems.Items.Size();
+ HRESULT res = EnumerateDirItems(curNode, parent, parent, phyPrefix + name2,
+ addArchivePrefix, dirItems, enterToSubFolders, callback, errorPaths, errorCodes);
+ if (numItems == dirItems.Items.Size())
+ dirItems.DeleteLastPrefix();
+ return res;
+}
+
+
+static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const UString &phyPrefix,
+ const UStringVector &addArchivePrefix, // prefix from curNode
+ CDirItems &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ if (!enterToSubFolders)
+ if (curNode.NeedCheckSubDirs())
+ enterToSubFolders = true;
+ if (callback)
+ RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix));
+
+ // try direct_names case at first
+ if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
+ {
+ // check that all names are direct
+ int i;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ break;
+ const UString &name = item.PathParts.Front();
+ if (name.IsEmpty() || DoesNameContainWildCard(name))
+ break;
+ }
+ if (i == curNode.IncludeItems.Size())
+ {
+ // all names are direct (no wildcards)
+ // so we don't need file_system's dir enumerator
+ CRecordVector<bool> needEnterVector;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ const UString &name = item.PathParts.Front();
+ const UString fullPath = phyPrefix + name;
+ NFind::CFileInfoW fi;
+ if (!fi.Find(fullPath))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ bool isDir = fi.IsDir();
+ if (isDir && !item.ForDir || !isDir && !item.ForFile)
+ {
+ errorCodes.Add((DWORD)E_FAIL);
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ {
+ UStringVector pathParts;
+ pathParts.Add(fi.Name);
+ if (curNode.CheckPathToRoot(false, pathParts, !isDir))
+ continue;
+ }
+ AddDirFileInfo(phyParent, logParent, fi, dirItems.Items);
+ if (!isDir)
+ continue;
+
+ UStringVector addArchivePrefixNew;
+ const NWildcard::CCensorNode *nextNode = 0;
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ {
+ for (int t = needEnterVector.Size(); t <= index; t++)
+ needEnterVector.Add(true);
+ needEnterVector[index] = false;
+ nextNode = &curNode.SubNodes[index];
+ }
+ else
+ {
+ nextNode = &curNode;
+ addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support
+ }
+
+ RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,
+ addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
+ }
+ for (i = 0; i < curNode.SubNodes.Size(); i++)
+ {
+ if (i < needEnterVector.Size())
+ if (!needEnterVector[i])
+ continue;
+ const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
+ const UString fullPath = phyPrefix + nextNode.Name;
+ NFind::CFileInfoW fi;
+ if (!fi.Find(fullPath))
+ {
+ if (!nextNode.AreThereIncludeItems())
+ continue;
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ if (!fi.IsDir())
+ {
+ errorCodes.Add((DWORD)E_FAIL);
+ errorPaths.Add(fullPath);
+ continue;
+ }
+
+ RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
+ UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+ }
+ }
+
+
+ NFind::CEnumeratorW enumerator(phyPrefix + wchar_t(kAnyStringWildcard));
+ for (int ttt = 0; ; ttt++)
+ {
+ NFind::CFileInfoW fi;
+ bool found;
+ if (!enumerator.Next(fi, found))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(phyPrefix);
+ break;
+ }
+ if (!found)
+ break;
+
+ if (callback && (ttt & 0xFF) == 0xFF)
+ RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix));
+ const UString &name = fi.Name;
+ bool enterToSubFolders2 = enterToSubFolders;
+ UStringVector addArchivePrefixNew = addArchivePrefix;
+ addArchivePrefixNew.Add(name);
+ {
+ UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
+ if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))
+ continue;
+ }
+ if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
+ {
+ AddDirFileInfo(phyParent, logParent, fi, dirItems.Items);
+ if (fi.IsDir())
+ enterToSubFolders2 = true;
+ }
+ if (!fi.IsDir())
+ continue;
+
+ const NWildcard::CCensorNode *nextNode = 0;
+ if (addArchivePrefix.IsEmpty())
+ {
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ nextNode = &curNode.SubNodes[index];
+ }
+ if (!enterToSubFolders2 && nextNode == 0)
+ continue;
+
+ addArchivePrefixNew = addArchivePrefix;
+ if (nextNode == 0)
+ {
+ nextNode = &curNode;
+ addArchivePrefixNew.Add(name);
+ }
+
+ RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, name, phyPrefix,
+ addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+}
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ CDirItems &dirItems,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ for (int i = 0; i < censor.Pairs.Size(); i++)
+ {
+ const NWildcard::CPair &pair = censor.Pairs[i];
+ int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);
+ RINOK(EnumerateDirItems(pair.Head, phyParent, -1, pair.Prefix, UStringVector(), dirItems, false,
+ callback, errorPaths, errorCodes));
+ }
+ dirItems.ReserveDown();
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.h
new file mode 100644
index 000000000..d0ce950e3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/EnumDirItems.h
@@ -0,0 +1,25 @@
+// EnumDirItems.h
+
+#ifndef __ENUM_DIR_ITEMS_H
+#define __ENUM_DIR_ITEMS_H
+
+#include "Common/Wildcard.h"
+#include "Windows/FileFind.h"
+#include "DirItem.h"
+
+void AddDirFileInfo(int phyParent, int logParent,
+ const NWindows::NFile::NFind::CFileInfoW &fi, CObjectVector<CDirItem> &dirItems);
+
+struct IEnumDirItemCallback
+{
+ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) = 0;
+};
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ CDirItems &dirItems,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ExitCode.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/ExitCode.h
new file mode 100644
index 000000000..b6d7d4dfc
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ExitCode.h
@@ -0,0 +1,27 @@
+// ExitCode.h
+
+#ifndef __EXIT_CODE_H
+#define __EXIT_CODE_H
+
+namespace NExitCode {
+
+enum EEnum {
+
+ kSuccess = 0, // Successful operation
+ kWarning = 1, // Non fatal error(s) occurred
+ kFatalError = 2, // A fatal error occurred
+ // kCRCError = 3, // A CRC error occurred when unpacking
+ // kLockedArchive = 4, // Attempt to modify an archive previously locked
+ // kWriteError = 5, // Write to disk error
+ // kOpenError = 6, // Open file error
+ kUserError = 7, // Command line option error
+ kMemoryError = 8, // Not enough memory for operation
+ // kCreateFileError = 9, // Create file error
+
+ kUserBreak = 255 // User stopped the process
+
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp
new file mode 100644
index 000000000..ca2c8c73d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.cpp
@@ -0,0 +1,263 @@
+// Extract.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "Extract.h"
+#include "SetProperties.h"
+
+using namespace NWindows;
+
+static HRESULT DecompressArchive(
+ const CArc &arc,
+ UInt64 packSize,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IExtractCallbackUI *callback,
+ CArchiveExtractCallback *extractCallbackSpec,
+ UString &errorMessage,
+ UInt64 &stdInProcessed)
+{
+ stdInProcessed = 0;
+ IInArchive *archive = arc.Archive;
+ CRecordVector<UInt32> realIndices;
+ if (!options.StdInMode)
+ {
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ UString filePath;
+ RINOK(arc.GetItemPath(i, filePath));
+ bool isFolder;
+ RINOK(IsArchiveItemFolder(archive, i, isFolder));
+ if (!wildcardCensor.CheckPath(filePath, !isFolder))
+ continue;
+ realIndices.Add(i);
+ }
+ if (realIndices.Size() == 0)
+ {
+ callback->ThereAreNoFiles();
+ return S_OK;
+ }
+ }
+
+ UStringVector removePathParts;
+
+ UString outDir = options.OutputDir;
+ outDir.Replace(L"*", GetCorrectFsPath(arc.DefaultName));
+ #ifdef _WIN32
+ // GetCorrectFullFsPath doesn't like "..".
+ // outDir.TrimRight();
+ // outDir = GetCorrectFullFsPath(outDir);
+ #endif
+
+ if (!outDir.IsEmpty())
+ if (!NFile::NDirectory::CreateComplexDirectory(outDir))
+ {
+ HRESULT res = ::GetLastError();
+ if (res == S_OK)
+ res = E_FAIL;
+ errorMessage = ((UString)L"Can not create output directory ") + outDir;
+ return res;
+ }
+
+ extractCallbackSpec->Init(
+ options.StdInMode ? &wildcardCensor : NULL,
+ &arc,
+ callback,
+ options.StdOutMode, options.TestMode, options.CalcCrc,
+ outDir,
+ removePathParts,
+ packSize);
+
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ RINOK(SetProperties(archive, options.Properties));
+ #endif
+
+ HRESULT result;
+ Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0;
+ if (options.StdInMode)
+ {
+ result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec);
+ NCOM::CPropVariant prop;
+ if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
+ if (prop.vt == VT_UI8 || prop.vt == VT_UI4)
+ stdInProcessed = ConvertPropVariantToUInt64(prop);
+ }
+ else
+ result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec);
+
+ return callback->ExtractResult(result);
+}
+
+HRESULT DecompressArchives(
+ CCodecs *codecs, const CIntVector &formatIndices,
+ UStringVector &arcPaths, UStringVector &arcPathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ UString &errorMessage,
+ CDecompressStat &stat)
+{
+ stat.Clear();
+ int i;
+ UInt64 totalPackSize = 0;
+ CRecordVector<UInt64> archiveSizes;
+
+ int numArcs = options.StdInMode ? 1 : arcPaths.Size();
+
+ for (i = 0; i < numArcs; i++)
+ {
+ NFile::NFind::CFileInfoW fi;
+ fi.Size = 0;
+ if (!options.StdInMode)
+ {
+ const UString &arcPath = arcPaths[i];
+ if (!fi.Find(arcPath))
+ throw "there is no such archive";
+ if (fi.IsDir())
+ throw "can't decompress folder";
+ }
+ archiveSizes.Add(fi.Size);
+ totalPackSize += fi.Size;
+ }
+ CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);
+ bool multi = (numArcs > 1);
+ extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);
+ if (multi)
+ {
+ RINOK(extractCallback->SetTotal(totalPackSize));
+ }
+ for (i = 0; i < numArcs; i++)
+ {
+ const UString &arcPath = arcPaths[i];
+ NFile::NFind::CFileInfoW fi;
+ if (options.StdInMode)
+ {
+ fi.Size = 0;
+ fi.Attrib = 0;
+ }
+ else
+ {
+ if (!fi.Find(arcPath) || fi.IsDir())
+ throw "there is no such archive";
+ }
+
+ #ifndef _NO_CRYPTO
+ openCallback->Open_ClearPasswordWasAskedFlag();
+ #endif
+
+ RINOK(extractCallback->BeforeOpen(arcPath));
+ CArchiveLink archiveLink;
+
+ CIntVector formatIndices2 = formatIndices;
+ #ifndef _SFX
+ if (formatIndices.IsEmpty())
+ {
+ int pos = arcPath.ReverseFind(L'.');
+ if (pos >= 0)
+ {
+ UString s = arcPath.Mid(pos + 1);
+ int index = codecs->FindFormatForExtension(s);
+ if (index >= 0 && s == L"001")
+ {
+ s = arcPath.Left(pos);
+ pos = s.ReverseFind(L'.');
+ if (pos >= 0)
+ {
+ int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1));
+ if (index2 >= 0 && s.CompareNoCase(L"rar") != 0)
+ {
+ formatIndices2.Add(index2);
+ formatIndices2.Add(index);
+ }
+ }
+ }
+ }
+ }
+ #endif
+ HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback);
+ if (result == E_ABORT)
+ return result;
+
+ bool crypted = false;
+ #ifndef _NO_CRYPTO
+ crypted = openCallback->Open_WasPasswordAsked();
+ #endif
+
+ RINOK(extractCallback->OpenResult(arcPath, result, crypted));
+ if (result != S_OK)
+ continue;
+
+ if (!options.StdInMode)
+ for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+ {
+ int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+ if (index >= 0 && index > i)
+ {
+ arcPaths.Delete(index);
+ arcPathsFull.Delete(index);
+ totalPackSize -= archiveSizes[index];
+ archiveSizes.Delete(index);
+ numArcs = arcPaths.Size();
+ }
+ }
+ if (archiveLink.VolumePaths.Size() != 0)
+ {
+ totalPackSize += archiveLink.VolumesSize;
+ RINOK(extractCallback->SetTotal(totalPackSize));
+ }
+
+ #ifndef _NO_CRYPTO
+ UString password;
+ RINOK(openCallback->Open_GetPasswordIfAny(password));
+ if (!password.IsEmpty())
+ {
+ RINOK(extractCallback->SetPassword(password));
+ }
+ #endif
+
+ for (int v = 0; v < archiveLink.Arcs.Size(); v++)
+ {
+ const UString &s = archiveLink.Arcs[v].ErrorMessage;
+ if (!s.IsEmpty())
+ {
+ RINOK(extractCallback->MessageError(s));
+ }
+ }
+
+ CArc &arc = archiveLink.Arcs.Back();
+ arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice);
+ arc.MTime = fi.MTime;
+
+ UInt64 packProcessed;
+ RINOK(DecompressArchive(arc,
+ fi.Size + archiveLink.VolumesSize,
+ wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage, packProcessed));
+ if (!options.StdInMode)
+ packProcessed = fi.Size + archiveLink.VolumesSize;
+ extractCallbackSpec->LocalProgressSpec->InSize += packProcessed;
+ extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;
+ if (!errorMessage.IsEmpty())
+ return E_FAIL;
+ }
+ stat.NumFolders = extractCallbackSpec->NumFolders;
+ stat.NumFiles = extractCallbackSpec->NumFiles;
+ stat.UnpackSize = extractCallbackSpec->UnpackSize;
+ stat.CrcSum = extractCallbackSpec->CrcSum;
+
+ stat.NumArchives = arcPaths.Size();
+ stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.h
new file mode 100644
index 000000000..5a939ed23
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/Extract.h
@@ -0,0 +1,76 @@
+// Extract.h
+
+#ifndef __EXTRACT_H
+#define __EXTRACT_H
+
+#include "Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ArchiveExtractCallback.h"
+#include "ArchiveOpenCallback.h"
+#include "ExtractMode.h"
+#include "Property.h"
+
+#include "../Common/LoadCodecs.h"
+
+struct CExtractOptions
+{
+ bool StdInMode;
+ bool StdOutMode;
+ bool YesToAll;
+ bool TestMode;
+ bool CalcCrc;
+ NExtract::NPathMode::EEnum PathMode;
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+ UString OutputDir;
+
+ // bool ShowDialog;
+ // bool PasswordEnabled;
+ // UString Password;
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ CObjectVector<CProperty> Properties;
+ #endif
+
+ #ifdef EXTERNAL_CODECS
+ CCodecs *Codecs;
+ #endif
+
+ CExtractOptions():
+ StdInMode(false),
+ StdOutMode(false),
+ YesToAll(false),
+ TestMode(false),
+ CalcCrc(false),
+ PathMode(NExtract::NPathMode::kFullPathnames),
+ OverwriteMode(NExtract::NOverwriteMode::kAskBefore)
+ {}
+};
+
+struct CDecompressStat
+{
+ UInt64 NumArchives;
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+ UInt32 CrcSum;
+
+ void Clear()
+ {
+ NumArchives = UnpackSize = PackSize = NumFolders = NumFiles = 0;
+ CrcSum = 0;
+ }
+};
+
+HRESULT DecompressArchives(
+ CCodecs *codecs, const CIntVector &formatIndices,
+ UStringVector &archivePaths, UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ UString &errorMessage,
+ CDecompressStat &stat);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractMode.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractMode.h
new file mode 100644
index 000000000..b448fb30a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractMode.h
@@ -0,0 +1,31 @@
+// ExtractMode.h
+
+#ifndef __EXTRACT_MODE_H
+#define __EXTRACT_MODE_H
+
+namespace NExtract {
+
+ namespace NPathMode
+ {
+ enum EEnum
+ {
+ kFullPathnames,
+ kCurrentPathnames,
+ kNoPathnames
+ };
+ }
+
+ namespace NOverwriteMode
+ {
+ enum EEnum
+ {
+ kAskBefore,
+ kWithoutPrompt,
+ kSkipExisting,
+ kAutoRename,
+ kAutoRenameExisting
+ };
+ }
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.cpp
new file mode 100644
index 000000000..8f31708b6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -0,0 +1,142 @@
+// ExtractingFilePath.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Types.h"
+
+#include "Common/Wildcard.h"
+
+#include "ExtractingFilePath.h"
+
+static UString ReplaceIncorrectChars(const UString &s)
+{
+ #ifdef _WIN32
+ UString res;
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ if (c < 0x20 || c == '*' || c == '?' || c == '<' || c == '>' || c == '|' || c == ':' || c == '"')
+ c = '_';
+ res += c;
+ }
+ res.TrimRight();
+ while (!res.IsEmpty() && res[res.Length() - 1] == '.')
+ res.Delete(res.Length() - 1);
+ return res;
+ #else
+ return s;
+ #endif
+}
+
+#ifdef _WIN32
+static const wchar_t *g_ReservedNames[] =
+{
+ L"CON", L"PRN", L"AUX", L"NUL"
+};
+
+static bool CheckTail(const UString &name, int len)
+{
+ int dotPos = name.Find(L'.');
+ if (dotPos < 0)
+ dotPos = name.Length();
+ UString s = name.Left(dotPos);
+ s.TrimRight();
+ return (s.Length() != len);
+}
+
+static bool CheckNameNum(const UString &name, const wchar_t *reservedName)
+{
+ int len = MyStringLen(reservedName);
+ if (name.Length() <= len)
+ return true;
+ if (name.Left(len).CompareNoCase(reservedName) != 0)
+ return true;
+ wchar_t c = name[len];
+ if (c < L'0' || c > L'9')
+ return true;
+ return CheckTail(name, len + 1);
+}
+
+static bool IsSupportedName(const UString &name)
+{
+ for (int i = 0; i < sizeof(g_ReservedNames) / sizeof(g_ReservedNames[0]); i++)
+ {
+ const wchar_t *reservedName = g_ReservedNames[i];
+ int len = MyStringLen(reservedName);
+ if (name.Length() < len)
+ continue;
+ if (name.Left(len).CompareNoCase(reservedName) != 0)
+ continue;
+ if (!CheckTail(name, len))
+ return false;
+ }
+ if (!CheckNameNum(name, L"COM"))
+ return false;
+ return CheckNameNum(name, L"LPT");
+}
+#endif
+
+static UString GetCorrectFileName(const UString &path)
+{
+ if (path == L".." || path == L".")
+ return UString();
+ return ReplaceIncorrectChars(path);
+}
+
+void MakeCorrectPath(UStringVector &pathParts)
+{
+ for (int i = 0; i < pathParts.Size();)
+ {
+ UString &s = pathParts[i];
+ s = GetCorrectFileName(s);
+ if (s.IsEmpty())
+ pathParts.Delete(i);
+ else
+ {
+ #ifdef _WIN32
+ if (!IsSupportedName(s))
+ s = (UString)L"_" + s;
+ #endif
+ i++;
+ }
+ }
+}
+
+UString MakePathNameFromParts(const UStringVector &parts)
+{
+ UString result;
+ for (int i = 0; i < parts.Size(); i++)
+ {
+ if (i != 0)
+ result += WCHAR_PATH_SEPARATOR;
+ result += parts[i];
+ }
+ return result;
+}
+
+UString GetCorrectFsPath(const UString &path)
+{
+ UString res = GetCorrectFileName(path);
+ #ifdef _WIN32
+ if (!IsSupportedName(res))
+ res = (UString)L"_" + res;
+ #endif
+ return res;
+}
+
+UString GetCorrectFullFsPath(const UString &path)
+{
+ UStringVector parts;
+ SplitPathToParts(path, parts);
+ for (int i = 0; i < parts.Size(); i++)
+ {
+ UString &s = parts[i];
+ #ifdef _WIN32
+ while (!s.IsEmpty() && s[s.Length() - 1] == '.')
+ s.Delete(s.Length() - 1);
+ if (!IsSupportedName(s))
+ s = (UString)L"_" + s;
+ #endif
+ }
+ return MakePathNameFromParts(parts);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.h
new file mode 100644
index 000000000..da28bfc23
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ExtractingFilePath.h
@@ -0,0 +1,13 @@
+// ExtractingFilePath.h
+
+#ifndef __EXTRACTING_FILE_PATH_H
+#define __EXTRACTING_FILE_PATH_H
+
+#include "Common/MyString.h"
+
+UString MakePathNameFromParts(const UStringVector &parts);
+void MakeCorrectPath(UStringVector &pathParts);
+UString GetCorrectFsPath(const UString &path);
+UString GetCorrectFullFsPath(const UString &path);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/HandlerLoader.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/HandlerLoader.h
new file mode 100644
index 000000000..4c7e1a8f4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/HandlerLoader.h
@@ -0,0 +1,38 @@
+// HandlerLoader.h
+
+#ifndef __HANDLERLOADER_H
+#define __HANDLERLOADER_H
+
+#include "../../ICoder.h"
+#include "Windows/DLL.h"
+
+typedef UInt32 (WINAPI * CreateObjectFunc)(
+ const GUID *clsID,
+ const GUID *interfaceID,
+ void **outObject);
+
+class CHandlerLoader: public NWindows::NDLL::CLibrary
+{
+public:
+ HRESULT CreateHandler(LPCWSTR filepath, REFGUID clsID,
+ void **archive, bool outHandler)
+ {
+ if (!Load(filepath))
+ return GetLastError();
+ CreateObjectFunc createObject = (CreateObjectFunc)
+ GetProcAddress("CreateObject");
+ if (createObject == NULL)
+ {
+ HRESULT res = ::GetLastError();
+ Free();
+ return res;
+ }
+ HRESULT res = createObject(&clsID,
+ outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
+ if (res != 0)
+ Free();
+ return res;
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/IFileExtractCallback.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/IFileExtractCallback.h
new file mode 100644
index 000000000..e8dcdce5f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/IFileExtractCallback.h
@@ -0,0 +1,46 @@
+// IFileExtractCallback.h
+
+#ifndef __IFILEEXTRACTCALLBACK_H
+#define __IFILEEXTRACTCALLBACK_H
+
+#include "Common/MyString.h"
+#include "../../IDecl.h"
+
+namespace NOverwriteAnswer
+{
+ enum EEnum
+ {
+ kYes,
+ kYesToAll,
+ kNo,
+ kNoToAll,
+ kAutoRename,
+ kCancel
+ };
+}
+
+DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07)
+{
+public:
+ STDMETHOD(AskOverwrite)(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer) PURE;
+ STDMETHOD(PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position) PURE;
+ STDMETHOD(MessageError)(const wchar_t *message) PURE;
+ STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted) PURE;
+};
+
+struct IExtractCallbackUI: IFolderArchiveExtractCallback
+{
+ virtual HRESULT BeforeOpen(const wchar_t *name) = 0;
+ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted) = 0;
+ virtual HRESULT ThereAreNoFiles() = 0;
+ virtual HRESULT ExtractResult(HRESULT result) = 0;
+
+ #ifndef _NO_CRYPTO
+ virtual HRESULT SetPassword(const UString &password) = 0;
+ #endif
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.cpp
new file mode 100644
index 000000000..171b7c104
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.cpp
@@ -0,0 +1,716 @@
+// LoadCodecs.cpp
+
+#include "StdAfx.h"
+
+#include "LoadCodecs.h"
+
+#include "../../../Common/MyCom.h"
+#ifdef NEW_FOLDER_INTERFACE
+#include "../../../Common/StringToInt.h"
+#endif
+#include "../../../Windows/PropVariant.h"
+
+#include "../../ICoder.h"
+#include "../../Common/RegisterArc.h"
+
+#ifdef EXTERNAL_CODECS
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/DLL.h"
+#ifdef NEW_FOLDER_INTERFACE
+#include "../../../Windows/ResourceString.h"
+static const UINT kIconTypesResId = 100;
+#endif
+
+#ifdef _WIN32
+#include "Windows/Registry.h"
+#else
+#include "Common/StringConvert.h"
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+
+#ifdef _WIN32
+extern HINSTANCE g_hInstance;
+#endif
+
+static CSysString GetLibraryFolderPrefix()
+{
+ #ifdef _WIN32
+ TCHAR fullPath[MAX_PATH + 1];
+ ::GetModuleFileName(g_hInstance, fullPath, MAX_PATH);
+ CSysString path = fullPath;
+ int pos = path.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+ return path.Left(pos + 1);
+ #else
+ const char *p7zip_home_dir = getenv("P7ZIP_HOME_DIR");
+ if (p7zip_home_dir == 0) p7zip_home_dir="./";
+#ifdef _UNICODE
+ return MultiByteToUnicodeString(p7zip_home_dir);
+#else
+ return p7zip_home_dir;
+#endif
+ #endif
+}
+
+#define kCodecsFolderName TEXT("Codecs")
+#define kFormatsFolderName TEXT("Formats")
+static const TCHAR *kMainDll = TEXT("7z.dll");
+
+#ifdef _WIN32
+static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
+static LPCTSTR kProgramPathValue = TEXT("Path");
+static bool ReadPathFromRegistry(HKEY baseKey, CSysString &path)
+{
+ NRegistry::CKey key;
+ if(key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
+ if (key.QueryValue(kProgramPathValue, path) == ERROR_SUCCESS)
+ {
+ NName::NormalizeDirPathPrefix(path);
+ return true;
+ }
+ return false;
+}
+
+#endif
+
+CSysString GetBaseFolderPrefixFromRegistry()
+{
+ CSysString moduleFolderPrefix = GetLibraryFolderPrefix();
+#ifdef _UNICODE
+ NFind::CFileInfoW fi;
+#else
+ NFind::CFileInfo fi;
+#endif
+ if (NFind::FindFile(moduleFolderPrefix + kMainDll, fi))
+ if (!fi.IsDir())
+ return moduleFolderPrefix;
+ if (NFind::FindFile(moduleFolderPrefix + kCodecsFolderName, fi))
+ if (fi.IsDir())
+ return moduleFolderPrefix;
+ if (NFind::FindFile(moduleFolderPrefix + kFormatsFolderName, fi))
+ if (fi.IsDir())
+ return moduleFolderPrefix;
+ #ifdef _WIN32
+ if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) &&
+ !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) &&
+ !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName))
+ {
+ CSysString path;
+ if (ReadPathFromRegistry(HKEY_CURRENT_USER, path))
+ return path;
+ if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path))
+ return path;
+ }
+ #endif
+ return moduleFolderPrefix;
+}
+
+typedef UInt32 (WINAPI *GetNumberOfMethodsFunc)(UInt32 *numMethods);
+typedef UInt32 (WINAPI *GetNumberOfFormatsFunc)(UInt32 *numFormats);
+typedef UInt32 (WINAPI *GetHandlerPropertyFunc)(PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *GetHandlerPropertyFunc2)(UInt32 index, PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *iid, void **outObject);
+typedef UInt32 (WINAPI *SetLargePageModeFunc)();
+
+
+static HRESULT GetCoderClass(GetMethodPropertyFunc getMethodProperty, UInt32 index,
+ PROPID propId, CLSID &clsId, bool &isAssigned)
+{
+ NWindows::NCOM::CPropVariant prop;
+ isAssigned = false;
+ RINOK(getMethodProperty(index, propId, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ isAssigned = true;
+ clsId = *(const GUID *)prop.bstrVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT CCodecs::LoadCodecs()
+{
+ CCodecLib &lib = Libs.Back();
+ lib.GetMethodProperty = (GetMethodPropertyFunc)lib.Lib.GetProc("GetMethodProperty");
+ if (lib.GetMethodProperty == NULL)
+ return S_OK;
+
+ UInt32 numMethods = 1;
+ GetNumberOfMethodsFunc getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)lib.Lib.GetProc("GetNumberOfMethods");
+ if (getNumberOfMethodsFunc != NULL)
+ {
+ RINOK(getNumberOfMethodsFunc(&numMethods));
+ }
+
+ for(UInt32 i = 0; i < numMethods; i++)
+ {
+ CDllCodecInfo info;
+ info.LibIndex = Libs.Size() - 1;
+ info.CodecIndex = i;
+
+ RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
+ RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
+
+ Codecs.Add(info);
+ }
+ return S_OK;
+}
+
+static HRESULT ReadProp(
+ GetHandlerPropertyFunc getProp,
+ GetHandlerPropertyFunc2 getProp2,
+ UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
+{
+ if (getProp2)
+ return getProp2(index, propID, &prop);;
+ return getProp(propID, &prop);
+}
+
+static HRESULT ReadBoolProp(
+ GetHandlerPropertyFunc getProp,
+ GetHandlerPropertyFunc2 getProp2,
+ UInt32 index, PROPID propID, bool &res)
+{
+ NCOM::CPropVariant prop;
+ RINOK(ReadProp(getProp, getProp2, index, propID, prop));
+ if (prop.vt == VT_BOOL)
+ res = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+static HRESULT ReadStringProp(
+ GetHandlerPropertyFunc getProp,
+ GetHandlerPropertyFunc2 getProp2,
+ UInt32 index, PROPID propID, UString &res)
+{
+ NCOM::CPropVariant prop;
+ RINOK(ReadProp(getProp, getProp2, index, propID, prop));
+ if (prop.vt == VT_BSTR)
+ res = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+#endif
+
+static const unsigned int kNumArcsMax = 48;
+static unsigned int g_NumArcs = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax];
+void RegisterArc(const CArcInfo *arcInfo)
+{
+ if (g_NumArcs < kNumArcsMax)
+ g_Arcs[g_NumArcs++] = arcInfo;
+}
+
+static void SplitString(const UString &srcString, UStringVector &destStrings)
+{
+ destStrings.Clear();
+ UString s;
+ int len = srcString.Length();
+ if (len == 0)
+ return;
+ for (int i = 0; i < len; i++)
+ {
+ wchar_t c = srcString[i];
+ if (c == L' ')
+ {
+ if (!s.IsEmpty())
+ {
+ destStrings.Add(s);
+ s.Empty();
+ }
+ }
+ else
+ s += c;
+ }
+ if (!s.IsEmpty())
+ destStrings.Add(s);
+}
+
+void CArcInfoEx::AddExts(const wchar_t *ext, const wchar_t *addExt)
+{
+ UStringVector exts, addExts;
+ if (ext != 0)
+ SplitString(ext, exts);
+ if (addExt != 0)
+ SplitString(addExt, addExts);
+ for (int i = 0; i < exts.Size(); i++)
+ {
+ CArcExtInfo extInfo;
+ extInfo.Ext = exts[i];
+ if (i < addExts.Size())
+ {
+ extInfo.AddExt = addExts[i];
+ if (extInfo.AddExt == L"*")
+ extInfo.AddExt.Empty();
+ }
+ Exts.Add(extInfo);
+ }
+}
+
+#ifdef EXTERNAL_CODECS
+
+HRESULT CCodecs::LoadFormats()
+{
+ const NDLL::CLibrary &lib = Libs.Back().Lib;
+ GetHandlerPropertyFunc getProp = 0;
+ GetHandlerPropertyFunc2 getProp2 = (GetHandlerPropertyFunc2)lib.GetProc("GetHandlerProperty2");
+ if (getProp2 == NULL)
+ {
+ getProp = (GetHandlerPropertyFunc)lib.GetProc("GetHandlerProperty");
+ if (getProp == NULL)
+ return S_OK;
+ }
+
+ UInt32 numFormats = 1;
+ GetNumberOfFormatsFunc getNumberOfFormats = (GetNumberOfFormatsFunc)lib.GetProc("GetNumberOfFormats");
+ if (getNumberOfFormats != NULL)
+ {
+ RINOK(getNumberOfFormats(&numFormats));
+ }
+ if (getProp2 == NULL)
+ numFormats = 1;
+
+ for(UInt32 i = 0; i < numFormats; i++)
+ {
+ CArcInfoEx item;
+ item.LibIndex = Libs.Size() - 1;
+ item.FormatIndex = i;
+
+ RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kName, item.Name));
+
+ NCOM::CPropVariant prop;
+ if (ReadProp(getProp, getProp2, i, NArchive::kClassID, prop) != S_OK)
+ continue;
+ if (prop.vt != VT_BSTR)
+ continue;
+ item.ClassID = *(const GUID *)prop.bstrVal;
+ prop.Clear();
+
+ UString ext, addExt;
+ RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kExtension, ext));
+ RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kAddExtension, addExt));
+ item.AddExts(ext, addExt);
+
+ ReadBoolProp(getProp, getProp2, i, NArchive::kUpdate, item.UpdateEnabled);
+ if (item.UpdateEnabled)
+ ReadBoolProp(getProp, getProp2, i, NArchive::kKeepName, item.KeepName);
+
+ if (ReadProp(getProp, getProp2, i, NArchive::kStartSignature, prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ {
+ UINT len = ::SysStringByteLen(prop.bstrVal);
+ item.StartSignature.SetCapacity(len);
+ memmove((Byte *)item.StartSignature, prop.bstrVal, len);
+ }
+ Formats.Add(item);
+ }
+ return S_OK;
+}
+
+#ifdef NEW_FOLDER_INTERFACE
+void CCodecIcons::LoadIcons(HMODULE m)
+{
+#ifdef _WIN32
+ UString iconTypes = MyLoadStringW(m, kIconTypesResId);
+ UStringVector pairs;
+ SplitString(iconTypes, pairs);
+ for (int i = 0; i < pairs.Size(); i++)
+ {
+ const UString &s = pairs[i];
+ int pos = s.Find(L':');
+ CIconPair iconPair;
+ iconPair.IconIndex = -1;
+ if (pos < 0)
+ pos = s.Length();
+ else
+ {
+ UString num = s.Mid(pos + 1);
+ if (!num.IsEmpty())
+ {
+ const wchar_t *end;
+ iconPair.IconIndex = (UInt32)ConvertStringToUInt64(num, &end);
+ if (*end != L'\0')
+ continue;
+ }
+ }
+ iconPair.Ext = s.Left(pos);
+ IconPairs.Add(iconPair);
+ }
+#endif // #ifdef _WIN32
+}
+
+bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
+{
+#ifdef _WIN32
+ iconIndex = -1;
+ for (int i = 0; i < IconPairs.Size(); i++)
+ {
+ const CIconPair &pair = IconPairs[i];
+ if (ext.CompareNoCase(pair.Ext) == 0)
+ {
+ iconIndex = pair.IconIndex;
+ return true;
+ }
+ }
+#endif // #ifdef _WIN32
+ return false;
+}
+#endif
+
+#ifdef _7ZIP_LARGE_PAGES
+extern "C"
+{
+ extern size_t g_LargePageSize;
+}
+#endif
+
+HRESULT CCodecs::LoadDll(const CSysString &dllPath, bool needCheckDll)
+{
+#ifdef _WIN32
+ if (needCheckDll)
+ {
+ NDLL::CLibrary library;
+ if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
+ return S_OK;
+ }
+#endif
+ Libs.Add(CCodecLib());
+ CCodecLib &lib = Libs.Back();
+ #ifdef NEW_FOLDER_INTERFACE
+ lib.Path = dllPath;
+ #endif
+ bool used = false;
+ HRESULT res = S_OK;
+ if (lib.Lib.Load(dllPath))
+ {
+ #ifdef NEW_FOLDER_INTERFACE
+ lib.LoadIcons();
+ #endif
+
+ #ifdef _7ZIP_LARGE_PAGES
+ if (g_LargePageSize != 0)
+ {
+ SetLargePageModeFunc setLargePageMode = (SetLargePageModeFunc)lib.Lib.GetProc("SetLargePageMode");
+ if (setLargePageMode != 0)
+ setLargePageMode();
+ }
+ #endif
+
+ lib.CreateObject = (CreateObjectFunc)lib.Lib.GetProc("CreateObject");
+ if (lib.CreateObject != 0)
+ {
+ int startSize = Codecs.Size();
+ res = LoadCodecs();
+ used = (Codecs.Size() != startSize);
+ if (res == S_OK)
+ {
+ startSize = Formats.Size();
+ res = LoadFormats();
+ used = used || (Formats.Size() != startSize);
+ }
+ }
+ }
+ if (!used)
+ Libs.DeleteBack();
+ return res;
+}
+
+HRESULT CCodecs::LoadDllsFromFolder(const CSysString &folderPrefix)
+{
+#ifdef _UNICODE
+ NFile::NFind::CEnumeratorW enumerator(folderPrefix + CSysString(TEXT("*")));
+ NFile::NFind::CFileInfoW fi;
+#else
+ NFile::NFind::CEnumerator enumerator(folderPrefix + CSysString(TEXT("*")));
+ NFile::NFind::CFileInfo fi;
+#endif
+ while (enumerator.Next(fi))
+ {
+ if (fi.IsDir())
+ continue;
+ RINOK(LoadDll(folderPrefix + fi.Name, true));
+ }
+ return S_OK;
+}
+
+#endif
+
+#ifndef _SFX
+static inline void SetBuffer(CByteBuffer &bb, const Byte *data, int size)
+{
+ bb.SetCapacity(size);
+ memmove((Byte *)bb, data, size);
+}
+#endif
+
+HRESULT CCodecs::Load()
+{
+ #ifdef NEW_FOLDER_INTERFACE
+ #ifdef _WIN32
+ InternalIcons.LoadIcons(g_hInstance);
+ #endif
+ #endif
+
+ Formats.Clear();
+ #ifdef EXTERNAL_CODECS
+ Codecs.Clear();
+ #endif
+ for (UInt32 i = 0; i < g_NumArcs; i++)
+ {
+ const CArcInfo &arc = *g_Arcs[i];
+ CArcInfoEx item;
+ item.Name = arc.Name;
+ item.CreateInArchive = arc.CreateInArchive;
+ item.CreateOutArchive = arc.CreateOutArchive;
+ item.AddExts(arc.Ext, arc.AddExt);
+ item.UpdateEnabled = (arc.CreateOutArchive != 0);
+ item.KeepName = arc.KeepName;
+
+ #ifndef _SFX
+ SetBuffer(item.StartSignature, arc.Signature, arc.SignatureSize);
+ #endif
+ Formats.Add(item);
+ }
+ #ifdef EXTERNAL_CODECS
+ const CSysString baseFolder = GetBaseFolderPrefixFromRegistry();
+ RINOK(LoadDll(baseFolder + kMainDll, false));
+ RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName TEXT(STRING_PATH_SEPARATOR)));
+ RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName TEXT(STRING_PATH_SEPARATOR)));
+ #endif
+ return S_OK;
+}
+
+#ifndef _SFX
+
+int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
+{
+ int slashPos1 = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR);
+ int slashPos2 = arcPath.ReverseFind(L'.');
+ int dotPos = arcPath.ReverseFind(L'.');
+ if (dotPos < 0 || dotPos < slashPos1 || dotPos < slashPos2)
+ return -1;
+ UString ext = arcPath.Mid(dotPos + 1);
+ for (int i = 0; i < Formats.Size(); i++)
+ {
+ const CArcInfoEx &arc = Formats[i];
+ if (!arc.UpdateEnabled)
+ continue;
+ if (arc.FindExtension(ext) >= 0)
+ return i;
+ }
+ return -1;
+}
+
+int CCodecs::FindFormatForExtension(const UString &ext) const
+{
+ if (ext.IsEmpty())
+ return -1;
+ for (int i = 0; i < Formats.Size(); i++)
+ if (Formats[i].FindExtension(ext) >= 0)
+ return i;
+ return -1;
+}
+
+int CCodecs::FindFormatForArchiveType(const UString &arcType) const
+{
+ for (int i = 0; i < Formats.Size(); i++)
+ if (Formats[i].Name.CompareNoCase(arcType) == 0)
+ return i;
+ return -1;
+}
+
+bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const
+{
+ formatIndices.Clear();
+ for (int pos = 0; pos < arcType.Length();)
+ {
+ int pos2 = arcType.Find('.', pos);
+ if (pos2 < 0)
+ pos2 = arcType.Length();
+ const UString name = arcType.Mid(pos, pos2 - pos);
+ int index = FindFormatForArchiveType(name);
+ if (index < 0 && name != L"*")
+ {
+ formatIndices.Clear();
+ return false;
+ }
+ formatIndices.Add(index);
+ pos = pos2 + 1;
+ }
+ return true;
+}
+
+#endif
+
+#ifdef EXTERNAL_CODECS
+
+#ifdef EXPORT_CODECS
+extern unsigned int g_NumCodecs;
+STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject);
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
+// STDAPI GetNumberOfMethods(UInt32 *numCodecs);
+#endif
+
+STDMETHODIMP CCodecs::GetNumberOfMethods(UInt32 *numMethods)
+{
+ *numMethods =
+ #ifdef EXPORT_CODECS
+ g_NumCodecs +
+ #endif
+ Codecs.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return GetMethodProperty(index, propID, value);
+ #endif
+
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+
+ if (propID == NMethodPropID::kDecoderIsAssigned)
+ {
+ NWindows::NCOM::CPropVariant propVariant;
+ propVariant = ci.DecoderIsAssigned;
+ propVariant.Detach(value);
+ return S_OK;
+ }
+ if (propID == NMethodPropID::kEncoderIsAssigned)
+ {
+ NWindows::NCOM::CPropVariant propVariant;
+ propVariant = ci.EncoderIsAssigned;
+ propVariant.Detach(value);
+ return S_OK;
+ }
+ return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value);
+}
+
+STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return CreateCoder2(false, index, iid, coder);
+ #endif
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+ if (ci.DecoderIsAssigned)
+ return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder);
+ return S_OK;
+}
+
+STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return CreateCoder2(true, index, iid, coder);
+ #endif
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+ if (ci.EncoderIsAssigned)
+ return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder);
+ return S_OK;
+}
+
+HRESULT CCodecs::CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const
+{
+ for (int i = 0; i < Codecs.Size(); i++)
+ {
+ const CDllCodecInfo &codec = Codecs[i];
+ if (encode && !codec.EncoderIsAssigned || !encode && !codec.DecoderIsAssigned)
+ continue;
+ const CCodecLib &lib = Libs[codec.LibIndex];
+ UString res;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(lib.GetMethodProperty(codec.CodecIndex, NMethodPropID::kName, &prop));
+ if (prop.vt == VT_BSTR)
+ res = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ continue;
+ if (name.CompareNoCase(res) == 0)
+ return lib.CreateObject(encode ? &codec.Encoder : &codec.Decoder, &IID_ICompressCoder, (void **)&coder);
+ }
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+int CCodecs::GetCodecLibIndex(UInt32 index)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return -1;
+ #endif
+ #ifdef EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+ return ci.LibIndex;
+ #else
+ return -1;
+ #endif
+}
+
+bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ {
+ NWindows::NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK)
+ if (prop.vt != VT_EMPTY)
+ return true;
+ return false;
+ }
+ #endif
+ #ifdef EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+ return ci.EncoderIsAssigned;
+ #else
+ return false;
+ #endif
+}
+
+HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id)
+{
+ UString s;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(GetProperty(index, NMethodPropID::kID, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ id = prop.uhVal.QuadPart;
+ return S_OK;
+}
+
+UString CCodecs::GetCodecName(UInt32 index)
+{
+ UString s;
+ NWindows::NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ s = prop.bstrVal;
+ return s;
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.h
new file mode 100644
index 000000000..a633dd2e1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/LoadCodecs.h
@@ -0,0 +1,235 @@
+// LoadCodecs.h
+
+#ifndef __LOADCODECS_H
+#define __LOADCODECS_H
+
+#include "../../../Common/Types.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/Buffer.h"
+#include "../../ICoder.h"
+
+#ifdef EXTERNAL_CODECS
+#include "../../../Windows/DLL.h"
+#endif
+
+struct CDllCodecInfo
+{
+ CLSID Encoder;
+ CLSID Decoder;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+ int LibIndex;
+ UInt32 CodecIndex;
+};
+
+#include "../../Archive/IArchive.h"
+
+typedef IInArchive * (*CreateInArchiveP)();
+typedef IOutArchive * (*CreateOutArchiveP)();
+
+struct CArcExtInfo
+{
+ UString Ext;
+ UString AddExt;
+ CArcExtInfo() {}
+ CArcExtInfo(const UString &ext): Ext(ext) {}
+ CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
+};
+
+
+struct CArcInfoEx
+{
+ #ifdef EXTERNAL_CODECS
+ int LibIndex;
+ UInt32 FormatIndex;
+ CLSID ClassID;
+ #endif
+ bool UpdateEnabled;
+ CreateInArchiveP CreateInArchive;
+ CreateOutArchiveP CreateOutArchive;
+ UString Name;
+ CObjectVector<CArcExtInfo> Exts;
+ #ifndef _SFX
+ CByteBuffer StartSignature;
+ // CByteBuffer FinishSignature;
+ #ifdef NEW_FOLDER_INTERFACE
+ UStringVector AssociateExts;
+ #endif
+ #endif
+ bool KeepName;
+ UString GetMainExt() const
+ {
+ if (Exts.IsEmpty())
+ return UString();
+ return Exts[0].Ext;
+ }
+ int FindExtension(const UString &ext) const
+ {
+ for (int i = 0; i < Exts.Size(); i++)
+ if (ext.CompareNoCase(Exts[i].Ext) == 0)
+ return i;
+ return -1;
+ }
+ UString GetAllExtensions() const
+ {
+ UString s;
+ for (int i = 0; i < Exts.Size(); i++)
+ {
+ if (i > 0)
+ s += ' ';
+ s += Exts[i].Ext;
+ }
+ return s;
+ }
+
+ void AddExts(const wchar_t* ext, const wchar_t* addExt);
+
+ CArcInfoEx():
+ #ifdef EXTERNAL_CODECS
+ LibIndex(-1),
+ #endif
+ UpdateEnabled(false),
+ CreateInArchive(0), CreateOutArchive(0),
+ KeepName(false)
+ #ifndef _SFX
+ #endif
+ {}
+};
+
+#ifdef EXTERNAL_CODECS
+typedef UInt32 (WINAPI *GetMethodPropertyFunc)(UInt32 index, PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *interfaceID, void **outObject);
+
+
+#ifdef NEW_FOLDER_INTERFACE
+struct CCodecIcons
+{
+ struct CIconPair
+ {
+ UString Ext;
+ int IconIndex;
+ };
+ CObjectVector<CIconPair> IconPairs;
+ void LoadIcons(HMODULE m);
+ bool FindIconIndex(const UString &ext, int &iconIndex) const;
+};
+#endif
+
+struct CCodecLib
+#ifdef NEW_FOLDER_INTERFACE
+: public CCodecIcons
+#endif
+{
+ NWindows::NDLL::CLibrary Lib;
+ GetMethodPropertyFunc GetMethodProperty;
+ CreateObjectFunc CreateObject;
+ #ifdef NEW_FOLDER_INTERFACE
+ CSysString Path;
+ void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }
+ #endif
+ CCodecLib(): GetMethodProperty(0) {}
+};
+#endif
+
+class CCodecs:
+ #ifdef EXTERNAL_CODECS
+ public ICompressCodecsInfo,
+ #else
+ public IUnknown,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ #ifdef EXTERNAL_CODECS
+ CObjectVector<CCodecLib> Libs;
+ CObjectVector<CDllCodecInfo> Codecs;
+
+ #ifdef NEW_FOLDER_INTERFACE
+ CCodecIcons InternalIcons;
+ #endif
+
+ HRESULT LoadCodecs();
+ HRESULT LoadFormats();
+ HRESULT LoadDll(const CSysString &path, bool needCheckDll);
+ HRESULT LoadDllsFromFolder(const CSysString &folderPrefix);
+
+ HRESULT CreateArchiveHandler(const CArcInfoEx &ai, void **archive, bool outHandler) const
+ {
+ return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
+ }
+ #endif
+
+public:
+ CObjectVector<CArcInfoEx> Formats;
+ HRESULT Load();
+
+ #ifndef _SFX
+ int FindFormatForArchiveName(const UString &arcPath) const;
+ int FindFormatForExtension(const UString &ext) const;
+ int FindFormatForArchiveType(const UString &arcType) const;
+ bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
+ #endif
+
+ MY_UNKNOWN_IMP
+
+ #ifdef EXTERNAL_CODECS
+ STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods);
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
+ STDMETHOD(CreateDecoder)(UInt32 index, const GUID *interfaceID, void **coder);
+ STDMETHOD(CreateEncoder)(UInt32 index, const GUID *interfaceID, void **coder);
+ #endif
+
+ int GetCodecLibIndex(UInt32 index);
+ bool GetCodecEncoderIsAssigned(UInt32 index);
+ HRESULT GetCodecId(UInt32 index, UInt64 &id);
+ UString GetCodecName(UInt32 index);
+
+ HRESULT CreateInArchive(int formatIndex, CMyComPtr<IInArchive> &archive) const
+ {
+ const CArcInfoEx &ai = Formats[formatIndex];
+ #ifdef EXTERNAL_CODECS
+ if (ai.LibIndex < 0)
+ #endif
+ {
+ archive = ai.CreateInArchive();
+ return S_OK;
+ }
+ #ifdef EXTERNAL_CODECS
+ return CreateArchiveHandler(ai, (void **)&archive, false);
+ #endif
+ }
+ HRESULT CreateOutArchive(int formatIndex, CMyComPtr<IOutArchive> &archive) const
+ {
+ const CArcInfoEx &ai = Formats[formatIndex];
+ #ifdef EXTERNAL_CODECS
+ if (ai.LibIndex < 0)
+ #endif
+ {
+ archive = ai.CreateOutArchive();
+ return S_OK;
+ }
+ #ifdef EXTERNAL_CODECS
+ return CreateArchiveHandler(ai, (void **)&archive, true);
+ #endif
+ }
+ int FindOutFormatFromName(const UString &name) const
+ {
+ for (int i = 0; i < Formats.Size(); i++)
+ {
+ const CArcInfoEx &arc = Formats[i];
+ if (!arc.UpdateEnabled)
+ continue;
+ if (arc.Name.CompareNoCase(name) == 0)
+ return i;
+ }
+ return -1;
+ }
+
+ #ifdef EXTERNAL_CODECS
+ HRESULT CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const;
+ #endif
+
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.cpp
new file mode 100644
index 000000000..12b8e148a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.cpp
@@ -0,0 +1,536 @@
+// OpenArchive.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "DefaultName.h"
+#include "OpenArchive.h"
+
+using namespace NWindows;
+
+// Static-SFX (for Linux) can be big.
+const UInt64 kMaxCheckStartPosition = 1 << 22;
+
+HRESULT GetArchiveItemBoolProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
+{
+ NCOM::CPropVariant prop;
+ result = false;
+ RINOK(archive->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_BOOL)
+ result = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
+{
+ return GetArchiveItemBoolProp(archive, index, kpidIsDir, result);
+}
+
+HRESULT CArc::GetItemPath(UInt32 index, UString &result) const
+{
+ {
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidPath, &prop));
+ if (prop.vt == VT_BSTR)
+ result = prop.bstrVal;
+ else if (prop.vt == VT_EMPTY)
+ result.Empty();
+ else
+ return E_FAIL;
+ }
+ if (result.IsEmpty())
+ {
+ result = DefaultName;
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidExtension, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ result += L'.';
+ result += prop.bstrVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const
+{
+ NCOM::CPropVariant prop;
+ defined = false;
+ ft.dwHighDateTime = ft.dwLowDateTime = 0;
+ RINOK(Archive->GetProperty(index, kpidMTime, &prop));
+ if (prop.vt == VT_FILETIME)
+ {
+ ft = prop.filetime;
+ defined = true;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ else if (MTimeDefined)
+ {
+ ft = MTime;
+ defined = true;
+ }
+ return S_OK;
+}
+
+#ifndef _SFX
+static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ if (p1[i] != p2[i])
+ return false;
+ return true;
+}
+#endif
+
+#ifdef UNDER_CE
+static const int kNumHashBytes = 1;
+#define HASH_VAL(buf, pos) ((buf)[pos])
+#else
+static const int kNumHashBytes = 2;
+#define HASH_VAL(buf, pos) ((buf)[pos] | ((UInt32)(buf)[pos + 1] << 8))
+#endif
+
+
+HRESULT CArc::OpenStream(
+ CCodecs *codecs,
+ int formatIndex,
+ IInStream *stream,
+ ISequentialInStream *seqStream,
+ IArchiveOpenCallback *callback)
+{
+ Archive.Release();
+ ErrorMessage.Empty();
+ const UString fileName = ExtractFileNameFromPath(Path);
+ UString extension;
+ {
+ int dotPos = fileName.ReverseFind(L'.');
+ if (dotPos >= 0)
+ extension = fileName.Mid(dotPos + 1);
+ }
+ CIntVector orderIndices;
+ if (formatIndex >= 0)
+ orderIndices.Add(formatIndex);
+ else
+ {
+
+ int i;
+ int numFinded = 0;
+ for (i = 0; i < codecs->Formats.Size(); i++)
+ if (codecs->Formats[i].FindExtension(extension) >= 0)
+ orderIndices.Insert(numFinded++, i);
+ else
+ orderIndices.Add(i);
+
+ if (!stream)
+ {
+ if (numFinded != 1)
+ return E_NOTIMPL;
+ orderIndices.DeleteFrom(1);
+ }
+
+ #ifndef _SFX
+ if (orderIndices.Size() >= 2 && (numFinded == 0 || extension.CompareNoCase(L"exe") == 0))
+ {
+ CIntVector orderIndices2;
+ CByteBuffer byteBuffer;
+ const size_t kBufferSize = (1 << 21);
+ byteBuffer.SetCapacity(kBufferSize);
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ size_t processedSize = kBufferSize;
+ RINOK(ReadStream(stream, byteBuffer, &processedSize));
+ if (processedSize == 0)
+ return S_FALSE;
+
+ const Byte *buf = byteBuffer;
+ CByteBuffer hashBuffer;
+ const UInt32 kNumVals = 1 << (kNumHashBytes * 8);
+ hashBuffer.SetCapacity(kNumVals);
+ Byte *hash = hashBuffer;
+ memset(hash, 0xFF, kNumVals);
+ Byte prevs[256];
+ if (orderIndices.Size() >= 256)
+ return S_FALSE;
+ int i;
+ for (i = 0; i < orderIndices.Size(); i++)
+ {
+ const CArcInfoEx &ai = codecs->Formats[orderIndices[i]];
+ const CByteBuffer &sig = ai.StartSignature;
+ if (sig.GetCapacity() < kNumHashBytes)
+ continue;
+ UInt32 v = HASH_VAL(sig, 0);
+ prevs[i] = hash[v];
+ hash[v] = (Byte)i;
+ }
+
+ processedSize -= (kNumHashBytes - 1);
+ for (UInt32 pos = 0; pos < processedSize; pos++)
+ {
+ for (; pos < processedSize && hash[HASH_VAL(buf, pos)] == 0xFF; pos++);
+ if (pos == processedSize)
+ break;
+ UInt32 v = HASH_VAL(buf, pos);
+ Byte *ptr = &hash[v];
+ int i = *ptr;
+ do
+ {
+ int index = orderIndices[i];
+ const CArcInfoEx &ai = codecs->Formats[index];
+ const CByteBuffer &sig = ai.StartSignature;
+ if (sig.GetCapacity() != 0 && pos + sig.GetCapacity() <= processedSize + (kNumHashBytes - 1) &&
+ TestSignature(buf + pos, sig, sig.GetCapacity()))
+ {
+ orderIndices2.Add(index);
+ orderIndices[i] = 0xFF;
+ *ptr = prevs[i];
+ }
+ else
+ ptr = &prevs[i];
+ i = *ptr;
+ }
+ while (i != 0xFF);
+ }
+
+ for (i = 0; i < orderIndices.Size(); i++)
+ {
+ int val = orderIndices[i];
+ if (val != 0xFF)
+ orderIndices2.Add(val);
+ }
+ orderIndices = orderIndices2;
+ }
+ else if (extension == L"000" || extension == L"001")
+ {
+ CByteBuffer byteBuffer;
+ const size_t kBufferSize = (1 << 10);
+ byteBuffer.SetCapacity(kBufferSize);
+ Byte *buffer = byteBuffer;
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ size_t processedSize = kBufferSize;
+ RINOK(ReadStream(stream, buffer, &processedSize));
+ if (processedSize >= 16)
+ {
+ Byte kRarHeader[] = {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
+ if (TestSignature(buffer, kRarHeader, 7) && buffer[9] == 0x73 && (buffer[10] & 1) != 0)
+ {
+ for (int i = 0; i < orderIndices.Size(); i++)
+ {
+ int index = orderIndices[i];
+ const CArcInfoEx &ai = codecs->Formats[index];
+ if (ai.Name.CompareNoCase(L"rar") != 0)
+ continue;
+ orderIndices.Delete(i--);
+ orderIndices.Insert(0, index);
+ break;
+ }
+ }
+ }
+ }
+ if (orderIndices.Size() >= 2)
+ {
+ int isoIndex = codecs->FindFormatForArchiveType(L"iso");
+ int udfIndex = codecs->FindFormatForArchiveType(L"udf");
+ int iIso = -1;
+ int iUdf = -1;
+ for (int i = 0; i < orderIndices.Size(); i++)
+ {
+ if (orderIndices[i] == isoIndex) iIso = i;
+ if (orderIndices[i] == udfIndex) iUdf = i;
+ }
+ if (iUdf > iIso && iIso >= 0)
+ {
+ orderIndices[iUdf] = isoIndex;
+ orderIndices[iIso] = udfIndex;
+ }
+ }
+
+ #endif
+ }
+
+ for (int i = 0; i < orderIndices.Size(); i++)
+ {
+ if (stream)
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+ CMyComPtr<IInArchive> archive;
+
+ FormatIndex = orderIndices[i];
+ RINOK(codecs->CreateInArchive(FormatIndex, archive));
+ if (!archive)
+ continue;
+
+ #ifdef EXTERNAL_CODECS
+ {
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
+ }
+ }
+ #endif
+
+ // OutputDebugStringW(codecs->Formats[FormatIndex].Name);
+
+ HRESULT result;
+ if (stream)
+ result = archive->Open(stream, &kMaxCheckStartPosition, callback);
+ else
+ {
+ CMyComPtr<IArchiveOpenSeq> openSeq;
+ archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq);
+ if (!openSeq)
+ return E_NOTIMPL;
+ result = openSeq->OpenSeq(seqStream);
+ }
+
+ if (result == S_FALSE)
+ continue;
+ RINOK(result);
+
+ {
+ NCOM::CPropVariant prop;
+ archive->GetArchiveProperty(kpidError, &prop);
+ if (prop.vt != VT_EMPTY)
+ ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error";
+ }
+
+ Archive = archive;
+ const CArcInfoEx &format = codecs->Formats[FormatIndex];
+ if (format.Exts.Size() == 0)
+ DefaultName = GetDefaultName2(fileName, L"", L"");
+ else
+ {
+ int subExtIndex = format.FindExtension(extension);
+ if (subExtIndex < 0)
+ subExtIndex = 0;
+ const CArcExtInfo &extInfo = format.Exts[subExtIndex];
+ DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt);
+ }
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+HRESULT CArc::OpenStreamOrFile(
+ CCodecs *codecs,
+ int formatIndex,
+ bool stdInMode,
+ IInStream *stream,
+ IArchiveOpenCallback *callback)
+{
+ CMyComPtr<IInStream> fileStream;
+ CMyComPtr<ISequentialInStream> seqStream;
+ if (stdInMode)
+ seqStream = new CStdInFileStream;
+ else if (!stream)
+ {
+ CInFileStream *fileStreamSpec = new CInFileStream(true);
+ fileStream = fileStreamSpec;
+ if (!fileStreamSpec->Open(Path))
+ return GetLastError();
+ stream = fileStream;
+ }
+
+ /*
+ if (callback)
+ {
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ RINOK(callback->SetTotal(NULL, &fileSize))
+ }
+ */
+
+ return OpenStream(codecs, formatIndex, stream, seqStream, callback);
+}
+
+HRESULT CArchiveLink::Close()
+{
+ for (int i = Arcs.Size() - 1; i >= 0; i--)
+ {
+ RINOK(Arcs[i].Archive->Close());
+ }
+ IsOpen = false;
+ return S_OK;
+}
+
+void CArchiveLink::Release()
+{
+ while (!Arcs.IsEmpty())
+ Arcs.DeleteBack();
+}
+
+HRESULT CArchiveLink::Open(
+ CCodecs *codecs,
+ const CIntVector &formatIndices,
+ bool stdInMode,
+ IInStream *stream,
+ const UString &filePath,
+ IArchiveOpenCallback *callback)
+{
+ Release();
+ if (formatIndices.Size() >= 32)
+ return E_NOTIMPL;
+
+ HRESULT resSpec;
+
+ for (;;)
+ {
+ resSpec = S_OK;
+ int formatIndex = -1;
+ if (formatIndices.Size() >= 1)
+ {
+ if (Arcs.Size() >= formatIndices.Size())
+ break;
+ formatIndex = formatIndices[formatIndices.Size() - Arcs.Size() - 1];
+ }
+ else if (Arcs.Size() >= 32)
+ break;
+
+ if (Arcs.IsEmpty())
+ {
+ CArc arc;
+ arc.Path = filePath;
+ arc.SubfileIndex = (UInt32)(Int32)-1;
+ RINOK(arc.OpenStreamOrFile(codecs, formatIndex, stdInMode, stream, callback));
+ Arcs.Add(arc);
+ continue;
+ }
+
+ const CArc &arc = Arcs.Back();
+
+ resSpec = (formatIndices.Size() == 0 ? S_OK : E_NOTIMPL);
+
+ UInt32 mainSubfile;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop));
+ if (prop.vt == VT_UI4)
+ mainSubfile = prop.ulVal;
+ else
+ break;
+ UInt32 numItems;
+ RINOK(arc.Archive->GetNumberOfItems(&numItems));
+ if (mainSubfile >= numItems)
+ break;
+ }
+
+
+ CMyComPtr<IInArchiveGetStream> getStream;
+ if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream)
+ break;
+
+ CMyComPtr<ISequentialInStream> subSeqStream;
+ if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream)
+ break;
+
+ CMyComPtr<IInStream> subStream;
+ if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream)
+ break;
+
+ CArc arc2;
+ RINOK(arc.GetItemPath(mainSubfile, arc2.Path));
+
+ CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
+ callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
+ if (setSubArchiveName)
+ setSubArchiveName->SetSubArchiveName(arc2.Path);
+
+ arc2.SubfileIndex = mainSubfile;
+ HRESULT result = arc2.OpenStream(codecs, formatIndex, subStream, NULL, callback);
+ resSpec = (formatIndices.Size() == 0 ? S_OK : S_FALSE);
+ if (result == S_FALSE)
+ break;
+ RINOK(result);
+ RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined));
+ Arcs.Add(arc2);
+ }
+ IsOpen = !Arcs.IsEmpty();
+ return S_OK;
+}
+
+static void SetCallback(const UString &filePath,
+ IOpenCallbackUI *callbackUI,
+ IArchiveOpenCallback *reOpenCallback,
+ CMyComPtr<IArchiveOpenCallback> &callback)
+{
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ callback = openCallbackSpec;
+ openCallbackSpec->Callback = callbackUI;
+ openCallbackSpec->ReOpenCallback = reOpenCallback;
+
+ UString fullName;
+ int fileNamePartStartIndex;
+ NFile::NDirectory::MyGetFullPathName(filePath, fullName, fileNamePartStartIndex);
+ openCallbackSpec->Init(
+ fullName.Left(fileNamePartStartIndex),
+ fullName.Mid(fileNamePartStartIndex));
+}
+
+HRESULT CArchiveLink::Open2(CCodecs *codecs,
+ const CIntVector &formatIndices,
+ bool stdInMode,
+ IInStream *stream,
+ const UString &filePath,
+ IOpenCallbackUI *callbackUI)
+{
+ VolumesSize = 0;
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec;
+ openCallbackSpec->Callback = callbackUI;
+
+ UString fullName, prefix, name;
+ if (!stream && !stdInMode)
+ {
+ int fileNamePartStartIndex;
+ if (!NFile::NDirectory::MyGetFullPathName(filePath, fullName, fileNamePartStartIndex))
+ return GetLastError();
+ prefix = fullName.Left(fileNamePartStartIndex);
+ name = fullName.Mid(fileNamePartStartIndex);
+ openCallbackSpec->Init(prefix, name);
+ }
+ else
+ {
+ openCallbackSpec->SetSubArchiveName(filePath);
+ }
+
+ RINOK(Open(codecs, formatIndices, stdInMode, stream, filePath, callback));
+ VolumePaths.Add(prefix + name);
+ for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
+ VolumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
+ VolumesSize = openCallbackSpec->TotalSize;
+ return S_OK;
+}
+
+HRESULT CArchiveLink::ReOpen(CCodecs *codecs, const UString &filePath,
+ IArchiveOpenCallback *callback)
+{
+ if (Arcs.Size() > 1)
+ return E_NOTIMPL;
+
+ if (Arcs.Size() == 0)
+ return Open2(codecs, CIntVector(), false, NULL, filePath, 0);
+
+ CMyComPtr<IArchiveOpenCallback> openCallbackNew;
+ SetCallback(filePath, NULL, callback, openCallbackNew);
+
+ CInFileStream *fileStreamSpec = new CInFileStream(true);
+ CMyComPtr<IInStream> stream(fileStreamSpec);
+ if (!fileStreamSpec->Open(filePath))
+ return GetLastError();
+ HRESULT res = GetArchive()->Open(stream, &kMaxCheckStartPosition, callback);
+ IsOpen = (res == S_OK);
+ return res;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.h
new file mode 100644
index 000000000..4a003ee63
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/OpenArchive.h
@@ -0,0 +1,87 @@
+// OpenArchive.h
+
+#ifndef __OPEN_ARCHIVE_H
+#define __OPEN_ARCHIVE_H
+
+#include "Common/MyString.h"
+
+#include "Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ArchiveOpenCallback.h"
+#include "LoadCodecs.h"
+
+HRESULT GetArchiveItemBoolProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result);
+HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result);
+
+struct CArc
+{
+ CMyComPtr<IInArchive> Archive;
+ UString Path;
+ UString DefaultName;
+ int FormatIndex;
+ int SubfileIndex;
+ FILETIME MTime;
+ bool MTimeDefined;
+ UString ErrorMessage;
+
+ CArc(): MTimeDefined(false) {}
+
+ HRESULT GetItemPath(UInt32 index, UString &result) const;
+ HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const;
+ HRESULT IsItemAnti(UInt32 index, bool &result) const
+ { return GetArchiveItemBoolProp(Archive, index, kpidIsAnti, result); }
+
+ HRESULT OpenStream(
+ CCodecs *codecs,
+ int formatIndex,
+ IInStream *stream,
+ ISequentialInStream *seqStream,
+ IArchiveOpenCallback *callback);
+
+ HRESULT OpenStreamOrFile(
+ CCodecs *codecs,
+ int formatIndex,
+ bool stdInMode,
+ IInStream *stream,
+ IArchiveOpenCallback *callback);
+};
+
+struct CArchiveLink
+{
+ CObjectVector<CArc> Arcs;
+ UStringVector VolumePaths;
+ UInt64 VolumesSize;
+ bool IsOpen;
+
+ CArchiveLink(): VolumesSize(0), IsOpen(false) {}
+ HRESULT Close();
+ void Release();
+ ~CArchiveLink() { Release(); }
+
+ IInArchive *GetArchive() const { return Arcs.Back().Archive; }
+
+ HRESULT Open(
+ CCodecs *codecs,
+ const CIntVector &formatIndices,
+ bool stdInMode,
+ IInStream *stream,
+ const UString &filePath,
+ IArchiveOpenCallback *callback);
+
+ HRESULT Open2(
+ CCodecs *codecs,
+ const CIntVector &formatIndices,
+ bool stdInMode,
+ IInStream *stream,
+ const UString &filePath,
+ IOpenCallbackUI *callbackUI);
+
+ HRESULT ReOpen(
+ CCodecs *codecs,
+ const UString &filePath,
+ IArchiveOpenCallback *callback);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.cpp
new file mode 100644
index 000000000..dacaca5f9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.cpp
@@ -0,0 +1,120 @@
+// PropIDUtils.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+
+#include "Windows/FileFind.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../PropID.h"
+
+#include "PropIDUtils.h"
+
+using namespace NWindows;
+
+void ConvertUInt32ToHex(UInt32 value, wchar_t *s)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ int t = value & 0xF;
+ value >>= 4;
+ s[7 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));
+ }
+ s[8] = L'\0';
+}
+
+static const char g_WinAttrib[17] = "RHS8DAdNTsrCOnE_";
+/*
+0 READONLY
+1 HIDDEN
+3 SYSTEM
+
+4 DIRECTORY
+5 ARCHIVE
+6 DEVICE
+7 NORMAL
+8 TEMPORARY
+9 SPARSE_FILE
+10 REPARSE_POINT
+11 COMPRESSED
+12 OFFLINE
+13 NOT_CONTENT_INDEXED
+14 ENCRYPTED
+
+16 VIRTUAL
+*/
+
+static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
+#define MY_ATTR_CHAR(a, n, c) ((a )& (1 << (n))) ? c : L'-';
+
+UString ConvertPropertyToString(const PROPVARIANT &prop, PROPID propID, bool full)
+{
+ switch(propID)
+ {
+ case kpidCTime:
+ case kpidATime:
+ case kpidMTime:
+ {
+ if (prop.vt != VT_FILETIME)
+ break;
+ FILETIME localFileTime;
+ if ((prop.filetime.dwHighDateTime == 0 &&
+ prop.filetime.dwLowDateTime == 0) ||
+ !::FileTimeToLocalFileTime(&prop.filetime, &localFileTime))
+ return UString();
+ return ConvertFileTimeToString(localFileTime, true, full);
+ }
+ case kpidCRC:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ wchar_t temp[12];
+ ConvertUInt32ToHex(prop.ulVal, temp);
+ return temp;
+ }
+ case kpidAttrib:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ UInt32 a = prop.ulVal;
+ wchar_t sz[32];
+ int pos = 0;
+ for (int i = 0; i < 16; i++)
+ if (a & (1 << i) && i != 7)
+ sz[pos++] = g_WinAttrib[i];
+ sz[pos] = '\0';
+ return sz;
+ }
+ case kpidPosixAttrib:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ UString res;
+ UInt32 a = prop.ulVal;
+ wchar_t temp[16];
+
+ temp[0] = kPosixTypes[(a >> 12) & 0xF];
+ for (int i = 6; i >= 0; i -= 3)
+ {
+ temp[7 - i] = MY_ATTR_CHAR(a, i + 2, L'r');
+ temp[8 - i] = MY_ATTR_CHAR(a, i + 1, L'w');
+ temp[9 - i] = MY_ATTR_CHAR(a, i + 0, L'x');
+ }
+ if ((a & 0x800) != 0) temp[3] = ((a & (1 << 6)) ? 's' : 'S');
+ if ((a & 0x400) != 0) temp[6] = ((a & (1 << 3)) ? 's' : 'S');
+ if ((a & 0x200) != 0) temp[9] = ((a & (1 << 0)) ? 't' : 'T');
+ temp[10] = 0;
+ res = temp;
+
+ a &= ~(UInt32)0xFFFF;
+ if (a != 0)
+ {
+ ConvertUInt32ToHex(a, temp);
+ res = UString(temp) + L' ' + res;
+ }
+ return res;
+ }
+ }
+ return ConvertPropVariantToString(prop);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.h
new file mode 100644
index 000000000..ca14d091d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/PropIDUtils.h
@@ -0,0 +1,12 @@
+// PropIDUtils.h
+
+#ifndef __PROPID_UTILS_H
+#define __PROPID_UTILS_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+void ConvertUInt32ToHex(UInt32 value, wchar_t *s);
+UString ConvertPropertyToString(const PROPVARIANT &propVariant, PROPID propID, bool full = true);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/Property.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/Property.h
new file mode 100644
index 000000000..9fd340cbc
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/Property.h
@@ -0,0 +1,14 @@
+// Property.h
+
+#ifndef __PROPERTY_H
+#define __PROPERTY_H
+
+#include "Common/MyString.h"
+
+struct CProperty
+{
+ UString Name;
+ UString Value;
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.cpp
new file mode 100644
index 000000000..4827f2a78
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.cpp
@@ -0,0 +1,79 @@
+// SetProperties.cpp
+
+#include "StdAfx.h"
+
+#include "SetProperties.h"
+
+#include "Windows/PropVariant.h"
+#include "Common/MyString.h"
+#include "Common/StringToInt.h"
+#include "Common/MyCom.h"
+
+#include "../../Archive/IArchive.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
+{
+ const wchar_t *endPtr;
+ UInt64 result = ConvertStringToUInt64(s, &endPtr);
+ if (endPtr - (const wchar_t *)s != s.Length())
+ prop = s;
+ else if (result <= 0xFFFFFFFF)
+ prop = (UInt32)result;
+ else
+ prop = result;
+}
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
+{
+ if (properties.IsEmpty())
+ return S_OK;
+ CMyComPtr<ISetProperties> setProperties;
+ unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);
+ if (!setProperties)
+ return S_OK;
+
+ UStringVector realNames;
+ CPropVariant *values = new CPropVariant[properties.Size()];
+ try
+ {
+ int i;
+ for(i = 0; i < properties.Size(); i++)
+ {
+ const CProperty &property = properties[i];
+ NCOM::CPropVariant propVariant;
+ UString name = property.Name;
+ if (property.Value.IsEmpty())
+ {
+ if (!name.IsEmpty())
+ {
+ wchar_t c = name[name.Length() - 1];
+ if (c == L'-')
+ propVariant = false;
+ else if (c == L'+')
+ propVariant = true;
+ if (propVariant.vt != VT_EMPTY)
+ name = name.Left(name.Length() - 1);
+ }
+ }
+ else
+ ParseNumberString(property.Value, propVariant);
+ realNames.Add(name);
+ values[i] = propVariant;
+ }
+ CRecordVector<const wchar_t *> names;
+ for(i = 0; i < realNames.Size(); i++)
+ names.Add((const wchar_t *)realNames[i]);
+
+ RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
+ }
+ catch(...)
+ {
+ delete []values;
+ throw;
+ }
+ delete []values;
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.h
new file mode 100644
index 000000000..892f1a210
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/SetProperties.h
@@ -0,0 +1,10 @@
+// SetProperties.h
+
+#ifndef __SETPROPERTIES_H
+#define __SETPROPERTIES_H
+
+#include "Property.h"
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.cpp
new file mode 100644
index 000000000..061e77730
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.cpp
@@ -0,0 +1,22 @@
+// SortUtils.cpp
+
+#include "StdAfx.h"
+
+#include "SortUtils.h"
+#include "Common/Wildcard.h"
+
+static int CompareStrings(const int *p1, const int *p2, void *param)
+{
+ const UStringVector &strings = *(const UStringVector *)param;
+ return CompareFileNames(strings[*p1], strings[*p2]);
+}
+
+void SortFileNames(const UStringVector &strings, CIntVector &indices)
+{
+ indices.Clear();
+ int numItems = strings.Size();
+ indices.Reserve(numItems);
+ for(int i = 0; i < numItems; i++)
+ indices.Add(i);
+ indices.Sort(CompareStrings, (void *)&strings);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.h
new file mode 100644
index 000000000..e15224611
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/SortUtils.h
@@ -0,0 +1,10 @@
+// SortUtils.h
+
+#ifndef __SORTUTLS_H
+#define __SORTUTLS_H
+
+#include "Common/MyString.h"
+
+void SortFileNames(const UStringVector &strings, CIntVector &indices);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.cpp
new file mode 100644
index 000000000..eeaec1802
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.cpp
@@ -0,0 +1,22 @@
+// TempFiles.cpp
+
+#include "StdAfx.h"
+
+#include "TempFiles.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileIO.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+void CTempFiles::Clear()
+{
+ while(!Paths.IsEmpty())
+ {
+ NDirectory::DeleteFileAlways((LPCWSTR)Paths.Back());
+ Paths.DeleteBack();
+ }
+}
+
+
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.h
new file mode 100644
index 000000000..eb474a760
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/TempFiles.h
@@ -0,0 +1,16 @@
+// TempFiles.h
+
+#ifndef __TEMPFILES_H
+#define __TEMPFILES_H
+
+#include "Common/MyString.h"
+
+class CTempFiles
+{
+ void Clear();
+public:
+ UStringVector Paths;
+ ~CTempFiles() { Clear(); }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/Update.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/Update.cpp
new file mode 100644
index 000000000..a5db3c18e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/Update.cpp
@@ -0,0 +1,912 @@
+// Update.cpp
+
+#include "StdAfx.h"
+
+#include "Update.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#ifdef _WIN32
+#include "Windows/DLL.h"
+#endif
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/FileName.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+#include "Windows/Time.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/DirItem.h"
+#include "../Common/EnumDirItems.h"
+#include "../Common/OpenArchive.h"
+#include "../Common/UpdateProduce.h"
+
+#include "EnumDirItems.h"
+#include "SetProperties.h"
+#include "TempFiles.h"
+#include "UpdateCallback.h"
+
+static const char *kUpdateIsNotSupoorted =
+ "update operations are not supported for this archive";
+
+using namespace NWindows;
+using namespace NCOM;
+using namespace NFile;
+using namespace NName;
+
+#ifdef _WIN32
+static const wchar_t *kTempFolderPrefix = L"7zE";
+#endif
+
+using namespace NUpdateArchive;
+
+class COutMultiVolStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ int _streamIndex; // required stream
+ UInt64 _offsetPos; // offset from start of _streamIndex index
+ UInt64 _absPos;
+ UInt64 _length;
+
+ struct CSubStreamInfo
+ {
+ COutFileStream *StreamSpec;
+ CMyComPtr<IOutStream> Stream;
+ UString Name;
+ UInt64 Pos;
+ UInt64 RealSize;
+ };
+ CObjectVector<CSubStreamInfo> Streams;
+public:
+ // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ CRecordVector<UInt64> Sizes;
+ UString Prefix;
+ CTempFiles *TempFiles;
+
+ void Init()
+ {
+ _streamIndex = 0;
+ _offsetPos = 0;
+ _absPos = 0;
+ _length = 0;
+ }
+
+ HRESULT Close();
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+// static NSynchronization::CCriticalSection g_TempPathsCS;
+
+HRESULT COutMultiVolStream::Close()
+{
+ HRESULT res = S_OK;
+ for (int i = 0; i < Streams.Size(); i++)
+ {
+ CSubStreamInfo &s = Streams[i];
+ if (s.StreamSpec)
+ {
+ HRESULT res2 = s.StreamSpec->Close();
+ if (res2 != S_OK)
+ res = res2;
+ }
+ }
+ return res;
+}
+
+STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while(size > 0)
+ {
+ if (_streamIndex >= Streams.Size())
+ {
+ CSubStreamInfo subStream;
+
+ wchar_t temp[16];
+ ConvertUInt32ToString(_streamIndex + 1, temp);
+ UString res = temp;
+ while (res.Length() < 3)
+ res = UString(L'0') + res;
+ UString name = Prefix + res;
+ subStream.StreamSpec = new COutFileStream;
+ subStream.Stream = subStream.StreamSpec;
+ if (!subStream.StreamSpec->Create(name, false))
+ return ::GetLastError();
+ {
+ // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);
+ TempFiles->Paths.Add(name);
+ }
+
+ subStream.Pos = 0;
+ subStream.RealSize = 0;
+ subStream.Name = name;
+ Streams.Add(subStream);
+ continue;
+ }
+ CSubStreamInfo &subStream = Streams[_streamIndex];
+
+ int index = _streamIndex;
+ if (index >= Sizes.Size())
+ index = Sizes.Size() - 1;
+ UInt64 volSize = Sizes[index];
+
+ if (_offsetPos >= volSize)
+ {
+ _offsetPos -= volSize;
+ _streamIndex++;
+ continue;
+ }
+ if (_offsetPos != subStream.Pos)
+ {
+ // CMyComPtr<IOutStream> outStream;
+ // RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
+ RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
+ subStream.Pos = _offsetPos;
+ }
+
+ UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos);
+ UInt32 realProcessed;
+ RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
+ data = (void *)((Byte *)data + realProcessed);
+ size -= realProcessed;
+ subStream.Pos += realProcessed;
+ _offsetPos += realProcessed;
+ _absPos += realProcessed;
+ if (_absPos > _length)
+ _length = _absPos;
+ if (_offsetPos > subStream.RealSize)
+ subStream.RealSize = _offsetPos;
+ if (processedSize != NULL)
+ *processedSize += realProcessed;
+ if (subStream.Pos == volSize)
+ {
+ _streamIndex++;
+ _offsetPos = 0;
+ }
+ if (realProcessed == 0 && curSize != 0)
+ return E_FAIL;
+ break;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if (seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET:
+ _absPos = offset;
+ break;
+ case STREAM_SEEK_CUR:
+ _absPos += offset;
+ break;
+ case STREAM_SEEK_END:
+ _absPos = _length + offset;
+ break;
+ }
+ _offsetPos = _absPos;
+ if (newPosition != NULL)
+ *newPosition = _absPos;
+ _streamIndex = 0;
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize)
+{
+ if (newSize < 0)
+ return E_INVALIDARG;
+ int i = 0;
+ while (i < Streams.Size())
+ {
+ CSubStreamInfo &subStream = Streams[i++];
+ if ((UInt64)newSize < subStream.RealSize)
+ {
+ RINOK(subStream.Stream->SetSize(newSize));
+ subStream.RealSize = newSize;
+ break;
+ }
+ newSize -= subStream.RealSize;
+ }
+ while (i < Streams.Size())
+ {
+ {
+ CSubStreamInfo &subStream = Streams.Back();
+ subStream.Stream.Release();
+ NDirectory::DeleteFileAlways(subStream.Name);
+ }
+ Streams.DeleteBack();
+ }
+ _offsetPos = _absPos;
+ _streamIndex = 0;
+ _length = newSize;
+ return S_OK;
+}
+
+static const wchar_t *kDefaultArchiveType = L"7z";
+static const wchar_t *kSFXExtension =
+ #ifdef _WIN32
+ L"exe";
+ #else
+ L"";
+ #endif
+
+bool CUpdateOptions::Init(const CCodecs *codecs, const CIntVector &formatIndices, const UString &arcPath)
+{
+ if (formatIndices.Size() > 1)
+ return false;
+ int arcTypeIndex = -1;
+ if (formatIndices.Size() != 0)
+ arcTypeIndex = formatIndices[0];
+ if (arcTypeIndex >= 0)
+ MethodMode.FormatIndex = arcTypeIndex;
+ else
+ {
+ MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath);
+ // It works incorrectly for update command if archive has some non-default extension!
+ if (MethodMode.FormatIndex < 0)
+ MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveType);
+ }
+ if (MethodMode.FormatIndex < 0)
+ return false;
+ const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex];
+ if (!arcInfo.UpdateEnabled)
+ return false;
+ UString typeExt = arcInfo.GetMainExt();
+ UString ext = typeExt;
+ if (SfxMode)
+ ext = kSFXExtension;
+ ArchivePath.BaseExtension = ext;
+ ArchivePath.VolExtension = typeExt;
+ ArchivePath.ParseFromPath(arcPath);
+ for (int i = 0; i < Commands.Size(); i++)
+ {
+ CUpdateArchiveCommand &uc = Commands[i];
+ uc.ArchivePath.BaseExtension = ext;
+ uc.ArchivePath.VolExtension = typeExt;
+ uc.ArchivePath.ParseFromPath(uc.UserArchivePath);
+ }
+ return true;
+}
+
+/*
+struct CUpdateProduceCallbackImp: public IUpdateProduceCallback
+{
+ const CObjectVector<CArcItem> *_arcItems;
+ IUpdateCallbackUI *_callback;
+
+ CUpdateProduceCallbackImp(const CObjectVector<CArcItem> *a,
+ IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {}
+ virtual HRESULT ShowDeleteFile(int arcIndex);
+};
+
+HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex)
+{
+ return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name);
+}
+*/
+
+static HRESULT Compress(
+ CCodecs *codecs,
+ const CActionSet &actionSet,
+ IInArchive *archive,
+ const CCompressionMethodMode &compressionMethod,
+ CArchivePath &archivePath,
+ const CObjectVector<CArcItem> &arcItems,
+ bool shareForWrite,
+ bool stdInMode,
+ /* const UString & stdInFileName, */
+ bool stdOutMode,
+ const CDirItems &dirItems,
+ bool sfxMode,
+ const UString &sfxModule,
+ const CRecordVector<UInt64> &volumesSizes,
+ CTempFiles &tempFiles,
+ CUpdateErrorInfo &errorInfo,
+ IUpdateCallbackUI *callback)
+{
+ CMyComPtr<IOutArchive> outArchive;
+ if (archive != NULL)
+ {
+ CMyComPtr<IInArchive> archive2 = archive;
+ HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
+ if (result != S_OK)
+ throw kUpdateIsNotSupoorted;
+ }
+ else
+ {
+ RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive));
+
+ #ifdef EXTERNAL_CODECS
+ {
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
+ }
+ }
+ #endif
+ }
+ if (outArchive == 0)
+ throw kUpdateIsNotSupoorted;
+
+ NFileTimeType::EEnum fileTimeType;
+ UInt32 value;
+ RINOK(outArchive->GetFileTimeType(&value));
+
+ switch(value)
+ {
+ case NFileTimeType::kWindows:
+ case NFileTimeType::kUnix:
+ case NFileTimeType::kDOS:
+ fileTimeType = (NFileTimeType::EEnum)value;
+ break;
+ default:
+ return E_FAIL;
+ }
+
+ CRecordVector<CUpdatePair2> updatePairs2;
+
+ {
+ CRecordVector<CUpdatePair> updatePairs;
+ GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!!
+ // CUpdateProduceCallbackImp upCallback(&arcItems, callback);
+ UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */);
+ }
+
+ UInt32 numFiles = 0;
+ for (int i = 0; i < updatePairs2.Size(); i++)
+ if (updatePairs2[i].NewData)
+ numFiles++;
+
+ RINOK(callback->SetNumFiles(numFiles));
+
+
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ updateCallbackSpec->ShareForWrite = shareForWrite;
+ updateCallbackSpec->StdInMode = stdInMode;
+ updateCallbackSpec->Callback = callback;
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->ArcItems = &arcItems;
+ updateCallbackSpec->UpdatePairs = &updatePairs2;
+
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ if (!stdOutMode)
+ {
+ UString resultPath;
+ int pos;
+ if (!NFile::NDirectory::MyGetFullPathName(archivePath.GetFinalPath(), resultPath, pos))
+ throw 1417161;
+ NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
+ }
+
+ COutFileStream *outStreamSpec = NULL;
+ COutMultiVolStream *volStreamSpec = NULL;
+
+ if (volumesSizes.Size() == 0)
+ {
+ if (stdOutMode)
+ outStream = new CStdOutFileStream;
+ else
+ {
+ outStreamSpec = new COutFileStream;
+ outStream = outStreamSpec;
+ bool isOK = false;
+ UString realPath;
+ for (int i = 0; i < (1 << 16); i++)
+ {
+ if (archivePath.Temp)
+ {
+ if (i > 0)
+ {
+ wchar_t s[16];
+ ConvertUInt32ToString(i, s);
+ archivePath.TempPostfix = s;
+ }
+ realPath = archivePath.GetTempPath();
+ }
+ else
+ realPath = archivePath.GetFinalPath();
+ if (outStreamSpec->Create(realPath, false))
+ {
+ tempFiles.Paths.Add(realPath);
+ isOK = true;
+ break;
+ }
+ if (::GetLastError() != ERROR_FILE_EXISTS)
+ break;
+ if (!archivePath.Temp)
+ break;
+ }
+ if (!isOK)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.FileName = realPath;
+ errorInfo.Message = L"7-Zip cannot open file";
+ return E_FAIL;
+ }
+ }
+ }
+ else
+ {
+ if (stdOutMode)
+ return E_FAIL;
+ volStreamSpec = new COutMultiVolStream;
+ outStream = volStreamSpec;
+ volStreamSpec->Sizes = volumesSizes;
+ volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L".");
+ volStreamSpec->TempFiles = &tempFiles;
+ volStreamSpec->Init();
+
+ /*
+ updateCallbackSpec->VolumesSizes = volumesSizes;
+ updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
+ if (!archivePath.VolExtension.IsEmpty())
+ updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
+ */
+ }
+
+ RINOK(SetProperties(outArchive, compressionMethod.Properties));
+
+ if (sfxMode)
+ {
+ CInFileStream *sfxStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+ if (!sfxStreamSpec->Open(sfxModule))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot open SFX module";
+ errorInfo.FileName = sfxModule;
+ return E_FAIL;
+ }
+
+ CMyComPtr<ISequentialOutStream> sfxOutStream;
+ COutFileStream *outStreamSpec = NULL;
+ if (volumesSizes.Size() == 0)
+ sfxOutStream = outStream;
+ else
+ {
+ outStreamSpec = new COutFileStream;
+ sfxOutStream = outStreamSpec;
+ UString realPath = archivePath.GetFinalPath();
+ if (!outStreamSpec->Create(realPath, false))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.FileName = realPath;
+ errorInfo.Message = L"7-Zip cannot open file";
+ return E_FAIL;
+ }
+ }
+ RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL));
+ if (outStreamSpec)
+ {
+ RINOK(outStreamSpec->Close());
+ }
+ }
+
+ HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updateCallback);
+ callback->Finilize();
+ RINOK(result);
+ if (outStreamSpec)
+ result = outStreamSpec->Close();
+ else if (volStreamSpec)
+ result = volStreamSpec->Close();
+ return result;
+}
+
+HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
+ const CArc &arc,
+ CObjectVector<CArcItem> &arcItems)
+{
+ arcItems.Clear();
+ UInt32 numItems;
+ IInArchive *archive = arc.Archive;
+ RINOK(archive->GetNumberOfItems(&numItems));
+ arcItems.Reserve(numItems);
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CArcItem ai;
+
+ RINOK(arc.GetItemPath(i, ai.Name));
+ RINOK(IsArchiveItemFolder(archive, i, ai.IsDir));
+ ai.Censored = censor.CheckPath(ai.Name, !ai.IsDir);
+ RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined));
+
+ {
+ CPropVariant prop;
+ RINOK(archive->GetProperty(i, kpidSize, &prop));
+ ai.SizeDefined = (prop.vt != VT_EMPTY);
+ if (ai.SizeDefined)
+ ai.Size = ConvertPropVariantToUInt64(prop);
+ }
+
+ {
+ CPropVariant prop;
+ RINOK(archive->GetProperty(i, kpidTimeType, &prop));
+ if (prop.vt == VT_UI4)
+ {
+ ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal;
+ switch(ai.TimeType)
+ {
+ case NFileTimeType::kWindows:
+ case NFileTimeType::kUnix:
+ case NFileTimeType::kDOS:
+ break;
+ default:
+ return E_FAIL;
+ }
+ }
+ }
+
+ ai.IndexInServer = i;
+ arcItems.Add(ai);
+ }
+ return S_OK;
+}
+
+
+static HRESULT UpdateWithItemLists(
+ CCodecs *codecs,
+ CUpdateOptions &options,
+ IInArchive *archive,
+ const CObjectVector<CArcItem> &arcItems,
+ CDirItems &dirItems,
+ CTempFiles &tempFiles,
+ CUpdateErrorInfo &errorInfo,
+ IUpdateCallbackUI2 *callback)
+{
+ for(int i = 0; i < options.Commands.Size(); i++)
+ {
+ CUpdateArchiveCommand &command = options.Commands[i];
+ if (options.StdOutMode)
+ {
+ RINOK(callback->StartArchive(L"stdout", archive != 0));
+ }
+ else
+ {
+ RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(),
+ i == 0 && options.UpdateArchiveItself && archive != 0));
+ }
+
+ RINOK(Compress(
+ codecs,
+ command.ActionSet, archive,
+ options.MethodMode,
+ command.ArchivePath,
+ arcItems,
+ options.OpenShareForWrite,
+ options.StdInMode,
+ /* options.StdInFileName, */
+ options.StdOutMode,
+ dirItems,
+ options.SfxMode, options.SfxModule,
+ options.VolumesSizes,
+ tempFiles,
+ errorInfo, callback));
+
+ RINOK(callback->FinishArchive());
+ }
+ return S_OK;
+}
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+class CCurrentDirRestorer
+{
+ UString _path;
+public:
+ CCurrentDirRestorer() { NFile::NDirectory::MyGetCurrentDirectory(_path); }
+ ~CCurrentDirRestorer() { RestoreDirectory();}
+ bool RestoreDirectory() { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(_path)); }
+};
+#endif
+
+struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
+{
+ IUpdateCallbackUI2 *Callback;
+ HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path)
+ {
+ return Callback->ScanProgress(numFolders, numFiles, path);
+ }
+};
+
+#ifdef _WIN32
+typedef ULONG (FAR PASCAL MY_MAPISENDDOCUMENTS)(
+ ULONG_PTR ulUIParam,
+ LPSTR lpszDelimChar,
+ LPSTR lpszFilePaths,
+ LPSTR lpszFileNames,
+ ULONG ulReserved
+);
+typedef MY_MAPISENDDOCUMENTS FAR *MY_LPMAPISENDDOCUMENTS;
+#endif
+
+HRESULT UpdateArchive(
+ CCodecs *codecs,
+ const NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ CUpdateErrorInfo &errorInfo,
+ IOpenCallbackUI *openCallback,
+ IUpdateCallbackUI2 *callback)
+{
+ if (options.StdOutMode && options.EMailMode)
+ return E_FAIL;
+
+ if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode))
+ return E_NOTIMPL;
+
+ if (options.SfxMode)
+ {
+ CProperty property;
+ property.Name = L"rsfx";
+ property.Value = L"on";
+ options.MethodMode.Properties.Add(property);
+ if (options.SfxModule.IsEmpty())
+ {
+ errorInfo.Message = L"SFX file is not specified";
+ return E_FAIL;
+ }
+ UString name = options.SfxModule;
+ #ifdef UNDER_CE
+ if (!NFind::DoesFileExist(name))
+ #else
+ if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule))
+ #endif
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot find specified SFX module";
+ errorInfo.FileName = name;
+ return E_FAIL;
+ }
+ }
+
+
+ CArchiveLink arcLink;
+ const UString arcPath = options.ArchivePath.GetFinalPath();
+
+ if (!options.ArchivePath.OriginalPath.IsEmpty())
+ {
+ NFind::CFileInfoW fi;
+ if (fi.Find(arcPath))
+ {
+ if (fi.IsDir())
+ throw "there is no such archive";
+ if (options.VolumesSizes.Size() > 0)
+ return E_NOTIMPL;
+ CIntVector formatIndices;
+ if (options.MethodMode.FormatIndex >= 0)
+ formatIndices.Add(options.MethodMode.FormatIndex);
+ HRESULT result = arcLink.Open2(codecs, formatIndices, false, NULL, arcPath, openCallback);
+ if (result == E_ABORT)
+ return result;
+ RINOK(callback->OpenResult(arcPath, result));
+ RINOK(result);
+ if (arcLink.VolumePaths.Size() > 1)
+ {
+ errorInfo.SystemError = (DWORD)E_NOTIMPL;
+ errorInfo.Message = L"Updating for multivolume archives is not implemented";
+ return E_NOTIMPL;
+ }
+
+ CArc &arc = arcLink.Arcs.Back();
+ arc.MTimeDefined = !fi.IsDevice;
+ arc.MTime = fi.MTime;
+ }
+ }
+ else
+ {
+ /*
+ if (archiveType.IsEmpty())
+ throw "type of archive is not specified";
+ */
+ }
+
+ CDirItems dirItems;
+ if (options.StdInMode)
+ {
+ CDirItem di;
+ di.Name = options.StdInFileName;
+ di.Size = (UInt64)(Int64)-1;
+ di.Attrib = 0;
+ NTime::GetCurUtcFileTime(di.MTime);
+ di.CTime = di.ATime = di.MTime;
+ dirItems.Items.Add(di);
+ }
+ else
+ {
+ bool needScanning = false;
+ for(int i = 0; i < options.Commands.Size(); i++)
+ if (options.Commands[i].ActionSet.NeedScanning())
+ needScanning = true;
+ if (needScanning)
+ {
+ CEnumDirItemUpdateCallback enumCallback;
+ enumCallback.Callback = callback;
+ RINOK(callback->StartScanning());
+ UStringVector errorPaths;
+ CRecordVector<DWORD> errorCodes;
+ HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths, errorCodes);
+ for (int i = 0; i < errorPaths.Size(); i++)
+ {
+ RINOK(callback->CanNotFindError(errorPaths[i], errorCodes[i]));
+ }
+ if (res != S_OK)
+ {
+ if (res != E_ABORT)
+ errorInfo.Message = L"Scanning error";
+ return res;
+ }
+ RINOK(callback->FinishScanning());
+ }
+ }
+
+ UString tempDirPrefix;
+ bool usesTempDir = false;
+
+ #ifdef _WIN32
+ NDirectory::CTempDirectoryW tempDirectory;
+ if (options.EMailMode && options.EMailRemoveAfter)
+ {
+ tempDirectory.Create(kTempFolderPrefix);
+ tempDirPrefix = tempDirectory.GetPath();
+ NormalizeDirPathPrefix(tempDirPrefix);
+ usesTempDir = true;
+ }
+ #endif
+
+ CTempFiles tempFiles;
+
+ bool createTempFile = false;
+
+ bool thereIsInArchive = arcLink.IsOpen;
+
+ if (!options.StdOutMode && options.UpdateArchiveItself)
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ ap = options.ArchivePath;
+ // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
+ if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
+ {
+ createTempFile = true;
+ ap.Temp = true;
+ if (!options.WorkingDir.IsEmpty())
+ {
+ ap.TempPrefix = options.WorkingDir;
+ NormalizeDirPathPrefix(ap.TempPrefix);
+ }
+ }
+ }
+
+ for(int i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ if (usesTempDir)
+ {
+ // Check it
+ ap.Prefix = tempDirPrefix;
+ // ap.Temp = true;
+ // ap.TempPrefix = tempDirPrefix;
+ }
+ if (!options.StdOutMode &&
+ (i > 0 || !createTempFile))
+ {
+ const UString &path = ap.GetFinalPath();
+ if (NFind::DoesFileOrDirExist(path))
+ {
+ errorInfo.SystemError = 0;
+ errorInfo.Message = L"The file already exists";
+ errorInfo.FileName = path;
+ return E_FAIL;
+ }
+ }
+ }
+
+ CObjectVector<CArcItem> arcItems;
+ if (thereIsInArchive)
+ {
+ RINOK(EnumerateInArchiveItems(censor, arcLink.Arcs.Back(), arcItems));
+ }
+
+ RINOK(UpdateWithItemLists(codecs, options,
+ thereIsInArchive ? arcLink.GetArchive() : 0,
+ arcItems, dirItems,
+ tempFiles, errorInfo, callback));
+
+ if (thereIsInArchive)
+ {
+ RINOK(arcLink.Close());
+ arcLink.Release();
+ }
+
+ tempFiles.Paths.Clear();
+ if (createTempFile)
+ {
+ try
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ const UString &tempPath = ap.GetTempPath();
+ if (thereIsInArchive)
+ if (!NDirectory::DeleteFileAlways(arcPath))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot delete the file";
+ errorInfo.FileName = arcPath;
+ return E_FAIL;
+ }
+ if (!NDirectory::MyMoveFile(tempPath, arcPath))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot move the file";
+ errorInfo.FileName = tempPath;
+ errorInfo.FileName2 = arcPath;
+ return E_FAIL;
+ }
+ }
+ catch(...)
+ {
+ throw;
+ }
+ }
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (options.EMailMode)
+ {
+ NDLL::CLibrary mapiLib;
+ if (!mapiLib.Load(TEXT("Mapi32.dll")))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot load Mapi32.dll";
+ return E_FAIL;
+ }
+ MY_LPMAPISENDDOCUMENTS fnSend = (MY_LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments");
+ if (fnSend == 0)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot find MAPISendDocuments function";
+ return E_FAIL;
+ }
+ UStringVector fullPaths;
+ int i;
+ for(i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ UString arcPath;
+ if (!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"GetFullPathName error";
+ return E_FAIL;
+ }
+ fullPaths.Add(arcPath);
+ }
+ CCurrentDirRestorer curDirRestorer;
+ for(i = 0; i < fullPaths.Size(); i++)
+ {
+ UString arcPath = fullPaths[i];
+ UString fileName = ExtractFileNameFromPath(arcPath);
+ AString path = GetAnsiString(arcPath);
+ AString name = GetAnsiString(fileName);
+ // Warning!!! MAPISendDocuments function changes Current directory
+ fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
+ }
+ }
+ #endif
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/Update.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/Update.h
new file mode 100644
index 000000000..49af0092a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/Update.h
@@ -0,0 +1,175 @@
+// Update.h
+
+#ifndef __COMMON_UPDATE_H
+#define __COMMON_UPDATE_H
+
+#include "Common/Wildcard.h"
+
+#include "ArchiveOpenCallback.h"
+#include "LoadCodecs.h"
+#include "Property.h"
+#include "UpdateAction.h"
+#include "UpdateCallback.h"
+
+struct CArchivePath
+{
+ UString OriginalPath;
+
+ UString Prefix; // path(folder) prefix including slash
+ UString Name; // base name
+ UString BaseExtension; // archive type extension or "exe" extension
+ UString VolExtension; // archive type extension for volumes
+
+ bool Temp;
+ UString TempPrefix; // path(folder) for temp location
+ UString TempPostfix;
+
+ CArchivePath(): Temp(false) {};
+
+ void ParseFromPath(const UString &path)
+ {
+ OriginalPath = path;
+
+ SplitPathToParts(path, Prefix, Name);
+ int dotPos = Name.ReverseFind(L'.');
+ if (dotPos < 0)
+ return;
+ if (dotPos == Name.Length() - 1)
+ {
+ Name = Name.Left(dotPos);
+ BaseExtension.Empty();
+ return;
+ }
+ if (BaseExtension.CompareNoCase(Name.Mid(dotPos + 1)) == 0)
+ {
+ BaseExtension = Name.Mid(dotPos + 1);
+ Name = Name.Left(dotPos);
+ }
+ else
+ BaseExtension.Empty();
+ }
+
+ UString GetPathWithoutExt() const
+ {
+ return Prefix + Name;
+ }
+
+ UString GetFinalPath() const
+ {
+ UString path = GetPathWithoutExt();
+ if (!BaseExtension.IsEmpty())
+ path += UString(L'.') + BaseExtension;
+ return path;
+ }
+
+
+ UString GetTempPath() const
+ {
+ UString path = TempPrefix + Name;
+ if (!BaseExtension.IsEmpty())
+ path += UString(L'.') + BaseExtension;
+ path += L".tmp";
+ path += TempPostfix;
+ return path;
+ }
+};
+
+struct CUpdateArchiveCommand
+{
+ UString UserArchivePath;
+ CArchivePath ArchivePath;
+ NUpdateArchive::CActionSet ActionSet;
+};
+
+struct CCompressionMethodMode
+{
+ int FormatIndex;
+ CObjectVector<CProperty> Properties;
+ CCompressionMethodMode(): FormatIndex(-1) {}
+};
+
+struct CUpdateOptions
+{
+ CCompressionMethodMode MethodMode;
+
+ CObjectVector<CUpdateArchiveCommand> Commands;
+ bool UpdateArchiveItself;
+ CArchivePath ArchivePath;
+
+ bool SfxMode;
+ UString SfxModule;
+
+ bool OpenShareForWrite;
+
+ bool StdInMode;
+ UString StdInFileName;
+ bool StdOutMode;
+
+ bool EMailMode;
+ bool EMailRemoveAfter;
+ UString EMailAddress;
+
+ UString WorkingDir;
+
+ bool Init(const CCodecs *codecs, const CIntVector &formatIndices, const UString &arcPath);
+
+ CUpdateOptions():
+ UpdateArchiveItself(true),
+ SfxMode(false),
+ StdInMode(false),
+ StdOutMode(false),
+ EMailMode(false),
+ EMailRemoveAfter(false),
+ OpenShareForWrite(false)
+ {};
+
+ void SetAddActionCommand()
+ {
+ Commands.Clear();
+ CUpdateArchiveCommand c;
+ c.ActionSet = NUpdateArchive::kAddActionSet;
+ Commands.Add(c);
+ }
+
+ CRecordVector<UInt64> VolumesSizes;
+};
+
+struct CErrorInfo
+{
+ DWORD SystemError;
+ UString FileName;
+ UString FileName2;
+ UString Message;
+ // UStringVector ErrorPaths;
+ // CRecordVector<DWORD> ErrorCodes;
+ CErrorInfo(): SystemError(0) {};
+};
+
+struct CUpdateErrorInfo: public CErrorInfo
+{
+};
+
+#define INTERFACE_IUpdateCallbackUI2(x) \
+ INTERFACE_IUpdateCallbackUI(x) \
+ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result) x; \
+ virtual HRESULT StartScanning() x; \
+ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) x; \
+ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \
+ virtual HRESULT FinishScanning() x; \
+ virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \
+ virtual HRESULT FinishArchive() x; \
+
+struct IUpdateCallbackUI2: public IUpdateCallbackUI
+{
+ INTERFACE_IUpdateCallbackUI2(=0)
+};
+
+HRESULT UpdateArchive(
+ CCodecs *codecs,
+ const NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ CUpdateErrorInfo &errorInfo,
+ IOpenCallbackUI *openCallback,
+ IUpdateCallbackUI2 *callback);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.cpp
new file mode 100644
index 000000000..879a49c57
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.cpp
@@ -0,0 +1,64 @@
+// UpdateAction.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateAction.h"
+
+namespace NUpdateArchive {
+
+const CActionSet kAddActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress
+}};
+
+const CActionSet kUpdateActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress
+}};
+
+const CActionSet kFreshActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress
+}};
+
+const CActionSet kSynchronizeActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+}};
+
+const CActionSet kDeleteActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore
+}};
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.h
new file mode 100644
index 000000000..0ac1c1080
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateAction.h
@@ -0,0 +1,57 @@
+// UpdateAction.h
+
+#ifndef __UPDATE_ACTION_H
+#define __UPDATE_ACTION_H
+
+namespace NUpdateArchive {
+
+ namespace NPairState
+ {
+ const int kNumValues = 7;
+ enum EEnum
+ {
+ kNotMasked = 0,
+ kOnlyInArchive,
+ kOnlyOnDisk,
+ kNewInArchive,
+ kOldInArchive,
+ kSameFiles,
+ kUnknowNewerFiles
+ };
+ }
+
+ namespace NPairAction
+ {
+ enum EEnum
+ {
+ kIgnore = 0,
+ kCopy,
+ kCompress,
+ kCompressAsAnti
+ };
+ }
+
+ struct CActionSet
+ {
+ NPairAction::EEnum StateActions[NPairState::kNumValues];
+ bool NeedScanning() const
+ {
+ int i;
+ for (i = 0; i < NPairState::kNumValues; i++)
+ if (StateActions[i] == NPairAction::kCompress)
+ return true;
+ for (i = 1; i < NPairState::kNumValues; i++)
+ if (StateActions[i] != NPairAction::kIgnore)
+ return true;
+ return false;
+ }
+ };
+
+ extern const CActionSet kAddActionSet;
+ extern const CActionSet kUpdateActionSet;
+ extern const CActionSet kFreshActionSet;
+ extern const CActionSet kSynchronizeActionSet;
+ extern const CActionSet kDeleteActionSet;
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.cpp
new file mode 100644
index 000000000..0f229058c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -0,0 +1,249 @@
+// UpdateCallback.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/Defs.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "UpdateCallback.h"
+
+using namespace NWindows;
+
+CArchiveUpdateCallback::CArchiveUpdateCallback():
+ Callback(0),
+ ShareForWrite(false),
+ StdInMode(false),
+ DirItems(0),
+ ArcItems(0),
+ UpdatePairs(0),
+ NewNames(0)
+ {}
+
+
+STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
+{
+ COM_TRY_BEGIN
+ return Callback->SetTotal(size);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
+{
+ COM_TRY_BEGIN
+ return Callback->SetCompleted(completeValue);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ COM_TRY_BEGIN
+ return Callback->SetRatioInfo(inSize, outSize);
+ COM_TRY_END
+}
+
+
+/*
+STATPROPSTG kProperties[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidIsAnti, VT_BOOL}
+};
+
+STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
+{
+ return CStatPropEnumerator::CreateEnumerator(kProperties, sizeof(kProperties) / sizeof(kProperties[0]), enumerator);
+}
+*/
+
+STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
+ Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)
+{
+ COM_TRY_BEGIN
+ RINOK(Callback->CheckBreak());
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (newData != NULL) *newData = BoolToInt(up.NewData);
+ if (newProps != NULL) *newProps = BoolToInt(up.NewProps);
+ if (indexInArchive != NULL)
+ {
+ *indexInArchive = (UInt32)-1;
+ if (up.ExistInArchive())
+ *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ NWindows::NCOM::CPropVariant prop;
+
+ if (propID == kpidIsAnti)
+ {
+ prop = up.IsAnti;
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ if (up.IsAnti)
+ {
+ switch(propID)
+ {
+ case kpidIsDir:
+ case kpidPath:
+ break;
+ case kpidSize:
+ prop = (UInt64)0;
+ prop.Detach(value);
+ return S_OK;
+ default:
+ prop.Detach(value);
+ return S_OK;
+ }
+ }
+
+ if (up.ExistOnDisk())
+ {
+ const CDirItem &di = DirItems->Items[up.DirIndex];
+ switch(propID)
+ {
+ case kpidPath: prop = DirItems->GetLogPath(up.DirIndex); break;
+ case kpidIsDir: prop = di.IsDir(); break;
+ case kpidSize: prop = di.Size; break;
+ case kpidAttrib: prop = di.Attrib; break;
+ case kpidCTime: prop = di.CTime; break;
+ case kpidATime: prop = di.ATime; break;
+ case kpidMTime: prop = di.MTime; break;
+ }
+ }
+ else
+ {
+ if (propID == kpidPath)
+ {
+ if (up.NewNameIndex >= 0)
+ {
+ prop = (*NewNames)[up.NewNameIndex];
+ prop.Detach(value);
+ return S_OK;
+ }
+ }
+ if (up.ExistInArchive() && Archive)
+ {
+ UInt32 indexInArchive;
+ if (ArcItems == 0)
+ indexInArchive = up.ArcIndex;
+ else
+ indexInArchive = (*ArcItems)[up.ArcIndex].IndexInServer;
+ return Archive->GetProperty(indexInArchive, propID, value);
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
+{
+ COM_TRY_BEGIN
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (!up.NewData)
+ return E_FAIL;
+
+ RINOK(Callback->CheckBreak());
+ RINOK(Callback->Finilize());
+
+ if (up.IsAnti)
+ {
+ return Callback->GetStream((*ArcItems)[up.ArcIndex].Name, true);
+ }
+ const CDirItem &di = DirItems->Items[up.DirIndex];
+ RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), false));
+
+ if (di.IsDir())
+ return S_OK;
+
+ if (StdInMode)
+ {
+ CStdInFileStream *inStreamSpec = new CStdInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ *inStream = inStreamLoc.Detach();
+ }
+ else
+ {
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ const UString path = DirItems->GetPhyPath(up.DirIndex);
+ if (!inStreamSpec->OpenShared(path, ShareForWrite))
+ {
+ return Callback->OpenFileError(path, ::GetLastError());
+ }
+ *inStream = inStreamLoc.Detach();
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult)
+{
+ COM_TRY_BEGIN
+ return Callback->SetOperationResult(operationResult);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
+{
+ if (VolumesSizes.Size() == 0)
+ return S_FALSE;
+ if (index >= (UInt32)VolumesSizes.Size())
+ index = VolumesSizes.Size() - 1;
+ *size = VolumesSizes[index];
+ return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
+{
+ COM_TRY_BEGIN
+ wchar_t temp[16];
+ ConvertUInt32ToString(index + 1, temp);
+ UString res = temp;
+ while (res.Length() < 2)
+ res = UString(L'0') + res;
+ UString fileName = VolName;
+ fileName += L'.';
+ fileName += res;
+ fileName += VolExt;
+ COutFileStream *streamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
+ if (!streamSpec->Create(fileName, false))
+ return ::GetLastError();
+ *volumeStream = streamLoc.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ COM_TRY_BEGIN
+ return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ return Callback->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.h
new file mode 100644
index 000000000..9a20c3159
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateCallback.h
@@ -0,0 +1,74 @@
+// UpdateCallback.h
+
+#ifndef __UPDATECALLBACK_H
+#define __UPDATECALLBACK_H
+
+#include "Common/MyCom.h"
+#include "Common/MyString.h"
+
+#include "../../IPassword.h"
+#include "../../ICoder.h"
+
+#include "../Common/UpdatePair.h"
+#include "../Common/UpdateProduce.h"
+
+#define INTERFACE_IUpdateCallbackUI(x) \
+ virtual HRESULT SetTotal(UInt64 size) x; \
+ virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \
+ virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \
+ virtual HRESULT CheckBreak() x; \
+ virtual HRESULT Finilize() x; \
+ virtual HRESULT SetNumFiles(UInt64 numFiles) x; \
+ virtual HRESULT GetStream(const wchar_t *name, bool isAnti) x; \
+ virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \
+ virtual HRESULT SetOperationResult(Int32 operationResult) x; \
+ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \
+ virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \
+ /* virtual HRESULT ShowDeleteFile(const wchar_t *name) x; */ \
+ /* virtual HRESULT CloseProgress() { return S_OK; }; */
+
+struct IUpdateCallbackUI
+{
+ INTERFACE_IUpdateCallbackUI(=0)
+};
+
+class CArchiveUpdateCallback:
+ public IArchiveUpdateCallback2,
+ public ICryptoGetTextPassword2,
+ public ICryptoGetTextPassword,
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP4(
+ IArchiveUpdateCallback2,
+ ICryptoGetTextPassword2,
+ ICryptoGetTextPassword,
+ ICompressProgressInfo)
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+
+ INTERFACE_IArchiveUpdateCallback2(;)
+
+ STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+public:
+ CRecordVector<UInt64> VolumesSizes;
+ UString VolName;
+ UString VolExt;
+
+ IUpdateCallbackUI *Callback;
+
+ bool ShareForWrite;
+ bool StdInMode;
+ const CDirItems *DirItems;
+ const CObjectVector<CArcItem> *ArcItems;
+ const CRecordVector<CUpdatePair2> *UpdatePairs;
+ const UStringVector *NewNames;
+ CMyComPtr<IInArchive> Archive;
+
+ CArchiveUpdateCallback();
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.cpp
new file mode 100644
index 000000000..a43a9e770
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.cpp
@@ -0,0 +1,158 @@
+// UpdatePair.cpp
+
+#include "StdAfx.h"
+
+#include <time.h>
+
+#include "Common/Defs.h"
+#include "Common/Wildcard.h"
+
+#include "Windows/Time.h"
+
+#include "SortUtils.h"
+#include "UpdatePair.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2)
+{
+ switch(fileTimeType)
+ {
+ case NFileTimeType::kWindows:
+ return ::CompareFileTime(&time1, &time2);
+ case NFileTimeType::kUnix:
+ {
+ UInt32 unixTime1, unixTime2;
+ FileTimeToUnixTime(time1, unixTime1);
+ FileTimeToUnixTime(time2, unixTime2);
+ return MyCompare(unixTime1, unixTime2);
+ }
+ case NFileTimeType::kDOS:
+ {
+ UInt32 dosTime1, dosTime2;
+ FileTimeToDosTime(time1, dosTime1);
+ FileTimeToDosTime(time2, dosTime2);
+ return MyCompare(dosTime1, dosTime2);
+ }
+ }
+ throw 4191618;
+}
+
+static const wchar_t *kDuplicateFileNameMessage = L"Duplicate filename:";
+static const wchar_t *kNotCensoredCollisionMessaged = L"Internal file name collision (file on disk, file in archive):";
+
+static void ThrowError(const UString &message, const UString &s1, const UString &s2)
+{
+ UString m = message;
+ m += L'\n';
+ m += s1;
+ m += L'\n';
+ m += s2;
+ throw m;
+}
+
+static void TestDuplicateString(const UStringVector &strings, const CIntVector &indices)
+{
+ for(int i = 0; i + 1 < indices.Size(); i++)
+ if (CompareFileNames(strings[indices[i]], strings[indices[i + 1]]) == 0)
+ ThrowError(kDuplicateFileNameMessage, strings[indices[i]], strings[indices[i + 1]]);
+}
+
+void GetUpdatePairInfoList(
+ const CDirItems &dirItems,
+ const CObjectVector<CArcItem> &arcItems,
+ NFileTimeType::EEnum fileTimeType,
+ CRecordVector<CUpdatePair> &updatePairs)
+{
+ CIntVector dirIndices, arcIndices;
+
+ int numDirItems = dirItems.Items.Size();
+ int numArcItems = arcItems.Size();
+
+
+ {
+ UStringVector arcNames;
+ arcNames.Reserve(numArcItems);
+ for (int i = 0; i < numArcItems; i++)
+ arcNames.Add(arcItems[i].Name);
+ SortFileNames(arcNames, arcIndices);
+ TestDuplicateString(arcNames, arcIndices);
+ }
+
+ UStringVector dirNames;
+ {
+ dirNames.Reserve(numDirItems);
+ for (int i = 0; i < numDirItems; i++)
+ dirNames.Add(dirItems.GetLogPath(i));
+ SortFileNames(dirNames, dirIndices);
+ TestDuplicateString(dirNames, dirIndices);
+ }
+
+ int dirIndex = 0, arcIndex = 0;
+ while (dirIndex < numDirItems && arcIndex < numArcItems)
+ {
+ CUpdatePair pair;
+ int dirIndex2 = dirIndices[dirIndex];
+ int arcIndex2 = arcIndices[arcIndex];
+ const CDirItem &di = dirItems.Items[dirIndex2];
+ const CArcItem &ai = arcItems[arcIndex2];
+ int compareResult = CompareFileNames(dirNames[dirIndex2], ai.Name);
+ if (compareResult < 0)
+ {
+ pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+ pair.DirIndex = dirIndex2;
+ dirIndex++;
+ }
+ else if (compareResult > 0)
+ {
+ pair.State = ai.Censored ?
+ NUpdateArchive::NPairState::kOnlyInArchive:
+ NUpdateArchive::NPairState::kNotMasked;
+ pair.ArcIndex = arcIndex2;
+ arcIndex++;
+ }
+ else
+ {
+ if (!ai.Censored)
+ ThrowError(kNotCensoredCollisionMessaged, dirNames[dirIndex2], ai.Name);
+ pair.DirIndex = dirIndex2;
+ pair.ArcIndex = arcIndex2;
+ switch (ai.MTimeDefined ? MyCompareTime(
+ ai.TimeType != - 1 ? (NFileTimeType::EEnum)ai.TimeType : fileTimeType,
+ di.MTime, ai.MTime): 0)
+ {
+ case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
+ case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
+ default:
+ pair.State = (ai.SizeDefined && di.Size == ai.Size) ?
+ NUpdateArchive::NPairState::kSameFiles :
+ NUpdateArchive::NPairState::kUnknowNewerFiles;
+ }
+ dirIndex++;
+ arcIndex++;
+ }
+ updatePairs.Add(pair);
+ }
+
+ for (; dirIndex < numDirItems; dirIndex++)
+ {
+ CUpdatePair pair;
+ pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+ pair.DirIndex = dirIndices[dirIndex];
+ updatePairs.Add(pair);
+ }
+
+ for (; arcIndex < numArcItems; arcIndex++)
+ {
+ CUpdatePair pair;
+ int arcIndex2 = arcIndices[arcIndex];
+ pair.State = arcItems[arcIndex2].Censored ?
+ NUpdateArchive::NPairState::kOnlyInArchive:
+ NUpdateArchive::NPairState::kNotMasked;
+ pair.ArcIndex = arcIndex2;
+ updatePairs.Add(pair);
+ }
+
+ updatePairs.ReserveDown();
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.h
new file mode 100644
index 000000000..3a332649c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdatePair.h
@@ -0,0 +1,25 @@
+// UpdatePair.h
+
+#ifndef __UPDATE_PAIR_H
+#define __UPDATE_PAIR_H
+
+#include "DirItem.h"
+#include "UpdateAction.h"
+
+#include "../../Archive/IArchive.h"
+
+struct CUpdatePair
+{
+ NUpdateArchive::NPairState::EEnum State;
+ int ArcIndex;
+ int DirIndex;
+ CUpdatePair(): ArcIndex(-1), DirIndex(-1) {}
+};
+
+void GetUpdatePairInfoList(
+ const CDirItems &dirItems,
+ const CObjectVector<CArcItem> &arcItems,
+ NFileTimeType::EEnum fileTimeType,
+ CRecordVector<CUpdatePair> &updatePairs);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.cpp
new file mode 100644
index 000000000..c21db3b2a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.cpp
@@ -0,0 +1,58 @@
+// UpdateProduce.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateProduce.h"
+
+using namespace NUpdateArchive;
+
+static const char *kUpdateActionSetCollision = "Internal collision in update action set";
+
+void UpdateProduce(
+ const CRecordVector<CUpdatePair> &updatePairs,
+ const CActionSet &actionSet,
+ CRecordVector<CUpdatePair2> &operationChain,
+ IUpdateProduceCallback *callback)
+{
+ for (int i = 0; i < updatePairs.Size(); i++)
+ {
+ const CUpdatePair &pair = updatePairs[i];
+
+ CUpdatePair2 up2;
+ up2.IsAnti = false;
+ up2.DirIndex = pair.DirIndex;
+ up2.ArcIndex = pair.ArcIndex;
+ up2.NewData = up2.NewProps = true;
+
+ switch(actionSet.StateActions[pair.State])
+ {
+ case NPairAction::kIgnore:
+ /*
+ if (pair.State != NPairState::kOnlyOnDisk)
+ IgnoreArchiveItem(m_ArchiveItems[pair.ArcIndex]);
+ // cout << "deleting";
+ */
+ if (callback)
+ callback->ShowDeleteFile(pair.ArcIndex);
+ continue;
+
+ case NPairAction::kCopy:
+ if (pair.State == NPairState::kOnlyOnDisk)
+ throw kUpdateActionSetCollision;
+ up2.NewData = up2.NewProps = false;
+ break;
+
+ case NPairAction::kCompress:
+ if (pair.State == NPairState::kOnlyInArchive ||
+ pair.State == NPairState::kNotMasked)
+ throw kUpdateActionSetCollision;
+ break;
+
+ case NPairAction::kCompressAsAnti:
+ up2.IsAnti = true;
+ break;
+ }
+ operationChain.Add(up2);
+ }
+ operationChain.ReserveDown();
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.h
new file mode 100644
index 000000000..e18648cd9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/UpdateProduce.h
@@ -0,0 +1,35 @@
+// UpdateProduce.h
+
+#ifndef __UPDATE_PRODUCE_H
+#define __UPDATE_PRODUCE_H
+
+#include "UpdatePair.h"
+
+struct CUpdatePair2
+{
+ bool NewData;
+ bool NewProps;
+ bool IsAnti;
+
+ int DirIndex;
+ int ArcIndex;
+ int NewNameIndex;
+
+ bool ExistOnDisk() const { return DirIndex != -1; }
+ bool ExistInArchive() const { return ArcIndex != -1; }
+
+ CUpdatePair2(): IsAnti(false), DirIndex(-1), ArcIndex(-1), NewNameIndex(-1) {}
+};
+
+struct IUpdateProduceCallback
+{
+ virtual HRESULT ShowDeleteFile(int arcIndex) = 0;
+};
+
+void UpdateProduce(
+ const CRecordVector<CUpdatePair> &updatePairs,
+ const NUpdateArchive::CActionSet &actionSet,
+ CRecordVector<CUpdatePair2> &operationChain,
+ IUpdateProduceCallback *callback);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/WorkDir.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/WorkDir.cpp
new file mode 100644
index 000000000..28d36df9e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/WorkDir.cpp
@@ -0,0 +1,59 @@
+// WorkDir.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StringConvert.h"
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileName.h"
+
+#include "WorkDir.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path)
+{
+ NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
+ #if !defined(UNDER_CE) && defined(_WIN32)
+ if (workDirInfo.ForRemovableOnly)
+ {
+ mode = NWorkDir::NMode::kCurrent;
+ UString prefix = path.Left(3);
+ if (prefix[1] == L':' && prefix[2] == L'\\')
+ {
+ UINT driveType = GetDriveType(GetSystemString(prefix, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP));
+ if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
+ mode = workDirInfo.Mode;
+ }
+ /*
+ CParsedPath parsedPath;
+ parsedPath.ParsePath(archiveName);
+ UINT driveType = GetDriveType(parsedPath.Prefix);
+ if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
+ mode = NZipSettings::NWorkDir::NMode::kCurrent;
+ */
+ }
+ #endif
+ switch(mode)
+ {
+ case NWorkDir::NMode::kCurrent:
+ {
+ return ExtractDirPrefixFromPath(path);
+ }
+ case NWorkDir::NMode::kSpecified:
+ {
+ UString tempDir = workDirInfo.Path;
+ NName::NormalizeDirPathPrefix(tempDir);
+ return tempDir;
+ }
+ default:
+ {
+ UString tempDir;
+ if (!NDirectory::MyGetTempPath(tempDir))
+ throw 141717;
+ return tempDir;
+ }
+ }
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/WorkDir.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/WorkDir.h
new file mode 100644
index 000000000..0643d67a4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/WorkDir.h
@@ -0,0 +1,10 @@
+// WorkDir.h
+
+#ifndef __WORKDIR_H
+#define __WORKDIR_H
+
+#include "ZipRegistry.h"
+
+UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ZipRegistry.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Common/ZipRegistry.cpp
new file mode 100644
index 000000000..ac178078a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ZipRegistry.cpp
@@ -0,0 +1,293 @@
+// ZipRegistry.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/Registry.h"
+#include "Windows/Synchronization.h"
+
+#include "ZipRegistry.h"
+
+using namespace NWindows;
+using namespace NRegistry;
+
+static NSynchronization::CCriticalSection g_CS;
+#define CS_LOCK NSynchronization::CCriticalSectionLock lock(g_CS);
+
+static const TCHAR *kCuPrefix = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR);
+
+static CSysString GetKeyPath(const CSysString &path) { return kCuPrefix + path; }
+
+static LONG OpenMainKey(CKey &key, LPCTSTR keyName)
+{
+ return key.Open(HKEY_CURRENT_USER, GetKeyPath(keyName), KEY_READ);
+}
+
+static LONG CreateMainKey(CKey &key, LPCTSTR keyName)
+{
+ return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName));
+}
+
+namespace NExtract
+{
+
+static const TCHAR *kKeyName = TEXT("Extraction");
+
+static const TCHAR *kExtractMode = TEXT("ExtractMode");
+static const TCHAR *kOverwriteMode = TEXT("OverwriteMode");
+static const TCHAR *kShowPassword = TEXT("ShowPassword");
+static const TCHAR *kPathHistory = TEXT("PathHistory");
+
+void CInfo::Save() const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kKeyName);
+ key.SetValue(kExtractMode, (UInt32)PathMode);
+ key.SetValue(kOverwriteMode, (UInt32)OverwriteMode);
+ key.SetValue(kShowPassword, ShowPassword);
+ key.RecurseDeleteKey(kPathHistory);
+ key.SetValue_Strings(kPathHistory, Paths);
+}
+
+
+void CInfo::Load()
+{
+ PathMode = NPathMode::kCurrentPathnames;
+ OverwriteMode = NOverwriteMode::kAskBefore;
+ ShowPassword = false;
+ Paths.Clear();
+
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
+ return;
+
+ key.GetValue_Strings(kPathHistory, Paths);
+ UInt32 v;
+ if (key.QueryValue(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kNoPathnames)
+ PathMode = (NPathMode::EEnum)v;
+ if (key.QueryValue(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kAutoRenameExisting)
+ OverwriteMode = (NOverwriteMode::EEnum)v;
+ key.GetValue_IfOk(kShowPassword, ShowPassword);
+}
+
+}
+
+namespace NCompression
+{
+
+static const TCHAR *kKeyName = TEXT("Compression");
+
+static const TCHAR *kArcHistory = TEXT("ArcHistory");
+static const WCHAR *kArchiver = L"Archiver";
+static const TCHAR *kShowPassword = TEXT("ShowPassword");
+static const TCHAR *kEncryptHeaders = TEXT("EncryptHeaders");
+
+static const TCHAR *kOptionsKeyName = TEXT("Options");
+
+static const TCHAR *kLevel = TEXT("Level");
+static const TCHAR *kDictionary = TEXT("Dictionary");
+static const TCHAR *kOrder = TEXT("Order");
+static const TCHAR *kBlockSize = TEXT("BlockSize");
+static const TCHAR *kNumThreads = TEXT("NumThreads");
+static const WCHAR *kMethod = L"Method";
+static const WCHAR *kOptions = L"Options";
+static const WCHAR *kEncryptionMethod = L"EncryptionMethod";
+
+static void SetRegString(CKey &key, const WCHAR *name, const UString &value)
+{
+ if (value.IsEmpty())
+ key.DeleteValue(name);
+ else
+ key.SetValue(name, value);
+}
+
+static void SetRegUInt32(CKey &key, const TCHAR *name, UInt32 value)
+{
+ if (value == (UInt32)-1)
+ key.DeleteValue(name);
+ else
+ key.SetValue(name, value);
+}
+
+static void GetRegString(CKey &key, const WCHAR *name, UString &value)
+{
+ if (key.QueryValue(name, value) != ERROR_SUCCESS)
+ value.Empty();
+}
+
+static void GetRegUInt32(CKey &key, const TCHAR *name, UInt32 &value)
+{
+ if (key.QueryValue(name, value) != ERROR_SUCCESS)
+ value = (UInt32)-1;
+}
+
+void CInfo::Save() const
+{
+ CS_LOCK
+
+ CKey key;
+ CreateMainKey(key, kKeyName);
+ key.SetValue(kLevel, (UInt32)Level);
+ key.SetValue(kArchiver, ArcType);
+ key.SetValue(kShowPassword, ShowPassword);
+ key.SetValue(kEncryptHeaders, EncryptHeaders);
+ key.RecurseDeleteKey(kArcHistory);
+ key.SetValue_Strings(kArcHistory, ArcPaths);
+
+ key.RecurseDeleteKey(kOptionsKeyName);
+ {
+ CKey optionsKey;
+ optionsKey.Create(key, kOptionsKeyName);
+ for (int i = 0; i < Formats.Size(); i++)
+ {
+ const CFormatOptions &fo = Formats[i];
+ CKey fk;
+ fk.Create(optionsKey, fo.FormatID);
+
+ SetRegUInt32(fk, kLevel, fo.Level);
+ SetRegUInt32(fk, kDictionary, fo.Dictionary);
+ SetRegUInt32(fk, kOrder, fo.Order);
+ SetRegUInt32(fk, kBlockSize, fo.BlockLogSize);
+ SetRegUInt32(fk, kNumThreads, fo.NumThreads);
+
+ SetRegString(fk, kMethod, fo.Method);
+ SetRegString(fk, kOptions, fo.Options);
+ SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
+ }
+ }
+}
+
+void CInfo::Load()
+{
+ ArcPaths.Clear();
+ Formats.Clear();
+
+ Level = 5;
+ ArcType = L"7z";
+ ShowPassword = false;
+ EncryptHeaders = false;
+
+ CS_LOCK
+ CKey key;
+
+ if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
+ return;
+
+ key.GetValue_Strings(kArcHistory, ArcPaths);
+
+ {
+ CKey optionsKey;
+ if (optionsKey.Open(key, kOptionsKeyName, KEY_READ) == ERROR_SUCCESS)
+ {
+ CSysStringVector formatIDs;
+ optionsKey.EnumKeys(formatIDs);
+ for (int i = 0; i < formatIDs.Size(); i++)
+ {
+ CKey fk;
+ CFormatOptions fo;
+ fo.FormatID = formatIDs[i];
+ if (fk.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS)
+ {
+ GetRegString(fk, kOptions, fo.Options);
+ GetRegString(fk, kMethod, fo.Method);
+ GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
+
+ GetRegUInt32(fk, kLevel, fo.Level);
+ GetRegUInt32(fk, kDictionary, fo.Dictionary);
+ GetRegUInt32(fk, kOrder, fo.Order);
+ GetRegUInt32(fk, kBlockSize, fo.BlockLogSize);
+ GetRegUInt32(fk, kNumThreads, fo.NumThreads);
+
+ Formats.Add(fo);
+ }
+ }
+ }
+ }
+
+ UString a;
+ if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS)
+ ArcType = a;
+ key.GetValue_IfOk(kLevel, Level);
+ key.GetValue_IfOk(kShowPassword, ShowPassword);
+ key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders);
+}
+
+}
+
+static const TCHAR *kOptionsInfoKeyName = TEXT("Options");
+
+namespace NWorkDir
+{
+static const TCHAR *kWorkDirType = TEXT("WorkDirType");
+static const WCHAR *kWorkDirPath = L"WorkDirPath";
+static const TCHAR *kTempRemovableOnly = TEXT("TempRemovableOnly");
+
+
+void CInfo::Save()const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kOptionsInfoKeyName);
+ key.SetValue(kWorkDirType, (UInt32)Mode);
+ key.SetValue(kWorkDirPath, Path);
+ key.SetValue(kTempRemovableOnly, ForRemovableOnly);
+}
+
+void CInfo::Load()
+{
+ SetDefault();
+
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
+ return;
+
+ UInt32 dirType;
+ if (key.QueryValue(kWorkDirType, dirType) != ERROR_SUCCESS)
+ return;
+ switch (dirType)
+ {
+ case NMode::kSystem:
+ case NMode::kCurrent:
+ case NMode::kSpecified:
+ Mode = (NMode::EEnum)dirType;
+ }
+ if (key.QueryValue(kWorkDirPath, Path) != ERROR_SUCCESS)
+ {
+ Path.Empty();
+ if (Mode == NMode::kSpecified)
+ Mode = NMode::kSystem;
+ }
+ key.GetValue_IfOk(kTempRemovableOnly, ForRemovableOnly);
+}
+
+}
+
+static const TCHAR *kCascadedMenu = TEXT("CascadedMenu");
+static const TCHAR *kContextMenu = TEXT("ContextMenu");
+
+void CContextMenuInfo::Save() const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kOptionsInfoKeyName);
+ key.SetValue(kCascadedMenu, Cascaded);
+ key.SetValue(kContextMenu, Flags);
+}
+
+void CContextMenuInfo::Load()
+{
+ Cascaded = true;
+ Flags = (UInt32)-1;
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
+ return;
+ key.GetValue_IfOk(kCascadedMenu, Cascaded);
+ key.GetValue_IfOk(kContextMenu, Flags);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Common/ZipRegistry.h b/src/libs/7zip/unix/CPP/7zip/UI/Common/ZipRegistry.h
new file mode 100644
index 000000000..378353868
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Common/ZipRegistry.h
@@ -0,0 +1,105 @@
+// ZipRegistry.h
+
+#ifndef __ZIP_REGISTRY_H
+#define __ZIP_REGISTRY_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+#include "ExtractMode.h"
+
+namespace NExtract
+{
+ struct CInfo
+ {
+ NPathMode::EEnum PathMode;
+ NOverwriteMode::EEnum OverwriteMode;
+ bool ShowPassword;
+ UStringVector Paths;
+
+ void Save() const;
+ void Load();
+ };
+}
+
+namespace NCompression
+{
+ struct CFormatOptions
+ {
+ UInt32 Level;
+ UInt32 Dictionary;
+ UInt32 Order;
+ UInt32 BlockLogSize;
+ UInt32 NumThreads;
+
+ CSysString FormatID;
+ UString Method;
+ UString Options;
+ UString EncryptionMethod;
+
+ void ResetForLevelChange()
+ {
+ BlockLogSize = NumThreads = Level = Dictionary = Order = UInt32(-1);
+ Method.Empty();
+ // Options.Empty();
+ // EncryptionMethod.Empty();
+ }
+ CFormatOptions() { ResetForLevelChange(); }
+ };
+
+ struct CInfo
+ {
+ UInt32 Level;
+ bool ShowPassword;
+ bool EncryptHeaders;
+ UString ArcType;
+ UStringVector ArcPaths;
+
+ CObjectVector<CFormatOptions> Formats;
+
+ void Save() const;
+ void Load();
+ };
+}
+
+namespace NWorkDir
+{
+ namespace NMode
+ {
+ enum EEnum
+ {
+ kSystem,
+ kCurrent,
+ kSpecified
+ };
+ }
+ struct CInfo
+ {
+ NMode::EEnum Mode;
+ UString Path;
+ bool ForRemovableOnly;
+
+ void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
+ void SetDefault()
+ {
+ Mode = NMode::kSystem;
+ Path.Empty();
+ SetForRemovableOnlyDefault();
+ }
+
+ void Save() const;
+ void Load();
+ };
+}
+
+
+struct CContextMenuInfo
+{
+ bool Cascaded;
+ UInt32 Flags;
+
+ void Save() const;
+ void Load();
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/BenchCon.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/BenchCon.cpp
new file mode 100644
index 000000000..35e868c9b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/BenchCon.cpp
@@ -0,0 +1,297 @@
+// BenchCon.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyCom.h"
+
+#if !defined(_7ZIP_ST) || defined(_WIN32)
+#include "../../../Windows/System.h"
+#endif
+
+#include "../Common/Bench.h"
+
+#include "BenchCon.h"
+#include "ConsoleClose.h"
+
+struct CTotalBenchRes
+{
+ UInt64 NumIterations;
+ UInt64 Rating;
+ UInt64 Usage;
+ UInt64 RPU;
+ void Init() { NumIterations = 0; Rating = 0; Usage = 0; RPU = 0; }
+ void Normalize()
+ {
+ if (NumIterations == 0)
+ return;
+ Rating /= NumIterations;
+ Usage /= NumIterations;
+ RPU /= NumIterations;
+ NumIterations = 1;
+ }
+ void SetMid(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
+ {
+ Rating = (r1.Rating + r2.Rating) / 2;
+ Usage = (r1.Usage + r2.Usage) / 2;
+ RPU = (r1.RPU + r2.RPU) / 2;
+ NumIterations = (r1.NumIterations + r2.NumIterations) / 2;
+ }
+};
+
+struct CBenchCallback: public IBenchCallback
+{
+ CTotalBenchRes EncodeRes;
+ CTotalBenchRes DecodeRes;
+ FILE *f;
+ void Init() { EncodeRes.Init(); DecodeRes.Init(); }
+ void Normalize() { EncodeRes.Normalize(); DecodeRes.Normalize(); }
+ UInt32 dictionarySize;
+ HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
+ HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
+};
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ while (v1 > 1000000)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
+{
+ UInt64 elTime = elapsedTime;
+ NormalizeVals(freq, elTime);
+ if (elTime == 0)
+ elTime = 1;
+ return value * freq / elTime;
+}
+
+static void PrintNumber(FILE *f, UInt64 value, int size)
+{
+ char s[32];
+ ConvertUInt64ToString(value, s);
+ fprintf(f, " ");
+ for (int len = (int)strlen(s); len < size; len++)
+ fprintf(f, " ");
+ fputs(s, f);
+}
+
+static void PrintRating(FILE *f, UInt64 rating)
+{
+ PrintNumber(f, rating / 1000000, 6);
+}
+
+static void PrintResults(FILE *f, UInt64 usage, UInt64 rpu, UInt64 rating)
+{
+ PrintNumber(f, (usage + 5000) / 10000, 5);
+ PrintRating(f, rpu);
+ PrintRating(f, rating);
+}
+
+
+static void PrintResults(FILE *f, const CBenchInfo &info, UInt64 rating, CTotalBenchRes &res)
+{
+ UInt64 speed = MyMultDiv64(info.UnpackSize, info.GlobalTime, info.GlobalFreq);
+ PrintNumber(f, speed / 1024, 7);
+ UInt64 usage = GetUsage(info);
+ UInt64 rpu = GetRatingPerUsage(info, rating);
+ PrintResults(f, usage, rpu, rating);
+ res.NumIterations++;
+ res.RPU += rpu;
+ res.Rating += rating;
+ res.Usage += usage;
+}
+
+static void PrintTotals(FILE *f, const CTotalBenchRes &res)
+{
+ fprintf(f, " ");
+ PrintResults(f, res.Usage, res.RPU, res.Rating);
+}
+
+
+HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ if (final)
+ {
+ UInt64 rating = GetCompressRating(dictionarySize, info.GlobalTime, info.GlobalFreq, info.UnpackSize);
+ PrintResults(f, info, rating, EncodeRes);
+ }
+ return S_OK;
+}
+
+static const char *kSep = " | ";
+
+
+HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ if (final)
+ {
+ UInt64 rating = GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
+ fputs(kSep, f);
+ CBenchInfo info2 = info;
+ info2.UnpackSize *= info2.NumIterations;
+ info2.PackSize *= info2.NumIterations;
+ info2.NumIterations = 1;
+ PrintResults(f, info2, rating, DecodeRes);
+ }
+ return S_OK;
+}
+
+static void PrintRequirements(FILE *f, const char *sizeString, UInt64 size, const char *threadsString, UInt32 numThreads)
+{
+ fprintf(f, "\nRAM %s ", sizeString);
+ PrintNumber(f, (size >> 20), 5);
+ fprintf(f, " MB, # %s %3d", threadsString, (unsigned int)numThreads);
+}
+
+HRESULT LzmaBenchCon(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
+{
+ if (!CrcInternalTest())
+ return S_FALSE;
+ #ifndef _7ZIP_ST
+ UInt64 ramSize = NWindows::NSystem::GetRamSize(); //
+ UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+ PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+ if (numThreads == (UInt32)-1)
+ numThreads = numCPUs;
+ if (numThreads > 1)
+ numThreads &= ~1;
+ if (dictionary == (UInt32)-1)
+ {
+ int dicSizeLog;
+ for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
+ if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
+ break;
+ dictionary = (1 << dicSizeLog);
+ }
+ #else
+ if (dictionary == (UInt32)-1)
+ dictionary = (1 << 22);
+ numThreads = 1;
+ #endif
+
+ PrintRequirements(f, "usage:", GetBenchMemoryUsage(numThreads, dictionary), "Benchmark threads: ", numThreads);
+
+ CBenchCallback callback;
+ callback.Init();
+ callback.f = f;
+
+ fprintf(f, "\n\nDict Compressing | Decompressing\n ");
+ int j;
+ for (j = 0; j < 2; j++)
+ {
+ fprintf(f, " Speed Usage R/U Rating");
+ if (j == 0)
+ fputs(kSep, f);
+ }
+ fprintf(f, "\n ");
+ for (j = 0; j < 2; j++)
+ {
+ fprintf(f, " KB/s %% MIPS MIPS");
+ if (j == 0)
+ fputs(kSep, f);
+ }
+ fprintf(f, "\n\n");
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ const int kStartDicLog = 22;
+ int pow = (dictionary < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
+ while (((UInt32)1 << pow) > dictionary)
+ pow--;
+ for (; ((UInt32)1 << pow) <= dictionary; pow++)
+ {
+ fprintf(f, "%2d:", pow);
+ callback.dictionarySize = (UInt32)1 << pow;
+ HRESULT res = LzmaBench(
+ EXTERNAL_CODECS_LOC_VARS
+ numThreads, callback.dictionarySize, &callback);
+ fprintf(f, "\n");
+ RINOK(res);
+ }
+ }
+ callback.Normalize();
+ fprintf(f, "----------------------------------------------------------------\nAvr:");
+ PrintTotals(f, callback.EncodeRes);
+ fprintf(f, " ");
+ PrintTotals(f, callback.DecodeRes);
+ fprintf(f, "\nTot:");
+ CTotalBenchRes midRes;
+ midRes.SetMid(callback.EncodeRes, callback.DecodeRes);
+ PrintTotals(f, midRes);
+ fprintf(f, "\n");
+ return S_OK;
+}
+
+struct CTempValues
+{
+ UInt64 *Values;
+ CTempValues(UInt32 num) { Values = new UInt64[num]; }
+ ~CTempValues() { delete []Values; }
+};
+
+HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
+{
+ if (!CrcInternalTest())
+ return S_FALSE;
+
+ #ifndef _7ZIP_ST
+ UInt64 ramSize = NWindows::NSystem::GetRamSize();
+ UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+ PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+ if (numThreads == (UInt32)-1)
+ numThreads = numCPUs;
+ #else
+ numThreads = 1;
+ #endif
+ if (dictionary == (UInt32)-1)
+ dictionary = (1 << 24);
+
+ CTempValues speedTotals(numThreads);
+ fprintf(f, "\n\nSize");
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ {
+ fprintf(f, " %5d", ti + 1);
+ speedTotals.Values[ti] = 0;
+ }
+ fprintf(f, "\n\n");
+
+ UInt64 numSteps = 0;
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ for (int pow = 10; pow < 32; pow++)
+ {
+ UInt32 bufSize = (UInt32)1 << pow;
+ if (bufSize > dictionary)
+ break;
+ fprintf(f, "%2d: ", pow);
+ UInt64 speed;
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ {
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ RINOK(CrcBench(ti + 1, bufSize, speed));
+ PrintNumber(f, (speed >> 20), 5);
+ speedTotals.Values[ti] += speed;
+ }
+ fprintf(f, "\n");
+ numSteps++;
+ }
+ }
+ if (numSteps != 0)
+ {
+ fprintf(f, "\nAvg:");
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), 5);
+ fprintf(f, "\n");
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/BenchCon.h b/src/libs/7zip/unix/CPP/7zip/UI/Console/BenchCon.h
new file mode 100644
index 000000000..966a83a6a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/BenchCon.h
@@ -0,0 +1,16 @@
+// BenchCon.h
+
+#ifndef __BENCH_CON_H
+#define __BENCH_CON_H
+
+#include <stdio.h>
+
+#include "../../Common/CreateCoder.h"
+
+HRESULT LzmaBenchCon(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary);
+
+HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/ConsoleClose.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/ConsoleClose.cpp
new file mode 100644
index 000000000..9bb2082bf
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/ConsoleClose.cpp
@@ -0,0 +1,49 @@
+// ConsoleClose.cpp
+
+#include "StdAfx.h"
+
+#include "ConsoleClose.h"
+
+#include <signal.h>
+
+static int g_BreakCounter = 0;
+static const int kBreakAbortThreshold = 2;
+
+namespace NConsoleClose {
+
+static void HandlerRoutine(int)
+{
+ g_BreakCounter++;
+ if (g_BreakCounter < kBreakAbortThreshold)
+ return ;
+ exit(EXIT_FAILURE);
+}
+
+bool TestBreakSignal()
+{
+ return (g_BreakCounter > 0);
+}
+
+void CheckCtrlBreak()
+{
+ if (TestBreakSignal())
+ throw CCtrlBreakException();
+}
+
+CCtrlHandlerSetter::CCtrlHandlerSetter()
+{
+ memo_sig_int = signal(SIGINT,HandlerRoutine); // CTRL-C
+ if (memo_sig_int == SIG_ERR)
+ throw "SetConsoleCtrlHandler fails (SIGINT)";
+ memo_sig_term = signal(SIGTERM,HandlerRoutine); // for kill -15 (before "kill -9")
+ if (memo_sig_term == SIG_ERR)
+ throw "SetConsoleCtrlHandler fails (SIGTERM)";
+}
+
+CCtrlHandlerSetter::~CCtrlHandlerSetter()
+{
+ signal(SIGINT,memo_sig_int); // CTRL-C
+ signal(SIGTERM,memo_sig_term); // kill {pid}
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/ConsoleClose.h b/src/libs/7zip/unix/CPP/7zip/UI/Console/ConsoleClose.h
new file mode 100644
index 000000000..042aaf2d6
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/ConsoleClose.h
@@ -0,0 +1,26 @@
+// ConsoleCloseUtils.h
+
+#ifndef __CONSOLECLOSEUTILS_H
+#define __CONSOLECLOSEUTILS_H
+
+namespace NConsoleClose {
+
+bool TestBreakSignal();
+
+class CCtrlHandlerSetter
+{
+ void (*memo_sig_int)(int);
+ void (*memo_sig_term)(int);
+public:
+ CCtrlHandlerSetter();
+ virtual ~CCtrlHandlerSetter();
+};
+
+class CCtrlBreakException
+{};
+
+void CheckCtrlBreak();
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
new file mode 100644
index 000000000..af65739c3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
@@ -0,0 +1,228 @@
+// ExtractCallbackConsole.h
+
+#include "StdAfx.h"
+
+#include "ExtractCallbackConsole.h"
+#include "UserInputUtils.h"
+#include "ConsoleClose.h"
+
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/Time.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+#include "Windows/Error.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDirectory;
+
+static const char *kTestString = "Testing ";
+static const char *kExtractString = "Extracting ";
+static const char *kSkipString = "Skipping ";
+
+// static const char *kCantAutoRename = "can not create file with auto name\n";
+// static const char *kCantRenameFile = "can not rename existing file\n";
+// static const char *kCantDeleteOutputFile = "can not delete output file ";
+static const char *kError = "ERROR: ";
+static const char *kMemoryExceptionMessage = "Can't allocate required memory!";
+
+static const char *kProcessing = "Processing archive: ";
+static const char *kEverythingIsOk = "Everything is Ok";
+static const char *kNoFiles = "No files to process";
+
+static const char *kUnsupportedMethod = "Unsupported Method";
+static const char *kCrcFailed = "CRC Failed";
+static const char *kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
+static const char *kDataError = "Data Error";
+static const char *kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
+static const char *kUnknownError = "Unknown Error";
+
+STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::AskOverwrite(
+ const wchar_t *existName, const FILETIME *, const UInt64 *,
+ const wchar_t *newName, const FILETIME *, const UInt64 *,
+ Int32 *answer)
+{
+ (*OutStream) << "file " << existName <<
+ "\nalready exists. Overwrite with " << endl;
+ (*OutStream) << newName;
+
+ NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(OutStream);
+
+ switch(overwriteAnswer)
+ {
+ case NUserAnswerMode::kQuit: return E_ABORT;
+ case NUserAnswerMode::kNo: *answer = NOverwriteAnswer::kNo; break;
+ case NUserAnswerMode::kNoAll: *answer = NOverwriteAnswer::kNoToAll; break;
+ case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break;
+ case NUserAnswerMode::kYes: *answer = NOverwriteAnswer::kYes; break;
+ case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break;
+ default: return E_FAIL;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, bool /* isFolder */, Int32 askExtractMode, const UInt64 *position)
+{
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract: (*OutStream) << kExtractString; break;
+ case NArchive::NExtract::NAskMode::kTest: (*OutStream) << kTestString; break;
+ case NArchive::NExtract::NAskMode::kSkip: (*OutStream) << kSkipString; break;
+ };
+ (*OutStream) << name;
+ if (position != 0)
+ (*OutStream) << " <" << *position << ">";
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::MessageError(const wchar_t *message)
+{
+ (*OutStream) << message << endl;
+ NumFileErrorsInCurrentArchive++;
+ NumFileErrors++;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetOperationResult(Int32 operationResult, bool encrypted)
+{
+ switch(operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+ default:
+ {
+ NumFileErrorsInCurrentArchive++;
+ NumFileErrors++;
+ (*OutStream) << " ";
+ switch(operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+ (*OutStream) << kUnsupportedMethod;
+ break;
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ (*OutStream) << (encrypted ? kCrcFailedEncrypted: kCrcFailed);
+ break;
+ case NArchive::NExtract::NOperationResult::kDataError:
+ (*OutStream) << (encrypted ? kDataErrorEncrypted : kDataError);
+ break;
+ default:
+ (*OutStream) << kUnknownError;
+ }
+ }
+ }
+ (*OutStream) << endl;
+ return S_OK;
+}
+
+#ifndef _NO_CRYPTO
+
+HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
+{
+ PasswordIsDefined = true;
+ Password = password;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+ if (!PasswordIsDefined)
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+#endif
+
+HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name)
+{
+ NumArchives++;
+ NumFileErrorsInCurrentArchive = 0;
+ (*OutStream) << endl << kProcessing << name << endl;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::OpenResult(const wchar_t * /* name */, HRESULT result, bool encrypted)
+{
+ (*OutStream) << endl;
+ if (result != S_OK)
+ {
+ (*OutStream) << "Error: ";
+ if (result == S_FALSE)
+ {
+ (*OutStream) << (encrypted ?
+ "Can not open encrypted archive. Wrong password?" :
+ "Can not open file as archive");
+ }
+ else
+ {
+ if (result == E_OUTOFMEMORY)
+ (*OutStream) << "Can't allocate required memory";
+ else
+ (*OutStream) << NError::MyFormatMessage(result);
+ }
+ (*OutStream) << endl;
+ NumArchiveErrors++;
+ }
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ThereAreNoFiles()
+{
+ (*OutStream) << endl << kNoFiles << endl;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
+{
+ if (result == S_OK)
+ {
+ (*OutStream) << endl;
+ if (NumFileErrorsInCurrentArchive == 0)
+ (*OutStream) << kEverythingIsOk << endl;
+ else
+ {
+ NumArchiveErrors++;
+ (*OutStream) << "Sub items Errors: " << NumFileErrorsInCurrentArchive << endl;
+ }
+ }
+ if (result == S_OK)
+ return result;
+ NumArchiveErrors++;
+ if (result == E_ABORT || result == ERROR_DISK_FULL)
+ return result;
+ (*OutStream) << endl << kError;
+ if (result == E_OUTOFMEMORY)
+ (*OutStream) << kMemoryExceptionMessage;
+ else
+ {
+ UString message;
+ NError::MyFormatMessage(result, message);
+ (*OutStream) << message;
+ }
+ (*OutStream) << endl;
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/ExtractCallbackConsole.h b/src/libs/7zip/unix/CPP/7zip/UI/Console/ExtractCallbackConsole.h
new file mode 100644
index 000000000..e42ca6f40
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/ExtractCallbackConsole.h
@@ -0,0 +1,73 @@
+// ExtractCallbackConsole.h
+
+#ifndef __EXTRACTCALLBACKCONSOLE_H
+#define __EXTRACTCALLBACKCONSOLE_H
+
+#include "Common/MyString.h"
+#include "Common/StdOutStream.h"
+#include "../../Common/FileStreams.h"
+#include "../../IPassword.h"
+#include "../../Archive/IArchive.h"
+#include "../Common/ArchiveExtractCallback.h"
+
+class CExtractCallbackConsole:
+ public IExtractCallbackUI,
+ #ifndef _NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)
+ #ifndef _NO_CRYPTO
+ MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
+ #endif
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ STDMETHOD(SetTotal)(UInt64 total);
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+
+ // IFolderArchiveExtractCallback
+ STDMETHOD(AskOverwrite)(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer);
+ STDMETHOD (PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position);
+
+ STDMETHOD(MessageError)(const wchar_t *message);
+ STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted);
+
+ HRESULT BeforeOpen(const wchar_t *name);
+ HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted);
+ HRESULT ThereAreNoFiles();
+ HRESULT ExtractResult(HRESULT result);
+
+
+ #ifndef _NO_CRYPTO
+ HRESULT SetPassword(const UString &password);
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+ bool PasswordIsDefined;
+ UString Password;
+
+ #endif
+
+ UInt64 NumArchives;
+ UInt64 NumArchiveErrors;
+ UInt64 NumFileErrors;
+ UInt64 NumFileErrorsInCurrentArchive;
+
+ CStdOutStream *OutStream;
+
+ void Init()
+ {
+ NumArchives = 0;
+ NumArchiveErrors = 0;
+ NumFileErrors = 0;
+ NumFileErrorsInCurrentArchive = 0;
+ }
+
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/List.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/List.cpp
new file mode 100644
index 000000000..f747cfda8
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/List.cpp
@@ -0,0 +1,654 @@
+// List.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/StdOutStream.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Error.h"
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../Common/OpenArchive.h"
+#include "../Common/PropIDUtils.h"
+
+#include "ConsoleClose.h"
+#include "List.h"
+#include "OpenCallbackConsole.h"
+
+using namespace NWindows;
+
+struct CPropIdToName
+{
+ PROPID PropID;
+ const wchar_t *Name;
+};
+
+static const CPropIdToName kPropIdToName[] =
+{
+ { kpidPath, L"Path" },
+ { kpidName, L"Name" },
+ { kpidIsDir, L"Folder" },
+ { kpidSize, L"Size" },
+ { kpidPackSize, L"Packed Size" },
+ { kpidAttrib, L"Attributes" },
+ { kpidCTime, L"Created" },
+ { kpidATime, L"Accessed" },
+ { kpidMTime, L"Modified" },
+ { kpidSolid, L"Solid" },
+ { kpidCommented, L"Commented" },
+ { kpidEncrypted, L"Encrypted" },
+ { kpidSplitBefore, L"Split Before" },
+ { kpidSplitAfter, L"Split After" },
+ { kpidDictionarySize, L"Dictionary Size" },
+ { kpidCRC, L"CRC" },
+ { kpidType, L"Type" },
+ { kpidIsAnti, L"Anti" },
+ { kpidMethod, L"Method" },
+ { kpidHostOS, L"Host OS" },
+ { kpidFileSystem, L"File System" },
+ { kpidUser, L"User" },
+ { kpidGroup, L"Group" },
+ { kpidBlock, L"Block" },
+ { kpidComment, L"Comment" },
+ { kpidPosition, L"Position" },
+ { kpidPrefix, L"Prefix" },
+ { kpidNumSubDirs, L"Folders" },
+ { kpidNumSubFiles, L"Files" },
+ { kpidUnpackVer, L"Version" },
+ { kpidVolume, L"Volume" },
+ { kpidIsVolume, L"Multivolume" },
+ { kpidOffset, L"Offset" },
+ { kpidLinks, L"Links" },
+ { kpidNumBlocks, L"Blocks" },
+ { kpidNumVolumes, L"Volumes" },
+
+ { kpidBit64, L"64-bit" },
+ { kpidBigEndian, L"Big-endian" },
+ { kpidCpu, L"CPU" },
+ { kpidPhySize, L"Physical Size" },
+ { kpidHeadersSize, L"Headers Size" },
+ { kpidChecksum, L"Checksum" },
+ { kpidCharacts, L"Characteristics" },
+ { kpidVa, L"Virtual Address" },
+ { kpidId, L"ID" },
+ { kpidShortName, L"Short Name" },
+ { kpidCreatorApp, L"Creator Application"},
+ { kpidSectorSize, L"Sector Size" },
+ { kpidPosixAttrib, L"Mode" },
+ { kpidLink, L"Link" },
+ { kpidError, L"Error" },
+
+ { kpidTotalSize, L"Total Size" },
+ { kpidFreeSpace, L"Free Space" },
+ { kpidClusterSize, L"Cluster Size" },
+ { kpidVolumeName, L"Label" }
+};
+
+static const char kEmptyAttribChar = '.';
+
+static const char *kListing = "Listing archive: ";
+static const wchar_t *kFilesMessage = L"files";
+static const wchar_t *kDirsMessage = L"folders";
+
+static void GetAttribString(DWORD wa, bool isDir, char *s)
+{
+ s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : kEmptyAttribChar;
+ s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar;
+ s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar;
+ s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar;
+ s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar;
+ s[5] = '\0';
+}
+
+enum EAdjustment
+{
+ kLeft,
+ kCenter,
+ kRight
+};
+
+struct CFieldInfo
+{
+ PROPID PropID;
+ UString Name;
+ EAdjustment TitleAdjustment;
+ EAdjustment TextAdjustment;
+ int PrefixSpacesWidth;
+ int Width;
+};
+
+struct CFieldInfoInit
+{
+ PROPID PropID;
+ const wchar_t *Name;
+ EAdjustment TitleAdjustment;
+ EAdjustment TextAdjustment;
+ int PrefixSpacesWidth;
+ int Width;
+};
+
+static CFieldInfoInit kStandardFieldTable[] =
+{
+ { kpidMTime, L" Date Time", kLeft, kLeft, 0, 19 },
+ { kpidAttrib, L"Attr", kRight, kCenter, 1, 5 },
+ { kpidSize, L"Size", kRight, kRight, 1, 12 },
+ { kpidPackSize, L"Compressed", kRight, kRight, 1, 12 },
+ { kpidPath, L"Name", kLeft, kLeft, 2, 24 }
+};
+
+static void PrintSpaces(int numSpaces)
+{
+ for (int i = 0; i < numSpaces; i++)
+ g_StdOut << ' ';
+}
+
+static void PrintString(EAdjustment adjustment, int width, const UString &textString)
+{
+ const int numSpaces = width - textString.Length();
+ int numLeftSpaces = 0;
+ switch (adjustment)
+ {
+ case kLeft:
+ numLeftSpaces = 0;
+ break;
+ case kCenter:
+ numLeftSpaces = numSpaces / 2;
+ break;
+ case kRight:
+ numLeftSpaces = numSpaces;
+ break;
+ }
+ PrintSpaces(numLeftSpaces);
+ g_StdOut << textString;
+ PrintSpaces(numSpaces - numLeftSpaces);
+}
+
+class CFieldPrinter
+{
+ CObjectVector<CFieldInfo> _fields;
+public:
+ void Clear() { _fields.Clear(); }
+ void Init(const CFieldInfoInit *standardFieldTable, int numItems);
+ HRESULT Init(IInArchive *archive);
+ void PrintTitle();
+ void PrintTitleLines();
+ HRESULT PrintItemInfo(const CArc &arc, UInt32 index, bool techMode);
+ HRESULT PrintSummaryInfo(UInt64 numFiles, UInt64 numDirs,
+ const UInt64 *size, const UInt64 *compressedSize);
+};
+
+void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, int numItems)
+{
+ Clear();
+ for (int i = 0; i < numItems; i++)
+ {
+ CFieldInfo fieldInfo;
+ const CFieldInfoInit &fieldInfoInit = standardFieldTable[i];
+ fieldInfo.PropID = fieldInfoInit.PropID;
+ fieldInfo.Name = fieldInfoInit.Name;
+ fieldInfo.TitleAdjustment = fieldInfoInit.TitleAdjustment;
+ fieldInfo.TextAdjustment = fieldInfoInit.TextAdjustment;
+ fieldInfo.PrefixSpacesWidth = fieldInfoInit.PrefixSpacesWidth;
+ fieldInfo.Width = fieldInfoInit.Width;
+ _fields.Add(fieldInfo);
+ }
+}
+
+static UString GetPropName(PROPID propID, BSTR name)
+{
+ for (int i = 0; i < sizeof(kPropIdToName) / sizeof(kPropIdToName[0]); i++)
+ {
+ const CPropIdToName &propIdToName = kPropIdToName[i];
+ if (propIdToName.PropID == propID)
+ return propIdToName.Name;
+ }
+ if (name)
+ return name;
+ wchar_t s[16];
+ ConvertUInt32ToString(propID, s);
+ return s;
+}
+
+HRESULT CFieldPrinter::Init(IInArchive *archive)
+{
+ Clear();
+ UInt32 numProps;
+ RINOK(archive->GetNumberOfProperties(&numProps));
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt));
+ CFieldInfo fieldInfo;
+ fieldInfo.PropID = propID;
+ fieldInfo.Name = GetPropName(propID, name);
+ _fields.Add(fieldInfo);
+ }
+ return S_OK;
+}
+
+void CFieldPrinter::PrintTitle()
+{
+ for (int i = 0; i < _fields.Size(); i++)
+ {
+ const CFieldInfo &fieldInfo = _fields[i];
+ PrintSpaces(fieldInfo.PrefixSpacesWidth);
+ PrintString(fieldInfo.TitleAdjustment,
+ ((fieldInfo.PropID == kpidPath) ? 0: fieldInfo.Width), fieldInfo.Name);
+ }
+}
+
+void CFieldPrinter::PrintTitleLines()
+{
+ for (int i = 0; i < _fields.Size(); i++)
+ {
+ const CFieldInfo &fieldInfo = _fields[i];
+ PrintSpaces(fieldInfo.PrefixSpacesWidth);
+ for (int i = 0; i < fieldInfo.Width; i++)
+ g_StdOut << '-';
+ }
+}
+
+
+static BOOL IsFileTimeZero(CONST FILETIME *lpFileTime)
+{
+ return (lpFileTime->dwLowDateTime == 0) && (lpFileTime->dwHighDateTime == 0);
+}
+
+static const char *kEmptyTimeString = " ";
+static void PrintTime(const NCOM::CPropVariant &prop)
+{
+ if (prop.vt != VT_FILETIME)
+ throw "incorrect item";
+ if (IsFileTimeZero(&prop.filetime))
+ g_StdOut << kEmptyTimeString;
+ else
+ {
+ FILETIME localFileTime;
+ if (!FileTimeToLocalFileTime(&prop.filetime, &localFileTime))
+ throw "FileTimeToLocalFileTime error";
+ char s[32];
+ if (ConvertFileTimeToString(localFileTime, s, true, true))
+ g_StdOut << s;
+ else
+ g_StdOut << kEmptyTimeString;
+ }
+}
+
+HRESULT CFieldPrinter::PrintItemInfo(const CArc &arc, UInt32 index, bool techMode)
+{
+ /*
+ if (techMode)
+ {
+ g_StdOut << "Index = ";
+ g_StdOut << (UInt64)index;
+ g_StdOut << endl;
+ }
+ */
+ for (int i = 0; i < _fields.Size(); i++)
+ {
+ const CFieldInfo &fieldInfo = _fields[i];
+ if (!techMode)
+ PrintSpaces(fieldInfo.PrefixSpacesWidth);
+
+ NCOM::CPropVariant prop;
+ if (fieldInfo.PropID == kpidPath)
+ {
+ UString s;
+ RINOK(arc.GetItemPath(index, s));
+ prop = s;
+ }
+ else
+ {
+ RINOK(arc.Archive->GetProperty(index, fieldInfo.PropID, &prop));
+ }
+ if (techMode)
+ {
+ g_StdOut << fieldInfo.Name << " = ";
+ }
+ int width = (fieldInfo.PropID == kpidPath) ? 0: fieldInfo.Width;
+ if (fieldInfo.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4))
+ {
+ UInt32 attrib = (prop.vt == VT_EMPTY) ? 0 : prop.ulVal;
+ bool isFolder;
+ RINOK(IsArchiveItemFolder(arc.Archive, index, isFolder));
+ char s[8];
+ GetAttribString(attrib, isFolder, s);
+ g_StdOut << s;
+ }
+ else if (prop.vt == VT_EMPTY)
+ {
+ if (!techMode)
+ PrintSpaces(width);
+ }
+ else if (fieldInfo.PropID == kpidMTime)
+ {
+ PrintTime(prop);
+ }
+ else if (prop.vt == VT_BSTR)
+ {
+ if (techMode)
+ g_StdOut << prop.bstrVal;
+ else
+ PrintString(fieldInfo.TextAdjustment, width, prop.bstrVal);
+ }
+ else
+ {
+ UString s = ConvertPropertyToString(prop, fieldInfo.PropID);
+ s.Replace(wchar_t(0xA), L' ');
+ s.Replace(wchar_t(0xD), L' ');
+
+ if (techMode)
+ g_StdOut << s;
+ else
+ PrintString(fieldInfo.TextAdjustment, width, s);
+ }
+ if (techMode)
+ g_StdOut << endl;
+ }
+ return S_OK;
+}
+
+static void PrintNumberString(EAdjustment adjustment, int width, const UInt64 *value)
+{
+ wchar_t textString[32] = { 0 };
+ if (value != NULL)
+ ConvertUInt64ToString(*value, textString);
+ PrintString(adjustment, width, textString);
+}
+
+
+HRESULT CFieldPrinter::PrintSummaryInfo(UInt64 numFiles, UInt64 numDirs,
+ const UInt64 *size, const UInt64 *compressedSize)
+{
+ for (int i = 0; i < _fields.Size(); i++)
+ {
+ const CFieldInfo &fieldInfo = _fields[i];
+ PrintSpaces(fieldInfo.PrefixSpacesWidth);
+ NCOM::CPropVariant prop;
+ if (fieldInfo.PropID == kpidSize)
+ PrintNumberString(fieldInfo.TextAdjustment, fieldInfo.Width, size);
+ else if (fieldInfo.PropID == kpidPackSize)
+ PrintNumberString(fieldInfo.TextAdjustment, fieldInfo.Width, compressedSize);
+ else if (fieldInfo.PropID == kpidPath)
+ {
+ wchar_t textString[32];
+ ConvertUInt64ToString(numFiles, textString);
+ UString temp = textString;
+ temp += L" ";
+ temp += kFilesMessage;
+ temp += L", ";
+ ConvertUInt64ToString(numDirs, textString);
+ temp += textString;
+ temp += L" ";
+ temp += kDirsMessage;
+ PrintString(fieldInfo.TextAdjustment, 0, temp);
+ }
+ else
+ PrintString(fieldInfo.TextAdjustment, fieldInfo.Width, L"");
+ }
+ return S_OK;
+}
+
+bool GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &value)
+{
+ NCOM::CPropVariant prop;
+ if (archive->GetProperty(index, propID, &prop) != S_OK)
+ throw "GetPropertyValue error";
+ if (prop.vt == VT_EMPTY)
+ return false;
+ value = ConvertPropVariantToUInt64(prop);
+ return true;
+}
+
+static void PrintPropPair(const wchar_t *name, const wchar_t *value)
+{
+ g_StdOut << name << " = " << value << endl;
+}
+
+HRESULT ListArchives(CCodecs *codecs, const CIntVector &formatIndices,
+ bool stdInMode,
+ UStringVector &arcPaths, UStringVector &arcPathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ bool enableHeaders, bool techMode,
+ #ifndef _NO_CRYPTO
+ bool &passwordEnabled, UString &password,
+ #endif
+ UInt64 &numErrors)
+{
+ numErrors = 0;
+ CFieldPrinter fieldPrinter;
+ if (!techMode)
+ fieldPrinter.Init(kStandardFieldTable, sizeof(kStandardFieldTable) / sizeof(kStandardFieldTable[0]));
+
+ UInt64 numFiles2 = 0, numDirs2 = 0, totalPackSize2 = 0, totalUnPackSize2 = 0;
+ UInt64 *totalPackSizePointer2 = 0, *totalUnPackSizePointer2 = 0;
+ int numArcs = /* stdInMode ? 1 : */ arcPaths.Size();
+ for (int i = 0; i < numArcs; i++)
+ {
+ const UString &archiveName = arcPaths[i];
+ UInt64 arcPackSize = 0;
+ if (!stdInMode)
+ {
+ NFile::NFind::CFileInfoW fi;
+ if (!fi.Find(archiveName) || fi.IsDir())
+ {
+ g_StdOut << endl << "Error: " << archiveName << " is not file" << endl;
+ numErrors++;
+ continue;
+ }
+ arcPackSize = fi.Size;
+ }
+
+ CArchiveLink archiveLink;
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = &g_StdOut;
+
+ #ifndef _NO_CRYPTO
+
+ openCallback.PasswordIsDefined = passwordEnabled;
+ openCallback.Password = password;
+
+ #endif
+
+ HRESULT result = archiveLink.Open2(codecs, formatIndices, stdInMode, NULL, archiveName, &openCallback);
+ if (result != S_OK)
+ {
+ if (result == E_ABORT)
+ return result;
+ g_StdOut << endl << "Error: " << archiveName << ": ";
+ if (result == S_FALSE)
+ {
+ #ifndef _NO_CRYPTO
+ if (openCallback.Open_WasPasswordAsked())
+ g_StdOut << "Can not open encrypted archive. Wrong password?";
+ else
+ #endif
+ g_StdOut << "Can not open file as archive";
+ }
+ else if (result == E_OUTOFMEMORY)
+ g_StdOut << "Can't allocate required memory";
+ else
+ g_StdOut << NError::MyFormatMessage(result);
+ g_StdOut << endl;
+ numErrors++;
+ continue;
+ }
+
+ if (!stdInMode)
+ for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+ {
+ int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+ if (index >= 0 && index > i)
+ {
+ arcPaths.Delete(index);
+ arcPathsFull.Delete(index);
+ numArcs = arcPaths.Size();
+ }
+ }
+
+ if (enableHeaders)
+ {
+ g_StdOut << endl << kListing << archiveName << endl << endl;
+
+ for (int i = 0; i < archiveLink.Arcs.Size(); i++)
+ {
+ const CArc &arc = archiveLink.Arcs[i];
+
+ g_StdOut << "--\n";
+ PrintPropPair(L"Path", arc.Path);
+ PrintPropPair(L"Type", codecs->Formats[arc.FormatIndex].Name);
+ if (!arc.ErrorMessage.IsEmpty())
+ PrintPropPair(L"Error", arc.ErrorMessage);
+ UInt32 numProps;
+ IInArchive *archive = arc.Archive;
+ if (archive->GetNumberOfArchiveProperties(&numProps) == S_OK)
+ {
+ for (UInt32 j = 0; j < numProps; j++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt));
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(propID, &prop));
+ UString s = ConvertPropertyToString(prop, propID);
+ if (!s.IsEmpty())
+ PrintPropPair(GetPropName(propID, name), s);
+ }
+ }
+ if (i != archiveLink.Arcs.Size() - 1)
+ {
+ UInt32 numProps;
+ g_StdOut << "----\n";
+ if (archive->GetNumberOfProperties(&numProps) == S_OK)
+ {
+ UInt32 mainIndex = archiveLink.Arcs[i + 1].SubfileIndex;
+ for (UInt32 j = 0; j < numProps; j++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt));
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(mainIndex, propID, &prop));
+ UString s = ConvertPropertyToString(prop, propID);
+ if (!s.IsEmpty())
+ PrintPropPair(GetPropName(propID, name), s);
+ }
+ }
+ }
+
+ }
+ g_StdOut << endl;
+ if (techMode)
+ g_StdOut << "----------\n";
+ }
+
+ if (enableHeaders && !techMode)
+ {
+ fieldPrinter.PrintTitle();
+ g_StdOut << endl;
+ fieldPrinter.PrintTitleLines();
+ g_StdOut << endl;
+ }
+
+ const CArc &arc = archiveLink.Arcs.Back();
+ IInArchive *archive = arc.Archive;
+ if (techMode)
+ {
+ RINOK(fieldPrinter.Init(archive));
+ }
+ UInt64 numFiles = 0, numDirs = 0, totalPackSize = 0, totalUnPackSize = 0;
+ UInt64 *totalPackSizePointer = 0, *totalUnPackSizePointer = 0;
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+
+ UString filePath;
+ HRESULT res = arc.GetItemPath(i, filePath);
+ if (stdInMode && res == E_INVALIDARG)
+ break;
+ RINOK(res);
+
+ bool isFolder;
+ RINOK(IsArchiveItemFolder(archive, i, isFolder));
+ if (!wildcardCensor.CheckPath(filePath, !isFolder))
+ continue;
+
+ fieldPrinter.PrintItemInfo(arc, i, techMode);
+
+ UInt64 packSize, unpackSize;
+ if (!GetUInt64Value(archive, i, kpidSize, unpackSize))
+ unpackSize = 0;
+ else
+ totalUnPackSizePointer = &totalUnPackSize;
+ if (!GetUInt64Value(archive, i, kpidPackSize, packSize))
+ packSize = 0;
+ else
+ totalPackSizePointer = &totalPackSize;
+
+ g_StdOut << endl;
+
+ if (isFolder)
+ numDirs++;
+ else
+ numFiles++;
+ totalPackSize += packSize;
+ totalUnPackSize += unpackSize;
+ }
+
+ if (!stdInMode && totalPackSizePointer == 0)
+ {
+ if (archiveLink.VolumePaths.Size() != 0)
+ arcPackSize += archiveLink.VolumesSize;
+ totalPackSize = (numFiles == 0) ? 0 : arcPackSize;
+ totalPackSizePointer = &totalPackSize;
+ }
+ if (totalUnPackSizePointer == 0 && numFiles == 0)
+ {
+ totalUnPackSize = 0;
+ totalUnPackSizePointer = &totalUnPackSize;
+ }
+ if (enableHeaders && !techMode)
+ {
+ fieldPrinter.PrintTitleLines();
+ g_StdOut << endl;
+ fieldPrinter.PrintSummaryInfo(numFiles, numDirs, totalUnPackSizePointer, totalPackSizePointer);
+ g_StdOut << endl;
+ }
+ if (totalPackSizePointer != 0)
+ {
+ totalPackSizePointer2 = &totalPackSize2;
+ totalPackSize2 += totalPackSize;
+ }
+ if (totalUnPackSizePointer != 0)
+ {
+ totalUnPackSizePointer2 = &totalUnPackSize2;
+ totalUnPackSize2 += totalUnPackSize;
+ }
+ numFiles2 += numFiles;
+ numDirs2 += numDirs;
+ }
+ if (enableHeaders && !techMode && numArcs > 1)
+ {
+ g_StdOut << endl;
+ fieldPrinter.PrintTitleLines();
+ g_StdOut << endl;
+ fieldPrinter.PrintSummaryInfo(numFiles2, numDirs2, totalUnPackSizePointer2, totalPackSizePointer2);
+ g_StdOut << endl;
+ g_StdOut << "Archives: " << numArcs << endl;
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/List.h b/src/libs/7zip/unix/CPP/7zip/UI/Console/List.h
new file mode 100644
index 000000000..97d9fb15a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/List.h
@@ -0,0 +1,20 @@
+// List.h
+
+#ifndef __LIST_H
+#define __LIST_H
+
+#include "Common/Wildcard.h"
+#include "../Common/LoadCodecs.h"
+
+HRESULT ListArchives(CCodecs *codecs, const CIntVector &formatIndices,
+ bool stdInMode,
+ UStringVector &archivePaths, UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ bool enableHeaders, bool techMode,
+ #ifndef _NO_CRYPTO
+ bool &passwordEnabled, UString &password,
+ #endif
+ UInt64 &errors);
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/Main.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/Main.cpp
new file mode 100644
index 000000000..cebfe2e42
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/Main.cpp
@@ -0,0 +1,628 @@
+// Main.cpp
+
+#include "StdAfx.h"
+
+#if defined( _7ZIP_LARGE_PAGES)
+#include "../../../../C/Alloc.h"
+#endif
+
+#include "Common/MyInitGuid.h"
+
+#include "Common/CommandLineParser.h"
+#include "Common/IntToString.h"
+#include "Common/MyException.h"
+#include "Common/StdOutStream.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/Error.h"
+#ifdef _WIN32
+#include "Windows/MemoryLock.h"
+#endif
+
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/ExitCode.h"
+#include "../Common/Extract.h"
+#ifdef EXTERNAL_CODECS
+#include "../Common/LoadCodecs.h"
+#endif
+
+#include "BenchCon.h"
+#include "ExtractCallbackConsole.h"
+#include "List.h"
+#include "OpenCallbackConsole.h"
+#include "UpdateCallbackConsole.h"
+
+#include "../../MyVersion.h"
+
+#include "myPrivate.h"
+#include "Windows/System.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NCommandLineParser;
+
+// HINSTANCE g_hInstance = 0;
+extern CStdOutStream *g_StdStream;
+
+static const char *kCopyrightString = "\n7-Zip"
+#ifndef EXTERNAL_CODECS
+" (A)"
+#endif
+
+#ifdef _WIN64
+" [64]"
+#endif
+
+" " MY_VERSION_COPYRIGHT_DATE "\n"
+"p7zip Version " P7ZIP_VERSION ;
+
+static const char *kHelpString =
+ "\nUsage: 7z"
+#ifdef _NO_CRYPTO
+ "r"
+#else
+#ifndef EXTERNAL_CODECS
+ "a"
+#endif
+#endif
+ " <command> [<switches>...] <archive_name> [<file_names>...]\n"
+ " [<@listfiles...>]\n"
+ "\n"
+ "<Commands>\n"
+ " a: Add files to archive\n"
+ " b: Benchmark\n"
+ " d: Delete files from archive\n"
+ " e: Extract files from archive (without using directory names)\n"
+ " l: List contents of archive\n"
+// " l[a|t][f]: List contents of archive\n"
+// " a - with Additional fields\n"
+// " t - with all fields\n"
+// " f - with Full pathnames\n"
+ " t: Test integrity of archive\n"
+ " u: Update files to archive\n"
+ " x: eXtract files with full paths\n"
+ "<Switches>\n"
+ " -ai[r[-|0]]{@listfile|!wildcard}: Include archives\n"
+ " -ax[r[-|0]]{@listfile|!wildcard}: eXclude archives\n"
+ " -bd: Disable percentage indicator\n"
+ " -i[r[-|0]]{@listfile|!wildcard}: Include filenames\n"
+ " -m{Parameters}: set compression Method\n"
+ " -o{Directory}: set Output directory\n"
+ #ifndef _NO_CRYPTO
+ " -p{Password}: set Password\n"
+ #endif
+ " -r[-|0]: Recurse subdirectories\n"
+ " -scs{UTF-8 | WIN | DOS}: set charset for list files\n"
+ " -sfx[{name}]: Create SFX archive\n"
+ " -si[{name}]: read data from stdin\n"
+ " -slt: show technical information for l (List) command\n"
+ " -so: write data to stdout\n"
+ " -ssc[-]: set sensitive case mode\n"
+ " -t{Type}: Set type of archive\n"
+ " -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName]: Update options\n"
+ " -v{Size}[b|k|m|g]: Create volumes\n"
+ " -w[{path}]: assign Work directory. Empty path means a temporary directory\n"
+ " -x[r[-|0]]]{@listfile|!wildcard}: eXclude filenames\n"
+ " -y: assume Yes on all queries\n";
+
+// ---------------------------
+// exception messages
+
+static const char *kEverythingIsOk = "Everything is Ok";
+static const char *kUserErrorMessage = "Incorrect command line";
+static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
+static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
+
+static const wchar_t *kDefaultSfxModule = L"7zCon.sfx";
+
+static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
+{
+ s << message << endl;
+ throw code;
+}
+
+static void PrintHelpAndExit(CStdOutStream &s)
+{
+ s << kHelpString;
+ ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError);
+}
+
+#ifndef _WIN32
+static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
+{
+ parts.Clear();
+ for (int i = 0; i < numArgs; i++)
+ {
+ UString s = MultiByteToUnicodeString(args[i]);
+ parts.Add(s);
+ }
+}
+#endif
+
+static void ShowCopyrightAndHelp(CStdOutStream &s, bool needHelp)
+{
+ s << kCopyrightString << " (locale=" << my_getlocale() <<",Utf16=";
+ if (global_use_utf16_conversion) s << "on";
+ else s << "off";
+ s << ",HugeFiles=";
+ if (sizeof(off_t) >= 8) s << "on,";
+ else s << "off,";
+ int nbcpu = NWindows::NSystem::GetNumberOfProcessors();
+ if (nbcpu > 1) s << nbcpu << " CPUs)\n";
+ else s << nbcpu << " CPU)\n";
+
+ if (needHelp)
+ s << kHelpString;
+}
+
+#ifdef EXTERNAL_CODECS
+static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
+{
+ int len = s.Length();
+ stdStream << s;
+ for (int i = len; i < size; i++)
+ stdStream << ' ';
+}
+#endif
+
+static void PrintString(CStdOutStream &stdStream, const UString &s, int size)
+{
+ int len = s.Length();
+ stdStream << s;
+ for (int i = len; i < size; i++)
+ stdStream << ' ';
+}
+
+static inline char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+int Main2(
+ #ifndef _WIN32
+ int numArgs, const char *args[]
+ #endif
+)
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ SetFileApisToOEM();
+ #endif
+
+ UStringVector commandStrings;
+ #ifdef _WIN32
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
+ #else
+ // GetArguments(numArgs, args, commandStrings);
+ extern void mySplitCommandLine(int numArgs,const char *args[],UStringVector &parts);
+ mySplitCommandLine(numArgs,args,commandStrings);
+ #endif
+
+ if (commandStrings.Size() == 1)
+ {
+ ShowCopyrightAndHelp(g_StdOut, true);
+ return 0;
+ }
+ commandStrings.Delete(0);
+
+ CArchiveCommandLineOptions options;
+
+ CArchiveCommandLineParser parser;
+
+ parser.Parse1(commandStrings, options);
+
+ if (options.HelpMode)
+ {
+ ShowCopyrightAndHelp(g_StdOut, true);
+ return 0;
+ }
+
+ #if defined(_7ZIP_LARGE_PAGES)
+ if (options.LargePages)
+ {
+ SetLargePageSize();
+#ifdef _WIN32
+ NSecurity::EnableLockMemoryPrivilege();
+#endif
+ }
+ #endif
+
+ CStdOutStream &stdStream = options.StdOutMode ? g_StdErr : g_StdOut;
+ g_StdStream = &stdStream;
+
+ if (options.EnableHeaders)
+ ShowCopyrightAndHelp(stdStream, false);
+
+ parser.Parse2(options);
+
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr<
+ #ifdef EXTERNAL_CODECS
+ ICompressCodecsInfo
+ #else
+ IUnknown
+ #endif
+ > compressCodecsInfo = codecs;
+ HRESULT result = codecs->Load();
+ if (result != S_OK)
+ throw CSystemException(result);
+
+ bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+
+ if (codecs->Formats.Size() == 0 &&
+ (isExtractGroupCommand ||
+ options.Command.CommandType == NCommandType::kList ||
+ options.Command.IsFromUpdateGroup()))
+ throw kNoFormats;
+
+ CIntVector formatIndices;
+ if (!codecs->FindFormatForArchiveType(options.ArcType, formatIndices))
+ throw kUnsupportedArcTypeMessage;
+
+ if (options.Command.CommandType == NCommandType::kInfo)
+ {
+ stdStream << endl << "Formats:" << endl;
+ int i;
+ for (i = 0; i < codecs->Formats.Size(); i++)
+ {
+ const CArcInfoEx &arc = codecs->Formats[i];
+ #ifdef EXTERNAL_CODECS
+ if (arc.LibIndex >= 0)
+ {
+ char s[16];
+ ConvertUInt32ToString(arc.LibIndex, s);
+ PrintString(stdStream, s, 2);
+ }
+ else
+ #endif
+ stdStream << " ";
+ stdStream << ' ';
+ stdStream << (char)(arc.UpdateEnabled ? 'C' : ' ');
+ stdStream << (char)(arc.KeepName ? 'K' : ' ');
+ stdStream << " ";
+ PrintString(stdStream, arc.Name, 6);
+ stdStream << " ";
+ UString s;
+ for (int t = 0; t < arc.Exts.Size(); t++)
+ {
+ const CArcExtInfo &ext = arc.Exts[t];
+ s += ext.Ext;
+ if (!ext.AddExt.IsEmpty())
+ {
+ s += L" (";
+ s += ext.AddExt;
+ s += L')';
+ }
+ s += L' ';
+ }
+ PrintString(stdStream, s, 14);
+ stdStream << " ";
+ const CByteBuffer &sig = arc.StartSignature;
+ for (size_t j = 0; j < sig.GetCapacity(); j++)
+ {
+ Byte b = sig[j];
+ if (b > 0x20 && b < 0x80)
+ {
+ stdStream << (char)b;
+ }
+ else
+ {
+ stdStream << GetHex((Byte)((b >> 4) & 0xF));
+ stdStream << GetHex((Byte)(b & 0xF));
+ }
+ stdStream << ' ';
+ }
+ stdStream << endl;
+ }
+ stdStream << endl << "Codecs:" << endl;
+
+ #ifdef EXTERNAL_CODECS
+ UInt32 numMethods;
+ if (codecs->GetNumberOfMethods(&numMethods) == S_OK)
+ for (UInt32 j = 0; j < numMethods; j++)
+ {
+ int libIndex = codecs->GetCodecLibIndex(j);
+ if (libIndex >= 0)
+ {
+ char s[16];
+ ConvertUInt32ToString(libIndex, s);
+ PrintString(stdStream, s, 2);
+ }
+ else
+ stdStream << " ";
+ stdStream << ' ';
+ stdStream << (char)(codecs->GetCodecEncoderIsAssigned(j) ? 'C' : ' ');
+ UInt64 id;
+ stdStream << " ";
+ HRESULT res = codecs->GetCodecId(j, id);
+ if (res != S_OK)
+ id = (UInt64)(Int64)-1;
+ char s[32];
+ ConvertUInt64ToString(id, s, 16);
+ PrintString(stdStream, s, 8);
+ stdStream << " ";
+ PrintString(stdStream, codecs->GetCodecName(j), 11);
+ stdStream << endl;
+ /*
+ if (res != S_OK)
+ throw "incorrect Codec ID";
+ */
+ }
+ #endif
+ return S_OK;
+ }
+ else if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ if (options.Method.CompareNoCase(L"CRC") == 0)
+ {
+ HRESULT res = CrcBenchCon((FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
+ if (res != S_OK)
+ {
+ if (res == S_FALSE)
+ {
+ stdStream << "\nCRC Error\n";
+ return NExitCode::kFatalError;
+ }
+ throw CSystemException(res);
+ }
+ }
+ else
+ {
+ HRESULT res;
+ #ifdef EXTERNAL_CODECS
+ CObjectVector<CCodecInfoEx> externalCodecs;
+ res = LoadExternalCodecs(compressCodecsInfo, externalCodecs);
+ if (res != S_OK)
+ throw CSystemException(res);
+ #endif
+ res = LzmaBenchCon(
+ #ifdef EXTERNAL_CODECS
+ compressCodecsInfo, &externalCodecs,
+ #endif
+ (FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
+ if (res != S_OK)
+ {
+ if (res == S_FALSE)
+ {
+ stdStream << "\nDecoding Error\n";
+ return NExitCode::kFatalError;
+ }
+ throw CSystemException(res);
+ }
+ }
+ }
+ else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
+ {
+ if (isExtractGroupCommand)
+ {
+ CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+ ecs->OutStream = &stdStream;
+
+ #ifndef _NO_CRYPTO
+ ecs->PasswordIsDefined = options.PasswordEnabled;
+ ecs->Password = options.Password;
+ #endif
+
+ ecs->Init();
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = &stdStream;
+
+ #ifndef _NO_CRYPTO
+ openCallback.PasswordIsDefined = options.PasswordEnabled;
+ openCallback.Password = options.Password;
+ #endif
+
+ CExtractOptions eo;
+ eo.StdInMode = options.StdInMode;
+ eo.StdOutMode = options.StdOutMode;
+ eo.PathMode = options.Command.GetPathMode();
+ eo.TestMode = options.Command.IsTestMode();
+ eo.OverwriteMode = options.OverwriteMode;
+ eo.OutputDir = options.OutputDir;
+ eo.YesToAll = options.YesToAll;
+ eo.CalcCrc = options.CalcCrc;
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ eo.Properties = options.ExtractProperties;
+ #endif
+ UString errorMessage;
+ CDecompressStat stat;
+ HRESULT result = DecompressArchives(
+ codecs,
+ formatIndices,
+ options.ArchivePathsSorted,
+ options.ArchivePathsFullSorted,
+ options.WildcardCensor.Pairs.Front().Head,
+ eo, &openCallback, ecs, errorMessage, stat);
+ if (!errorMessage.IsEmpty())
+ {
+ stdStream << endl << "Error: " << errorMessage;
+ if (result == S_OK)
+ result = E_FAIL;
+ }
+
+ stdStream << endl;
+ if (ecs->NumArchives > 1)
+ stdStream << "Archives: " << ecs->NumArchives << endl;
+ if (ecs->NumArchiveErrors != 0 || ecs->NumFileErrors != 0)
+ {
+ if (ecs->NumArchives > 1)
+ {
+ stdStream << endl;
+ if (ecs->NumArchiveErrors != 0)
+ stdStream << "Archive Errors: " << ecs->NumArchiveErrors << endl;
+ if (ecs->NumFileErrors != 0)
+ stdStream << "Sub items Errors: " << ecs->NumFileErrors << endl;
+ }
+ if (result != S_OK)
+ throw CSystemException(result);
+ return NExitCode::kFatalError;
+ }
+ if (result != S_OK)
+ throw CSystemException(result);
+ if (stat.NumFolders != 0)
+ stdStream << "Folders: " << stat.NumFolders << endl;
+ if (stat.NumFiles != 1 || stat.NumFolders != 0)
+ stdStream << "Files: " << stat.NumFiles << endl;
+ stdStream
+ << "Size: " << stat.UnpackSize << endl
+ << "Compressed: " << stat.PackSize << endl;
+ if (options.CalcCrc)
+ {
+ char s[16];
+ ConvertUInt32ToHexWithZeros(stat.CrcSum, s);
+ stdStream << "CRC: " << s << endl;
+ }
+ }
+ else
+ {
+ UInt64 numErrors = 0;
+ HRESULT result = ListArchives(
+ codecs,
+ formatIndices,
+ options.StdInMode,
+ options.ArchivePathsSorted,
+ options.ArchivePathsFullSorted,
+ options.WildcardCensor.Pairs.Front().Head,
+ options.EnableHeaders,
+ options.TechMode,
+ #ifndef _NO_CRYPTO
+ options.PasswordEnabled,
+ options.Password,
+ #endif
+ numErrors);
+ if (numErrors > 0)
+ {
+ g_StdOut << endl << "Errors: " << numErrors;
+ return NExitCode::kFatalError;
+ }
+ if (result != S_OK)
+ throw CSystemException(result);
+ }
+ }
+ else if (options.Command.IsFromUpdateGroup())
+ {
+ CUpdateOptions &uo = options.UpdateOptions;
+ if (uo.SfxMode && uo.SfxModule.IsEmpty())
+ uo.SfxModule = kDefaultSfxModule;
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = &stdStream;
+
+ #ifndef _NO_CRYPTO
+ bool passwordIsDefined =
+ options.PasswordEnabled && !options.Password.IsEmpty();
+ openCallback.PasswordIsDefined = passwordIsDefined;
+ openCallback.Password = options.Password;
+ #endif
+
+ CUpdateCallbackConsole callback;
+ callback.EnablePercents = options.EnablePercents;
+
+ #ifndef _NO_CRYPTO
+ callback.PasswordIsDefined = passwordIsDefined;
+ callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty();
+ callback.Password = options.Password;
+ #endif
+ callback.StdOutMode = uo.StdOutMode;
+ callback.Init(&stdStream);
+
+ CUpdateErrorInfo errorInfo;
+
+ if (!uo.Init(codecs, formatIndices, options.ArchiveName))
+ throw kUnsupportedArcTypeMessage;
+ HRESULT result = UpdateArchive(codecs,
+ options.WildcardCensor, uo,
+ errorInfo, &openCallback, &callback);
+
+#ifdef ENV_UNIX
+ if (uo.SfxMode)
+ {
+ void myAddExeFlag(const UString &name);
+ for(int i = 0; i < uo.Commands.Size(); i++)
+ {
+ CUpdateArchiveCommand &command = uo.Commands[i];
+ if (!uo.StdOutMode)
+ {
+ myAddExeFlag(command.ArchivePath.GetFinalPath());
+ }
+ }
+ }
+#endif
+
+ int exitCode = NExitCode::kSuccess;
+ if (callback.CantFindFiles.Size() > 0)
+ {
+ stdStream << endl;
+ stdStream << "WARNINGS for files:" << endl << endl;
+ int numErrors = callback.CantFindFiles.Size();
+ for (int i = 0; i < numErrors; i++)
+ {
+ stdStream << callback.CantFindFiles[i] << " : ";
+ stdStream << NError::MyFormatMessageW(callback.CantFindCodes[i]) << endl;
+ }
+ stdStream << "----------------" << endl;
+ stdStream << "WARNING: Cannot find " << numErrors << " file";
+ if (numErrors > 1)
+ stdStream << "s";
+ stdStream << endl;
+ exitCode = NExitCode::kWarning;
+ }
+
+ if (result != S_OK)
+ {
+ UString message;
+ if (!errorInfo.Message.IsEmpty())
+ {
+ message += errorInfo.Message;
+ message += L"\n";
+ }
+ if (!errorInfo.FileName.IsEmpty())
+ {
+ message += errorInfo.FileName;
+ message += L"\n";
+ }
+ if (!errorInfo.FileName2.IsEmpty())
+ {
+ message += errorInfo.FileName2;
+ message += L"\n";
+ }
+ if (errorInfo.SystemError != 0)
+ {
+ message += NError::MyFormatMessageW(errorInfo.SystemError);
+ message += L"\n";
+ }
+ if (!message.IsEmpty())
+ stdStream << L"\nError:\n" << message;
+ throw CSystemException(result);
+ }
+ int numErrors = callback.FailedFiles.Size();
+ if (numErrors == 0)
+ {
+ if (callback.CantFindFiles.Size() == 0)
+ stdStream << kEverythingIsOk << endl;
+ }
+ else
+ {
+ stdStream << endl;
+ stdStream << "WARNINGS for files:" << endl << endl;
+ for (int i = 0; i < numErrors; i++)
+ {
+ stdStream << callback.FailedFiles[i] << " : ";
+ stdStream << NError::MyFormatMessageW(callback.FailedCodes[i]) << endl;
+ }
+ stdStream << "----------------" << endl;
+ stdStream << "WARNING: Cannot open " << numErrors << " file";
+ if (numErrors > 1)
+ stdStream << "s";
+ stdStream << endl;
+ exitCode = NExitCode::kWarning;
+ }
+ return exitCode;
+ }
+ else
+ PrintHelpAndExit(stdStream);
+ return 0;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/MainAr.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/MainAr.cpp
new file mode 100644
index 000000000..68059575b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/MainAr.cpp
@@ -0,0 +1,127 @@
+// MainAr.cpp
+
+#include "StdAfx.h"
+
+#include "Common/NewHandler.h" // FIXME
+
+#include "Common/MyException.h"
+#include "Common/StdOutStream.h"
+
+#include "Windows/Error.h"
+#include "Windows/NtCheck.h"
+
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/ExitCode.h"
+
+#include "ConsoleClose.h"
+
+using namespace NWindows;
+
+CStdOutStream *g_StdStream = 0;
+
+extern int Main2(
+ #ifndef _WIN32
+ int numArgs, const char *args[]
+ #endif
+);
+
+static const char *kExceptionErrorMessage = "\n\nError:\n";
+static const char *kUserBreak = "\nBreak signaled\n";
+static const char *kMemoryExceptionMessage = "\n\nERROR: Can't allocate required memory!\n";
+static const char *kUnknownExceptionMessage = "\n\nUnknown Error\n";
+static const char *kInternalExceptionMessage = "\n\nInternal Error #";
+
+#define NT_CHECK_FAIL_ACTION (*g_StdStream) << "Unsupported Windows version"; return NExitCode::kFatalError;
+
+int MY_CDECL main
+(
+ #ifndef _WIN32
+ int numArgs, const char *args[]
+ #endif
+)
+{
+ g_StdStream = &g_StdOut;
+
+ NT_CHECK
+
+ NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
+ int res = 0;
+ try
+ {
+ res = Main2(
+ #ifndef _WIN32
+ numArgs, args
+ #endif
+ );
+ }
+ catch(const CNewException &)
+ {
+ (*g_StdStream) << kMemoryExceptionMessage;
+ return (NExitCode::kMemoryError);
+ }
+ catch(const NConsoleClose::CCtrlBreakException &)
+ {
+ (*g_StdStream) << endl << kUserBreak;
+ return (NExitCode::kUserBreak);
+ }
+ catch(const CArchiveCommandLineException &e)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << e << endl;
+ return (NExitCode::kUserError);
+ }
+ catch(const CSystemException &systemError)
+ {
+ if (systemError.ErrorCode == E_OUTOFMEMORY)
+ {
+ (*g_StdStream) << kMemoryExceptionMessage;
+ return (NExitCode::kMemoryError);
+ }
+ if (systemError.ErrorCode == E_ABORT)
+ {
+ (*g_StdStream) << endl << kUserBreak;
+ return (NExitCode::kUserBreak);
+ }
+ UString message;
+ NError::MyFormatMessage(systemError.ErrorCode, message);
+ (*g_StdStream) << endl << endl << "System error:" << endl << message << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(NExitCode::EEnum &exitCode)
+ {
+ (*g_StdStream) << kInternalExceptionMessage << exitCode << endl;
+ return (exitCode);
+ }
+ /*
+ catch(const NExitCode::CMultipleErrors &multipleErrors)
+ {
+ (*g_StdStream) << endl << multipleErrors.NumErrors << " errors" << endl;
+ return (NExitCode::kFatalError);
+ }
+ */
+ catch(const UString &s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(const AString &s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(const char *s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(int t)
+ {
+ (*g_StdStream) << kInternalExceptionMessage << t << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(...)
+ {
+ (*g_StdStream) << kUnknownExceptionMessage;
+ return (NExitCode::kFatalError);
+ }
+ return res;
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
new file mode 100644
index 000000000..7dba2ad5d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
@@ -0,0 +1,58 @@
+// OpenCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "OpenCallbackConsole.h"
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+
+HRESULT COpenCallbackConsole::Open_CheckBreak()
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *, const UInt64 *)
+{
+ return Open_CheckBreak();
+}
+
+HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *, const UInt64 *)
+{
+ return Open_CheckBreak();
+}
+
+#ifndef _NO_CRYPTO
+
+HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password)
+{
+ PasswordWasAsked = true;
+ RINOK(Open_CheckBreak());
+ if (!PasswordIsDefined)
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+HRESULT COpenCallbackConsole::Open_GetPasswordIfAny(UString &password)
+{
+ if (PasswordIsDefined)
+ password = Password;
+ return S_OK;
+}
+
+bool COpenCallbackConsole::Open_WasPasswordAsked()
+{
+ return PasswordWasAsked;
+}
+
+void COpenCallbackConsole::Open_ClearPasswordWasAskedFlag()
+{
+ PasswordWasAsked = false;
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/OpenCallbackConsole.h b/src/libs/7zip/unix/CPP/7zip/UI/Console/OpenCallbackConsole.h
new file mode 100644
index 000000000..c002e6a72
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/OpenCallbackConsole.h
@@ -0,0 +1,24 @@
+// OpenCallbackConsole.h
+
+#ifndef __OPENCALLBACKCONSOLE_H
+#define __OPENCALLBACKCONSOLE_H
+
+#include "Common/StdOutStream.h"
+#include "../Common/ArchiveOpenCallback.h"
+
+class COpenCallbackConsole: public IOpenCallbackUI
+{
+public:
+ INTERFACE_IOpenCallbackUI(;)
+
+ CStdOutStream *OutStream;
+
+ #ifndef _NO_CRYPTO
+ bool PasswordIsDefined;
+ bool PasswordWasAsked;
+ UString Password;
+ COpenCallbackConsole(): PasswordIsDefined(false), PasswordWasAsked(false) {}
+ #endif
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.cpp
new file mode 100644
index 000000000..28452b177
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.cpp
@@ -0,0 +1,90 @@
+// PercentPrinter.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "PercentPrinter.h"
+
+const int kPaddingSize = 2;
+const int kPercentsSize = 4;
+const int kMaxExtraSize = kPaddingSize + 32 + kPercentsSize;
+
+static void ClearPrev(char *p, int num)
+{
+ int i;
+ for (i = 0; i < num; i++) *p++ = '\b';
+ for (i = 0; i < num; i++) *p++ = ' ';
+ for (i = 0; i < num; i++) *p++ = '\b';
+ *p = '\0';
+}
+
+void CPercentPrinter::ClosePrint()
+{
+ if (m_NumExtraChars == 0)
+ return;
+ char s[kMaxExtraSize * 3 + 1];
+ ClearPrev(s, m_NumExtraChars);
+ (*OutStream) << s;
+ m_NumExtraChars = 0;
+}
+
+void CPercentPrinter::PrintString(const char *s)
+{
+ ClosePrint();
+ (*OutStream) << s;
+}
+
+void CPercentPrinter::PrintString(const wchar_t *s)
+{
+ ClosePrint();
+ (*OutStream) << s;
+}
+
+void CPercentPrinter::PrintNewLine()
+{
+ ClosePrint();
+ (*OutStream) << "\n";
+}
+
+void CPercentPrinter::RePrintRatio()
+{
+ char s[32];
+ ConvertUInt64ToString(((m_Total == 0) ? 0 : (m_CurValue * 100 / m_Total)), s);
+ int size = (int)strlen(s);
+ s[size++] = '%';
+ s[size] = '\0';
+
+ int extraSize = kPaddingSize + MyMax(size, kPercentsSize);
+ if (extraSize < m_NumExtraChars)
+ extraSize = m_NumExtraChars;
+
+ char fullString[kMaxExtraSize * 3];
+ char *p = fullString;
+ int i;
+ if (m_NumExtraChars == 0)
+ {
+ for (i = 0; i < extraSize; i++)
+ *p++ = ' ';
+ m_NumExtraChars = extraSize;
+ }
+
+ for (i = 0; i < m_NumExtraChars; i++)
+ *p++ = '\b';
+ m_NumExtraChars = extraSize;
+ for (; size < m_NumExtraChars; size++)
+ *p++ = ' ';
+ MyStringCopy(p, s);
+ (*OutStream) << fullString;
+ OutStream->Flush();
+ m_PrevValue = m_CurValue;
+}
+
+void CPercentPrinter::PrintRatio()
+{
+ if (m_CurValue < m_PrevValue + m_MinStepSize &&
+ m_CurValue + m_MinStepSize > m_PrevValue && m_NumExtraChars != 0)
+ return;
+ RePrintRatio();
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.h b/src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.h
new file mode 100644
index 000000000..97f2e6adb
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/PercentPrinter.h
@@ -0,0 +1,31 @@
+// PercentPrinter.h
+
+#ifndef __PERCENTPRINTER_H
+#define __PERCENTPRINTER_H
+
+#include "Common/Types.h"
+#include "Common/StdOutStream.h"
+
+class CPercentPrinter
+{
+ UInt64 m_MinStepSize;
+ UInt64 m_PrevValue;
+ UInt64 m_CurValue;
+ UInt64 m_Total;
+ int m_NumExtraChars;
+public:
+ CStdOutStream *OutStream;
+
+ CPercentPrinter(UInt64 minStepSize = 1): m_MinStepSize(minStepSize),
+ m_PrevValue(0), m_CurValue(0), m_Total(1), m_NumExtraChars(0) {}
+ void SetTotal(UInt64 total) { m_Total = total; m_PrevValue = 0; }
+ void SetRatio(UInt64 doneValue) { m_CurValue = doneValue; }
+ void PrintString(const char *s);
+ void PrintString(const wchar_t *s);
+ void PrintNewLine();
+ void ClosePrint();
+ void RePrintRatio();
+ void PrintRatio();
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
new file mode 100644
index 000000000..e0eb4dec7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
@@ -0,0 +1,261 @@
+// UpdateCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateCallbackConsole.h"
+
+#include "Windows/Error.h"
+#ifndef _7ZIP_ST
+#include "Windows/Synchronization.h"
+#endif
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+
+using namespace NWindows;
+
+#ifndef _7ZIP_ST
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+static const wchar_t *kEmptyFileAlias = L"[Content]";
+
+static const char *kCreatingArchiveMessage = "Creating archive ";
+static const char *kUpdatingArchiveMessage = "Updating archive ";
+static const char *kScanningMessage = "Scanning";
+
+
+HRESULT CUpdateCallbackConsole::OpenResult(const wchar_t *name, HRESULT result)
+{
+ (*OutStream) << endl;
+ if (result != S_OK)
+ (*OutStream) << "Error: " << name << " is not supported archive" << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartScanning()
+{
+ (*OutStream) << kScanningMessage;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::ScanProgress(UInt64 /* numFolders */, UInt64 /* numFiles */, const wchar_t * /* path */)
+{
+ return CheckBreak();
+}
+
+HRESULT CUpdateCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError)
+{
+ CantFindFiles.Add(name);
+ CantFindCodes.Add(systemError);
+ // m_PercentPrinter.ClosePrint();
+ if (!m_WarningsMode)
+ {
+ (*OutStream) << endl << endl;
+ m_PercentPrinter.PrintNewLine();
+ m_WarningsMode = true;
+ }
+ m_PercentPrinter.PrintString(name);
+ m_PercentPrinter.PrintString(": WARNING: ");
+ m_PercentPrinter.PrintString(NError::MyFormatMessageW(systemError));
+ m_PercentPrinter.PrintNewLine();
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::FinishScanning()
+{
+ (*OutStream) << endl << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
+{
+ if(updating)
+ (*OutStream) << kUpdatingArchiveMessage;
+ else
+ (*OutStream) << kCreatingArchiveMessage;
+ if (name != 0)
+ (*OutStream) << name;
+ else
+ (*OutStream) << "StdOut";
+ (*OutStream) << endl << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::FinishArchive()
+{
+ (*OutStream) << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CheckBreak()
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::Finilize()
+{
+ MT_LOCK
+ if (m_NeedBeClosed)
+ {
+ if (EnablePercents)
+ {
+ m_PercentPrinter.ClosePrint();
+ }
+ if (!StdOutMode && m_NeedNewLine)
+ {
+ m_PercentPrinter.PrintNewLine();
+ m_NeedNewLine = false;
+ }
+ m_NeedBeClosed = false;
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
+{
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
+{
+ MT_LOCK
+ if (EnablePercents)
+ m_PercentPrinter.SetTotal(size);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
+{
+ MT_LOCK
+ if (completeValue != NULL)
+ {
+ if (EnablePercents)
+ {
+ m_PercentPrinter.SetRatio(*completeValue);
+ m_PercentPrinter.PrintRatio();
+ m_NeedBeClosed = true;
+ }
+ }
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isAnti)
+{
+ MT_LOCK
+ if (StdOutMode)
+ return S_OK;
+ if(isAnti)
+ m_PercentPrinter.PrintString("Anti item ");
+ else
+ m_PercentPrinter.PrintString("Compressing ");
+ if (name[0] == 0)
+ name = kEmptyFileAlias;
+ m_PercentPrinter.PrintString(name);
+ if (EnablePercents)
+ m_PercentPrinter.RePrintRatio();
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::OpenFileError(const wchar_t *name, DWORD systemError)
+{
+ MT_LOCK
+ FailedCodes.Add(systemError);
+ FailedFiles.Add(name);
+ // if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ m_PercentPrinter.ClosePrint();
+ m_PercentPrinter.PrintNewLine();
+ m_PercentPrinter.PrintString("WARNING: ");
+ m_PercentPrinter.PrintString(NError::MyFormatMessageW(systemError));
+ return S_FALSE;
+ }
+ // return systemError;
+}
+
+HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 )
+{
+ m_NeedBeClosed = true;
+ m_NeedNewLine = true;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ *password = NULL;
+
+ #ifdef _NO_CRYPTO
+
+ *passwordIsDefined = false;
+ return S_OK;
+
+ #else
+
+ if (!PasswordIsDefined)
+ {
+ if (AskPassword)
+ {
+ Password = GetPassword(OutStream,true);
+ PasswordIsDefined = true;
+ }
+ }
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ return StringToBstr(Password, password);
+
+ #endif
+}
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+ *password = NULL;
+
+ #ifdef _NO_CRYPTO
+
+ return E_NOTIMPL;
+
+ #else
+
+ if (!PasswordIsDefined)
+ {
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ }
+ return StringToBstr(Password, password);
+
+ #endif
+}
+
+/*
+HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name)
+{
+ // MT_LOCK
+ if (StdOutMode)
+ return S_OK;
+ RINOK(Finilize());
+ m_PercentPrinter.PrintString("Deleting ");
+ if (name[0] == 0)
+ name = kEmptyFileAlias;
+ m_PercentPrinter.PrintString(name);
+ if (EnablePercents)
+ m_PercentPrinter.RePrintRatio();
+ m_NeedBeClosed = true;
+ m_NeedNewLine = true;
+ return S_OK;
+}
+*/
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/src/libs/7zip/unix/CPP/7zip/UI/Console/UpdateCallbackConsole.h
new file mode 100644
index 000000000..5ffe3eb7a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/UpdateCallbackConsole.h
@@ -0,0 +1,62 @@
+// UpdateCallbackConsole.h
+
+#ifndef __UPDATE_CALLBACK_CONSOLE_H
+#define __UPDATE_CALLBACK_CONSOLE_H
+
+#include "Common/StdOutStream.h"
+
+#include "../Common/Update.h"
+
+#include "PercentPrinter.h"
+
+class CUpdateCallbackConsole: public IUpdateCallbackUI2
+{
+ CPercentPrinter m_PercentPrinter;
+ bool m_NeedBeClosed;
+ bool m_NeedNewLine;
+
+ bool m_WarningsMode;
+
+ CStdOutStream *OutStream;
+public:
+ bool EnablePercents;
+ bool StdOutMode;
+
+ #ifndef _NO_CRYPTO
+ bool PasswordIsDefined;
+ UString Password;
+ bool AskPassword;
+ #endif
+
+ CUpdateCallbackConsole():
+ m_PercentPrinter(1 << 16),
+ #ifndef _NO_CRYPTO
+ PasswordIsDefined(false),
+ AskPassword(false),
+ #endif
+ StdOutMode(false),
+ EnablePercents(true),
+ m_WarningsMode(false)
+ {}
+
+ ~CUpdateCallbackConsole() { Finilize(); }
+ void Init(CStdOutStream *outStream)
+ {
+ m_NeedBeClosed = false;
+ m_NeedNewLine = false;
+ FailedFiles.Clear();
+ FailedCodes.Clear();
+ OutStream = outStream;
+ m_PercentPrinter.OutStream = outStream;
+ }
+
+ INTERFACE_IUpdateCallbackUI2(;)
+
+ UStringVector FailedFiles;
+ CRecordVector<HRESULT> FailedCodes;
+
+ UStringVector CantFindFiles;
+ CRecordVector<HRESULT> CantFindCodes;
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/UserInputUtils.cpp b/src/libs/7zip/unix/CPP/7zip/UI/Console/UserInputUtils.cpp
new file mode 100644
index 000000000..4733e4ffb
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/UserInputUtils.cpp
@@ -0,0 +1,96 @@
+// UserInputUtils.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StdInStream.h"
+#include "Common/StringConvert.h"
+
+#include "UserInputUtils.h"
+
+#ifdef USE_FLTK
+// the programs like file-roller or xarchiver do not support archives with password
+// these programs freeze because p7zip is waiting for a password
+// defining USE_FLTK allows p7zip to use a popup in order to ask the password.
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/fl_ask.H>
+#else
+#ifdef ENV_HAVE_GETPASS
+#include <pwd.h>
+#include <unistd.h>
+#include "Common/MyException.h"
+#endif
+#endif
+
+static const char kYes = 'Y';
+static const char kNo = 'N';
+static const char kYesAll = 'A';
+static const char kNoAll = 'S';
+static const char kAutoRenameAll = 'U';
+static const char kQuit = 'Q';
+
+static const char *kFirstQuestionMessage = "?\n";
+static const char *kHelpQuestionMessage =
+ "(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename all / (Q)uit? ";
+
+// return true if pressed Quite;
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream)
+{
+ (*outStream) << kFirstQuestionMessage;
+ for (;;)
+ {
+ (*outStream) << kHelpQuestionMessage;
+ outStream->Flush();
+ AString scannedString = g_StdIn.ScanStringUntilNewLine();
+ scannedString.Trim();
+ if (!scannedString.IsEmpty())
+ switch(
+ ::MyCharUpper(
+ #ifdef UNDER_CE
+ (wchar_t)
+ #endif
+ scannedString[0]))
+ {
+ case kYes:
+ return NUserAnswerMode::kYes;
+ case kNo:
+ return NUserAnswerMode::kNo;
+ case kYesAll:
+ return NUserAnswerMode::kYesAll;
+ case kNoAll:
+ return NUserAnswerMode::kNoAll;
+ case kAutoRenameAll:
+ return NUserAnswerMode::kAutoRenameAll;
+ case kQuit:
+ return NUserAnswerMode::kQuit;
+ }
+ }
+}
+
+UString GetPassword(CStdOutStream *outStream,bool verify)
+{
+#ifdef USE_FLTK
+ const char *r = fl_password("Enter password", 0);
+ AString oemPassword = "";
+ if (r) oemPassword = r;
+#else /* USE_FLTK */
+#ifdef ENV_HAVE_GETPASS
+ (*outStream) << "\nEnter password (will not be echoed) :";
+ outStream->Flush();
+ AString oemPassword = getpass("");
+ if (verify)
+ {
+ (*outStream) << "Verify password (will not be echoed) :";
+ outStream->Flush();
+ AString oemPassword2 = getpass("");
+ if (oemPassword != oemPassword2) throw "password verification failed";
+ }
+#else
+ (*outStream) << "\nEnter password:";
+ outStream->Flush();
+ AString oemPassword = g_StdIn.ScanStringUntilNewLine();
+#endif
+#endif /* USE_FLTK */
+ return MultiByteToUnicodeString(oemPassword, CP_OEMCP);
+}
diff --git a/src/libs/7zip/unix/CPP/7zip/UI/Console/UserInputUtils.h b/src/libs/7zip/unix/CPP/7zip/UI/Console/UserInputUtils.h
new file mode 100644
index 000000000..8c575194d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/UI/Console/UserInputUtils.h
@@ -0,0 +1,24 @@
+// UserInputUtils.h
+
+#ifndef __USERINPUTUTILS_H
+#define __USERINPUTUTILS_H
+
+#include "Common/StdOutStream.h"
+
+namespace NUserAnswerMode {
+
+enum EEnum
+{
+ kYes,
+ kNo,
+ kYesAll,
+ kNoAll,
+ kAutoRenameAll,
+ kQuit
+};
+}
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream);
+UString GetPassword(CStdOutStream *outStream,bool verify = false);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/AutoPtr.h b/src/libs/7zip/unix/CPP/Common/AutoPtr.h
new file mode 100644
index 000000000..006d31551
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/AutoPtr.h
@@ -0,0 +1,35 @@
+// Common/AutoPtr.h
+
+#ifndef __COMMON_AUTOPTR_H
+#define __COMMON_AUTOPTR_H
+
+template<class T> class CMyAutoPtr
+{
+ T *_p;
+public:
+ CMyAutoPtr(T *p = 0) : _p(p) {}
+ CMyAutoPtr(CMyAutoPtr<T>& p): _p(p.release()) {}
+ CMyAutoPtr<T>& operator=(CMyAutoPtr<T>& p)
+ {
+ reset(p.release());
+ return (*this);
+ }
+ ~CMyAutoPtr() { delete _p; }
+ T& operator*() const { return *_p; }
+ // T* operator->() const { return (&**this); }
+ T* get() const { return _p; }
+ T* release()
+ {
+ T *tmp = _p;
+ _p = 0;
+ return tmp;
+ }
+ void reset(T* p = 0)
+ {
+ if (p != _p)
+ delete _p;
+ _p = p;
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/Buffer.h b/src/libs/7zip/unix/CPP/Common/Buffer.h
new file mode 100644
index 000000000..118fe11fc
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/Buffer.h
@@ -0,0 +1,77 @@
+// Common/Buffer.h
+
+#ifndef __COMMON_BUFFER_H
+#define __COMMON_BUFFER_H
+
+#include "Defs.h"
+
+template <class T> class CBuffer
+{
+protected:
+ size_t _capacity;
+ T *_items;
+public:
+ void Free()
+ {
+ delete []_items;
+ _items = 0;
+ _capacity = 0;
+ }
+ CBuffer(): _capacity(0), _items(0) {};
+ CBuffer(const CBuffer &buffer): _capacity(0), _items(0) { *this = buffer; }
+ CBuffer(size_t size): _items(0), _capacity(0) { SetCapacity(size); }
+ virtual ~CBuffer() { delete []_items; }
+ operator T *() { return _items; };
+ operator const T *() const { return _items; };
+ size_t GetCapacity() const { return _capacity; }
+ void SetCapacity(size_t newCapacity)
+ {
+ if (newCapacity == _capacity)
+ return;
+ T *newBuffer;
+ if (newCapacity > 0)
+ {
+ newBuffer = new T[newCapacity];
+ if (_capacity > 0)
+ memmove(newBuffer, _items, MyMin(_capacity, newCapacity) * sizeof(T));
+ }
+ else
+ newBuffer = 0;
+ delete []_items;
+ _items = newBuffer;
+ _capacity = newCapacity;
+ }
+ CBuffer& operator=(const CBuffer &buffer)
+ {
+ Free();
+ if (buffer._capacity > 0)
+ {
+ SetCapacity(buffer._capacity);
+ memmove(_items, buffer._items, buffer._capacity * sizeof(T));
+ }
+ return *this;
+ }
+};
+
+template <class T>
+bool operator==(const CBuffer<T>& b1, const CBuffer<T>& b2)
+{
+ if (b1.GetCapacity() != b2.GetCapacity())
+ return false;
+ for (size_t i = 0; i < b1.GetCapacity(); i++)
+ if (b1[i] != b2[i])
+ return false;
+ return true;
+}
+
+template <class T>
+bool operator!=(const CBuffer<T>& b1, const CBuffer<T>& b2)
+{
+ return !(b1 == b2);
+}
+
+typedef CBuffer<char> CCharBuffer;
+typedef CBuffer<wchar_t> CWCharBuffer;
+typedef CBuffer<unsigned char> CByteBuffer;
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/CRC.cpp b/src/libs/7zip/unix/CPP/Common/CRC.cpp
new file mode 100644
index 000000000..9a9f81fb7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/CRC.cpp
@@ -0,0 +1,7 @@
+// Common/CRC.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/7zCrc.h"
+
+struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit;
diff --git a/src/libs/7zip/unix/CPP/Common/C_FileIO.cpp b/src/libs/7zip/unix/CPP/Common/C_FileIO.cpp
new file mode 100644
index 000000000..b4893d658
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/C_FileIO.cpp
@@ -0,0 +1,88 @@
+// Common/C_FileIO.h
+
+#include "C_FileIO.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace NC {
+namespace NFile {
+namespace NIO {
+
+bool CFileBase::OpenBinary(const char *name, int flags)
+{
+ #ifdef O_BINARY
+ flags |= O_BINARY;
+ #endif
+ Close();
+ _handle = ::open(name, flags, 0666);
+ return _handle != -1;
+}
+
+bool CFileBase::Close()
+{
+ if (_handle == -1)
+ return true;
+ if (close(_handle) != 0)
+ return false;
+ _handle = -1;
+ return true;
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+ off_t curPos = Seek(0, SEEK_CUR);
+ off_t lengthTemp = Seek(0, SEEK_END);
+ Seek(curPos, SEEK_SET);
+ length = (UInt64)lengthTemp;
+ return true;
+}
+
+off_t CFileBase::Seek(off_t distanceToMove, int moveMethod) const
+{
+ return ::lseek(_handle, distanceToMove, moveMethod);
+}
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(const char *name)
+{
+ return CFileBase::OpenBinary(name, O_RDONLY);
+}
+
+bool CInFile::OpenShared(const char *name, bool)
+{
+ return Open(name);
+}
+
+ssize_t CInFile::Read(void *data, size_t size)
+{
+ return read(_handle, data, size);
+}
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Create(const char *name, bool createAlways)
+{
+ if (createAlways)
+ {
+ Close();
+ _handle = ::creat(name, 0666);
+ return _handle != -1;
+ }
+ return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY);
+}
+
+bool COutFile::Open(const char *name, DWORD creationDisposition)
+{
+ return Create(name, false);
+}
+
+ssize_t COutFile::Write(const void *data, size_t size)
+{
+ return write(_handle, data, size);
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/Common/C_FileIO.h b/src/libs/7zip/unix/CPP/Common/C_FileIO.h
new file mode 100644
index 000000000..27aa56869
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/C_FileIO.h
@@ -0,0 +1,47 @@
+// Common/C_FileIO.h
+
+#ifndef __COMMON_C_FILEIO_H
+#define __COMMON_C_FILEIO_H
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "Types.h"
+#include "MyWindows.h"
+
+namespace NC {
+namespace NFile {
+namespace NIO {
+
+class CFileBase
+{
+protected:
+ int _handle;
+ bool OpenBinary(const char *name, int flags);
+public:
+ CFileBase(): _handle(-1) {};
+ ~CFileBase() { Close(); }
+ bool Close();
+ bool GetLength(UInt64 &length) const;
+ off_t Seek(off_t distanceToMove, int moveMethod) const;
+};
+
+class CInFile: public CFileBase
+{
+public:
+ bool Open(const char *name);
+ bool OpenShared(const char *name, bool shareForWrite);
+ ssize_t Read(void *data, size_t size);
+};
+
+class COutFile: public CFileBase
+{
+public:
+ bool Create(const char *name, bool createAlways);
+ bool Open(const char *name, DWORD creationDisposition);
+ ssize_t Write(const void *data, size_t size);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/ComTry.h b/src/libs/7zip/unix/CPP/Common/ComTry.h
new file mode 100644
index 000000000..1f20e5d93
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/ComTry.h
@@ -0,0 +1,18 @@
+// ComTry.h
+
+#ifndef __COM_TRY_H
+#define __COM_TRY_H
+
+#include "MyWindows.h"
+// #include "Exception.h"
+// #include "NewHandler.h"
+
+#define COM_TRY_BEGIN try {
+#define COM_TRY_END } catch(const char * s) { throw s ; } \
+ catch(...) { return E_OUTOFMEMORY; }
+
+ // catch(const CNewException &) { return E_OUTOFMEMORY; }
+ // catch(const CSystemException &e) { return e.ErrorCode; }
+ // catch(...) { return E_FAIL; }
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/CommandLineParser.cpp b/src/libs/7zip/unix/CPP/Common/CommandLineParser.cpp
new file mode 100644
index 000000000..91fecc7af
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/CommandLineParser.cpp
@@ -0,0 +1,230 @@
+// CommandLineParser.cpp
+
+#include "StdAfx.h"
+
+#include "CommandLineParser.h"
+
+namespace NCommandLineParser {
+
+#ifdef _WIN32
+bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
+{
+ dest1.Empty();
+ dest2.Empty();
+ bool quoteMode = false;
+ int i;
+ for (i = 0; i < src.Length(); i++)
+ {
+ wchar_t c = src[i];
+ if (c == L' ' && !quoteMode)
+ {
+ dest2 = src.Mid(i + 1);
+ return i != 0;
+ }
+ if (c == L'\"')
+ quoteMode = !quoteMode;
+ else
+ dest1 += c;
+ }
+ return i != 0;
+}
+
+void SplitCommandLine(const UString &s, UStringVector &parts)
+{
+ UString sTemp = s;
+ sTemp.Trim();
+ parts.Clear();
+ for (;;)
+ {
+ UString s1, s2;
+ if (SplitCommandLine(sTemp, s1, s2))
+ parts.Add(s1);
+ if (s2.IsEmpty())
+ break;
+ sTemp = s2;
+ }
+}
+#endif
+
+static const wchar_t kSwitchID1 = '-';
+// static const wchar_t kSwitchID2 = '/';
+
+static const wchar_t kSwitchMinus = '-';
+static const wchar_t *kStopSwitchParsing = L"--";
+
+static bool IsItSwitchChar(wchar_t c)
+{
+ return (c == kSwitchID1 /*|| c == kSwitchID2 */);
+}
+
+CParser::CParser(int numSwitches):
+ _numSwitches(numSwitches)
+{
+ _switches = new CSwitchResult[_numSwitches];
+}
+
+CParser::~CParser()
+{
+ delete []_switches;
+}
+
+void CParser::ParseStrings(const CSwitchForm *switchForms,
+ const UStringVector &commandStrings)
+{
+ int numCommandStrings = commandStrings.Size();
+ bool stopSwitch = false;
+ for (int i = 0; i < numCommandStrings; i++)
+ {
+ const UString &s = commandStrings[i];
+ if (stopSwitch)
+ NonSwitchStrings.Add(s);
+ else
+ if (s == kStopSwitchParsing)
+ stopSwitch = true;
+ else
+ if (!ParseString(s, switchForms))
+ NonSwitchStrings.Add(s);
+ }
+}
+
+// if string contains switch then function updates switch structures
+// out: (string is a switch)
+bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms)
+{
+ int len = s.Length();
+ if (len == 0)
+ return false;
+ int pos = 0;
+ if (!IsItSwitchChar(s[pos]))
+ return false;
+ while (pos < len)
+ {
+ if (IsItSwitchChar(s[pos]))
+ pos++;
+ const int kNoLen = -1;
+ int matchedSwitchIndex = 0; // GCC Warning
+ int maxLen = kNoLen;
+ for (int switchIndex = 0; switchIndex < _numSwitches; switchIndex++)
+ {
+ int switchLen = MyStringLen(switchForms[switchIndex].IDString);
+ if (switchLen <= maxLen || pos + switchLen > len)
+ continue;
+
+ UString temp = s + pos;
+ temp = temp.Left(switchLen);
+ if (temp.CompareNoCase(switchForms[switchIndex].IDString) == 0)
+ // if (_strnicmp(switchForms[switchIndex].IDString, LPCSTR(s) + pos, switchLen) == 0)
+ {
+ matchedSwitchIndex = switchIndex;
+ maxLen = switchLen;
+ }
+ }
+ if (maxLen == kNoLen)
+ throw "maxLen == kNoLen";
+ CSwitchResult &matchedSwitch = _switches[matchedSwitchIndex];
+ const CSwitchForm &switchForm = switchForms[matchedSwitchIndex];
+ if ((!switchForm.Multi) && matchedSwitch.ThereIs)
+ throw "switch must be single";
+ matchedSwitch.ThereIs = true;
+ pos += maxLen;
+ int tailSize = len - pos;
+ NSwitchType::EEnum type = switchForm.Type;
+ switch(type)
+ {
+ case NSwitchType::kPostMinus:
+ {
+ if (tailSize == 0)
+ matchedSwitch.WithMinus = false;
+ else
+ {
+ matchedSwitch.WithMinus = (s[pos] == kSwitchMinus);
+ if (matchedSwitch.WithMinus)
+ pos++;
+ }
+ break;
+ }
+ case NSwitchType::kPostChar:
+ {
+ if (tailSize < switchForm.MinLen)
+ throw "switch is not full";
+ UString set = switchForm.PostCharSet;
+ const int kEmptyCharValue = -1;
+ if (tailSize == 0)
+ matchedSwitch.PostCharIndex = kEmptyCharValue;
+ else
+ {
+ int index = set.Find(s[pos]);
+ if (index < 0)
+ matchedSwitch.PostCharIndex = kEmptyCharValue;
+ else
+ {
+ matchedSwitch.PostCharIndex = index;
+ pos++;
+ }
+ }
+ break;
+ }
+ case NSwitchType::kLimitedPostString:
+ case NSwitchType::kUnLimitedPostString:
+ {
+ int minLen = switchForm.MinLen;
+ if (tailSize < minLen)
+ throw "switch is not full";
+ if (type == NSwitchType::kUnLimitedPostString)
+ {
+ matchedSwitch.PostStrings.Add(s.Mid(pos));
+ return true;
+ }
+ int maxLen = switchForm.MaxLen;
+ UString stringSwitch = s.Mid(pos, minLen);
+ pos += minLen;
+ for (int i = minLen; i < maxLen && pos < len; i++, pos++)
+ {
+ wchar_t c = s[pos];
+ if (IsItSwitchChar(c))
+ break;
+ stringSwitch += c;
+ }
+ matchedSwitch.PostStrings.Add(stringSwitch);
+ break;
+ }
+ case NSwitchType::kSimple:
+ break;
+ }
+ }
+ return true;
+}
+
+const CSwitchResult& CParser::operator[](size_t index) const
+{
+ return _switches[index];
+}
+
+/////////////////////////////////
+// Command parsing procedures
+
+int ParseCommand(int numCommandForms, const CCommandForm *commandForms,
+ const UString &commandString, UString &postString)
+{
+ for (int i = 0; i < numCommandForms; i++)
+ {
+ const UString id = commandForms[i].IDString;
+ if (commandForms[i].PostStringMode)
+ {
+ if (commandString.Find(id) == 0)
+ {
+ postString = commandString.Mid(id.Length());
+ return i;
+ }
+ }
+ else
+ if (commandString == id)
+ {
+ postString.Empty();
+ return i;
+ }
+ }
+ return -1;
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/Common/CommandLineParser.h b/src/libs/7zip/unix/CPP/Common/CommandLineParser.h
new file mode 100644
index 000000000..3d0b41dd4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/CommandLineParser.h
@@ -0,0 +1,72 @@
+// Common/CommandLineParser.h
+
+#ifndef __COMMON_COMMAND_LINE_PARSER_H
+#define __COMMON_COMMAND_LINE_PARSER_H
+
+#include "MyString.h"
+
+namespace NCommandLineParser {
+
+bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2);
+void SplitCommandLine(const UString &s, UStringVector &parts);
+
+namespace NSwitchType {
+ enum EEnum
+ {
+ kSimple,
+ kPostMinus,
+ kLimitedPostString,
+ kUnLimitedPostString,
+ kPostChar
+ };
+}
+
+struct CSwitchForm
+{
+ const wchar_t *IDString;
+ NSwitchType::EEnum Type;
+ bool Multi;
+ int MinLen;
+ int MaxLen;
+ const wchar_t *PostCharSet;
+};
+
+struct CSwitchResult
+{
+ bool ThereIs;
+ bool WithMinus;
+ UStringVector PostStrings;
+ int PostCharIndex;
+ CSwitchResult(): ThereIs(false) {};
+};
+
+class CParser
+{
+ int _numSwitches;
+ CSwitchResult *_switches;
+ bool ParseString(const UString &s, const CSwitchForm *switchForms);
+public:
+ UStringVector NonSwitchStrings;
+ CParser(int numSwitches);
+ ~CParser();
+ void ParseStrings(const CSwitchForm *switchForms,
+ const UStringVector &commandStrings);
+ const CSwitchResult& operator[](size_t index) const;
+};
+
+/////////////////////////////////
+// Command parsing procedures
+
+struct CCommandForm
+{
+ const wchar_t *IDString;
+ bool PostStringMode;
+};
+
+// Returns: Index of form and postString; -1, if there is no match
+int ParseCommand(int numCommandForms, const CCommandForm *commandForms,
+ const UString &commandString, UString &postString);
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/Defs.h b/src/libs/7zip/unix/CPP/Common/Defs.h
new file mode 100644
index 000000000..dad3ae8f1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/Defs.h
@@ -0,0 +1,20 @@
+// Common/Defs.h
+
+#ifndef __COMMON_DEFS_H
+#define __COMMON_DEFS_H
+
+template <class T> inline T MyMin(T a, T b)
+ { return a < b ? a : b; }
+template <class T> inline T MyMax(T a, T b)
+ { return a > b ? a : b; }
+
+template <class T> inline int MyCompare(T a, T b)
+ { return a < b ? -1 : (a == b ? 0 : 1); }
+
+inline int BoolToInt(bool value)
+ { return (value ? 1: 0); }
+
+inline bool IntToBool(int value)
+ { return (value != 0); }
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/DynamicBuffer.h b/src/libs/7zip/unix/CPP/Common/DynamicBuffer.h
new file mode 100644
index 000000000..b5fd97823
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/DynamicBuffer.h
@@ -0,0 +1,50 @@
+// Common/DynamicBuffer.h
+
+#ifndef __COMMON_DYNAMIC_BUFFER_H
+#define __COMMON_DYNAMIC_BUFFER_H
+
+#include "Buffer.h"
+
+template <class T> class CDynamicBuffer: public CBuffer<T>
+{
+ void GrowLength(size_t size)
+ {
+ size_t delta;
+ if (this->_capacity > 64)
+ delta = this->_capacity / 4;
+ else if (this->_capacity > 8)
+ delta = 16;
+ else
+ delta = 4;
+ delta = MyMax(delta, size);
+ size_t newCap = this->_capacity + delta;
+ if (newCap < delta)
+ newCap = this->_capacity + size;
+ this->SetCapacity(newCap);
+ }
+public:
+ CDynamicBuffer(): CBuffer<T>() {};
+ CDynamicBuffer(const CDynamicBuffer &buffer): CBuffer<T>(buffer) {};
+ CDynamicBuffer(size_t size): CBuffer<T>(size) {};
+ CDynamicBuffer& operator=(const CDynamicBuffer &buffer)
+ {
+ this->Free();
+ if (buffer._capacity > 0)
+ {
+ SetCapacity(buffer._capacity);
+ memmove(this->_items, buffer._items, buffer._capacity * sizeof(T));
+ }
+ return *this;
+ }
+ void EnsureCapacity(size_t capacity)
+ {
+ if (this->_capacity < capacity)
+ GrowLength(capacity - this->_capacity);
+ }
+};
+
+typedef CDynamicBuffer<char> CCharDynamicBuffer;
+typedef CDynamicBuffer<wchar_t> CWCharDynamicBuffer;
+typedef CDynamicBuffer<unsigned char> CByteDynamicBuffer;
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/IntToString.cpp b/src/libs/7zip/unix/CPP/Common/IntToString.cpp
new file mode 100644
index 000000000..013fee527
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/IntToString.cpp
@@ -0,0 +1,77 @@
+// Common/IntToString.cpp
+
+#include "StdAfx.h"
+
+#include "IntToString.h"
+
+void ConvertUInt64ToString(UInt64 value, char *s, UInt32 base)
+{
+ if (base < 2 || base > 36)
+ {
+ *s = '\0';
+ return;
+ }
+ char temp[72];
+ int pos = 0;
+ do
+ {
+ int delta = (int)(value % base);
+ temp[pos++] = (char)((delta < 10) ? ('0' + delta) : ('a' + (delta - 10)));
+ value /= base;
+ }
+ while (value != 0);
+ do
+ *s++ = temp[--pos];
+ while (pos > 0);
+ *s = '\0';
+}
+
+void ConvertUInt64ToString(UInt64 value, wchar_t *s)
+{
+ wchar_t temp[32];
+ int pos = 0;
+ do
+ {
+ temp[pos++] = (wchar_t)(L'0' + (int)(value % 10));
+ value /= 10;
+ }
+ while (value != 0);
+ do
+ *s++ = temp[--pos];
+ while (pos > 0);
+ *s = L'\0';
+}
+
+void ConvertUInt32ToString(UInt32 value, char *s) { ConvertUInt64ToString(value, s); }
+void ConvertUInt32ToString(UInt32 value, wchar_t *s) { ConvertUInt64ToString(value, s); }
+
+void ConvertInt64ToString(Int64 value, char *s)
+{
+ if (value < 0)
+ {
+ *s++ = '-';
+ value = -value;
+ }
+ ConvertUInt64ToString(value, s);
+}
+
+void ConvertInt64ToString(Int64 value, wchar_t *s)
+{
+ if (value < 0)
+ {
+ *s++ = L'-';
+ value = -value;
+ }
+ ConvertUInt64ToString(value, s);
+}
+
+void ConvertUInt32ToHexWithZeros(UInt32 value, char *s)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ int t = value & 0xF;
+ value >>= 4;
+ s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ s[8] = '\0';
+}
diff --git a/src/libs/7zip/unix/CPP/Common/IntToString.h b/src/libs/7zip/unix/CPP/Common/IntToString.h
new file mode 100644
index 000000000..782f930c5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/IntToString.h
@@ -0,0 +1,19 @@
+// Common/IntToString.h
+
+#ifndef __COMMON_INT_TO_STRING_H
+#define __COMMON_INT_TO_STRING_H
+
+#include <stddef.h>
+#include "Types.h"
+
+void ConvertUInt64ToString(UInt64 value, char *s, UInt32 base = 10);
+void ConvertUInt64ToString(UInt64 value, wchar_t *s);
+void ConvertInt64ToString(Int64 value, char *s);
+void ConvertInt64ToString(Int64 value, wchar_t *s);
+
+void ConvertUInt32ToString(UInt32 value, char *s);
+void ConvertUInt32ToString(UInt32 value, wchar_t *s);
+
+void ConvertUInt32ToHexWithZeros(UInt32 value, char *s);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/Lang.cpp b/src/libs/7zip/unix/CPP/Common/Lang.cpp
new file mode 100644
index 000000000..75dfed426
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/Lang.cpp
@@ -0,0 +1,130 @@
+// Common/Lang.cpp
+
+#include "StdAfx.h"
+
+#include "Lang.h"
+#include "TextConfig.h"
+
+#include "../Windows/FileIO.h"
+#include "UTFConvert.h"
+#include "Defs.h"
+
+static bool HexStringToNumber(const UString &s, UInt32 &value)
+{
+ value = 0;
+ if (s.IsEmpty())
+ return false;
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ int a;
+ if (c >= L'0' && c <= L'9')
+ a = c - L'0';
+ else if (c >= L'A' && c <= L'F')
+ a = 10 + c - L'A';
+ else if (c >= L'a' && c <= L'f')
+ a = 10 + c - L'a';
+ else
+ return false;
+ value *= 0x10;
+ value += a;
+ }
+ return true;
+}
+
+
+static bool WaitNextLine(const AString &s, int &pos)
+{
+ for (; pos < s.Length(); pos++)
+ if (s[pos] == 0x0A)
+ return true;
+ return false;
+}
+
+static int CompareLangItems(void *const *elem1, void *const *elem2, void *)
+{
+ const CLangPair &langPair1 = *(*((const CLangPair **)elem1));
+ const CLangPair &langPair2 = *(*((const CLangPair **)elem2));
+ return MyCompare(langPair1.Value, langPair2.Value);
+}
+
+bool CLang::Open(LPCWSTR fileName)
+{
+ _langPairs.Clear();
+ NWindows::NFile::NIO::CInFile file;
+ if (!file.Open(fileName))
+ return false;
+ UInt64 length;
+ if (!file.GetLength(length))
+ return false;
+ if (length > (1 << 20))
+ return false;
+ AString s;
+ char *p = s.GetBuffer((int)length + 1);
+ UInt32 processed;
+ if (!file.Read(p, (UInt32)length, processed))
+ return false;
+ p[(UInt32)length] = 0;
+ s.ReleaseBuffer();
+ file.Close();
+ int pos = 0;
+ if (s.Length() >= 3)
+ {
+ if (Byte(s[0]) == 0xEF && Byte(s[1]) == 0xBB && Byte(s[2]) == 0xBF)
+ pos += 3;
+ }
+
+ /////////////////////
+ // read header
+
+ AString stringID = ";!@Lang@!UTF-8!";
+ if (s.Mid(pos, stringID.Length()) != stringID)
+ return false;
+ pos += stringID.Length();
+
+ if (!WaitNextLine(s, pos))
+ return false;
+
+ CObjectVector<CTextConfigPair> pairs;
+ if (!GetTextConfig(s.Mid(pos), pairs))
+ return false;
+
+ _langPairs.Reserve(_langPairs.Size());
+ for (int i = 0; i < pairs.Size(); i++)
+ {
+ CTextConfigPair textConfigPair = pairs[i];
+ CLangPair langPair;
+ if (!HexStringToNumber(textConfigPair.ID, langPair.Value))
+ return false;
+ langPair.String = textConfigPair.String;
+ _langPairs.Add(langPair);
+ }
+ _langPairs.Sort(CompareLangItems, NULL);
+ return true;
+}
+
+int CLang::FindItem(UInt32 value) const
+{
+ int left = 0, right = _langPairs.Size();
+ while (left != right)
+ {
+ UInt32 mid = (left + right) / 2;
+ UInt32 midValue = _langPairs[mid].Value;
+ if (value == midValue)
+ return mid;
+ if (value < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+bool CLang::GetMessage(UInt32 value, UString &message) const
+{
+ int index = FindItem(value);
+ if (index < 0)
+ return false;
+ message = _langPairs[index].String;
+ return true;
+}
diff --git a/src/libs/7zip/unix/CPP/Common/Lang.h b/src/libs/7zip/unix/CPP/Common/Lang.h
new file mode 100644
index 000000000..cf978758e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/Lang.h
@@ -0,0 +1,28 @@
+// Common/Lang.h
+
+#ifndef __COMMON_LANG_H
+#define __COMMON_LANG_H
+
+#include "MyVector.h"
+#include "MyString.h"
+#include "Types.h"
+
+struct CLangPair
+{
+ UInt32 Value;
+ UString String;
+};
+
+class CLang
+{
+ CObjectVector<CLangPair> _langPairs;
+public:
+ bool Open(LPCWSTR fileName);
+ void Clear() { _langPairs.Clear(); }
+ int FindItem(UInt32 value) const;
+ bool GetMessage(UInt32 value, UString &message) const;
+};
+
+#endif
+
+
diff --git a/src/libs/7zip/unix/CPP/Common/ListFileUtils.cpp b/src/libs/7zip/unix/CPP/Common/ListFileUtils.cpp
new file mode 100644
index 000000000..8e409016e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/ListFileUtils.cpp
@@ -0,0 +1,75 @@
+// Common/ListFileUtils.cpp
+
+#include "StdAfx.h"
+
+#include "MyWindows.h"
+#include "../Windows/FileIO.h"
+
+#include "ListFileUtils.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+static const char kQuoteChar = '\"';
+static void RemoveQuote(UString &s)
+{
+ if (s.Length() >= 2)
+ if (s[0] == kQuoteChar && s[s.Length() - 1] == kQuoteChar)
+ s = s.Mid(1, s.Length() - 2);
+}
+
+bool ReadNamesFromListFile(LPCWSTR fileName, UStringVector &resultStrings, UINT codePage)
+{
+ NWindows::NFile::NIO::CInFile file;
+ if (!file.Open(fileName,true)) /* follow the symbolic link */
+ return false;
+ UInt64 length;
+ if (!file.GetLength(length))
+ return false;
+ if (length > ((UInt32)1 << 31))
+ return false;
+ AString s;
+ char *p = s.GetBuffer((int)length + 1);
+ UInt32 processed;
+ if (!file.Read(p, (UInt32)length, processed))
+ return false;
+ p[(UInt32)length] = 0;
+ s.ReleaseBuffer();
+ file.Close();
+
+ UString u;
+ #ifdef CP_UTF8
+ if (codePage == CP_UTF8)
+ {
+ if (!ConvertUTF8ToUnicode(s, u))
+ return false;
+ }
+ else
+ #endif
+ u = MultiByteToUnicodeString(s, codePage);
+ if (!u.IsEmpty())
+ {
+ if (u[0] == 0xFEFF)
+ u.Delete(0);
+ }
+
+ UString t;
+ for (int i = 0; i < u.Length(); i++)
+ {
+ wchar_t c = u[i];
+ if (c == L'\n' || c == 0xD)
+ {
+ t.Trim();
+ RemoveQuote(t);
+ if (!t.IsEmpty())
+ resultStrings.Add(t);
+ t.Empty();
+ }
+ else
+ t += c;
+ }
+ t.Trim();
+ RemoveQuote(t);
+ if (!t.IsEmpty())
+ resultStrings.Add(t);
+ return true;
+}
diff --git a/src/libs/7zip/unix/CPP/Common/ListFileUtils.h b/src/libs/7zip/unix/CPP/Common/ListFileUtils.h
new file mode 100644
index 000000000..c58a8bd42
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/ListFileUtils.h
@@ -0,0 +1,11 @@
+// Common/ListFileUtils.h
+
+#ifndef __COMMON_LISTFILEUTILS_H
+#define __COMMON_LISTFILEUTILS_H
+
+#include "MyString.h"
+#include "Types.h"
+
+bool ReadNamesFromListFile(LPCWSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyCom.h b/src/libs/7zip/unix/CPP/Common/MyCom.h
new file mode 100644
index 000000000..2f00c258f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyCom.h
@@ -0,0 +1,225 @@
+// MyCom.h
+
+#ifndef __MYCOM_H
+#define __MYCOM_H
+
+#include "MyWindows.h"
+
+#ifndef RINOK
+#define RINOK(x) { HRESULT __result_ = (x); if (__result_ != S_OK) return __result_; }
+#endif
+
+template <class T>
+class CMyComPtr
+{
+ T* _p;
+public:
+ // typedef T _PtrClass;
+ CMyComPtr() { _p = NULL;}
+ CMyComPtr(T* p) {if ((_p = p) != NULL) p->AddRef(); }
+ CMyComPtr(const CMyComPtr<T>& lp)
+ {
+ if ((_p = lp._p) != NULL)
+ _p->AddRef();
+ }
+ ~CMyComPtr() { if (_p) _p->Release(); }
+ void Release() { if (_p) { _p->Release(); _p = NULL; } }
+ operator T*() const { return (T*)_p; }
+ // T& operator*() const { return *_p; }
+ T** operator&() { return &_p; }
+ T* operator->() const { return _p; }
+ T* operator=(T* p)
+ {
+ if (p != 0)
+ p->AddRef();
+ if (_p)
+ _p->Release();
+ _p = p;
+ return p;
+ }
+ T* operator=(const CMyComPtr<T>& lp) { return (*this = lp._p); }
+ bool operator!() const { return (_p == NULL); }
+ // bool operator==(T* pT) const { return _p == pT; }
+ // Compare two objects for equivalence
+ void Attach(T* p2)
+ {
+ Release();
+ _p = p2;
+ }
+ T* Detach()
+ {
+ T* pt = _p;
+ _p = NULL;
+ return pt;
+ }
+ #ifdef _WIN32
+ HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p);
+ }
+ #endif
+ /*
+ HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ CLSID clsid;
+ HRESULT hr = CLSIDFromProgID(szProgID, &clsid);
+ ATLASSERT(_p == NULL);
+ if (SUCCEEDED(hr))
+ hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p);
+ return hr;
+ }
+ */
+ template <class Q>
+ HRESULT QueryInterface(REFGUID iid, Q** pp) const
+ {
+ return _p->QueryInterface(iid, (void**)pp);
+ }
+};
+
+//////////////////////////////////////////////////////////
+
+inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr)
+{
+ *bstr = ::SysAllocString(src);
+ return (*bstr != 0) ? S_OK : E_OUTOFMEMORY;
+}
+
+class CMyComBSTR
+{
+public:
+ BSTR m_str;
+ CMyComBSTR(): m_str(NULL) {}
+ CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); }
+ // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); }
+ // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); }
+ CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); }
+ /*
+ CMyComBSTR(REFGUID src)
+ {
+ LPOLESTR szGuid;
+ StringFromCLSID(src, &szGuid);
+ m_str = ::SysAllocString(szGuid);
+ CoTaskMemFree(szGuid);
+ }
+ */
+ ~CMyComBSTR() { ::SysFreeString(m_str); }
+ CMyComBSTR& operator=(const CMyComBSTR& src)
+ {
+ if (m_str != src.m_str)
+ {
+ if (m_str)
+ ::SysFreeString(m_str);
+ m_str = src.MyCopy();
+ }
+ return *this;
+ }
+ CMyComBSTR& operator=(LPCOLESTR src)
+ {
+ ::SysFreeString(m_str);
+ m_str = ::SysAllocString(src);
+ return *this;
+ }
+ unsigned int Length() const { return ::SysStringLen(m_str); }
+ operator BSTR() const { return m_str; }
+ BSTR* operator&() { return &m_str; }
+ BSTR MyCopy() const
+ {
+ int byteLen = ::SysStringByteLen(m_str);
+ BSTR res = ::SysAllocStringByteLen(NULL, byteLen);
+ memcpy(res, m_str, byteLen);
+ return res;
+ }
+ /*
+ void Attach(BSTR src) { m_str = src; }
+ BSTR Detach()
+ {
+ BSTR s = m_str;
+ m_str = NULL;
+ return s;
+ }
+ */
+ void Empty()
+ {
+ ::SysFreeString(m_str);
+ m_str = NULL;
+ }
+ bool operator!() const { return (m_str == NULL); }
+};
+
+//////////////////////////////////////////////////////////
+
+class CMyUnknownImp
+{
+public:
+ ULONG __m_RefCount;
+ CMyUnknownImp(): __m_RefCount(0) {}
+};
+
+#define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \
+ (REFGUID iid, void **outObject) {
+
+#define MY_QUERYINTERFACE_ENTRY(i) if (iid == IID_ ## i) \
+ { *outObject = (void *)(i *)this; AddRef(); return S_OK; }
+
+#define MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) if (iid == IID_IUnknown) \
+ { *outObject = (void *)(IUnknown *)(i *)this; AddRef(); return S_OK; }
+
+#define MY_QUERYINTERFACE_BEGIN2(i) MY_QUERYINTERFACE_BEGIN \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \
+ MY_QUERYINTERFACE_ENTRY(i)
+
+#define MY_QUERYINTERFACE_END return E_NOINTERFACE; }
+
+#define MY_ADDREF_RELEASE \
+STDMETHOD_(ULONG, AddRef)() { return ++__m_RefCount; } \
+STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0) \
+ return __m_RefCount; delete this; return 0; }
+
+#define MY_UNKNOWN_IMP_SPEC(i) \
+ MY_QUERYINTERFACE_BEGIN \
+ i \
+ MY_QUERYINTERFACE_END \
+ MY_ADDREF_RELEASE
+
+
+#define MY_UNKNOWN_IMP MY_QUERYINTERFACE_BEGIN \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(IUnknown) \
+ MY_QUERYINTERFACE_END \
+ MY_ADDREF_RELEASE
+
+#define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \
+ MY_QUERYINTERFACE_ENTRY(i) \
+ )
+
+#define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ )
+
+#define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ )
+
+#define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ MY_QUERYINTERFACE_ENTRY(i4) \
+ )
+
+#define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ MY_QUERYINTERFACE_ENTRY(i4) \
+ MY_QUERYINTERFACE_ENTRY(i5) \
+ )
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyException.h b/src/libs/7zip/unix/CPP/Common/MyException.h
new file mode 100644
index 000000000..f0ad11158
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyException.h
@@ -0,0 +1,14 @@
+// Common/Exception.h
+
+#ifndef __COMMON_EXCEPTION_H
+#define __COMMON_EXCEPTION_H
+
+#include "MyWindows.h"
+
+struct CSystemException
+{
+ HRESULT ErrorCode;
+ CSystemException(HRESULT errorCode): ErrorCode(errorCode) {}
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyGuidDef.h b/src/libs/7zip/unix/CPP/Common/MyGuidDef.h
new file mode 100644
index 000000000..3c52cc07d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyGuidDef.h
@@ -0,0 +1,54 @@
+// Common/MyGuidDef.h
+
+#ifndef GUID_DEFINED
+#define GUID_DEFINED
+
+#include "Types.h"
+
+typedef struct {
+ UInt32 Data1;
+ UInt16 Data2;
+ UInt16 Data3;
+ unsigned char Data4[8];
+} GUID;
+
+#ifdef __cplusplus
+#define REFGUID const GUID &
+#else
+#define REFGUID const GUID *
+#endif
+
+#define REFCLSID REFGUID
+#define REFIID REFGUID
+
+#ifdef __cplusplus
+inline int operator==(REFGUID g1, REFGUID g2)
+{
+ for (int i = 0; i < (int)sizeof(g1); i++)
+ if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i])
+ return 0;
+ return 1;
+}
+inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); }
+#endif
+
+#ifdef __cplusplus
+ #define MY_EXTERN_C extern "C"
+#else
+ #define MY_EXTERN_C extern
+#endif
+
+#endif
+
+
+#ifdef DEFINE_GUID
+#undef DEFINE_GUID
+#endif
+
+#ifdef INITGUID
+ #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ MY_EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#else
+ #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ MY_EXTERN_C const GUID name
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyInitGuid.h b/src/libs/7zip/unix/CPP/Common/MyInitGuid.h
new file mode 100644
index 000000000..d6a486980
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyInitGuid.h
@@ -0,0 +1,22 @@
+// Common/MyInitGuid.h
+
+#ifndef __COMMON_MY_INITGUID_H
+#define __COMMON_MY_INITGUID_H
+
+#ifdef _WIN32
+#ifdef UNDER_CE
+#include <basetyps.h>
+#endif
+#include <initguid.h>
+#ifdef UNDER_CE
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+#endif
+#else
+#define INITGUID
+#include "MyGuidDef.h"
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyMap.cpp b/src/libs/7zip/unix/CPP/Common/MyMap.cpp
new file mode 100644
index 000000000..0ee11e8cd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyMap.cpp
@@ -0,0 +1,140 @@
+// MyMap.cpp
+
+#include "StdAfx.h"
+
+#include "MyMap.h"
+
+static const unsigned kNumBitsMax = sizeof(UInt32) * 8;
+
+static UInt32 GetSubBits(UInt32 value, unsigned startPos, unsigned numBits)
+{
+ if (startPos == sizeof(value) * 8)
+ return 0;
+ value >>= startPos;
+ if (numBits == sizeof(value) * 8)
+ return value;
+ return value & (((UInt32)1 << numBits) - 1);
+}
+
+static inline unsigned GetSubBit(UInt32 v, unsigned n) { return (unsigned)(v >> n) & 1; }
+
+bool CMap32::Find(UInt32 key, UInt32 &valueRes) const
+{
+ valueRes = (UInt32)(Int32)-1;
+ if (Nodes.Size() == 0)
+ return false;
+ if (Nodes.Size() == 1)
+ {
+ const CNode &n = Nodes[0];
+ if (n.Len == kNumBitsMax)
+ {
+ valueRes = n.Values[0];
+ return (key == n.Key);
+ }
+ }
+
+ int cur = 0;
+ unsigned bitPos = kNumBitsMax;
+ for (;;)
+ {
+ const CNode &n = Nodes[cur];
+ bitPos -= n.Len;
+ if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len))
+ return false;
+ unsigned bit = GetSubBit(key, --bitPos);
+ if (n.IsLeaf[bit])
+ {
+ valueRes = n.Values[bit];
+ return (key == n.Keys[bit]);
+ }
+ cur = (int)n.Keys[bit];
+ }
+}
+
+bool CMap32::Set(UInt32 key, UInt32 value)
+{
+ if (Nodes.Size() == 0)
+ {
+ CNode n;
+ n.Key = n.Keys[0] = n.Keys[1] = key;
+ n.Values[0] = n.Values[1] = value;
+ n.IsLeaf[0] = n.IsLeaf[1] = 1;
+ n.Len = kNumBitsMax;
+ Nodes.Add(n);
+ return false;
+ }
+ if (Nodes.Size() == 1)
+ {
+ CNode &n = Nodes[0];
+ if (n.Len == kNumBitsMax)
+ {
+ if (key == n.Key)
+ {
+ n.Values[0] = n.Values[1] = value;
+ return true;
+ }
+ unsigned i = kNumBitsMax - 1;
+ for (;GetSubBit(key, i) == GetSubBit(n.Key, i); i--);
+ n.Len = (UInt16)(kNumBitsMax - (1 + i));
+ unsigned newBit = GetSubBit(key, i);
+ n.Values[newBit] = value;
+ n.Keys[newBit] = key;
+ return false;
+ }
+ }
+
+ int cur = 0;
+ unsigned bitPos = kNumBitsMax;
+ for (;;)
+ {
+ CNode &n = Nodes[cur];
+ bitPos -= n.Len;
+ if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len))
+ {
+ unsigned i = n.Len - 1;
+ for (; GetSubBit(key, bitPos + i) == GetSubBit(n.Key, bitPos + i); i--);
+
+ CNode e2(n);
+ e2.Len = (UInt16)i;
+
+ n.Len = (UInt16)(n.Len - (1 + i));
+ unsigned newBit = GetSubBit(key, bitPos + i);
+ n.Values[newBit] = value;
+ n.IsLeaf[newBit] = 1;
+ n.IsLeaf[1 - newBit] = 0;
+ n.Keys[newBit] = key;
+ n.Keys[1 - newBit] = Nodes.Size();
+ Nodes.Add(e2);
+ return false;
+ }
+ unsigned bit = GetSubBit(key, --bitPos);
+
+ if (n.IsLeaf[bit])
+ {
+ if (key == n.Keys[bit])
+ {
+ n.Values[bit] = value;
+ return true;
+ }
+ unsigned i = bitPos - 1;
+ for (;GetSubBit(key, i) == GetSubBit(n.Keys[bit], i); i--);
+
+ CNode e2;
+
+ unsigned newBit = GetSubBit(key, i);
+ e2.Values[newBit] = value;
+ e2.Values[1 - newBit] = n.Values[bit];
+ e2.IsLeaf[newBit] = e2.IsLeaf[1 - newBit] = 1;
+ e2.Keys[newBit] = key;
+ e2.Keys[1 - newBit] = e2.Key = n.Keys[bit];
+ e2.Len = (UInt16)(bitPos - (1 + i));
+
+ n.IsLeaf[bit] = 0;
+ n.Keys[bit] = Nodes.Size();
+
+ Nodes.Add(e2);
+ return false;
+ }
+ cur = (int)n.Keys[bit];
+ }
+}
diff --git a/src/libs/7zip/unix/CPP/Common/MyMap.h b/src/libs/7zip/unix/CPP/Common/MyMap.h
new file mode 100644
index 000000000..d0dd43f53
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyMap.h
@@ -0,0 +1,28 @@
+// MyMap.h
+
+#ifndef __COMMON_MYMAP_H
+#define __COMMON_MYMAP_H
+
+#include "MyVector.h"
+#include "Types.h"
+
+class CMap32
+{
+ struct CNode
+ {
+ UInt32 Key;
+ UInt32 Keys[2];
+ UInt32 Values[2];
+ UInt16 Len;
+ Byte IsLeaf[2];
+ };
+ CRecordVector<CNode> Nodes;
+
+public:
+
+ void Clear() { Nodes.Clear(); }
+ bool Find(UInt32 key, UInt32 &valueRes) const;
+ bool Set(UInt32 key, UInt32 value); // returns true, if there is such key already
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyString.cpp b/src/libs/7zip/unix/CPP/Common/MyString.cpp
new file mode 100644
index 000000000..697a35558
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyString.cpp
@@ -0,0 +1,206 @@
+// Common/String.cpp
+
+#include "StdAfx.h"
+
+#include <ctype.h>
+#ifdef ENV_HAVE_WCTYPE_H
+#include <wctype.h>
+#endif
+#include "StringConvert.h" // FIXED
+
+#include "MyString.h" // FIXED to avoid confusion with <string.h> on some filesystems
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef ENV_HAVE_WCHAR__H
+#include <wchar.h>
+#endif
+
+#include <limits.h>
+#ifndef MB_LEN_MAX
+#define MB_LEN_MAX 1024
+#endif
+
+#include "myPrivate.h"
+
+LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr ) { // OK for MBS
+ while (*start && (start < ptr)) {
+ LPCSTR next = CharNextA( start );
+ if (next >= ptr)
+ break;
+ start = next;
+ }
+ return (LPSTR)start;
+}
+
+LPSTR WINAPI CharNextA( LPCSTR ptr ) {
+ if (!*ptr)
+ return (LPSTR)ptr;
+// #ifdef ENV_HAVE_MBRTOWC
+// if (global_use_utf16_conversion)
+// {
+// wchar_t wc;
+// size_t len = mbrtowc(&wc,ptr,MB_LEN_MAX,0); // mbrtowc stales on some configurations.
+// if (len >= 1) return (LPSTR)(ptr + len);
+// printf("INTERNAL ERROR - CharNextA\n");
+// exit(EXIT_FAILURE);
+// } else {
+// return (LPSTR)(ptr + 1);
+// }
+//#else
+ return (LPSTR)(ptr + 1); // p7zip search only for ASCII characters like '/' so no need to worry about current locale
+//#endif
+}
+
+char MyCharLower(char c)
+{
+ int r = c & 0xFF;
+
+ return tolower(r);
+}
+
+wchar_t MyCharLower(wchar_t c)
+{
+#ifdef ENV_HAVE_TOWUPPER
+ return towlower(c);
+#else
+ int ret = c;
+ if ((ret >= 1) && (ret <256)) ret = tolower(ret);
+ return (wchar_t)ret;
+#endif
+}
+
+char * MyStringLower(char *s)
+{
+ if (s == 0)
+ return 0;
+ char *ret = s;
+ while (*s)
+ {
+ *s = MyCharLower(*s);
+ s++;
+ }
+ return ret;
+}
+
+wchar_t * MyStringLower(wchar_t *s)
+{
+ if (s == 0)
+ return 0;
+ wchar_t *ret = s;
+ while (*s)
+ {
+ *s = MyCharLower(*s);
+ s++;
+ }
+ return ret;
+}
+
+wchar_t MyCharUpper(wchar_t c)
+{
+#ifdef ENV_HAVE_TOWUPPER
+ return towupper(c);
+#else
+ int ret = c;
+ if ((ret >= 1) && (ret <256)) ret = toupper(ret);
+ return (wchar_t)ret;
+#endif
+}
+
+wchar_t * MyStringUpper(wchar_t *s)
+{
+ if (s == 0)
+ return 0;
+ wchar_t *ret = s;
+ while (*s)
+ {
+ *s = MyCharUpper(*s);
+ s++;
+ }
+ return ret;
+}
+
+int MyStringCompare(const char *s1, const char *s2)
+{
+ while (true)
+ {
+ unsigned char c1 = (unsigned char)*s1++;
+ unsigned char c2 = (unsigned char)*s2++;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ }
+}
+
+int MyStringCompare(const wchar_t *s1, const wchar_t *s2)
+{
+ while (true)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ }
+}
+
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ while (true)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 != c2)
+ {
+ wchar_t u1 = MyCharUpper(c1);
+ wchar_t u2 = MyCharUpper(c2);
+ if (u1 < u2) return -1;
+ if (u1 > u2) return 1;
+ }
+ if (c1 == 0) return 0;
+ }
+}
+
+int MyStringCompareNoCase(const char *s1, const char *s2)
+{
+ return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
+}
+
+
+#ifndef ENV_HAVE_WCHAR__H
+
+EXTERN_C_BEGIN
+
+size_t wcslen(const wchar_t *s)
+{
+ register const wchar_t *p;
+
+ for (p=s ; *p ; p++);
+
+ return p - s;
+}
+
+wchar_t *wcscpy(wchar_t * s1, const wchar_t * s2)
+{
+ register wchar_t *s = s1;
+
+ while ( (*s++ = *s2++) != 0 );
+
+ return s1;
+}
+
+wchar_t *wcscat(wchar_t * s1, const wchar_t * s2)
+{
+ register wchar_t *s = s1;
+
+ while (*s++);
+ --s;
+ while ((*s++ = *s2++) != 0);
+
+ return s1;
+}
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyString.h b/src/libs/7zip/unix/CPP/Common/MyString.h
new file mode 100644
index 000000000..3daa137d0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyString.h
@@ -0,0 +1,601 @@
+// Common/String.h
+
+#ifndef __COMMON_STRING_H
+#define __COMMON_STRING_H
+
+#include <string.h>
+// #include <wchar.h>
+
+#include "MyVector.h"
+
+LPSTR WINAPI CharNextA( LPCSTR ptr );
+LPSTR WINAPI CharPrevA( LPCSTR start, LPCSTR ptr );
+
+template <class T>
+inline int MyStringLen(const T *s)
+{
+ int i;
+ for (i = 0; s[i] != '\0'; i++);
+ return i;
+}
+
+template <class T>
+inline T * MyStringCopy(T *dest, const T *src)
+{
+ T *destStart = dest;
+ while ((*dest++ = *src++) != 0);
+ return destStart;
+}
+
+inline wchar_t* MyStringGetNextCharPointer(wchar_t *p)
+ { return (p + 1); }
+inline const wchar_t* MyStringGetNextCharPointer(const wchar_t *p)
+ { return (p + 1); }
+inline wchar_t* MyStringGetPrevCharPointer(const wchar_t *, wchar_t *p)
+ { return (p - 1); }
+inline const wchar_t* MyStringGetPrevCharPointer(const wchar_t *, const wchar_t *p)
+ { return (p - 1); }
+
+wchar_t MyCharUpper(wchar_t c);
+char * MyStringUpper(char *s);
+wchar_t * MyStringUpper(wchar_t *s);
+
+char MyCharLower(char c);
+char * MyStringLower(char *s);
+wchar_t MyCharLower(wchar_t c);
+wchar_t * MyStringLower(wchar_t *s);
+
+
+inline char* MyStringGetPrevCharPointer(char *base, char *p)
+ { return CharPrevA(base, p); }
+inline const char* MyStringGetPrevCharPointer(const char *base, const char *p)
+ { return CharPrevA(base, p); }
+inline char* MyStringGetNextCharPointer(char *p)
+ { return CharNextA(p); }
+inline const char* MyStringGetNextCharPointer(const char *p)
+ { return CharNextA(p); }
+
+//////////////////////////////////////
+// Compare
+
+/*
+#ifndef _WIN32_WCE
+int MyStringCollate(const char *s1, const char *s2);
+int MyStringCollateNoCase(const char *s1, const char *s2);
+#endif
+int MyStringCollate(const wchar_t *s1, const wchar_t *s2);
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2);
+*/
+
+int MyStringCompare(const char *s1, const char *s2);
+int MyStringCompare(const wchar_t *s1, const wchar_t *s2);
+
+// int MyStringCompareNoCase(const char *s1, const char *s2);
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2);
+
+template <class T>
+class CStringBase
+{
+ void TrimLeftWithCharSet(const CStringBase &charSet)
+ {
+ const T *p = _chars;
+ while (charSet.Find(*p) >= 0 && (*p != 0))
+ p = GetNextCharPointer(p);
+ Delete(0, (int)(p - _chars));
+ }
+ void TrimRightWithCharSet(const CStringBase &charSet)
+ {
+ const T *p = _chars;
+ const T *pLast = NULL;
+ while (*p != 0)
+ {
+ if (charSet.Find(*p) >= 0)
+ {
+ if (pLast == NULL)
+ pLast = p;
+ }
+ else
+ pLast = NULL;
+ p = GetNextCharPointer(p);
+ }
+ if (pLast != NULL)
+ {
+ int i = (int)(pLast - _chars);
+ Delete(i, _length - i);
+ }
+
+ }
+ void MoveItems(int destIndex, int srcIndex)
+ {
+ memmove(_chars + destIndex, _chars + srcIndex,
+ sizeof(T) * (_length - srcIndex + 1));
+ }
+
+ void InsertSpace(int &index, int size)
+ {
+ CorrectIndex(index);
+ GrowLength(size);
+ MoveItems(index + size, index);
+ }
+
+ static T *GetNextCharPointer(T *p)
+ { return MyStringGetNextCharPointer(p); }
+ static const T *GetNextCharPointer(const T *p)
+ { return MyStringGetNextCharPointer(p); }
+ static T *GetPrevCharPointer(T *base, T *p)
+ { return MyStringGetPrevCharPointer(base, p); }
+ static const T *GetPrevCharPointer(const T *base, const T *p)
+ { return MyStringGetPrevCharPointer(base, p); }
+protected:
+ T *_chars;
+ int _length;
+ int _capacity;
+
+ void SetCapacity(int newCapacity)
+ {
+ int realCapacity = newCapacity + 1;
+ if (realCapacity == _capacity)
+ return;
+ /*
+ const int kMaxStringSize = 0x20000000;
+ #ifndef _WIN32_WCE
+ if (newCapacity > kMaxStringSize || newCapacity < _length)
+ throw 1052337;
+ #endif
+ */
+ T *newBuffer = new T[realCapacity];
+ if (_capacity > 0)
+ {
+ for (int i = 0; i < _length; i++)
+ newBuffer[i] = _chars[i];
+ delete []_chars;
+ }
+ _chars = newBuffer;
+ _chars[_length] = 0;
+ _capacity = realCapacity;
+ }
+
+ void GrowLength(int n)
+ {
+ int freeSize = _capacity - _length - 1;
+ if (n <= freeSize)
+ return;
+ int delta;
+ if (_capacity > 64)
+ delta = _capacity / 2;
+ else if (_capacity > 8)
+ delta = 16;
+ else
+ delta = 4;
+ if (freeSize + delta < n)
+ delta = n - freeSize;
+ SetCapacity(_capacity + delta);
+ }
+
+ void CorrectIndex(int &index) const
+ {
+ if (index > _length)
+ index = _length;
+ }
+
+public:
+ CStringBase(): _chars(0), _length(0), _capacity(0) { SetCapacity(3); }
+ CStringBase(T c): _chars(0), _length(0), _capacity(0)
+ {
+ SetCapacity(1);
+ _chars[0] = c;
+ _chars[1] = 0;
+ _length = 1;
+ }
+ CStringBase(const T *chars): _chars(0), _length(0), _capacity(0)
+ {
+ int length = MyStringLen(chars);
+ SetCapacity(length);
+ MyStringCopy(_chars, chars); // can be optimized by memove()
+ _length = length;
+ }
+ CStringBase(const CStringBase &s): _chars(0), _length(0), _capacity(0)
+ {
+ SetCapacity(s._length);
+ MyStringCopy(_chars, s._chars);
+ _length = s._length;
+ }
+ ~CStringBase() { delete []_chars; }
+
+ operator const T*() const { return _chars;}
+
+ T Back() const { return _chars[_length - 1]; }
+
+ // The minimum size of the character buffer in characters.
+ // This value does not include space for a null terminator.
+ T* GetBuffer(int minBufLength)
+ {
+ if (minBufLength >= _capacity)
+ SetCapacity(minBufLength);
+ return _chars;
+ }
+ void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); }
+ void ReleaseBuffer(int newLength)
+ {
+ /*
+ #ifndef _WIN32_WCE
+ if (newLength >= _capacity)
+ throw 282217;
+ #endif
+ */
+ _chars[newLength] = 0;
+ _length = newLength;
+ }
+
+ CStringBase& operator=(T c)
+ {
+ Empty();
+ SetCapacity(1);
+ _chars[0] = c;
+ _chars[1] = 0;
+ _length = 1;
+ return *this;
+ }
+ CStringBase& operator=(const T *chars)
+ {
+ Empty();
+ int length = MyStringLen(chars);
+ SetCapacity(length);
+ MyStringCopy(_chars, chars);
+ _length = length;
+ return *this;
+ }
+ CStringBase& operator=(const CStringBase& s)
+ {
+ if (&s == this)
+ return *this;
+ Empty();
+ SetCapacity(s._length);
+ MyStringCopy(_chars, s._chars);
+ _length = s._length;
+ return *this;
+ }
+
+ CStringBase& operator+=(T c)
+ {
+ GrowLength(1);
+ _chars[_length] = c;
+ _chars[++_length] = 0;
+ return *this;
+ }
+ CStringBase& operator+=(const T *s)
+ {
+ int len = MyStringLen(s);
+ GrowLength(len);
+ MyStringCopy(_chars + _length, s);
+ _length += len;
+ return *this;
+ }
+ CStringBase& operator+=(const CStringBase &s)
+ {
+ GrowLength(s._length);
+ MyStringCopy(_chars + _length, s._chars);
+ _length += s._length;
+ return *this;
+ }
+ void Empty()
+ {
+ _length = 0;
+ _chars[0] = 0;
+ }
+ int Length() const { return _length; }
+ bool IsEmpty() const { return (_length == 0); }
+
+ CStringBase Mid(int startIndex) const
+ { return Mid(startIndex, _length - startIndex); }
+ CStringBase Mid(int startIndex, int count ) const
+ {
+ if (startIndex + count > _length)
+ count = _length - startIndex;
+
+ if (startIndex == 0 && startIndex + count == _length)
+ return *this;
+
+ CStringBase<T> result;
+ result.SetCapacity(count);
+ // MyStringNCopy(result._chars, _chars + startIndex, count);
+ for (int i = 0; i < count; i++)
+ result._chars[i] = _chars[startIndex + i];
+ result._chars[count] = 0;
+ result._length = count;
+ return result;
+ }
+ CStringBase Left(int count) const
+ { return Mid(0, count); }
+ CStringBase Right(int count) const
+ {
+ if (count > _length)
+ count = _length;
+ return Mid(_length - count, count);
+ }
+
+ void MakeUpper()
+ { MyStringUpper(_chars); }
+ void MakeLower()
+ { MyStringLower(_chars); }
+
+ int Compare(const CStringBase& s) const
+ { return MyStringCompare(_chars, s._chars); }
+
+ int Compare(const T *s) const
+ { return MyStringCompare(_chars, s); }
+
+ int CompareNoCase(const CStringBase& s) const
+ { return MyStringCompareNoCase(_chars, s._chars); }
+
+ int CompareNoCase(const T *s) const
+ { return MyStringCompareNoCase(_chars, s); }
+
+ /*
+ int Collate(const CStringBase& s) const
+ { return MyStringCollate(_chars, s._chars); }
+ int CollateNoCase(const CStringBase& s) const
+ { return MyStringCollateNoCase(_chars, s._chars); }
+ */
+
+ int Find(T c) const { return Find(c, 0); }
+ int Find(T c, int startIndex) const
+ {
+ T *p = _chars + startIndex;
+ for (;;)
+ {
+ if (*p == c)
+ return (int)(p - _chars);
+ if (*p == 0)
+ return -1;
+ p = GetNextCharPointer(p);
+ }
+ }
+ int Find(const CStringBase &s) const { return Find(s, 0); }
+ int Find(const CStringBase &s, int startIndex) const
+ {
+ if (s.IsEmpty())
+ return startIndex;
+ for (; startIndex < _length; startIndex++)
+ {
+ int j;
+ for (j = 0; j < s._length && startIndex + j < _length; j++)
+ if (_chars[startIndex+j] != s._chars[j])
+ break;
+ if (j == s._length)
+ return startIndex;
+ }
+ return -1;
+ }
+ int ReverseFind(T c) const
+ {
+ if (_length == 0)
+ return -1;
+ T *p = _chars + _length - 1;
+ for (;;)
+ {
+ if (*p == c)
+ return (int)(p - _chars);
+ if (p == _chars)
+ return -1;
+ p = GetPrevCharPointer(_chars, p);
+ }
+ }
+ int FindOneOf(const CStringBase &s) const
+ {
+ for (int i = 0; i < _length; i++)
+ if (s.Find(_chars[i]) >= 0)
+ return i;
+ return -1;
+ }
+
+ void TrimLeft(T c)
+ {
+ const T *p = _chars;
+ while (c == *p)
+ p = GetNextCharPointer(p);
+ Delete(0, p - _chars);
+ }
+ private:
+ CStringBase GetTrimDefaultCharSet()
+ {
+ CStringBase<T> charSet;
+ charSet += (T)' ';
+ charSet += (T)'\n';
+ charSet += (T)'\t';
+ return charSet;
+ }
+ public:
+
+ void TrimLeft()
+ {
+ TrimLeftWithCharSet(GetTrimDefaultCharSet());
+ }
+ void TrimRight()
+ {
+ TrimRightWithCharSet(GetTrimDefaultCharSet());
+ }
+ void TrimRight(T c)
+ {
+ const T *p = _chars;
+ const T *pLast = NULL;
+ while (*p != 0)
+ {
+ if (*p == c)
+ {
+ if (pLast == NULL)
+ pLast = p;
+ }
+ else
+ pLast = NULL;
+ p = GetNextCharPointer(p);
+ }
+ if (pLast != NULL)
+ {
+ int i = pLast - _chars;
+ Delete(i, _length - i);
+ }
+ }
+ void Trim()
+ {
+ TrimRight();
+ TrimLeft();
+ }
+
+ int Insert(int index, T c)
+ {
+ InsertSpace(index, 1);
+ _chars[index] = c;
+ _length++;
+ return _length;
+ }
+ int Insert(int index, const CStringBase &s)
+ {
+ CorrectIndex(index);
+ if (s.IsEmpty())
+ return _length;
+ int numInsertChars = s.Length();
+ InsertSpace(index, numInsertChars);
+ for (int i = 0; i < numInsertChars; i++)
+ _chars[index + i] = s[i];
+ _length += numInsertChars;
+ return _length;
+ }
+
+ // !!!!!!!!!!!!!!! test it if newChar = '\0'
+ int Replace(T oldChar, T newChar)
+ {
+ if (oldChar == newChar)
+ return 0;
+ int number = 0;
+ int pos = 0;
+ while (pos < Length())
+ {
+ pos = Find(oldChar, pos);
+ if (pos < 0)
+ break;
+ _chars[pos] = newChar;
+ pos++;
+ number++;
+ }
+ return number;
+ }
+ int Replace(const CStringBase &oldString, const CStringBase &newString)
+ {
+ if (oldString.IsEmpty())
+ return 0;
+ if (oldString == newString)
+ return 0;
+ int oldStringLength = oldString.Length();
+ int newStringLength = newString.Length();
+ int number = 0;
+ int pos = 0;
+ while (pos < _length)
+ {
+ pos = Find(oldString, pos);
+ if (pos < 0)
+ break;
+ Delete(pos, oldStringLength);
+ Insert(pos, newString);
+ pos += newStringLength;
+ number++;
+ }
+ return number;
+ }
+ int Delete(int index, int count = 1 )
+ {
+ if (index + count > _length)
+ count = _length - index;
+ if (count > 0)
+ {
+ MoveItems(index, index + count);
+ _length -= count;
+ }
+ return _length;
+ }
+ void DeleteBack() { Delete(_length - 1); }
+};
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s1, const CStringBase<T>& s2)
+{
+ CStringBase<T> result(s1);
+ result += s2;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s, T c)
+{
+ CStringBase<T> result(s);
+ result += c;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(T c, const CStringBase<T>& s)
+{
+ CStringBase<T> result(c);
+ result += s;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s, const T * chars)
+{
+ CStringBase<T> result(s);
+ result += chars;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const T * chars, const CStringBase<T>& s)
+{
+ CStringBase<T> result(chars);
+ result += s;
+ return result;
+}
+
+template <class T>
+bool operator==(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) == 0); }
+
+template <class T>
+bool operator<(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) < 0); }
+
+template <class T>
+bool operator==(const T *s1, const CStringBase<T>& s2)
+ { return (s2.Compare(s1) == 0); }
+
+template <class T>
+bool operator==(const CStringBase<T>& s1, const T *s2)
+ { return (s1.Compare(s2) == 0); }
+
+template <class T>
+bool operator!=(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) != 0); }
+
+template <class T>
+bool operator!=(const T *s1, const CStringBase<T>& s2)
+ { return (s2.Compare(s1) != 0); }
+
+template <class T>
+bool operator!=(const CStringBase<T>& s1, const T *s2)
+ { return (s1.Compare(s2) != 0); }
+
+typedef CStringBase<char> AString;
+typedef CStringBase<wchar_t> UString;
+
+typedef CObjectVector<AString> AStringVector;
+typedef CObjectVector<UString> UStringVector;
+
+#ifdef _UNICODE
+ typedef UString CSysString;
+#else
+ typedef AString CSysString;
+#endif
+
+typedef CObjectVector<CSysString> CSysStringVector;
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyUnknown.h b/src/libs/7zip/unix/CPP/Common/MyUnknown.h
new file mode 100644
index 000000000..e9e8666b9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyUnknown.h
@@ -0,0 +1,13 @@
+// MyUnknown.h
+
+#ifndef __MY_UNKNOWN_H
+#define __MY_UNKNOWN_H
+
+#ifdef _WIN32
+#include <basetyps.h>
+#include <unknwn.h>
+#else
+#include "MyWindows.h"
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyVector.cpp b/src/libs/7zip/unix/CPP/Common/MyVector.cpp
new file mode 100644
index 000000000..3b5317688
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyVector.cpp
@@ -0,0 +1,87 @@
+// Common/MyVector.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "MyVector.h"
+
+CBaseRecordVector::~CBaseRecordVector() { ClearAndFree(); }
+
+void CBaseRecordVector::ClearAndFree()
+{
+ Clear();
+ delete []((unsigned char *)_items);
+ _capacity = 0;
+ _size = 0;
+ _items = 0;
+}
+
+void CBaseRecordVector::Clear() { DeleteFrom(0); }
+void CBaseRecordVector::DeleteBack() { Delete(_size - 1); }
+void CBaseRecordVector::DeleteFrom(int index) { Delete(index, _size - index); }
+
+void CBaseRecordVector::ReserveOnePosition()
+{
+ if (_size != _capacity)
+ return;
+ unsigned delta = 1;
+ if (_capacity >= 64)
+ delta = (unsigned)_capacity / 4;
+ else if (_capacity >= 8)
+ delta = 8;
+ Reserve(_capacity + (int)delta);
+}
+
+void CBaseRecordVector::Reserve(int newCapacity)
+{
+ // if (newCapacity <= _capacity)
+ if (newCapacity == _capacity)
+ return;
+ if ((unsigned)newCapacity >= ((unsigned)1 << (sizeof(unsigned) * 8 - 1)))
+ throw 1052353;
+ size_t newSize = (size_t)(unsigned)newCapacity * _itemSize;
+ if (newSize / _itemSize != (size_t)(unsigned)newCapacity)
+ throw 1052354;
+ unsigned char *p = NULL;
+ if (newSize > 0)
+ {
+ p = new unsigned char[newSize];
+ if (p == 0)
+ throw 1052355;
+ int numRecordsToMove = (_size < newCapacity ? _size : newCapacity);
+ memcpy(p, _items, _itemSize * numRecordsToMove);
+ }
+ delete [](unsigned char *)_items;
+ _items = p;
+ _capacity = newCapacity;
+}
+
+void CBaseRecordVector::ReserveDown()
+{
+ Reserve(_size);
+}
+
+void CBaseRecordVector::MoveItems(int destIndex, int srcIndex)
+{
+ memmove(((unsigned char *)_items) + destIndex * _itemSize,
+ ((unsigned char *)_items) + srcIndex * _itemSize,
+ _itemSize * (_size - srcIndex));
+}
+
+void CBaseRecordVector::InsertOneItem(int index)
+{
+ ReserveOnePosition();
+ MoveItems(index + 1, index);
+ _size++;
+}
+
+void CBaseRecordVector::Delete(int index, int num)
+{
+ TestIndexAndCorrectNum(index, num);
+ if (num > 0)
+ {
+ MoveItems(index, index + num);
+ _size -= num;
+ }
+}
diff --git a/src/libs/7zip/unix/CPP/Common/MyVector.h b/src/libs/7zip/unix/CPP/Common/MyVector.h
new file mode 100644
index 000000000..781b648bc
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyVector.h
@@ -0,0 +1,266 @@
+// Common/Vector.h
+
+#ifndef __COMMON_VECTOR_H
+#define __COMMON_VECTOR_H
+
+#include "Defs.h"
+
+class CBaseRecordVector
+{
+ void MoveItems(int destIndex, int srcIndex);
+protected:
+ int _capacity;
+ int _size;
+ void *_items;
+ size_t _itemSize;
+
+ void ReserveOnePosition();
+ void InsertOneItem(int index);
+ void TestIndexAndCorrectNum(int index, int &num) const
+ { if (index + num > _size) num = _size - index; }
+public:
+ CBaseRecordVector(size_t itemSize): _capacity(0), _size(0), _items(0), _itemSize(itemSize) {}
+ virtual ~CBaseRecordVector();
+ void ClearAndFree();
+ int Size() const { return _size; }
+ bool IsEmpty() const { return (_size == 0); }
+ void Reserve(int newCapacity);
+ void ReserveDown();
+ virtual void Delete(int index, int num = 1);
+ void Clear();
+ void DeleteFrom(int index);
+ void DeleteBack();
+};
+
+template <class T>
+class CRecordVector: public CBaseRecordVector
+{
+public:
+ CRecordVector(): CBaseRecordVector(sizeof(T)){};
+ CRecordVector(const CRecordVector &v): CBaseRecordVector(sizeof(T)) { *this = v; }
+ CRecordVector& operator=(const CRecordVector &v)
+ {
+ Clear();
+ return (*this += v);
+ }
+ CRecordVector& operator+=(const CRecordVector &v)
+ {
+ int size = v.Size();
+ Reserve(Size() + size);
+ for (int i = 0; i < size; i++)
+ Add(v[i]);
+ return *this;
+ }
+ int Add(T item)
+ {
+ ReserveOnePosition();
+ ((T *)_items)[_size] = item;
+ return _size++;
+ }
+ void Insert(int index, T item)
+ {
+ InsertOneItem(index);
+ ((T *)_items)[index] = item;
+ }
+ // T* GetPointer() const { return (T*)_items; }
+ // operator const T *() const { return _items; };
+ const T& operator[](int index) const { return ((T *)_items)[index]; }
+ T& operator[](int index) { return ((T *)_items)[index]; }
+ const T& Front() const { return operator[](0); }
+ T& Front() { return operator[](0); }
+ const T& Back() const { return operator[](_size - 1); }
+ T& Back() { return operator[](_size - 1); }
+
+ void Swap(int i, int j)
+ {
+ T temp = operator[](i);
+ operator[](i) = operator[](j);
+ operator[](j) = temp;
+ }
+
+ int FindInSorted(const T& item, int left, int right) const
+ {
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+ int FindInSorted(const T& item) const
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+ int AddToUniqueSorted(const T& item)
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+
+ static void SortRefDown(T* p, int k, int size, int (*compare)(const T*, const T*, void *), void *param)
+ {
+ T temp = p[k];
+ for (;;)
+ {
+ int s = (k << 1);
+ if (s > size)
+ break;
+ if (s < size && compare(p + s + 1, p + s, param) > 0)
+ s++;
+ if (compare(&temp, p + s, param) >= 0)
+ break;
+ p[k] = p[s];
+ k = s;
+ }
+ p[k] = temp;
+ }
+
+ void Sort(int (*compare)(const T*, const T*, void *), void *param)
+ {
+ int size = _size;
+ if (size <= 1)
+ return;
+ T* p = (&Front()) - 1;
+ {
+ int i = size / 2;
+ do
+ SortRefDown(p, i, size, compare, param);
+ while (--i != 0);
+ }
+ do
+ {
+ T temp = p[size];
+ p[size--] = p[1];
+ p[1] = temp;
+ SortRefDown(p, 1, size, compare, param);
+ }
+ while (size > 1);
+ }
+};
+
+typedef CRecordVector<int> CIntVector;
+typedef CRecordVector<unsigned int> CUIntVector;
+typedef CRecordVector<bool> CBoolVector;
+typedef CRecordVector<unsigned char> CByteVector;
+typedef CRecordVector<void *> CPointerVector;
+
+template <class T>
+class CObjectVector: public CPointerVector
+{
+public:
+ CObjectVector() {};
+ ~CObjectVector() { Clear(); };
+ CObjectVector(const CObjectVector &v): CPointerVector() { *this = v; }
+ CObjectVector& operator=(const CObjectVector &v)
+ {
+ Clear();
+ return (*this += v);
+ }
+ CObjectVector& operator+=(const CObjectVector &v)
+ {
+ int size = v.Size();
+ Reserve(Size() + size);
+ for (int i = 0; i < size; i++)
+ Add(v[i]);
+ return *this;
+ }
+ const T& operator[](int index) const { return *((T *)CPointerVector::operator[](index)); }
+ T& operator[](int index) { return *((T *)CPointerVector::operator[](index)); }
+ T& Front() { return operator[](0); }
+ const T& Front() const { return operator[](0); }
+ T& Back() { return operator[](_size - 1); }
+ const T& Back() const { return operator[](_size - 1); }
+ int Add(const T& item) { return CPointerVector::Add(new T(item)); }
+ void Insert(int index, const T& item) { CPointerVector::Insert(index, new T(item)); }
+ virtual void Delete(int index, int num = 1)
+ {
+ TestIndexAndCorrectNum(index, num);
+ for (int i = 0; i < num; i++)
+ delete (T *)(((void **)_items)[index + i]);
+ CPointerVector::Delete(index, num);
+ }
+ int Find(const T& item) const
+ {
+ for (int i = 0; i < Size(); i++)
+ if (item == (*this)[i])
+ return i;
+ return -1;
+ }
+ int FindInSorted(const T& item) const
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+ int AddToSorted(const T& item)
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ {
+ right = mid + 1;
+ break;
+ }
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+
+ void Sort(int (*compare)(void *const *, void *const *, void *), void *param)
+ { CPointerVector::Sort(compare, param); }
+
+ static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */)
+ { return MyCompare(*(*((const T **)a1)), *(*((const T **)a2))); }
+ void Sort() { CPointerVector::Sort(CompareObjectItems, 0); }
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyWindows.cpp b/src/libs/7zip/unix/CPP/Common/MyWindows.cpp
new file mode 100644
index 000000000..bee4acd47
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyWindows.cpp
@@ -0,0 +1,111 @@
+// MyWindows.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+
+#include "MyWindows.h"
+#include "Types.h"
+#include <stdlib.h> /* FIXED <malloc.h> */
+
+static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); }
+static inline void FreeForBSTR(void *pv) { ::free(pv);}
+
+static UINT MyStringLen(const wchar_t *s)
+{
+ UINT i;
+ for (i = 0; s[i] != '\0'; i++);
+ return i;
+}
+
+BSTR SysAllocStringByteLen(LPCSTR psz, UINT len)
+{
+ // FIXED int realLen = len + sizeof(UINT) + 3;
+ const int LEN_ADDON = sizeof(wchar_t) - 1;
+ int realLen = len + sizeof(UINT) + sizeof(wchar_t) + LEN_ADDON;
+ void *p = AllocateForBSTR(realLen);
+ if (p == 0)
+ return 0;
+ *(UINT *)p = len;
+ // "void *" instead of "BSTR" to avoid unaligned copy of "wchar_t" because of optimizer on Solaris
+ void * bstr = (void *)((UINT *)p + 1);
+ if (psz) memmove(bstr, psz, len); // psz does not always have "wchar_t" alignment.
+ void *pb = (void *)(((Byte *)bstr) + len);
+ memset(pb,0,sizeof(wchar_t) + LEN_ADDON);
+ return (BSTR)bstr;
+}
+
+BSTR SysAllocString(const OLECHAR *sz)
+{
+ if (sz == 0)
+ return 0;
+ UINT strLen = MyStringLen(sz);
+ UINT len = (strLen + 1) * sizeof(OLECHAR);
+ void *p = AllocateForBSTR(len + sizeof(UINT));
+ if (p == 0)
+ return 0;
+ *(UINT *)p = strLen * sizeof(OLECHAR); // FIXED
+ void * bstr = (void *)((UINT *)p + 1);
+ memmove(bstr, sz, len); // sz does not always have "wchar_t" alignment.
+ return (BSTR)bstr;
+}
+
+void SysFreeString(BSTR bstr)
+{
+ if (bstr != 0)
+ FreeForBSTR((UINT *)bstr - 1);
+}
+
+UINT SysStringByteLen(BSTR bstr)
+{
+ if (bstr == 0)
+ return 0;
+ return *((UINT *)bstr - 1);
+
+}
+
+UINT SysStringLen(BSTR bstr)
+{
+ return SysStringByteLen(bstr) / sizeof(OLECHAR);
+}
+
+HRESULT VariantClear(VARIANTARG *prop)
+{
+ if (prop->vt == VT_BSTR)
+ SysFreeString(prop->bstrVal);
+ prop->vt = VT_EMPTY;
+ return S_OK;
+}
+
+HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src)
+{
+ HRESULT res = ::VariantClear(dest);
+ if (res != S_OK)
+ return res;
+ if (src->vt == VT_BSTR)
+ {
+ dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal,
+ SysStringByteLen(src->bstrVal));
+ if (dest->bstrVal == 0)
+ return E_OUTOFMEMORY;
+ dest->vt = VT_BSTR;
+ }
+ else
+ *dest = *src;
+ return S_OK;
+}
+
+LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2)
+{
+ if(ft1->dwHighDateTime < ft2->dwHighDateTime)
+ return -1;
+ if(ft1->dwHighDateTime > ft2->dwHighDateTime)
+ return 1;
+ if(ft1->dwLowDateTime < ft2->dwLowDateTime)
+ return -1;
+ if(ft1->dwLowDateTime > ft2->dwLowDateTime)
+ return 1;
+ return 0;
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyWindows.h b/src/libs/7zip/unix/CPP/Common/MyWindows.h
new file mode 100644
index 000000000..d91f10f1b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyWindows.h
@@ -0,0 +1,218 @@
+// MyWindows.h
+
+#ifndef __MYWINDOWS_H
+#define __MYWINDOWS_H
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+#else
+
+#include <stddef.h> // for wchar_t
+#include <string.h>
+
+#include "MyGuidDef.h"
+
+typedef char CHAR;
+typedef unsigned char UCHAR;
+
+#undef BYTE
+typedef unsigned char BYTE;
+
+typedef short SHORT;
+typedef unsigned short USHORT;
+
+#undef WORD
+typedef unsigned short WORD;
+typedef short VARIANT_BOOL;
+
+typedef int INT;
+typedef Int32 INT32;
+typedef unsigned int UINT;
+typedef UInt32 UINT32;
+typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit
+typedef UINT32 ULONG;
+
+#undef DWORD
+typedef UINT32 DWORD;
+
+typedef Int64 LONGLONG;
+typedef UInt64 ULONGLONG;
+
+typedef struct LARGE_INTEGER { LONGLONG QuadPart; }LARGE_INTEGER;
+typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart;} ULARGE_INTEGER;
+
+typedef const CHAR *LPCSTR;
+
+typedef wchar_t WCHAR;
+
+#ifdef _UNICODE
+typedef WCHAR TCHAR;
+#define lstrcpy wcscpy
+#define lstrcat wcscat
+#define lstrlen wcslen
+#else
+typedef CHAR TCHAR;
+#define lstrcpy strcpy
+#define lstrcat strcat
+#define lstrlen strlen
+#endif
+#define _wcsicmp(str1,str2) MyStringCompareNoCase(str1,str2)
+
+typedef const TCHAR *LPCTSTR;
+typedef WCHAR OLECHAR;
+typedef const WCHAR *LPCWSTR;
+typedef OLECHAR *BSTR;
+typedef const OLECHAR *LPCOLESTR;
+typedef OLECHAR *LPOLESTR;
+
+typedef struct _FILETIME
+{
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+}FILETIME;
+
+#define HRESULT LONG
+#define FAILED(Status) ((HRESULT)(Status)<0)
+typedef ULONG PROPID;
+typedef LONG SCODE;
+
+#define S_OK ((HRESULT)0x00000000L)
+#define S_FALSE ((HRESULT)0x00000001L)
+#define E_NOTIMPL ((HRESULT)0x80004001L)
+#define E_NOINTERFACE ((HRESULT)0x80004002L)
+#define E_ABORT ((HRESULT)0x80004004L)
+#define E_FAIL ((HRESULT)0x80004005L)
+#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L)
+#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
+#define E_INVALIDARG ((HRESULT)0x80070057L)
+
+#ifdef _MSC_VER
+#define STDMETHODCALLTYPE __stdcall
+#else
+#define STDMETHODCALLTYPE
+#endif
+
+#define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f
+#define STDMETHOD(f) STDMETHOD_(HRESULT, f)
+#define STDMETHODIMP_(type) type STDMETHODCALLTYPE
+#define STDMETHODIMP STDMETHODIMP_(HRESULT)
+
+#define PURE = 0
+
+#define MIDL_INTERFACE(x) struct
+
+#ifdef __cplusplus
+
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+struct IUnknown
+{
+ STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE;
+ STDMETHOD_(ULONG, AddRef)() PURE;
+ STDMETHOD_(ULONG, Release)() PURE;
+ #ifndef _WIN32
+ virtual ~IUnknown() {}
+ #endif
+};
+
+typedef IUnknown *LPUNKNOWN;
+
+#endif
+
+#define VARIANT_TRUE ((VARIANT_BOOL)-1)
+#define VARIANT_FALSE ((VARIANT_BOOL)0)
+
+enum VARENUM
+{
+ VT_EMPTY = 0,
+ VT_NULL = 1,
+ VT_I2 = 2,
+ VT_I4 = 3,
+ VT_R4 = 4,
+ VT_R8 = 5,
+ VT_CY = 6,
+ VT_DATE = 7,
+ VT_BSTR = 8,
+ VT_DISPATCH = 9,
+ VT_ERROR = 10,
+ VT_BOOL = 11,
+ VT_VARIANT = 12,
+ VT_UNKNOWN = 13,
+ VT_DECIMAL = 14,
+ VT_I1 = 16,
+ VT_UI1 = 17,
+ VT_UI2 = 18,
+ VT_UI4 = 19,
+ VT_I8 = 20,
+ VT_UI8 = 21,
+ VT_INT = 22,
+ VT_UINT = 23,
+ VT_VOID = 24,
+ VT_HRESULT = 25,
+ VT_FILETIME = 64
+};
+
+typedef unsigned short VARTYPE;
+typedef WORD PROPVAR_PAD1;
+typedef WORD PROPVAR_PAD2;
+typedef WORD PROPVAR_PAD3;
+
+#ifdef __cplusplus
+
+typedef struct tagPROPVARIANT
+{
+ VARTYPE vt;
+ PROPVAR_PAD1 wReserved1;
+ PROPVAR_PAD2 wReserved2;
+ PROPVAR_PAD3 wReserved3;
+ union
+ {
+ CHAR cVal;
+ UCHAR bVal;
+ SHORT iVal;
+ USHORT uiVal;
+ LONG lVal;
+ ULONG ulVal;
+ INT intVal;
+ UINT uintVal;
+ LARGE_INTEGER hVal;
+ ULARGE_INTEGER uhVal;
+ VARIANT_BOOL boolVal;
+ SCODE scode;
+ FILETIME filetime;
+ BSTR bstrVal;
+ };
+} PROPVARIANT;
+
+typedef PROPVARIANT tagVARIANT;
+typedef tagVARIANT VARIANT;
+typedef VARIANT VARIANTARG;
+
+MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop);
+MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src);
+
+#endif
+
+MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len);
+MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz);
+MY_EXTERN_C void SysFreeString(BSTR bstr);
+MY_EXTERN_C UINT SysStringByteLen(BSTR bstr);
+MY_EXTERN_C UINT SysStringLen(BSTR bstr);
+
+/* MY_EXTERN_C DWORD GetLastError(); */
+MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2);
+
+#define CP_ACP 0
+#define CP_OEMCP 1
+
+typedef enum tagSTREAM_SEEK
+{
+ STREAM_SEEK_SET = 0,
+ STREAM_SEEK_CUR = 1,
+ STREAM_SEEK_END = 2
+} STREAM_SEEK;
+
+#endif
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/MyXml.cpp b/src/libs/7zip/unix/CPP/Common/MyXml.cpp
new file mode 100644
index 000000000..8aa9ce8cd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyXml.cpp
@@ -0,0 +1,209 @@
+// MyXml.cpp
+
+#include "StdAfx.h"
+
+#include "MyXml.h"
+
+static bool IsValidChar(char c)
+{
+ return
+ c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == '-';
+}
+
+static bool IsSpaceChar(char c)
+{
+ return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A);
+}
+
+#define SKIP_SPACES(s, pos) while (IsSpaceChar(s[pos])) pos++;
+
+static bool ReadProperty(const AString &s, int &pos, CXmlProp &prop)
+{
+ prop.Name.Empty();
+ prop.Value.Empty();
+ for (; pos < s.Length(); pos++)
+ {
+ char c = s[pos];
+ if (!IsValidChar(c))
+ break;
+ prop.Name += c;
+ }
+
+ if (prop.Name.IsEmpty())
+ return false;
+
+ SKIP_SPACES(s, pos);
+ if (s[pos++] != '=')
+ return false;
+
+ SKIP_SPACES(s, pos);
+ if (s[pos++] != '\"')
+ return false;
+
+ while (pos < s.Length())
+ {
+ char c = s[pos++];
+ if (c == '\"')
+ return true;
+ prop.Value += c;
+ }
+ return false;
+}
+
+int CXmlItem::FindProperty(const AString &propName) const
+{
+ for (int i = 0; i < Props.Size(); i++)
+ if (Props[i].Name == propName)
+ return i;
+ return -1;
+}
+
+AString CXmlItem::GetPropertyValue(const AString &propName) const
+{
+ int index = FindProperty(propName);
+ if (index >= 0)
+ return Props[index].Value;
+ return AString();
+}
+
+bool CXmlItem::IsTagged(const AString &tag) const
+{
+ return (IsTag && Name == tag);
+}
+
+int CXmlItem::FindSubTag(const AString &tag) const
+{
+ for (int i = 0; i < SubItems.Size(); i++)
+ if (SubItems[i].IsTagged(tag))
+ return i;
+ return -1;
+}
+
+AString CXmlItem::GetSubString() const
+{
+ if (SubItems.Size() == 1)
+ {
+ const CXmlItem &item = SubItems[0];
+ if (!item.IsTag)
+ return item.Name;
+ }
+ return AString();
+}
+
+AString CXmlItem::GetSubStringForTag(const AString &tag) const
+{
+ int index = FindSubTag(tag);
+ if (index >= 0)
+ return SubItems[index].GetSubString();
+ return AString();
+}
+
+bool CXmlItem::ParseItems(const AString &s, int &pos, int numAllowedLevels)
+{
+ if (numAllowedLevels == 0)
+ return false;
+ SubItems.Clear();
+ AString finishString = "</";
+ for (;;)
+ {
+ SKIP_SPACES(s, pos);
+
+ if (s.Mid(pos, finishString.Length()) == finishString)
+ return true;
+
+ CXmlItem item;
+ if (!item.ParseItem(s, pos, numAllowedLevels - 1))
+ return false;
+ SubItems.Add(item);
+ }
+}
+
+bool CXmlItem::ParseItem(const AString &s, int &pos, int numAllowedLevels)
+{
+ SKIP_SPACES(s, pos);
+
+ int pos2 = s.Find('<', pos);
+ if (pos2 < 0)
+ return false;
+ if (pos2 != pos)
+ {
+ IsTag = false;
+ Name += s.Mid(pos, pos2 - pos);
+ pos = pos2;
+ return true;
+ }
+ IsTag = true;
+
+ pos++;
+ SKIP_SPACES(s, pos);
+
+ for (; pos < s.Length(); pos++)
+ {
+ char c = s[pos];
+ if (!IsValidChar(c))
+ break;
+ Name += c;
+ }
+ if (Name.IsEmpty() || pos == s.Length())
+ return false;
+
+ int posTemp = pos;
+ for (;;)
+ {
+ SKIP_SPACES(s, pos);
+ if (s[pos] == '/')
+ {
+ pos++;
+ // SKIP_SPACES(s, pos);
+ return (s[pos++] == '>');
+ }
+ if (s[pos] == '>')
+ {
+ if (!ParseItems(s, ++pos, numAllowedLevels))
+ return false;
+ AString finishString = AString("</") + Name + AString(">");
+ if (s.Mid(pos, finishString.Length()) != finishString)
+ return false;
+ pos += finishString.Length();
+ return true;
+ }
+ if (posTemp == pos)
+ return false;
+
+ CXmlProp prop;
+ if (!ReadProperty(s, pos, prop))
+ return false;
+ Props.Add(prop);
+ posTemp = pos;
+ }
+}
+
+static bool SkipHeader(const AString &s, int &pos, const AString &startString, const AString &endString)
+{
+ SKIP_SPACES(s, pos);
+ if (s.Mid(pos, startString.Length()) == startString)
+ {
+ pos = s.Find(endString, pos);
+ if (pos < 0)
+ return false;
+ pos += endString.Length();
+ SKIP_SPACES(s, pos);
+ }
+ return true;
+}
+
+bool CXml::Parse(const AString &s)
+{
+ int pos = 0;
+ if (!SkipHeader(s, pos, "<?xml", "?>"))
+ return false;
+ if (!SkipHeader(s, pos, "<!DOCTYPE", ">"))
+ return false;
+ if (!Root.ParseItem(s, pos, 1000))
+ return false;
+ SKIP_SPACES(s, pos);
+ return (pos == s.Length() && Root.IsTag);
+}
diff --git a/src/libs/7zip/unix/CPP/Common/MyXml.h b/src/libs/7zip/unix/CPP/Common/MyXml.h
new file mode 100644
index 000000000..c6e8829ad
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/MyXml.h
@@ -0,0 +1,40 @@
+// MyXml.h
+
+#ifndef __MYXML_H
+#define __MYXML_H
+
+#include "MyString.h"
+
+struct CXmlProp
+{
+ AString Name;
+ AString Value;
+};
+
+class CXmlItem
+{
+ bool ParseItems(const AString &s, int &pos, int numAllowedLevels);
+
+public:
+ AString Name;
+ bool IsTag;
+ CObjectVector<CXmlProp> Props;
+ CObjectVector<CXmlItem> SubItems;
+
+ bool ParseItem(const AString &s, int &pos, int numAllowedLevels);
+
+ bool IsTagged(const AString &tag) const;
+ int FindProperty(const AString &propName) const;
+ AString GetPropertyValue(const AString &propName) const;
+ AString GetSubString() const;
+ int FindSubTag(const AString &tag) const;
+ AString GetSubStringForTag(const AString &tag) const;
+};
+
+struct CXml
+{
+ CXmlItem Root;
+ bool Parse(const AString &s);
+};
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/NewHandler.h b/src/libs/7zip/unix/CPP/Common/NewHandler.h
new file mode 100644
index 000000000..215ba05f1
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/NewHandler.h
@@ -0,0 +1,16 @@
+// Common/NewHandler.h
+
+#ifndef __COMMON_NEWHANDLER_H
+#define __COMMON_NEWHANDLER_H
+
+class CNewException {};
+
+#ifdef _WIN32
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw();
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/StdInStream.cpp b/src/libs/7zip/unix/CPP/Common/StdInStream.cpp
new file mode 100644
index 000000000..78897e5ef
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/StdInStream.cpp
@@ -0,0 +1,100 @@
+// Common/StdInStream.cpp
+
+#include "StdAfx.h"
+
+#include <tchar.h>
+#include "StdInStream.h"
+
+#ifdef _MSC_VER
+// "was declared deprecated" disabling
+#pragma warning(disable : 4996 )
+#endif
+
+#ifdef _UNICODE
+#include "Common/StringConvert.h"
+#define NEED_NAME_WINDOWS_TO_UNIX
+#include "myPrivate.h"
+#endif
+
+static const char kIllegalChar = '\0';
+static const char kNewLineChar = '\n';
+
+static const char *kEOFMessage = "Unexpected end of input stream";
+static const char *kReadErrorMessage ="Error reading input stream";
+static const char *kIllegalCharMessage = "Illegal character in input stream";
+
+static const char * kFileOpenMode = "r";
+
+CStdInStream g_StdIn(stdin);
+
+bool CStdInStream::Open(LPCTSTR fileName)
+{
+ Close();
+#ifdef _UNICODE
+ AString aStr = UnicodeStringToMultiByte(fileName, CP_ACP); // FIXME
+ const char * name = nameWindowToUnix(aStr);
+#else
+ const char * name = nameWindowToUnix(fileName);
+#endif
+ _stream = fopen(name, kFileOpenMode);
+ _streamIsOpen = (_stream != 0);
+ return _streamIsOpen;
+}
+
+bool CStdInStream::Close()
+{
+ if (!_streamIsOpen)
+ return true;
+ _streamIsOpen = (fclose(_stream) != 0);
+ return !_streamIsOpen;
+}
+
+CStdInStream::~CStdInStream()
+{
+ Close();
+}
+
+AString CStdInStream::ScanStringUntilNewLine(bool allowEOF)
+{
+ AString s;
+ for (;;)
+ {
+ int intChar = GetChar();
+ if (intChar == EOF)
+ {
+ if (allowEOF)
+ break;
+ throw kEOFMessage;
+ }
+ char c = char(intChar);
+ if (c == kIllegalChar)
+ throw kIllegalCharMessage;
+ if (c == kNewLineChar)
+ break;
+ s += c;
+ }
+ return s;
+}
+
+void CStdInStream::ReadToString(AString &resultString)
+{
+ resultString.Empty();
+ int c;
+ while ((c = GetChar()) != EOF)
+ resultString += char(c);
+}
+
+bool CStdInStream::Eof()
+{
+ return (feof(_stream) != 0);
+}
+
+int CStdInStream::GetChar()
+{
+ int c = fgetc(_stream); // getc() doesn't work in BeOS?
+ if (c == EOF && !Eof())
+ throw kReadErrorMessage;
+ return c;
+}
+
+
diff --git a/src/libs/7zip/unix/CPP/Common/StdInStream.h b/src/libs/7zip/unix/CPP/Common/StdInStream.h
new file mode 100644
index 000000000..0d182cc3c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/StdInStream.h
@@ -0,0 +1,32 @@
+// Common/StdInStream.h
+
+#ifndef __COMMON_STDINSTREAM_H
+#define __COMMON_STDINSTREAM_H
+
+#include <stdio.h>
+
+#include "MyString.h"
+#include "Types.h"
+
+class CStdInStream
+{
+ bool _streamIsOpen;
+ FILE *_stream;
+public:
+ CStdInStream(): _streamIsOpen(false) {};
+ CStdInStream(FILE *stream): _streamIsOpen(false), _stream(stream) {};
+ ~CStdInStream();
+ bool Open(LPCTSTR fileName);
+ bool Close();
+
+ AString ScanStringUntilNewLine(bool allowEOF = false);
+ void ReadToString(AString &resultString);
+ UString ScanUStringUntilNewLine();
+
+ bool Eof();
+ int GetChar();
+};
+
+extern CStdInStream g_StdIn;
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/StdOutStream.cpp b/src/libs/7zip/unix/CPP/Common/StdOutStream.cpp
new file mode 100644
index 000000000..b93e255f9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/StdOutStream.cpp
@@ -0,0 +1,93 @@
+// Common/StdOutStream.cpp
+
+#include "StdAfx.h"
+
+#include <tchar.h>
+
+#include "StdOutStream.h"
+#include "IntToString.h"
+#include "StringConvert.h"
+
+#ifdef _MSC_VER
+// "was declared deprecated" disabling
+#pragma warning(disable : 4996 )
+#endif
+
+static const char kNewLineChar = '\n';
+
+static const char *kFileOpenMode = "wt";
+
+CStdOutStream g_StdOut(stdout);
+CStdOutStream g_StdErr(stderr);
+
+bool CStdOutStream::Open(const char *fileName)
+{
+ Close();
+ _stream = fopen(fileName, kFileOpenMode);
+ _streamIsOpen = (_stream != 0);
+ return _streamIsOpen;
+}
+
+bool CStdOutStream::Close()
+{
+ if (!_streamIsOpen)
+ return true;
+ if (fclose(_stream) != 0)
+ return false;
+ _stream = 0;
+ _streamIsOpen = false;
+ return true;
+}
+
+bool CStdOutStream::Flush()
+{
+ return (fflush(_stream) == 0);
+}
+
+CStdOutStream::~CStdOutStream ()
+{
+ Close();
+}
+
+CStdOutStream & CStdOutStream::operator<<(CStdOutStream & (*aFunction)(CStdOutStream &))
+{
+ (*aFunction)(*this);
+ return *this;
+}
+
+CStdOutStream & endl(CStdOutStream & outStream)
+{
+ return outStream << kNewLineChar;
+}
+
+CStdOutStream & CStdOutStream::operator<<(const char *string)
+{
+ fputs(string, _stream);
+ return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(const wchar_t *string)
+{
+ *this << (const char *)UnicodeStringToMultiByte(string, CP_OEMCP);
+ return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(char c)
+{
+ fputc(c, _stream);
+ return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(int number)
+{
+ char textString[32];
+ ConvertInt64ToString(number, textString);
+ return operator<<(textString);
+}
+
+CStdOutStream & CStdOutStream::operator<<(UInt64 number)
+{
+ char textString[32];
+ ConvertUInt64ToString(number, textString);
+ return operator<<(textString);
+}
diff --git a/src/libs/7zip/unix/CPP/Common/StdOutStream.h b/src/libs/7zip/unix/CPP/Common/StdOutStream.h
new file mode 100644
index 000000000..b0b2c615c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/StdOutStream.h
@@ -0,0 +1,35 @@
+// Common/StdOutStream.h
+
+#ifndef __COMMON_STDOUTSTREAM_H
+#define __COMMON_STDOUTSTREAM_H
+
+#include <stdio.h>
+
+#include "Types.h"
+
+class CStdOutStream
+{
+ bool _streamIsOpen;
+ FILE *_stream;
+public:
+ CStdOutStream (): _streamIsOpen(false), _stream(0) {};
+ CStdOutStream (FILE *stream): _streamIsOpen(false), _stream(stream) {};
+ ~CStdOutStream ();
+ operator FILE *() { return _stream; }
+ bool Open(const char *fileName);
+ bool Close();
+ bool Flush();
+ CStdOutStream & operator<<(CStdOutStream & (* aFunction)(CStdOutStream &));
+ CStdOutStream & operator<<(const char *string);
+ CStdOutStream & operator<<(const wchar_t *string);
+ CStdOutStream & operator<<(char c);
+ CStdOutStream & operator<<(int number);
+ CStdOutStream & operator<<(UInt64 number);
+};
+
+CStdOutStream & endl(CStdOutStream & outStream);
+
+extern CStdOutStream g_StdOut;
+extern CStdOutStream g_StdErr;
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/StringConvert.cpp b/src/libs/7zip/unix/CPP/Common/StringConvert.cpp
new file mode 100644
index 000000000..dc7dc2669
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/StringConvert.cpp
@@ -0,0 +1,181 @@
+// Common/StringConvert.cpp
+
+#include "StdAfx.h"
+#include <stdlib.h>
+
+#include "StringConvert.h"
+extern "C"
+{
+int global_use_utf16_conversion = 0;
+}
+
+
+#ifdef LOCALE_IS_UTF8
+
+#ifdef __APPLE_CC__
+#define UInt32 macUIn32
+#include <CoreFoundation/CoreFoundation.h>
+#undef UInt32
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+ if (!srcString.IsEmpty())
+ {
+ UString resultString;
+ const char * path = &srcString[0];
+
+// FIXME size_t n = strlen(path);
+
+ CFStringRef cfpath = CFStringCreateWithCString(NULL,path,kCFStringEncodingUTF8);
+
+ if (cfpath)
+ {
+
+ CFMutableStringRef cfpath2 = CFStringCreateMutableCopy(NULL,0,cfpath);
+ CFRelease(cfpath);
+ CFStringNormalize(cfpath2,kCFStringNormalizationFormC);
+
+ size_t n = CFStringGetLength(cfpath2);
+ for(size_t i = 0 ; i< n ;i++) {
+ resultString += CFStringGetCharacterAtIndex(cfpath2,i);
+ }
+
+ CFRelease(cfpath2);
+
+ return resultString;
+ }
+ }
+
+ UString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ resultString += wchar_t(srcString[i] & 255);
+
+ return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+ if (!srcString.IsEmpty())
+ {
+ const wchar_t * wcs = &srcString[0];
+ char utf8[4096];
+ UniChar unipath[4096];
+
+ size_t n = wcslen(wcs);
+
+ for(size_t i = 0 ; i<= n ;i++) {
+ unipath[i] = wcs[i];
+ }
+
+ CFStringRef cfpath = CFStringCreateWithCharacters(NULL,unipath,n);
+
+ CFMutableStringRef cfpath2 = CFStringCreateMutableCopy(NULL,0,cfpath);
+ CFRelease(cfpath);
+ CFStringNormalize(cfpath2,kCFStringNormalizationFormD);
+
+ CFStringGetCString(cfpath2,(char *)utf8,4096,kCFStringEncodingUTF8);
+
+ CFRelease(cfpath2);
+
+ return AString(utf8);
+ }
+
+ AString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ {
+ if (srcString[i] >= 256) resultString += '?';
+ else resultString += char(srcString[i]);
+ }
+ return resultString;
+}
+
+#else /* __APPLE_CC__ */
+
+
+#include "UTFConvert.h"
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+ if ((global_use_utf16_conversion) && (!srcString.IsEmpty()))
+ {
+ UString resultString;
+ bool bret = ConvertUTF8ToUnicode(srcString,resultString);
+ if (bret) return resultString;
+ }
+
+ UString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ resultString += wchar_t(srcString[i] & 255);
+
+ return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+ if ((global_use_utf16_conversion) && (!srcString.IsEmpty()))
+ {
+ AString resultString;
+ bool bret = ConvertUnicodeToUTF8(srcString,resultString);
+ if (bret) return resultString;
+ }
+
+ AString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ {
+ if (srcString[i] >= 256) resultString += '?';
+ else resultString += char(srcString[i]);
+ }
+ return resultString;
+}
+
+#endif /* __APPLE_CC__ */
+
+#else /* LOCALE_IS_UTF8 */
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT /* codePage */ )
+{
+#ifdef ENV_HAVE_MBSTOWCS
+ if ((global_use_utf16_conversion) && (!srcString.IsEmpty()))
+ {
+ UString resultString;
+ int numChars = mbstowcs(resultString.GetBuffer(srcString.Length()),srcString,srcString.Length()+1);
+ if (numChars >= 0) {
+ resultString.ReleaseBuffer(numChars);
+ return resultString;
+ }
+ }
+#endif
+
+ UString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ resultString += wchar_t(srcString[i] & 255);
+
+ return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT /* codePage */ )
+{
+#ifdef ENV_HAVE_WCSTOMBS
+ if ((global_use_utf16_conversion) && (!srcString.IsEmpty()))
+ {
+ AString resultString;
+ int numRequiredBytes = srcString.Length() * 6+1;
+ int numChars = wcstombs(resultString.GetBuffer(numRequiredBytes),srcString,numRequiredBytes);
+ if (numChars >= 0) {
+ resultString.ReleaseBuffer(numChars);
+ return resultString;
+ }
+ }
+#endif
+
+ AString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ {
+ if (srcString[i] >= 256) resultString += '?';
+ else resultString += char(srcString[i]);
+ }
+ return resultString;
+}
+
+#endif /* LOCALE_IS_UTF8 */
+
diff --git a/src/libs/7zip/unix/CPP/Common/StringConvert.h b/src/libs/7zip/unix/CPP/Common/StringConvert.h
new file mode 100644
index 000000000..cd737becb
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/StringConvert.h
@@ -0,0 +1,73 @@
+// Common/StringConvert.h
+
+#ifndef __COMMON_STRING_CONVERT_H
+#define __COMMON_STRING_CONVERT_H
+
+#include "MyWindows.h"
+#include "MyString.h"
+#include "Types.h"
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage = CP_ACP);
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage, char defaultChar, bool &defaultCharWasUsed);
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage = CP_ACP);
+
+
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString)
+ { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString)
+ { return unicodeString; }
+inline UString GetUnicodeString(const AString &ansiString)
+ { return MultiByteToUnicodeString(ansiString); }
+inline UString GetUnicodeString(const AString &multiByteString, UINT codePage)
+ { return MultiByteToUnicodeString(multiByteString, codePage); }
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString, UINT)
+ { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString, UINT)
+ { return unicodeString; }
+
+inline const char* GetAnsiString(const char* ansiString)
+ { return ansiString; }
+inline const AString& GetAnsiString(const AString &ansiString)
+ { return ansiString; }
+inline AString GetAnsiString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString); }
+
+inline const char* GetOemString(const char* oemString)
+ { return oemString; }
+inline const AString& GetOemString(const AString &oemString)
+ { return oemString; }
+inline AString GetOemString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString, CP_OEMCP); }
+
+
+#ifdef _UNICODE
+ inline const wchar_t* GetSystemString(const wchar_t* unicodeString)
+ { return unicodeString;}
+ inline const UString& GetSystemString(const UString &unicodeString)
+ { return unicodeString;}
+ inline const wchar_t* GetSystemString(const wchar_t* unicodeString, UINT /* codePage */)
+ { return unicodeString;}
+ inline const UString& GetSystemString(const UString &unicodeString, UINT /* codePage */)
+ { return unicodeString;}
+ inline UString GetSystemString(const AString &multiByteString, UINT codePage)
+ { return MultiByteToUnicodeString(multiByteString, codePage);}
+ inline UString GetSystemString(const AString &multiByteString)
+ { return MultiByteToUnicodeString(multiByteString);}
+#else
+ inline const char* GetSystemString(const char *ansiString)
+ { return ansiString; }
+ inline const AString& GetSystemString(const AString &multiByteString, UINT)
+ { return multiByteString; }
+ inline const char * GetSystemString(const char *multiByteString, UINT)
+ { return multiByteString; }
+ inline AString GetSystemString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString); }
+ inline AString GetSystemString(const UString &unicodeString, UINT codePage)
+ { return UnicodeStringToMultiByte(unicodeString, codePage); }
+#endif
+
+#ifndef UNDER_CE
+AString SystemStringToOemString(const CSysString &srcString);
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/StringToInt.cpp b/src/libs/7zip/unix/CPP/Common/StringToInt.cpp
new file mode 100644
index 000000000..9473766bc
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/StringToInt.cpp
@@ -0,0 +1,90 @@
+// Common/StringToInt.cpp
+
+#include "StdAfx.h"
+
+#include "StringToInt.h"
+
+UInt64 ConvertStringToUInt64(const char *s, const char **end)
+{
+ UInt64 result = 0;
+ for (;;)
+ {
+ char c = *s;
+ if (c < '0' || c > '9')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result *= 10;
+ result += (c - '0');
+ s++;
+ }
+}
+
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end)
+{
+ UInt64 result = 0;
+ for (;;)
+ {
+ char c = *s;
+ if (c < '0' || c > '7')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result <<= 3;
+ result += (c - '0');
+ s++;
+ }
+}
+
+UInt64 ConvertHexStringToUInt64(const char *s, const char **end)
+{
+ UInt64 result = 0;
+ for (;;)
+ {
+ char c = *s;
+ UInt32 v;
+ if (c >= '0' && c <= '9') v = (c - '0');
+ else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
+ else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
+ else
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result <<= 4;
+ result |= v;
+ s++;
+ }
+}
+
+
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end)
+{
+ UInt64 result = 0;
+ for (;;)
+ {
+ wchar_t c = *s;
+ if (c < '0' || c > '9')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result *= 10;
+ result += (c - '0');
+ s++;
+ }
+}
+
+
+Int64 ConvertStringToInt64(const char *s, const char **end)
+{
+ if (*s == '-')
+ return -(Int64)ConvertStringToUInt64(s + 1, end);
+ return ConvertStringToUInt64(s, end);
+}
diff --git a/src/libs/7zip/unix/CPP/Common/StringToInt.h b/src/libs/7zip/unix/CPP/Common/StringToInt.h
new file mode 100644
index 000000000..c0d860eff
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/StringToInt.h
@@ -0,0 +1,18 @@
+// Common/StringToInt.h
+
+#ifndef __COMMON_STRINGTOINT_H
+#define __COMMON_STRINGTOINT_H
+
+#include <string.h>
+#include "Types.h"
+
+UInt64 ConvertStringToUInt64(const char *s, const char **end);
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end);
+UInt64 ConvertHexStringToUInt64(const char *s, const char **end);
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end);
+
+Int64 ConvertStringToInt64(const char *s, const char **end);
+
+#endif
+
+
diff --git a/src/libs/7zip/unix/CPP/Common/TextConfig.cpp b/src/libs/7zip/unix/CPP/Common/TextConfig.cpp
new file mode 100644
index 000000000..6a55012c3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/TextConfig.cpp
@@ -0,0 +1,138 @@
+// Common/TextConfig.cpp
+
+#include "StdAfx.h"
+
+#include "TextConfig.h"
+
+#include "Defs.h"
+#include "UTFConvert.h"
+
+static bool IsDelimitChar(char c)
+{
+ return (c == ' ' || c == 0x0A || c == 0x0D ||
+ c == '\0' || c == '\t');
+}
+
+static AString GetIDString(const char *string, int &finishPos)
+{
+ AString result;
+ for (finishPos = 0; ; finishPos++)
+ {
+ char c = string[finishPos];
+ if (IsDelimitChar(c) || c == '=')
+ break;
+ result += c;
+ }
+ return result;
+}
+
+static bool WaitNextLine(const AString &string, int &pos)
+{
+ for (;pos < string.Length(); pos++)
+ if (string[pos] == 0x0A)
+ return true;
+ return false;
+}
+
+static bool SkipSpaces(const AString &string, int &pos)
+{
+ for (;pos < string.Length(); pos++)
+ {
+ char c = string[pos];
+ if (!IsDelimitChar(c))
+ {
+ if (c != ';')
+ return true;
+ if (!WaitNextLine(string, pos))
+ return false;
+ }
+ }
+ return false;
+}
+
+bool GetTextConfig(const AString &string, CObjectVector<CTextConfigPair> &pairs)
+{
+ pairs.Clear();
+ int pos = 0;
+
+ /////////////////////
+ // read strings
+
+ for (;;)
+ {
+ if (!SkipSpaces(string, pos))
+ break;
+ CTextConfigPair pair;
+ int finishPos;
+ AString temp = GetIDString(((const char *)string) + pos, finishPos);
+ if (!ConvertUTF8ToUnicode(temp, pair.ID))
+ return false;
+ if (finishPos == 0)
+ return false;
+ pos += finishPos;
+ if (!SkipSpaces(string, pos))
+ return false;
+ if (string[pos] != '=')
+ return false;
+ pos++;
+ if (!SkipSpaces(string, pos))
+ return false;
+ if (string[pos] != '\"')
+ return false;
+ pos++;
+ AString message;
+ for (;;)
+ {
+ if (pos >= string.Length())
+ return false;
+ char c = string[pos++];
+ if (c == '\"')
+ break;
+ if (c == '\\') // FIXME ?
+ {
+ char c = string[pos++];
+ switch(c)
+ {
+ case 'n':
+ message += '\n';
+ break;
+ case 't':
+ message += '\t';
+ break;
+ case '\\': // FIXME ?
+ message += '\\';
+ break;
+ case '\"':
+ message += '\"';
+ break;
+ default:
+ message += '\\'; // FIXME ?
+ message += c;
+ break;
+ }
+ }
+ else
+ message += c;
+ }
+ if (!ConvertUTF8ToUnicode(message, pair.String))
+ return false;
+ pairs.Add(pair);
+ }
+ return true;
+}
+
+int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const UString &id)
+{
+ for (int i = 0; i < pairs.Size(); i++)
+ if (pairs[i].ID.Compare(id) == 0)
+ return i;
+ return -1;
+}
+
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const UString &id)
+{
+ int index = FindTextConfigItem(pairs, id);
+ if (index < 0)
+ return UString();
+ return pairs[index].String;
+}
diff --git a/src/libs/7zip/unix/CPP/Common/TextConfig.h b/src/libs/7zip/unix/CPP/Common/TextConfig.h
new file mode 100644
index 000000000..a25142a70
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/TextConfig.h
@@ -0,0 +1,22 @@
+// Common/TextConfig.h
+
+#ifndef __COMMON_TEXTCONFIG_H
+#define __COMMON_TEXTCONFIG_H
+
+#include "MyVector.h"
+#include "MyString.h"
+
+struct CTextConfigPair
+{
+ UString ID;
+ UString String;
+};
+
+bool GetTextConfig(const AString &text, CObjectVector<CTextConfigPair> &pairs);
+
+int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const UString &id);
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const UString &id);
+
+#endif
+
+
diff --git a/src/libs/7zip/unix/CPP/Common/Types.h b/src/libs/7zip/unix/CPP/Common/Types.h
new file mode 100644
index 000000000..9365b327f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/Types.h
@@ -0,0 +1,11 @@
+// Common/Types.h
+
+#ifndef __COMMON_TYPES_H
+#define __COMMON_TYPES_H
+
+#include "../../C/Types.h"
+
+typedef int HRes;
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Common/UTFConvert.cpp b/src/libs/7zip/unix/CPP/Common/UTFConvert.cpp
new file mode 100644
index 000000000..95362430a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/UTFConvert.cpp
@@ -0,0 +1,145 @@
+// UTFConvert.cpp
+
+#include "StdAfx.h"
+
+#include "UTFConvert.h"
+#include "Types.h"
+
+static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+static Bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, size_t srcLen)
+{
+ size_t destPos = 0, srcPos = 0;
+ for (;;)
+ {
+ Byte c;
+ int numAdds;
+ if (srcPos == srcLen)
+ {
+ *destLen = destPos;
+ return True;
+ }
+ c = (Byte)src[srcPos++];
+
+ if (c < 0x80)
+ {
+ if (dest)
+ dest[destPos] = (wchar_t)c;
+ destPos++;
+ continue;
+ }
+ if (c < 0xC0)
+ break;
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (c < kUtf8Limits[numAdds])
+ break;
+ UInt32 value = (c - kUtf8Limits[numAdds - 1]);
+
+ do
+ {
+ Byte c2;
+ if (srcPos == srcLen)
+ break;
+ c2 = (Byte)src[srcPos++];
+ if (c2 < 0x80 || c2 >= 0xC0)
+ break;
+ value <<= 6;
+ value |= (c2 - 0x80);
+ }
+ while (--numAdds != 0);
+
+ if (value < 0x10000)
+ {
+ if (dest)
+ dest[destPos] = (wchar_t)value;
+ destPos++;
+ }
+ else
+ {
+ value -= 0x10000;
+ if (value >= 0x100000)
+ break;
+ if (dest)
+ {
+ dest[destPos + 0] = (wchar_t)(0xD800 + (value >> 10));
+ dest[destPos + 1] = (wchar_t)(0xDC00 + (value & 0x3FF));
+ }
+ destPos += 2;
+ }
+ }
+ *destLen = destPos;
+ return False;
+}
+
+static Bool Utf16_To_Utf8(char *dest, size_t *destLen, const wchar_t *src, size_t srcLen)
+{
+ size_t destPos = 0, srcPos = 0;
+ for (;;)
+ {
+ unsigned numAdds;
+ UInt32 value;
+ if (srcPos == srcLen)
+ {
+ *destLen = destPos;
+ return True;
+ }
+ value = src[srcPos++];
+ if (value < 0x80)
+ {
+ if (dest)
+ dest[destPos] = (char)value;
+ destPos++;
+ continue;
+ }
+ if (value >= 0xD800 && value < 0xE000)
+ {
+ UInt32 c2;
+ if (value >= 0xDC00 || srcPos == srcLen)
+ break;
+ c2 = src[srcPos++];
+ if (c2 < 0xDC00 || c2 >= 0xE000)
+ break;
+ value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
+ }
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+ break;
+ if (dest)
+ dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+ destPos++;
+ do
+ {
+ numAdds--;
+ if (dest)
+ dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+ destPos++;
+ }
+ while (numAdds != 0);
+ }
+ *destLen = destPos;
+ return False;
+}
+
+bool ConvertUTF8ToUnicode(const AString &src, UString &dest)
+{
+ dest.Empty();
+ size_t destLen = 0;
+ Utf8_To_Utf16(NULL, &destLen, src, src.Length());
+ wchar_t *p = dest.GetBuffer((int)destLen);
+ Bool res = Utf8_To_Utf16(p, &destLen, src, src.Length());
+ p[destLen] = 0;
+ dest.ReleaseBuffer();
+ return res ? true : false;
+}
+
+bool ConvertUnicodeToUTF8(const UString &src, AString &dest)
+{
+ dest.Empty();
+ size_t destLen = 0;
+ Utf16_To_Utf8(NULL, &destLen, src, src.Length());
+ char *p = dest.GetBuffer((int)destLen);
+ Bool res = Utf16_To_Utf8(p, &destLen, src, src.Length());
+ p[destLen] = 0;
+ dest.ReleaseBuffer();
+ return res ? true : false;
+}
diff --git a/src/libs/7zip/unix/CPP/Common/UTFConvert.h b/src/libs/7zip/unix/CPP/Common/UTFConvert.h
new file mode 100644
index 000000000..2a14600d9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/UTFConvert.h
@@ -0,0 +1,11 @@
+// Common/UTFConvert.h
+
+#ifndef __COMMON_UTFCONVERT_H
+#define __COMMON_UTFCONVERT_H
+
+#include "MyString.h"
+
+bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString);
+bool ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Common/Wildcard.cpp b/src/libs/7zip/unix/CPP/Common/Wildcard.cpp
new file mode 100644
index 000000000..476ddebde
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/Wildcard.cpp
@@ -0,0 +1,462 @@
+// Common/Wildcard.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/Types.h"
+
+#include "Wildcard.h"
+
+bool g_CaseSensitive =
+ #ifdef _WIN32
+ false;
+ #else
+ true;
+ #endif
+
+static const wchar_t kAnyCharsChar = L'*';
+static const wchar_t kAnyCharChar = L'?';
+
+#ifdef _WIN32
+static const wchar_t kDirDelimiter1 = L'\\';
+#endif
+static const wchar_t kDirDelimiter2 = L'/';
+
+static const UString kWildCardCharSet = L"?*";
+
+static const UString kIllegalWildCardFileNameChars=
+ L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF"
+ L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
+ L"\"/:<>\\|";
+
+
+static inline bool IsCharDirLimiter(wchar_t c)
+{
+ return (
+ #ifdef _WIN32
+ c == kDirDelimiter1 ||
+ #endif
+ c == kDirDelimiter2);
+}
+
+int CompareFileNames(const UString &s1, const UString &s2)
+{
+ if (g_CaseSensitive)
+ return s1.Compare(s2);
+ return s1.CompareNoCase(s2);
+}
+
+// -----------------------------------------
+// this function compares name with mask
+// ? - any char
+// * - any char or empty
+
+static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
+{
+ for (;;)
+ {
+ wchar_t m = *mask;
+ wchar_t c = *name;
+ if (m == 0)
+ return (c == 0);
+ if (m == kAnyCharsChar)
+ {
+ if (EnhancedMaskTest(mask + 1, name))
+ return true;
+ if (c == 0)
+ return false;
+ }
+ else
+ {
+ if (m == kAnyCharChar)
+ {
+ if (c == 0)
+ return false;
+ }
+ else if (m != c)
+ if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c))
+ return false;
+ mask++;
+ }
+ name++;
+ }
+}
+
+// --------------------------------------------------
+// Splits path to strings
+
+void SplitPathToParts(const UString &path, UStringVector &pathParts)
+{
+ pathParts.Clear();
+ UString name;
+ int len = path.Length();
+ if (len == 0)
+ return;
+ for (int i = 0; i < len; i++)
+ {
+ wchar_t c = path[i];
+ if (IsCharDirLimiter(c))
+ {
+ pathParts.Add(name);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ pathParts.Add(name);
+}
+
+void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name)
+{
+ int i;
+ for (i = path.Length() - 1; i >= 0; i--)
+ if (IsCharDirLimiter(path[i]))
+ break;
+ dirPrefix = path.Left(i + 1);
+ name = path.Mid(i + 1);
+}
+
+UString ExtractDirPrefixFromPath(const UString &path)
+{
+ int i;
+ for (i = path.Length() - 1; i >= 0; i--)
+ if (IsCharDirLimiter(path[i]))
+ break;
+ return path.Left(i + 1);
+}
+
+UString ExtractFileNameFromPath(const UString &path)
+{
+ int i;
+ for (i = path.Length() - 1; i >= 0; i--)
+ if (IsCharDirLimiter(path[i]))
+ break;
+ return path.Mid(i + 1);
+}
+
+
+bool CompareWildCardWithName(const UString &mask, const UString &name)
+{
+ return EnhancedMaskTest(mask, name);
+}
+
+bool DoesNameContainWildCard(const UString &path)
+{
+ return (path.FindOneOf(kWildCardCharSet) >= 0);
+}
+
+
+// ----------------------------------------------------------'
+// NWildcard
+
+namespace NWildcard {
+
+
+/*
+M = MaskParts.Size();
+N = TestNameParts.Size();
+
+ File Dir
+ForFile req M<=N [N-M, N) -
+ nonreq M=N [0, M) -
+
+ForDir req M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File
+ nonreq [0, M) same as ForBoth-File
+
+ForBoth req m<=N [0, M) ... [N-M, N) same as ForBoth-File
+ nonreq [0, M) same as ForBoth-File
+
+*/
+
+bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
+{
+ if (!isFile && !ForDir)
+ return false;
+ int delta = (int)pathParts.Size() - (int)PathParts.Size();
+ if (delta < 0)
+ return false;
+ int start = 0;
+ int finish = 0;
+ if (isFile)
+ {
+ if (!ForDir && !Recursive && delta !=0)
+ return false;
+ if (!ForFile && delta == 0)
+ return false;
+ if (!ForDir && Recursive)
+ start = delta;
+ }
+ if (Recursive)
+ {
+ finish = delta;
+ if (isFile && !ForFile)
+ finish = delta - 1;
+ }
+ for (int d = start; d <= finish; d++)
+ {
+ int i;
+ for (i = 0; i < PathParts.Size(); i++)
+ if (!CompareWildCardWithName(PathParts[i], pathParts[i + d]))
+ break;
+ if (i == PathParts.Size())
+ return true;
+ }
+ return false;
+}
+
+int CCensorNode::FindSubNode(const UString &name) const
+{
+ for (int i = 0; i < SubNodes.Size(); i++)
+ if (CompareFileNames(SubNodes[i].Name, name) == 0)
+ return i;
+ return -1;
+}
+
+void CCensorNode::AddItemSimple(bool include, CItem &item)
+{
+ if (include)
+ IncludeItems.Add(item);
+ else
+ ExcludeItems.Add(item);
+}
+
+void CCensorNode::AddItem(bool include, CItem &item)
+{
+ if (item.PathParts.Size() <= 1)
+ {
+ AddItemSimple(include, item);
+ return;
+ }
+ const UString &front = item.PathParts.Front();
+ if (DoesNameContainWildCard(front))
+ {
+ AddItemSimple(include, item);
+ return;
+ }
+ int index = FindSubNode(front);
+ if (index < 0)
+ index = SubNodes.Add(CCensorNode(front, this));
+ item.PathParts.Delete(0);
+ SubNodes[index].AddItem(include, item);
+}
+
+void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir)
+{
+ CItem item;
+ SplitPathToParts(path, item.PathParts);
+ item.Recursive = recursive;
+ item.ForFile = forFile;
+ item.ForDir = forDir;
+ AddItem(include, item);
+}
+
+bool CCensorNode::NeedCheckSubDirs() const
+{
+ for (int i = 0; i < IncludeItems.Size(); i++)
+ {
+ const CItem &item = IncludeItems[i];
+ if (item.Recursive || item.PathParts.Size() > 1)
+ return true;
+ }
+ return false;
+}
+
+bool CCensorNode::AreThereIncludeItems() const
+{
+ if (IncludeItems.Size() > 0)
+ return true;
+ for (int i = 0; i < SubNodes.Size(); i++)
+ if (SubNodes[i].AreThereIncludeItems())
+ return true;
+ return false;
+}
+
+bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
+{
+ const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
+ for (int i = 0; i < items.Size(); i++)
+ if (items[i].CheckPath(pathParts, isFile))
+ return true;
+ return false;
+}
+
+bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include) const
+{
+ if (CheckPathCurrent(false, pathParts, isFile))
+ {
+ include = false;
+ return true;
+ }
+ include = true;
+ bool finded = CheckPathCurrent(true, pathParts, isFile);
+ if (pathParts.Size() == 1)
+ return finded;
+ int index = FindSubNode(pathParts.Front());
+ if (index >= 0)
+ {
+ UStringVector pathParts2 = pathParts;
+ pathParts2.Delete(0);
+ if (SubNodes[index].CheckPath(pathParts2, isFile, include))
+ return true;
+ }
+ return finded;
+}
+
+bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const
+{
+ UStringVector pathParts;
+ SplitPathToParts(path, pathParts);
+ return CheckPath(pathParts, isFile, include);
+}
+
+bool CCensorNode::CheckPath(const UString &path, bool isFile) const
+{
+ bool include;
+ if (CheckPath(path, isFile, include))
+ return include;
+ return false;
+}
+
+bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const
+{
+ if (CheckPathCurrent(include, pathParts, isFile))
+ return true;
+ if (Parent == 0)
+ return false;
+ pathParts.Insert(0, Name);
+ return Parent->CheckPathToRoot(include, pathParts, isFile);
+}
+
+/*
+bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const
+{
+ UStringVector pathParts;
+ SplitPathToParts(path, pathParts);
+ return CheckPathToRoot(include, pathParts, isFile);
+}
+*/
+
+void CCensorNode::AddItem2(bool include, const UString &path, bool recursive)
+{
+ if (path.IsEmpty())
+ return;
+ bool forFile = true;
+ bool forFolder = true;
+ UString path2 = path;
+ if (IsCharDirLimiter(path[path.Length() - 1]))
+ {
+ path2.Delete(path.Length() - 1);
+ forFile = false;
+ }
+ AddItem(include, path2, recursive, forFile, forFolder);
+}
+
+void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
+{
+ ExcludeItems += fromNodes.ExcludeItems;
+ for (int i = 0; i < fromNodes.SubNodes.Size(); i++)
+ {
+ const CCensorNode &node = fromNodes.SubNodes[i];
+ int subNodeIndex = FindSubNode(node.Name);
+ if (subNodeIndex < 0)
+ subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this));
+ SubNodes[subNodeIndex].ExtendExclude(node);
+ }
+}
+
+int CCensor::FindPrefix(const UString &prefix) const
+{
+ for (int i = 0; i < Pairs.Size(); i++)
+ if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)
+ return i;
+ return -1;
+}
+
+void CCensor::AddItem(bool include, const UString &path, bool recursive)
+{
+ UStringVector pathParts;
+ if (path.IsEmpty())
+ throw "Empty file path";
+ SplitPathToParts(path, pathParts);
+ bool forFile = true;
+ if (pathParts.Back().IsEmpty())
+ {
+ forFile = false;
+ pathParts.DeleteBack();
+ }
+ const UString &front = pathParts.Front();
+ bool isAbs = false;
+ if (front.IsEmpty())
+ isAbs = true;
+ else if (front.Length() == 2 && front[1] == L':')
+ isAbs = true;
+ else
+ {
+ for (int i = 0; i < pathParts.Size(); i++)
+ {
+ const UString &part = pathParts[i];
+ if (part == L".." || part == L".")
+ {
+ isAbs = true;
+ break;
+ }
+ }
+ }
+ int numAbsParts = 0;
+ if (isAbs)
+ if (pathParts.Size() > 1)
+ numAbsParts = pathParts.Size() - 1;
+ else
+ numAbsParts = 1;
+ UString prefix;
+ for (int i = 0; i < numAbsParts; i++)
+ {
+ const UString &front = pathParts.Front();
+ if (DoesNameContainWildCard(front))
+ break;
+ prefix += front;
+ prefix += WCHAR_PATH_SEPARATOR;
+ pathParts.Delete(0);
+ }
+ int index = FindPrefix(prefix);
+ if (index < 0)
+ index = Pairs.Add(CPair(prefix));
+
+ CItem item;
+ item.PathParts = pathParts;
+ item.ForDir = true;
+ item.ForFile = forFile;
+ item.Recursive = recursive;
+ Pairs[index].Head.AddItem(include, item);
+}
+
+bool CCensor::CheckPath(const UString &path, bool isFile) const
+{
+ bool finded = false;
+ for (int i = 0; i < Pairs.Size(); i++)
+ {
+ bool include;
+ if (Pairs[i].Head.CheckPath(path, isFile, include))
+ {
+ if (!include)
+ return false;
+ finded = true;
+ }
+ }
+ return finded;
+}
+
+void CCensor::ExtendExclude()
+{
+ int i;
+ for (i = 0; i < Pairs.Size(); i++)
+ if (Pairs[i].Prefix.IsEmpty())
+ break;
+ if (i == Pairs.Size())
+ return;
+ int index = i;
+ for (i = 0; i < Pairs.Size(); i++)
+ if (index != i)
+ Pairs[i].Head.ExtendExclude(Pairs[index].Head);
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/Common/Wildcard.h b/src/libs/7zip/unix/CPP/Common/Wildcard.h
new file mode 100644
index 000000000..6d4cbcece
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Common/Wildcard.h
@@ -0,0 +1,80 @@
+// Common/Wildcard.h
+
+#ifndef __COMMON_WILDCARD_H
+#define __COMMON_WILDCARD_H
+
+#include "MyString.h"
+
+int CompareFileNames(const UString &s1, const UString &s2);
+
+void SplitPathToParts(const UString &path, UStringVector &pathParts);
+void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name);
+UString ExtractDirPrefixFromPath(const UString &path);
+UString ExtractFileNameFromPath(const UString &path);
+bool DoesNameContainWildCard(const UString &path);
+bool CompareWildCardWithName(const UString &mask, const UString &name);
+
+namespace NWildcard {
+
+struct CItem
+{
+ UStringVector PathParts;
+ bool Recursive;
+ bool ForFile;
+ bool ForDir;
+ bool CheckPath(const UStringVector &pathParts, bool isFile) const;
+};
+
+class CCensorNode
+{
+ CCensorNode *Parent;
+ bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const;
+ void AddItemSimple(bool include, CItem &item);
+ bool CheckPath(UStringVector &pathParts, bool isFile, bool &include) const;
+public:
+ CCensorNode(): Parent(0) { };
+ CCensorNode(const UString &name, CCensorNode *parent): Name(name), Parent(parent) { };
+ UString Name;
+ CObjectVector<CCensorNode> SubNodes;
+ CObjectVector<CItem> IncludeItems;
+ CObjectVector<CItem> ExcludeItems;
+
+ int FindSubNode(const UString &path) const;
+
+ void AddItem(bool include, CItem &item);
+ void AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir);
+ void AddItem2(bool include, const UString &path, bool recursive);
+
+ bool NeedCheckSubDirs() const;
+ bool AreThereIncludeItems() const;
+
+ bool CheckPath(const UString &path, bool isFile, bool &include) const;
+ bool CheckPath(const UString &path, bool isFile) const;
+
+ bool CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const;
+ // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const;
+ void ExtendExclude(const CCensorNode &fromNodes);
+};
+
+struct CPair
+{
+ UString Prefix;
+ CCensorNode Head;
+ CPair(const UString &prefix): Prefix(prefix) { };
+};
+
+class CCensor
+{
+ int FindPrefix(const UString &prefix) const;
+public:
+ CObjectVector<CPair> Pairs;
+ bool AllAreRelative() const
+ { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); }
+ void AddItem(bool include, const UString &path, bool recursive);
+ bool CheckPath(const UString &path, bool isFile) const;
+ void ExtendExclude();
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/COM.cpp b/src/libs/7zip/unix/CPP/Windows/COM.cpp
new file mode 100644
index 000000000..a746de12b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/COM.cpp
@@ -0,0 +1,37 @@
+// Windows/COM.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/COM.h"
+#include "Common/StringConvert.h"
+
+namespace NWindows {
+namespace NCOM {
+
+// CoInitialize (NULL); must be called!
+
+UString GUIDToStringW(REFGUID guid)
+{
+ UString string;
+ const int kStringSize = 48;
+ StringFromGUID2(guid, string.GetBuffer(kStringSize), kStringSize);
+ string.ReleaseBuffer();
+ return string;
+}
+
+AString GUIDToStringA(REFGUID guid)
+{
+ return UnicodeStringToMultiByte(GUIDToStringW(guid));
+}
+
+HRESULT StringToGUIDW(const wchar_t *string, GUID &classID)
+{
+ return CLSIDFromString((wchar_t *)string, &classID);
+}
+
+HRESULT StringToGUIDA(const char *string, GUID &classID)
+{
+ return StringToGUIDW(MultiByteToUnicodeString(string), classID);
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/Windows/COM.h b/src/libs/7zip/unix/CPP/Windows/COM.h
new file mode 100644
index 000000000..506bbbc64
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/COM.h
@@ -0,0 +1,69 @@
+// Windows/COM.h
+
+#ifndef __WINDOWS_COM_H
+#define __WINDOWS_COM_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+namespace NCOM {
+
+#ifdef _WIN32
+
+class CComInitializer
+{
+public:
+ CComInitializer()
+ {
+ #ifdef UNDER_CE
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ #else
+ // it's single thread. Do we need multithread?
+ CoInitialize(NULL);
+ #endif
+ };
+ ~CComInitializer() { CoUninitialize(); };
+};
+
+class CStgMedium
+{
+ STGMEDIUM _object;
+public:
+ bool _mustBeReleased;
+ CStgMedium(): _mustBeReleased(false) {}
+ ~CStgMedium() { Free(); }
+ void Free()
+ {
+ if (_mustBeReleased)
+ ReleaseStgMedium(&_object);
+ _mustBeReleased = false;
+ }
+ const STGMEDIUM* operator->() const { return &_object;}
+ STGMEDIUM* operator->() { return &_object;}
+ STGMEDIUM* operator&() { return &_object; }
+};
+
+#endif
+
+//////////////////////////////////
+// GUID <--> String Conversions
+UString GUIDToStringW(REFGUID guid);
+AString GUIDToStringA(REFGUID guid);
+#ifdef UNICODE
+ #define GUIDToString GUIDToStringW
+#else
+ #define GUIDToString GUIDToStringA
+#endif
+
+HRESULT StringToGUIDW(const wchar_t *string, GUID &classID);
+HRESULT StringToGUIDA(const char *string, GUID &classID);
+#ifdef UNICODE
+ #define StringToGUID StringToGUIDW
+#else
+ #define StringToGUID StringToGUIDA
+#endif
+
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Clipboard.cpp b/src/libs/7zip/unix/CPP/Windows/Clipboard.cpp
new file mode 100644
index 000000000..bb081e153
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Clipboard.cpp
@@ -0,0 +1,160 @@
+// Windows/Clipboard.cpp
+
+#include "StdAfx.h"
+
+
+#include "Windows/Clipboard.h"
+#include "Windows/Defs.h"
+#ifdef _WIN32
+#include "Windows/Memory.h"
+#include "Windows/Shell.h"
+#include "Windows/Memory.h"
+#else
+#include <wx/clipbrd.h>
+#include <wx/dataobj.h>
+#undef _WIN32
+#endif
+
+#include "Common/StringConvert.h"
+
+namespace NWindows {
+
+bool CClipboard::Open(HWND wndNewOwner)
+{
+#ifdef _WIN32
+ m_Open = BOOLToBool(::OpenClipboard(wndNewOwner));
+#else
+ m_Open = wxTheClipboard->Open();
+#endif
+ return m_Open;
+}
+
+CClipboard::~CClipboard()
+{
+ Close();
+}
+
+bool CClipboard::Close()
+{
+ if (!m_Open)
+ return true;
+#ifdef _WIN32
+ m_Open = !BOOLToBool(CloseClipboard());
+#else
+ wxTheClipboard->Close();
+ m_Open = false;
+#endif
+ return !m_Open;
+}
+
+#ifdef _WIN32
+bool ClipboardIsFormatAvailableHDROP()
+{
+ return BOOLToBool(IsClipboardFormatAvailable(CF_HDROP));
+}
+#endif
+
+/*
+bool ClipboardGetTextString(AString &s)
+{
+ s.Empty();
+ if (!IsClipboardFormatAvailable(CF_TEXT))
+ return false;
+ CClipboard clipboard;
+
+ if (!clipboard.Open(NULL))
+ return false;
+
+ HGLOBAL h = ::GetClipboardData(CF_TEXT);
+ if (h != NULL)
+ {
+ NMemory::CGlobalLock globalLock(h);
+ const char *p = (const char *)globalLock.GetPointer();
+ if (p != NULL)
+ {
+ s = p;
+ return true;
+ }
+ }
+ return false;
+}
+*/
+
+/*
+bool ClipboardGetFileNames(UStringVector &names)
+{
+ names.Clear();
+ if (!IsClipboardFormatAvailable(CF_HDROP))
+ return false;
+ CClipboard clipboard;
+
+ if (!clipboard.Open(NULL))
+ return false;
+
+ HGLOBAL h = ::GetClipboardData(CF_HDROP);
+ if (h != NULL)
+ {
+ NMemory::CGlobalLock globalLock(h);
+ void *p = (void *)globalLock.GetPointer();
+ if (p != NULL)
+ {
+ NShell::CDrop drop(false);
+ drop.Attach((HDROP)p);
+ drop.QueryFileNames(names);
+ return true;
+ }
+ }
+ return false;
+}
+*/
+
+#ifdef _WIN32
+static bool ClipboardSetData(UINT uFormat, const void *data, size_t size)
+{
+ NMemory::CGlobal global;
+ if (!global.Alloc(GMEM_DDESHARE | GMEM_MOVEABLE, size))
+ return false;
+ {
+ NMemory::CGlobalLock globalLock(global);
+ LPVOID p = globalLock.GetPointer();
+ if (p == NULL)
+ return false;
+ memcpy(p, data, size);
+ }
+ if (::SetClipboardData(uFormat, global) == NULL)
+ return false;
+ global.Detach();
+ return true;
+}
+#endif
+
+bool ClipboardSetText(HWND owner, const UString &s)
+{
+ CClipboard clipboard;
+ if (!clipboard.Open(owner))
+ return false;
+#ifdef _WIN32
+ if (!::EmptyClipboard())
+ return false;
+
+ bool res;
+ res = ClipboardSetData(CF_UNICODETEXT, (const wchar_t *)s, (s.Length() + 1) * sizeof(wchar_t));
+ #ifndef _UNICODE
+ AString a;
+ a = UnicodeStringToMultiByte(s, CP_ACP);
+ res |= ClipboardSetData(CF_TEXT, (const char *)a, (a.Length() + 1) * sizeof(char));
+ a = UnicodeStringToMultiByte(s, CP_OEMCP);
+ res |= ClipboardSetData(CF_OEMTEXT, (const char *)a, (a.Length() + 1) * sizeof(char));
+ #endif
+ return res;
+#else
+ wxTheClipboard->Clear();
+ // This data objects are held by the clipboard,
+ // so do not delete them in the app.
+ wxString ws(s);
+ wxTheClipboard->SetData( new wxTextDataObject(ws) );
+ return true;
+#endif
+}
+
+}
diff --git a/src/libs/7zip/unix/CPP/Windows/Clipboard.h b/src/libs/7zip/unix/CPP/Windows/Clipboard.h
new file mode 100644
index 000000000..c80ba5ea7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Clipboard.h
@@ -0,0 +1,28 @@
+// Windows/Clipboard.h
+
+#ifndef __CLIPBOARD_H
+#define __CLIPBOARD_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+
+class CClipboard
+{
+ bool m_Open;
+public:
+ CClipboard(): m_Open(false) {};
+ ~CClipboard();
+ bool Open(HWND wndNewOwner);
+ bool Close();
+};
+
+bool ClipboardIsFormatAvailableHDROP();
+
+// bool ClipboardGetFileNames(UStringVector &names);
+// bool ClipboardGetTextString(AString &s);
+bool ClipboardSetText(HWND owner, const UString &s);
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/CommonDialog.h b/src/libs/7zip/unix/CPP/Windows/CommonDialog.h
new file mode 100644
index 000000000..f24bb5b24
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/CommonDialog.h
@@ -0,0 +1,19 @@
+// Windows/CommonDialog.h
+
+#ifndef __WINDOWS_COMMON_DIALOG_H
+#define __WINDOWS_COMMON_DIALOG_H
+
+#include "Common/MyString.h"
+
+namespace NWindows{
+
+bool MyGetOpenFileName(HWND hwnd, LPCWSTR title, LPCWSTR fullFileName,
+ LPCWSTR s, UString &resPath
+ #ifdef UNDER_CE
+ , bool openFolder = false
+ #endif
+);
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/ComboBox.h b/src/libs/7zip/unix/CPP/Windows/Control/ComboBox.h
new file mode 100644
index 000000000..8717b4867
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/ComboBox.h
@@ -0,0 +1,82 @@
+// Windows/Control/ComboBox.h
+
+#ifndef __WINDOWS_WX_CONTROL_COMBOBOX_H
+#define __WINDOWS_WX_CONTROL_COMBOBOX_H
+
+#include "Windows/Window.h"
+#include "Windows/Defs.h"
+
+
+#include "Windows/Control/Window2.h" // NMHDR
+
+#ifndef _WIN32
+#define CB_ERR (-1) // wxNOT_FOUND
+#endif
+
+typedef struct
+{
+ NMHDR hdr;
+#define CBENF_ESCAPE 1
+#define CBENF_RETURN 2
+ int iWhy;
+} NMCBEENDEDITW;
+
+typedef NMCBEENDEDITW * PNMCBEENDEDITW;
+
+
+class wxComboBox;
+
+namespace NWindows {
+ namespace NControl {
+
+ class CComboBox // : public CWindow
+ {
+ wxComboBox* _choice;
+ public:
+ CComboBox() : _choice(0) {}
+
+ void Attach(wxWindow * newWindow);
+ wxWindow * Detach();
+ operator HWND() const;
+
+ int AddString(const TCHAR * txt);
+
+ void SetText(LPCTSTR s);
+
+ void GetText(CSysString &s);
+
+ int GetCount() const ;
+ void GetLBText(int index, CSysString &s);
+
+ void SetCurSel(int index);
+ int GetCurSel();
+
+ void SetItemData(int index, int val);
+
+ int GetItemData(int index);
+
+ void Enable(bool state);
+
+ void ResetContent();
+ };
+
+ class CComboBoxEx : public CComboBox // : public CWindow
+ {
+ public:
+ /* FIXME
+ LRESULT DeleteItem(int index)
+ { return SendMessage(CBEM_DELETEITEM, index, 0); }
+ LRESULT InsertItem(COMBOBOXEXITEM *item)
+ { return SendMessage(CBEM_INSERTITEM, 0, (LPARAM)item); }
+ DWORD SetExtendedStyle(DWORD exMask, DWORD exStyle)
+ { return (DWORD)SendMessage(CBEM_SETEXTENDEDSTYLE, exMask, exStyle); }
+ HWND GetEditControl()
+ { return (HWND)SendMessage(CBEM_GETEDITCONTROL, 0, 0); }
+ */
+ };
+
+
+ }
+}
+
+#endif // __WINDOWS_WX_CONTROL_COMBOBOX_H
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/Controls.cpp b/src/libs/7zip/unix/CPP/Windows/Control/Controls.cpp
new file mode 100644
index 000000000..2191d8009
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/Controls.cpp
@@ -0,0 +1,515 @@
+// Dialog.cpp
+
+#include "StdAfx.h"
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWidgets headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+ #include "wx/imaglist.h"
+ #include "wx/listctrl.h"
+#endif
+
+#undef _WIN32
+
+#include "Windows/Control/Dialog.h"
+
+void verify_main_thread(void);
+
+class LockGUI
+{
+ bool _IsMain;
+ public:
+ LockGUI() {
+ verify_main_thread();
+ _IsMain = wxThread::IsMain();
+ if (!_IsMain) {
+ // DEBUG
+ printf("GuiEnter-Controls(0x%lx)\n",wxThread::GetCurrentId());
+ abort(); // FIXME wxMutexGuiEnter();
+ }
+ }
+ ~LockGUI() {
+ if (!_IsMain) {
+ wxMutexGuiLeave();
+ // DEBUG printf("GuiLeave(0x%lx)\n",wxThread::GetCurrentId());
+ }
+ }
+};
+/////////////////////////
+
+static const wxString CLASS_NAME_wxStaticText = wxT("wxStaticText");
+static const wxString CLASS_NAME_wxTextCtrl = wxT("wxTextCtrl");
+
+namespace NWindows {
+ namespace NControl {
+
+ void CDialogChildControl::SetText(LPCWSTR s)
+ {
+ LockGUI lock;
+ const wxChar * class_name = _window->GetClassInfo()->GetClassName ();
+
+ if ( CLASS_NAME_wxStaticText == class_name) {
+ ((wxStaticText *)_window)->SetLabel(s);
+ } else if ( CLASS_NAME_wxTextCtrl == class_name) {
+ ((wxTextCtrl *)_window)->SetLabel(s);
+ } else {
+ // ((wxControl *)_window)->SetValue(s); // FIXME
+ printf("INTERNAL ERROR - CDialogChildControl::SetText(class=%ls) not implemented\n",class_name);
+ exit(-1);
+ }
+ }
+
+ bool CDialogChildControl::GetText(CSysString &s)
+ {
+ wxString str;
+ {
+ LockGUI lock;
+ const wxChar * class_name = _window->GetClassInfo()->GetClassName ();
+ if ( CLASS_NAME_wxStaticText == class_name) {
+ str = ((wxStaticText *)_window)->GetLabel();
+ } else if ( CLASS_NAME_wxTextCtrl == class_name) {
+ str = ((wxTextCtrl *)_window)->GetLabel();
+ } else {
+ // FIXME str = ((wxTextCtrl *)_window)->GetValue();
+ printf("INTERNAL ERROR - CDialogChildControl::GetText(class=%ls) not implemented\n",class_name);
+ exit(-1);
+ }
+ }
+ s = str;
+ return true;
+ }
+ }
+}
+
+///////////////////////// Windows/Control/ComboBox.cpp
+#include "Windows/Control/ComboBox.h"
+
+namespace NWindows {
+ namespace NControl {
+
+ void CComboBox::Attach(wxWindow * newWindow) { _choice = (wxComboBox*)newWindow; }
+
+ wxWindow * CComboBox::Detach()
+ {
+ wxWindow * window = _choice;
+ _choice = NULL;
+ return window;
+ }
+
+ CComboBox::operator HWND() const { return (HWND)_choice; }
+
+
+ int CComboBox::AddString(const TCHAR * txt) {
+ LockGUI lock;
+ wxString item(txt);
+ return _choice->Append(item);
+ }
+
+ void CComboBox::SetText(LPCTSTR s) {
+ LockGUI lock;
+ wxString str(s);
+ _choice->SetValue(str);
+ }
+
+ void CComboBox::GetText(CSysString &s) {
+ LockGUI lock;
+ wxString str = _choice->GetValue();
+ s = str;
+ }
+
+ int CComboBox::GetCount() const {
+ LockGUI lock;
+ return _choice->GetCount();
+ }
+
+ void CComboBox::GetLBText(int index, CSysString &s) {
+ LockGUI lock;
+ wxString str = _choice->GetString(index);
+ s = str;
+ }
+
+ void CComboBox::SetCurSel(int index) {
+ LockGUI lock;
+ _choice->SetSelection(index);
+ }
+
+ int CComboBox::GetCurSel() {
+ LockGUI lock;
+ return _choice->GetSelection();
+ }
+
+ void CComboBox::SetItemData(int index, int val) {
+ LockGUI lock;
+ _choice->SetClientData( index, (void *)(((char *)0) + val));
+ }
+
+ int CComboBox::GetItemData(int index)
+ {
+ LockGUI lock;
+ void * data = _choice->GetClientData(index);
+ int ret = (int)(((char *)data) - ((char *)0));
+ return ret;
+ }
+
+ void CComboBox::Enable(bool state) {
+ LockGUI lock;
+ _choice->Enable(state);
+ }
+
+ void CComboBox::ResetContent() {
+ LockGUI lock;
+ _choice->Clear();
+ }
+ }
+}
+
+///////////////////////// Windows/Control/Edit.cpp
+#include "Windows/Control/Edit.h"
+
+namespace NWindows {
+ namespace NControl {
+
+ void CEdit::SetPasswordChar(WPARAM c) // Warning : does not work for wxMSW
+ {
+ LockGUI lock;
+ long style = _window->GetWindowStyle();
+ if ( c == 0 ) style &= ~(wxTE_PASSWORD);
+ else style |= wxTE_PASSWORD;
+ _window->SetWindowStyle(style);
+ _window->Refresh();
+ }
+
+
+ void CEdit::Show(int cmdShow)
+ {
+ LockGUI lock;
+ // FIXME _window->Show(cmdShow != SW_HIDE);
+ _window->Enable(cmdShow != SW_HIDE);
+ }
+
+ void CEdit::SetText(LPCWSTR s)
+ {
+ LockGUI lock;
+ ((wxTextCtrl *)_window)->SetValue(s);
+ }
+
+ bool CEdit::GetText(CSysString &s)
+ {
+ wxString str;
+ {
+ LockGUI lock;
+ str = ((wxTextCtrl *)_window)->GetValue();
+ }
+ s = str;
+ return true;
+ }
+
+ }
+}
+
+///////////////////////// Windows/Control/ProgressBar.cpp
+#include "Windows/Control/ProgressBar.h"
+
+namespace NWindows {
+ namespace NControl {
+
+ CProgressBar::CProgressBar(wxWindow* newWindow):
+ _window((wxGauge *)newWindow) , _minValue(0), _range(0) { }
+
+ void CProgressBar::Attach(wxWindow* newWindow) {
+ _window = (wxGauge *)newWindow;
+ _minValue = 0;
+ _range = 0;
+ }
+
+ void CProgressBar::SetRange32(int minValue, int maxValue) {
+ int range = maxValue - minValue;
+ if (range >= 1)
+ {
+ LockGUI lock;
+ _minValue = minValue;
+ _range = range;
+ _window->SetRange(_range);
+ }
+ }
+
+ void CProgressBar::SetPos(int pos) {
+ if (_range >= 1)
+ {
+ LockGUI lock;
+ int value = pos - _minValue;
+ if ((value >= 0) && (value <= _range)) _window->SetValue(value);
+ }
+ }
+
+ }
+}
+
+///////////////////////// Windows/Control/StatusBar.cpp
+#include "Windows/Control/StatusBar.h"
+
+namespace NWindows {
+ namespace NControl {
+
+ void CStatusBar::Attach(wxWindow * newWindow) { _statusBar = (wxStatusBar*)newWindow; }
+
+ wxWindow * CStatusBar::Detach()
+ {
+ wxWindow * window = _statusBar;
+ _statusBar = NULL;
+ return window;
+ }
+
+ void CStatusBar::SetText(int index, LPCTSTR text)
+ {
+ _statusBar->SetStatusText(text,index);
+ }
+
+ }
+
+}
+
+///////////////////////// Windows/Control/ListView.cpp
+#include "Windows/Control/ListView.h"
+
+namespace NWindows {
+namespace NControl {
+
+ void CListView::Attach(wxWindow * newWindow) {
+ _list = (wxListCtrl *)newWindow;
+ }
+
+ CListView::operator HWND() const { return (HWND)_list; }
+
+ int CListView::GetItemCount() const {return _list->GetItemCount(); }
+
+ int CListView::InsertItem(int index, LPCTSTR text) {
+ return _list->InsertItem(index, text);
+ }
+ int CListView::InsertItem(const LVITEM* item) {
+ /*
+ int col = item->iSubItem;
+ wxString text;
+ if (item->mask & LVIF_TEXT) text = item->pszText;
+
+ // printf("%p->InsertItem(id=%d,%ls)\n",_list,item->iItem, (const wchar_t *)text);
+ return _list->InsertItem(item->iItem, text);
+ */
+ wxListItem info;
+ long mask = 0;
+ info.SetId(item->iItem);
+ if (item->mask & LVIF_TEXT)
+ {
+ info.SetText(item->pszText);
+ mask |= wxLIST_MASK_TEXT;
+ }
+ if (item->mask & LVIF_PARAM)
+ {
+ info.SetData(item->lParam);
+ mask |= wxLIST_MASK_DATA;
+ }
+ if (item->mask & LVIF_STATE)
+ {
+ info.SetState(item->state);
+ mask |= wxLIST_MASK_STATE;
+ }
+ // FIXME if (item->mask & LVIF_IMAGE)
+
+ info.SetMask(mask);
+
+ return _list->InsertItem(info);
+ }
+
+ void CListView::SetItem(const LVITEM* item) {
+ int col = item->iSubItem;
+ wxString text;
+ if (item->mask & LVIF_TEXT) text = item->pszText;
+ // printf("%p->SetItem(id=%d,col=%d,%ls)\n",_list,item->iItem, col,(const wchar_t *)text);
+ _list->SetItem(item->iItem, col, text);
+ }
+
+ int CListView::SetSubItem(int index, int subIndex, LPCTSTR text)
+ {
+ return _list->SetItem(index, subIndex, text);
+ }
+
+ void SetUnicodeFormat(bool fUnicode) { return ; }
+
+ void CListView::InsertColumn(int columnIndex, LPCTSTR text, int width)
+ {
+ _list->InsertColumn(columnIndex, text, wxLIST_FORMAT_LEFT, width);
+ }
+
+ void CListView::InsertColumn(int columnIndex, const LVCOLUMNW *columnInfo)
+ {
+ wxString text;
+ int format = wxLIST_FORMAT_LEFT;
+ int width = -1;
+ if (columnInfo->mask & LVCF_FMT)
+ {
+ if (columnInfo->fmt == LVCFMT_LEFT) format = wxLIST_FORMAT_LEFT;
+ if (columnInfo->fmt == LVCFMT_RIGHT) format = wxLIST_FORMAT_RIGHT;
+ }
+ if (columnInfo->mask & LVCF_TEXT) text = columnInfo->pszText;
+ if (columnInfo->mask & LVCF_WIDTH) width = columnInfo->cx;
+ // FIXME LVCF_SUBITEM
+ // printf("%p->InsertColumn(%d,%ls)\n",_list,columnIndex,(const wchar_t *)heading);
+ _list->InsertColumn(columnIndex, text, format, width);
+ }
+
+ void CListView::DeleteAllItems() {
+ _list->DeleteAllItems();
+ printf("%p->DeleteAllItems()\n",_list);
+ }
+
+ void CListView::SetRedraw(bool b) {
+ if (b) _list->Thaw();
+ else _list->Freeze();
+ printf(" %p->SetRedraw()\n",_list);
+ }
+
+ void CListView::SetItemCount(int count) {
+ // ONLY IF VIRTUAL REPORT -- _list->SetItemCount(count);
+ printf(" %p->SetItemCount(%d)\n",_list,count);
+ }
+
+ void CListView::InvalidateRect(void *, bool) {
+ printf("FIXME %p->InvalidateRect()\n",_list);/* FIXME */
+ }
+
+ int CListView::GetSelectedCount() const {
+ int nb = _list->GetSelectedItemCount();
+ printf(" %p->GetSelectedCount()=>%d\n",_list,nb);
+ return nb;
+ }
+
+ void /* bool */ CListView::EnsureVisible(int index, bool partialOK) {
+
+ printf(" %p->EnsureVisible(%d)\n",_list,index);
+
+ if (index == -1) index = 0;
+ _list->EnsureVisible(index);
+
+ // return true;
+ }
+
+ void CListView::SetItemState(int index, UINT state, UINT mask) {
+ // don't work _list->SetItemState(index, state, mask); !?
+ // try SetItem ...
+ /*
+ wxListItem info;
+
+ info.m_mask = wxLIST_MASK_STATE;
+ info.m_itemId = index;
+ info.m_col = 0;
+ info.m_state = state;
+ info.m_mask = mask;
+
+ _list->SetItem(info);
+ */
+
+ printf(" %p->EnsureVisible(%d)\n",_list,index);
+
+ if (index == -1) return;
+
+ if (mask & LVIS_FOCUSED) {
+ _list->SetItemState(index, state & LVIS_FOCUSED, mask & LVIS_FOCUSED);
+ }
+
+ if (mask & LVIS_SELECTED) {
+ _list->SetItemState(index, state & LVIS_SELECTED, mask & LVIS_SELECTED);
+ }
+
+ }
+
+ UINT CListView::GetItemState(int index, UINT mask) const
+ {
+ UINT state = _list->GetItemState(index, mask);
+ printf("FIXME %p->GetItemState(index=%d,mask=0x%x)=0x%x\n",_list,index,(unsigned)mask,(unsigned)state); /* FIXME */
+
+ return state;
+ }
+
+ void /* bool */ CListView::Update() {
+ printf("FIXME %p->Update()\n",_list); /* FIXME */
+ }
+
+ bool CListView::DeleteColumn(int columnIndex) {
+ // printf("%p->DeleteColumn()\n",_list);
+ if (_list->GetColumnCount() < 1) return false;
+ return _list->DeleteColumn(columnIndex); // always return true !?
+ }
+
+ bool CListView::GetItemParam(int itemIndex, LPARAM &param) const
+ {
+ param = _list->GetItemData(itemIndex);
+
+ // printf(" %p->GetItemParam(%d) => %ld\n",_list,itemIndex,(long)param);
+
+ return true;
+ }
+
+ int CListView::GetNextItem(int startIndex, UINT flags) const
+ {
+ int item = _list->GetNextItem(startIndex, wxLIST_NEXT_ALL, flags);
+ printf(" %p->GetNextItem(%d) => %d\n",_list,startIndex,item);
+ return item;
+
+ }
+
+ int CListView::GetFocusedItem() const
+ {
+ int item = _list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
+ printf(" %p->GetFocusedItem() => %d\n",_list,item);
+ return item;
+ }
+
+ void CListView::RedrawAllItems()
+ {
+ printf("FIXME %p->RedrawAllItems()\n",_list);
+ }
+
+ // FIXME added
+ int CListView::GetColumnCount()
+ {
+ return _list->GetColumnCount();
+ }
+
+ void CListView::SetFocus() { /* FIXME */ }
+
+ void CListView::RedrawItem(int item) { /* FIXME */ }
+
+ bool CListView::SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam) {
+ printf(" %p->SortItems()\n",_list);
+ return _list->SortItems(compareFunction, dataParam);
+ }
+
+ bool CListView::GetColumn(int columnIndex, LVCOLUMN* columnInfo)
+ {
+ columnInfo->cx = _list->GetColumnWidth(columnIndex);// FIXME
+
+ bool ret = false;
+
+ if (columnInfo->cx >= 1) ret = true;
+
+ // printf("CListView::GetColumn(%d) cx=%d\n",columnIndex,(int)columnInfo->cx);
+
+ return ret;
+ }
+
+ // HWND EditLabel(int itemIndex)
+ void CListView::EditLabel(int itemIndex)
+ {
+ /* FIXME */
+ }
+
+}}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/Dialog.cpp b/src/libs/7zip/unix/CPP/Windows/Control/Dialog.cpp
new file mode 100644
index 000000000..464ae302c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/Dialog.cpp
@@ -0,0 +1,560 @@
+// Dialog.cpp
+
+#include "StdAfx.h"
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWidgets headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#include <wx/filename.h>
+
+
+#undef _WIN32
+
+#include "Windows/Control/DialogImpl.h"
+#include "Windows/Synchronization.h"
+
+
+// FIXME
+class MyApp : public wxApp
+{
+public:
+ virtual bool OnInit();
+};
+
+DECLARE_APP(MyApp)
+
+// #include "../GUI/p7zip_32.xpm"
+extern const char * p7zip_32_xpm[];
+
+const TCHAR * nameWindowToUnix(const TCHAR * lpFileName) {
+ if ((lpFileName[0] == wxT('c')) && (lpFileName[1] == wxT(':'))) return lpFileName+2;
+ return lpFileName;
+}
+
+
+extern time_t g_T0; // FIXME
+
+#define DIALOG_ID_MESSAGEBOX 8100
+#define DIALOG_ID_DIR_DIALOG 8101
+#define DIALOG_ID_FILE_DIALOG 8102
+#define DIALOG_ID_POST_DIALOG 8190
+#define DIALOG_ID_END_DIALOG 8199
+
+static struct
+{
+ bool busy;
+
+ int id;
+ wxWindow *parentWindow;
+
+ // CreateDialog
+ NWindows::NControl::CModalDialog * dialog;
+
+ // EndModal
+ int value;
+ NWindows::NControl::CModalDialogImpl * window;
+
+ // MessageBox
+ const TCHAR * msg;
+ const TCHAR * title;
+ int flag;
+
+ //
+ LPCWSTR initialFolderOrFile;
+
+ wxSemaphore * sem;
+ int ret;
+
+ UString resultPath;
+
+#define MAX_CREATE 16
+} g_tabCreate[MAX_CREATE];
+
+static int myCreateHandle2(int n);
+
+static int findFreeInd()
+{
+static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
+
+ g_CriticalSection.Enter();
+ int ind = 0;
+ while (ind < MAX_CREATE)
+ {
+ if (g_tabCreate[ind].busy == false)
+ {
+ g_tabCreate[ind].busy = true;
+ break;
+ }
+ ind++;
+ }
+ g_CriticalSection.Leave();
+
+ return ind;
+}
+
+static int WaitInd(wxWindow * destWindow, int ind,int id,wxWindow * parent,UString &resultPath)
+{
+ int ret = 0;
+
+ g_tabCreate[ind].id = id;
+ g_tabCreate[ind].parentWindow = parent;
+ g_tabCreate[ind].ret = 0;
+ g_tabCreate[ind].resultPath = wxEmptyString;
+
+ if (wxThread::IsMain())
+ {
+ ret = myCreateHandle2(ind);
+ resultPath = g_tabCreate[ind].resultPath;
+ }
+ else
+ {
+ if (destWindow == 0) {
+ extern wxWindow * g_window;
+ if (g_window == 0)
+ {
+ printf("INTERNAL ERROR : g_window and destWindow == NULL\n"); abort();
+ }
+ destWindow = g_window;
+ }
+ g_tabCreate[ind].sem = new wxSemaphore(0);
+
+ // create any type of command event here
+ wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
+ event.SetInt( ind );
+
+ // send in a thread-safe way
+ // DEBUG printf("T=0x%lx - %d : WaitInd(%d,%p): BEGIN\n", wxThread::GetCurrentId(),time(0)-g_T0,g_tabCreate[ind].id,g_tabCreate[ind].parentWindow);
+ wxPostEvent( destWindow, event );
+
+ g_tabCreate[ind].sem->Wait();
+
+ ret = g_tabCreate[ind].ret;
+ resultPath = g_tabCreate[ind].resultPath;
+ // DEBUG printf("T=0x%lx - %d : WaitInd(%d,%p): ret=%d\n", wxThread::GetCurrentId(),time(0)-g_T0,g_tabCreate[ind].id,g_tabCreate[ind].parentWindow,ret);
+ delete g_tabCreate[ind].sem;
+ g_tabCreate[ind].sem = 0;
+ }
+
+ g_tabCreate[ind].busy = false;
+
+ return ret;
+}
+
+static int WaitInd(wxWindow * destWindow,int ind,int id,wxWindow * parent)
+{
+ UString resultPath;
+ return WaitInd(destWindow,ind,id,parent,resultPath);
+}
+
+void verify_main_thread(void);
+
+class LockGUI
+{
+ bool _IsMain;
+ public:
+ LockGUI() {
+
+ verify_main_thread();
+
+ _IsMain = wxThread::IsMain();
+ if (!_IsMain) {
+ // DEBUG
+ printf("GuiEnter-Dialog(0x%lx)\n",wxThread::GetCurrentId());
+ abort(); // FIXME wxMutexGuiEnter();
+ }
+ }
+ ~LockGUI() {
+ if (!_IsMain) {
+ wxMutexGuiLeave();
+ // DEBUG printf("GuiLeave(0x%lx)\n",wxThread::GetCurrentId());
+ }
+ }
+};
+
+static const unsigned int kNumDialogsMax = 32;
+static unsigned int g_NumDialogs = 0;
+static const CDialogInfo *g_Dialogs[kNumDialogsMax];
+
+void RegisterDialog(const CDialogInfo *dialogInfo)
+{
+ // DEBUG printf("RegisterDialog : %d\n",dialogInfo->id);
+ if (g_NumDialogs < kNumDialogsMax)
+ g_Dialogs[g_NumDialogs++] = dialogInfo;
+}
+
+namespace NWindows {
+
+ CSysString MyLoadString(unsigned int resourceID)
+ {
+ for(unsigned i=0; i < g_NumDialogs; i++) {
+ if (g_Dialogs[i]->stringTable) {
+ int j = 0;
+ while(g_Dialogs[i]->stringTable[j].str) {
+ if (resourceID == g_Dialogs[i]->stringTable[j].id) {
+ return g_Dialogs[i]->stringTable[j].str;
+ }
+
+ j++;
+ }
+ }
+ }
+ return L"FIXME-MyLoadStringW-";
+ }
+
+ namespace NControl {
+
+/////////////////////////////////////////// CModalDialog //////////////////////////////////
+
+ bool CModalDialog::CheckButton(int buttonID, UINT checkState)
+ {
+ LockGUI lock;
+ wxCheckBox* w = (wxCheckBox*)_window->FindWindow(buttonID);
+ if (w)
+ {
+ w->SetValue(checkState == BST_CHECKED);
+ return true;
+ }
+ return false;
+ }
+
+ UINT CModalDialog::IsButtonChecked(int buttonID) const
+ {
+ LockGUI lock;
+ wxCheckBox* w = (wxCheckBox*)_window->FindWindow(buttonID);
+ if (w)
+ {
+ bool bret = w->GetValue();
+ if (bret) return BST_CHECKED;
+ }
+ return BST_UNCHECKED;
+ }
+
+ void CModalDialog::EnableItem(int id, bool state)
+ {
+ LockGUI lock;
+ wxWindow* w = _window->FindWindow(id);
+ if (w) w->Enable(state);
+ }
+
+ void CModalDialog::SetItemText(int id, const TCHAR *txt)
+ {
+ LockGUI lock;
+ wxWindow* w = _window->FindWindow(id);
+ if (w)
+ {
+ wxString label(txt);
+ w->SetLabel(label);
+ }
+ }
+
+ wxWindow * CModalDialog::GetItem(long id) const
+ {
+ LockGUI lock;
+ return _window->FindWindow(id);
+ }
+
+ void CModalDialog::ShowItem(int itemID, int cmdShow) const
+ {
+ LockGUI lock;
+ // cmdShow = SW_HIDE or SW_SHOW (sometimes false or true !)
+ wxWindow* w = _window->FindWindow(itemID);
+ if (w)
+ {
+// FIXME w->Show(cmdShow != SW_HIDE);
+ w->Enable(cmdShow != SW_HIDE);
+ }
+ }
+
+ UINT_PTR CModalDialog::SetTimer(UINT_PTR idEvent , unsigned milliseconds)
+ {
+ LockGUI lock;
+ return _window->SetTimer(idEvent , milliseconds);
+ }
+
+ void CModalDialog::KillTimer(UINT_PTR idEvent)
+ {
+ LockGUI lock;
+ _window->KillTimer(idEvent);
+ }
+
+ void CModalDialog::SetText(const TCHAR *_title) {
+ LockGUI lock;
+ _window->SetTitle(_title);
+ }
+
+
+ bool CModalDialog::GetText(CSysString &s) {
+ wxString str;
+ {
+ LockGUI lock;
+ str = _window->GetTitle();
+ }
+ s = str;
+ return true;
+ }
+
+ INT_PTR CModalDialog::Create(int id , HWND parentWindow)
+ {
+ int ind = findFreeInd();
+
+ g_tabCreate[ind].dialog = this;
+
+ return WaitInd(0, ind,id,parentWindow);
+ }
+
+ void CModalDialog::End(int result)
+ {
+ int ind = findFreeInd();
+
+ g_tabCreate[ind].window = _window;
+ g_tabCreate[ind].value = result;
+
+ WaitInd(this->_window,ind,DIALOG_ID_END_DIALOG,0);
+ }
+
+ void CModalDialog::PostMessage(UINT message)
+ {
+ int ind = findFreeInd();
+
+ g_tabCreate[ind].dialog = this;
+ g_tabCreate[ind].value = message;
+
+ WaitInd(this->_window,ind,DIALOG_ID_POST_DIALOG,0);
+ }
+
+/////////////////////////////////////////// CModalDialogImpl ///////////////////////////////////////
+
+ CModalDialogImpl::CModalDialogImpl(CDialog *dialog, wxWindow* parent, wxWindowID id,
+ const wxString& title, const wxPoint& pos,
+ const wxSize& size, long style) :
+ wxDialog(parent, id, title , pos , size, style /* | wxDIALOG_NO_PARENT */ ) ,
+ _timer(this, TIMER_ID_IMPL), _dialog(dialog)
+ {
+ // set the frame icon
+ this->SetIcon(wxICON(p7zip_32));
+ }
+
+ void CModalDialogImpl::OnAnyButton(wxCommandEvent& event)
+ {
+ int id = event.GetId();
+ if (id == wxID_OK)
+ {
+ if (_dialog) _dialog->OnOK();
+ // event.Skip(true);
+ }
+ else if (id == wxID_CANCEL)
+ {
+ if (_dialog) _dialog->OnCancel();
+ // event.Skip(true);
+ }
+ else if (id == wxID_HELP)
+ {
+ if (_dialog) _dialog->OnHelp();
+ }
+ else
+ {
+ if (_dialog)
+ {
+ /* bool bret = */ _dialog->OnButtonClicked(id, FindWindow(id) );
+ }
+ }
+ }
+
+ void CModalDialogImpl::OnAnyChoice(wxCommandEvent &event)
+ {
+ int itemID = event.GetId();
+ if (_dialog) _dialog->OnCommand(CBN_SELCHANGE, itemID, 0);
+ }
+
+ void CModalDialogImpl::OnAnyTimer(wxTimerEvent &event)
+ {
+ int timerID = event.GetId();
+ if (_dialog) _dialog->OnTimer(timerID , 0);
+ }
+ }
+}
+
+///////////////////////// myCreateHandle
+
+
+static int myCreateHandle2(int n)
+{
+ unsigned int id = g_tabCreate[n].id;
+ wxWindow * parentWindow = g_tabCreate[n].parentWindow;
+ NWindows::NControl::CModalDialogImpl * window = 0;
+
+ // DEBUG printf("T=0x%lx - %d : myCreateHandle(%d): BEGIN\n", wxThread::GetCurrentId(),time(0)-g_T0,n);
+
+ if (id == DIALOG_ID_END_DIALOG)
+ {
+ /* FIXME : the dialog must be shown before ending it ?
+ while (!g_tabCreate[n].window->IsShownOnScreen()) Sleep(200);
+ Sleep(200);
+ */
+ g_tabCreate[n].window->EndModal(g_tabCreate[n].value);
+ return 0;
+ }
+
+ if (id == DIALOG_ID_POST_DIALOG)
+ {
+ g_tabCreate[n].dialog->OnMessage(g_tabCreate[n].value, 0, 0);
+ return 0;
+ }
+
+ if (id == DIALOG_ID_MESSAGEBOX)
+ {
+ long style = g_tabCreate[n].flag;
+ long decorated_style = style;
+ if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION |
+ wxICON_QUESTION ) ) == 0 )
+ {
+ decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ;
+ }
+ wxMessageDialog dialog(parentWindow, g_tabCreate[n].msg, g_tabCreate[n].title, decorated_style);
+ dialog.SetIcon(wxICON(p7zip_32));
+ int ret = dialog.ShowModal();
+
+ return ret;
+ }
+
+ if (id == DIALOG_ID_DIR_DIALOG)
+ {
+ wxString defaultDir = g_tabCreate[n].initialFolderOrFile;
+ wxDirDialog dirDialog(g_tabCreate[n].parentWindow,
+ g_tabCreate[n].title, defaultDir);
+ dirDialog.SetIcon(wxICON(p7zip_32));
+ int ret = dirDialog.ShowModal();
+ if (ret == wxID_OK) g_tabCreate[n].resultPath = dirDialog.GetPath();
+ return ret;
+ }
+
+ if (id == DIALOG_ID_FILE_DIALOG)
+ {
+ wxString defaultFilename = g_tabCreate[n].initialFolderOrFile;
+
+ wxFileName filename(defaultFilename);
+
+ wxString dir = filename.GetPath();
+ wxString name = filename.GetFullName();
+
+
+ // printf("DIALOG_ID_FILE_DIALOG = '%ls' => '%ls' '%ls'\n",&defaultFilename[0],&dir[0],&name[0]);
+
+
+ wxFileDialog fileDialog(g_tabCreate[n].parentWindow, g_tabCreate[n].title,
+ dir, name, wxT("All Files (*.*)|*.*"), wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
+ fileDialog.SetIcon(wxICON(p7zip_32));
+ int ret = fileDialog.ShowModal();
+ if (ret == wxID_OK) g_tabCreate[n].resultPath = fileDialog.GetPath();
+ return ret;
+ }
+
+ for(unsigned i=0; i < g_NumDialogs; i++) {
+ if (id == g_Dialogs[i]->id) {
+ // DEBUG printf("%d : Create(%d,%p): CreateDialog-1\n",time(0)-g_T0,id,parentWindow);
+ window = (g_Dialogs[i]->createDialog)(g_tabCreate[n].dialog,g_tabCreate[n].parentWindow);
+ // DEBUG printf("%d : Create(%d,%p): CreateDialog-2\n",time(0)-g_T0,id,parentWindow);
+ break;
+ }
+ }
+
+ if (window) {
+
+ // DEBUG printf("%d : Create(%d,%p): %p->ShowModal()\n",time(0)-g_T0,id,parentWindow,window);
+
+ // window->Show(true);
+ // wxGetApp().ProcessPendingEvents();
+
+ INT_PTR ret = window->ShowModal();
+
+ // DEBUG printf("%d : Create(%d,%p): %p->ShowModal() - ret=%d\n",time(0)-g_T0,id,parentWindow,window,ret);
+ window->Detach();
+ window->Destroy();
+
+ // DEBUG printf("%d : Create(%d,%p): END\n",time(0)-g_T0,id,parentWindow,window);
+
+ return ret;
+ }
+
+ // FIXME
+ printf("INTERNAL ERROR : cannot find dialog %d\n",id);
+
+ return 0;
+}
+
+void myCreateHandle(int n)
+{
+ int ret = myCreateHandle2(n);
+ g_tabCreate[n].ret = ret;
+ g_tabCreate[n].sem->Post();
+}
+
+int MessageBoxW(wxWindow * parent, const TCHAR * msg, const TCHAR * title,int flag)
+{
+ int ind = findFreeInd();
+
+ g_tabCreate[ind].msg = msg;
+ g_tabCreate[ind].title = title;
+ g_tabCreate[ind].flag = flag;
+
+ return WaitInd(parent,ind,DIALOG_ID_MESSAGEBOX,parent); // FIXME
+}
+
+
+
+// FIXME : should be in Windows/Shell.cpp
+
+namespace NWindows{
+namespace NShell{
+
+bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath)
+{
+ int ind = findFreeInd();
+
+ g_tabCreate[ind].title = title;
+ g_tabCreate[ind].initialFolderOrFile = nameWindowToUnix(initialFolder);
+
+ UString resTmp;
+ int ret = WaitInd(0,ind,DIALOG_ID_DIR_DIALOG,owner,resTmp); // FIXME
+ if(ret == wxID_OK)
+ {
+ resultPath = resTmp;
+ return true;
+ }
+ return false;
+}
+
+}}
+
+/////////////////////////// CPP/Windows/CommonDialog.cpp
+namespace NWindows
+{
+
+ bool MyGetOpenFileName(HWND hwnd, LPCWSTR title, LPCWSTR fullFileName, LPCWSTR s, UString &resPath)
+ {
+ int ind = findFreeInd();
+
+ g_tabCreate[ind].title = title;
+ g_tabCreate[ind].initialFolderOrFile = nameWindowToUnix(fullFileName);
+
+ UString resTmp;
+ int ret = WaitInd(0,ind,DIALOG_ID_FILE_DIALOG,hwnd,resTmp); // FIXME
+ if(ret == wxID_OK)
+ {
+ resPath = resTmp;
+ return true;
+ }
+ return false;
+ }
+}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/Dialog.h b/src/libs/7zip/unix/CPP/Windows/Control/Dialog.h
new file mode 100644
index 000000000..54899a104
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/Dialog.h
@@ -0,0 +1,179 @@
+// Windows/Control/Dialog.h
+
+#ifndef __WINDOWS_CONTROL_DIALOG_H
+#define __WINDOWS_CONTROL_DIALOG_H
+
+#include "Windows/Window.h"
+
+#ifndef _WIN32
+#define SW_HIDE 0
+#define SW_SHOW 5
+
+#define WM_SETTEXT (6000) // wxID_HIGHEST + 1
+#define WM_USER (6999) // wxID_HIGHEST + 1000
+
+#endif
+
+#ifndef _WIN32
+#define CBN_SELCHANGE 1
+#endif
+
+// FIXME
+#define IDCLOSE (5001) // wxID_CLOSE
+#define IDEXIT (5006) // wxID_EXIT
+#define IDOK (5100) // wxID_OK
+#define IDCANCEL (5101) // wxID_CANCEL
+#define IDABORT (5115) // wxID_ABORT
+#define IDYES (5103) // wxID_YES
+#define IDNO (5104) // wxID_NO
+#define IDHELP (5009) // wxID_HELP
+
+#define BST_CHECKED 1
+#define BST_UNCHECKED 0
+// #define BST_INDETERMINATE 0x0002
+
+#define wsprintf(a,b,c,d,e) swprintf(a,9999,b,c,d,e) // FIXME
+
+namespace NWindows {
+ namespace NControl {
+
+ class CModalDialogImpl;
+
+ class CDialog
+ {
+ protected:
+ CModalDialogImpl * _window;
+ public:
+ operator HWND() const { return HWND(_window); }
+
+ bool OnInit(CModalDialogImpl * window) {
+ _window = window;
+ return OnInit();
+ }
+ virtual bool OnInit() { return false; }
+ virtual void OnOK() {}
+ virtual void OnCancel() {}
+ virtual void OnHelp() {}
+ virtual bool OnButtonClicked(int buttonID, wxWindow * buttonHWND) { return false; }
+ virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) { return false; }
+ virtual bool OnCommand(int code, int itemID, LPARAM lParam) { return false; }
+ virtual bool OnTimer(WPARAM /* timerID */, LPARAM /* callback */) { return false; }
+
+ void NormalizeSize(bool fullNormalize = false) { /* FIXME */ }
+ void NormalizePosition() { /* FIXME */ }
+ };
+
+ class CModalDialog : public CDialog
+ {
+ public:
+
+
+ ////////////////// COMPATIBILITY
+
+ bool CheckRadioButton(int firstButtonID, int lastButtonID, int checkButtonID)
+ {
+/*
+ for(int id = firstButtonID; id <= lastButtonID; id++)
+ {
+ CheckButton(id,id == checkButtonID);
+ }
+*/
+ this->CheckButton(checkButtonID,true);
+
+ return true;
+ }
+
+
+ bool CheckButton(int buttonID, UINT checkState);
+ bool CheckButton(int buttonID, bool checkState)
+ {
+ return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED));
+ }
+
+
+ UINT IsButtonChecked(int buttonID) const;
+
+ bool IsButtonCheckedBool(long buttonID) const
+ { return (IsButtonChecked(buttonID) == BST_CHECKED); }
+
+ void EnableItem(int id, bool state);
+
+ void SetItemText(int id, const TCHAR *txt);
+
+ wxWindow * GetItem(long id) const ;
+
+ void ShowItem(int itemID, int cmdShow) const;
+
+ void HideItem(int itemID) const { ShowItem(itemID, SW_HIDE); }
+
+ void End(int result);
+
+ void SetText(const TCHAR *_title); // { _dialog->SetTitle(_title); }
+
+ bool GetText(CSysString &s);
+
+ INT_PTR Create(int id , HWND parentWindow);
+
+ void PostMessage(UINT message);
+
+ virtual void OnHelp() {}
+
+ UINT_PTR SetTimer(UINT_PTR idEvent , unsigned milliseconds);
+
+ void KillTimer(UINT_PTR idEvent);
+
+ virtual void OnOK() { End(IDOK); }
+ virtual void OnCancel() { End(IDCANCEL); }
+ };
+
+class CDialogChildControl : public NWindows::CWindow
+{
+public:
+ CDialogChildControl() {}
+
+ int m_ID;
+ void Init(const NWindows::NControl::CModalDialog &parentDialog, int id)
+ {
+ m_ID = id;
+ this->Attach(parentDialog.GetItem(id));
+ }
+ virtual void SetText(LPCWSTR s);
+ virtual bool GetText(CSysString &s);
+};
+
+}
+}
+
+struct CStringTable
+{
+ unsigned int id;
+ const wchar_t *str;
+};
+
+struct CDialogInfo
+{
+ unsigned int id;
+ NWindows::NControl::CModalDialogImpl * (*createDialog)(NWindows::NControl::CModalDialog * dialog, HWND parentWindow);
+ CStringTable * stringTable;
+};
+
+void RegisterDialog(const CDialogInfo *dialogInfo);
+
+#define REGISTER_DIALOG_NAME(x) CRegister ## x
+
+#define REGISTER_DIALOG(id,x,stringTable) \
+ static NWindows::NControl::CModalDialogImpl * myCreate##x(NWindows::NControl::CModalDialog * dialog,HWND parentWindow) \
+ { return new x##Impl(dialog,parentWindow,id); } \
+ static struct CDialogInfo g_DialogInfo = { id , myCreate##x, stringTable }; \
+ struct REGISTER_DIALOG_NAME(x) { \
+ REGISTER_DIALOG_NAME(x)() { RegisterDialog(&g_DialogInfo); }}; \
+ static REGISTER_DIALOG_NAME(x) g_RegisterDialog;
+
+#define REGISTER_STRINGTABLE(stringTable) \
+ static struct CDialogInfo g_DialogInfo = { -1 , 0 , stringTable }; \
+ struct REGISTER_DIALOG_NAME(x) { \
+ REGISTER_DIALOG_NAME(x)() { RegisterDialog(&g_DialogInfo); }}; \
+ static REGISTER_DIALOG_NAME(x) g_RegisterDialog;
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/DialogImpl.h b/src/libs/7zip/unix/CPP/Windows/Control/DialogImpl.h
new file mode 100644
index 000000000..a9720b778
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/DialogImpl.h
@@ -0,0 +1,73 @@
+// Windows/Control/DialogImpl.h
+
+#ifndef __WINDOWS_CONTROL_DIALOGIMPL_H
+#define __WINDOWS_CONTROL_DIALOGIMPL_H
+
+#include "Windows/Window.h"
+#include "Windows/Control/Dialog.h"
+
+void myCreateHandle(int n); // FIXME - duplicate
+
+enum {
+ WORKER_EVENT=100 // this one gets sent from the worker thread
+};
+
+namespace NWindows {
+ namespace NControl {
+
+#define TIMER_ID_IMPL (1234)
+
+ class CModalDialogImpl : public wxDialog
+ {
+ wxTimer _timer;
+
+ CDialog *_dialog;
+ public:
+ CModalDialogImpl(CDialog *dialog, wxWindow* parent, wxWindowID id, const wxString& title,
+ const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+ long style = wxDEFAULT_DIALOG_STYLE );
+
+ CDialog * Detach()
+ {
+ CDialog * oldDialog = _dialog;
+ _dialog = NULL;
+ return oldDialog;
+ }
+
+ void OnInit()
+ {
+ if (_dialog) _dialog->OnInit(this);
+ }
+
+ void OnAnyButton(wxCommandEvent& event);
+ void OnAnyChoice(wxCommandEvent &event);
+ void OnAnyTimer(wxTimerEvent &event);
+
+/* FIXME virtual void SetLabel(const wxString &title)
+ {
+ // Why we must do this "alias" ?
+ this->SetTitle(title);
+ }
+*/
+ //////////////////
+ UINT_PTR SetTimer(UINT_PTR /* FIXME idEvent */, unsigned milliseconds)
+ {
+ _timer.Start(milliseconds);
+ return TIMER_ID_IMPL;
+ }
+ void KillTimer(UINT_PTR idEvent)
+ {
+ if (idEvent == TIMER_ID_IMPL) _timer.Stop();
+ }
+ void OnWorkerEvent(wxCommandEvent& event)
+ {
+ int n = event.GetInt();
+ // printf("CModalDialogImpl::OnWorkerEvent(n=%d)\n",n);
+ myCreateHandle(n);
+ }
+ };
+}
+}
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/Edit.h b/src/libs/7zip/unix/CPP/Windows/Control/Edit.h
new file mode 100644
index 000000000..e6930e5d4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/Edit.h
@@ -0,0 +1,24 @@
+// Windows/Control/Edit.h
+
+#ifndef __WINDOWS_CONTROL_EDIT_H
+#define __WINDOWS_CONTROL_EDIT_H
+
+#include "Windows/Window.h"
+#include "Windows/Defs.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CEdit: public CWindow
+{
+public:
+ void SetPasswordChar(WPARAM c);
+ void Show(int cmdShow);
+ virtual void SetText(LPCWSTR s);
+ virtual bool GetText(CSysString &s);
+};
+
+}}
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/ListView.h b/src/libs/7zip/unix/CPP/Windows/Control/ListView.h
new file mode 100644
index 000000000..149f4a450
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/ListView.h
@@ -0,0 +1,164 @@
+// Windows/Control/ListView.h
+
+#ifndef __WINDOWS_CONTROL_LISTVIEW_H
+#define __WINDOWS_CONTROL_LISTVIEW_H
+
+#include "Windows/Window.h"
+#include "Windows/Defs.h"
+
+/*
+#include <commctrl.h>
+*/
+
+#ifndef _WIN32
+
+#define LVCF_FMT 0x0001
+#define LVCF_WIDTH 0x0002
+#define LVCF_TEXT 0x0004
+#define LVCF_SUBITEM 0x0008
+#define LVCF_IMAGE 0x0010
+#define LVCF_ORDER 0x0020
+
+#define LVCFMT_LEFT 0x0000
+#define LVCFMT_RIGHT 0x0001
+#define LVCFMT_CENTER 0x0002
+#define LVCFMT_JUSTIFYMASK 0x0003
+
+
+// state
+#define LVIS_FOCUSED 0x0002 /* wxLIST_STATE_FOCUSED */
+#define LVIS_SELECTED 0x0004 /* wxLIST_STATE_SELECTED */
+
+#define LVNI_SELECTED 0x0004 /* wxLIST_STATE_SELECTED */
+
+typedef INT (CALLBACK *PFNLVCOMPARE)(LPARAM, LPARAM, LPARAM);
+
+typedef struct tagLVCOLUMNW
+{
+ UINT mask;
+ int fmt;
+ int cx;
+ LPWSTR pszText;
+ int cchTextMax;
+ int iSubItem;
+ int iOrder; // FIXME
+} LVCOLUMNW;
+
+#define LVCOLUMN LVCOLUMNW
+#define LV_COLUMNW LVCOLUMNW /* FIXME */
+
+
+
+typedef struct tagLVITEMW
+{
+ UINT mask;
+ int iItem;
+ int iSubItem;
+ UINT state;
+ UINT stateMask;
+ LPWSTR pszText;
+ int cchTextMax;
+ int iImage;
+ LPARAM lParam;
+#if (_WIN32_IE >= 0x0300)
+ int iIndent;
+#endif
+#if (_WIN32_WINNT >= 0x501)
+ int iGroupId;
+ UINT cColumns; // tile view columns
+ PUINT puColumns;
+#endif
+} LVITEMW;
+
+#define LVITEM LVITEMW
+
+#define LVIF_TEXT 0x0001
+// FIXME - mask
+#define LVIF_PARAM 2
+#define LVIF_IMAGE 4
+#define LVIF_STATE 8
+
+#endif
+
+class wxListCtrl;
+
+namespace NWindows {
+namespace NControl {
+
+class CListView // : public NWindows::CWindow
+{
+ wxListCtrl *_list;
+public:
+ CListView() : _list(0) {}
+ void Attach(wxWindow * newWindow);
+
+ operator HWND() const;
+
+ int GetItemCount() const;
+
+ int InsertItem(int index, LPCTSTR text);
+ int InsertItem(const LVITEM* item);
+
+ void SetItem(const LVITEM* item);
+
+ int SetSubItem(int index, int subIndex, LPCTSTR text);
+
+ void SetUnicodeFormat(bool fUnicode) { return ; }
+
+ void InsertColumn(int columnIndex, LPCTSTR text, int width);
+
+ void InsertColumn(int columnIndex, const LVCOLUMNW *columnInfo);
+
+ void DeleteAllItems();
+
+ void SetRedraw(bool);
+
+ void SetItemCount(int );
+
+ void InvalidateRect(void *, bool);
+
+ int GetSelectedCount() const;
+
+ void /* bool */ EnsureVisible(int index, bool partialOK);
+
+ void SetItemState(int index, UINT state, UINT mask);
+
+ void SetItemState_FocusedSelected(int index) { SetItemState(index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); }
+
+ UINT GetItemState(int index, UINT mask) const;
+
+ void /* bool */ Update();
+
+ bool DeleteColumn(int columnIndex);
+
+ bool GetItemParam(int itemIndex, LPARAM &param) const;
+
+ int GetNextItem(int startIndex, UINT flags) const;
+
+ int GetFocusedItem() const;
+
+ void RedrawAllItems();
+ // FIXME added
+ int GetColumnCount();
+
+ void SetFocus();
+
+ void RedrawItem(int item);
+
+ bool SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam);
+
+ bool GetColumn(int columnIndex, LVCOLUMN* columnInfo);
+
+ // HWND EditLabel(int itemIndex)
+ void EditLabel(int itemIndex);
+
+ bool SetColumnWidthAuto(int iCol) {
+ return true; // FIXME SetColumnWidth(iCol, LVSCW_AUTOSIZE);
+ }
+
+
+};
+
+}}
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/ProgressBar.h b/src/libs/7zip/unix/CPP/Windows/Control/ProgressBar.h
new file mode 100644
index 000000000..c7bfa8e8d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/ProgressBar.h
@@ -0,0 +1,34 @@
+// Windows/Control/ProgressBar.h
+
+#ifndef __WINDOWS_CONTROL_PROGRESSBAR_H
+#define __WINDOWS_CONTROL_PROGRESSBAR_H
+
+#include "Windows/Window.h"
+#include "Windows/Defs.h"
+
+class wxGauge;
+
+namespace NWindows {
+namespace NControl {
+
+
+class CProgressBar : public CWindow
+{
+protected:
+ wxGauge* _window;
+ int _minValue;
+ int _range;
+public:
+ CProgressBar(wxWindow* newWindow = NULL);
+
+ void Attach(wxWindow* newWindow);
+
+ void SetRange32(int minValue, int maxValue);
+
+ void SetPos(int pos);
+};
+
+}}
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/Static.h b/src/libs/7zip/unix/CPP/Windows/Control/Static.h
new file mode 100644
index 000000000..36469c18f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/Static.h
@@ -0,0 +1,23 @@
+// Windows/Control/Static.h
+
+#ifndef __WINDOWS_CONTROL_STATIC_H
+#define __WINDOWS_CONTROL_STATIC_H
+
+#include "Windows/Window.h"
+#include "Windows/Defs.h"
+
+typedef void * HICON;
+
+namespace NWindows {
+namespace NControl {
+
+class CStatic : public CWindow
+{
+public:
+
+ HICON SetIcon(HICON icon) { return 0; } // FIXME
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/StatusBar.h b/src/libs/7zip/unix/CPP/Windows/Control/StatusBar.h
new file mode 100644
index 000000000..6b4417d10
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/StatusBar.h
@@ -0,0 +1,56 @@
+// Windows/Control/StatusBar.h
+
+#ifndef __WINDOWS_CONTROL_STATUSBAR_H
+#define __WINDOWS_CONTROL_STATUSBAR_H
+
+#include "Windows/Window.h"
+#include "Windows/Defs.h"
+
+class wxStatusBar;
+
+namespace NWindows {
+namespace NControl {
+
+class CStatusBar // : public NWindows::CWindow
+{
+ wxStatusBar * _statusBar;
+public:
+ CStatusBar() : _statusBar(0) {}
+
+ void Attach(wxWindow * newWindow);
+ wxWindow * Detach();
+
+ void SetText(int index, LPCTSTR text);
+
+/* FIXME
+ bool Create(LONG style, LPCTSTR text, HWND hwndParent, UINT id)
+ { return (_window = ::CreateStatusWindow(style, text, hwndParent, id)) != 0; }
+ bool SetParts(int numParts, const int *edgePostions)
+ { return LRESULTToBool(SendMessage(SB_SETPARTS, numParts, (LPARAM)edgePostions)); }
+ bool SetText(LPCTSTR text)
+ { return CWindow::SetText(text); }
+
+ bool SetText(int index, LPCTSTR text, UINT type)
+ { return LRESULTToBool(SendMessage(SB_SETTEXT, index | type, (LPARAM)text)); }
+ bool SetText(int index, LPCTSTR text)
+ { return SetText(index, text, 0); }
+ void Simple(bool simple)
+ { SendMessage(SB_SIMPLE, BoolToBOOL(simple), 0); }
+
+ #ifndef _UNICODE
+ bool Create(LONG style, LPCWSTR text, HWND hwndParent, UINT id)
+ { return (_window = ::CreateStatusWindowW(style, text, hwndParent, id)) != 0; }
+ bool SetText(LPCWSTR text)
+ { return CWindow::SetText(text); }
+ bool SetText(int index, LPCWSTR text, UINT type)
+ { return LRESULTToBool(SendMessage(SB_SETTEXTW, index | type, (LPARAM)text)); }
+ bool SetText(int index, LPCWSTR text)
+ { return SetText(index, text, 0); }
+ #endif
+*/
+};
+
+}}
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/Window2.cpp b/src/libs/7zip/unix/CPP/Windows/Control/Window2.cpp
new file mode 100644
index 000000000..dda1da090
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/Window2.cpp
@@ -0,0 +1,211 @@
+// Windows/Control/Window2.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+#include "Windows/Control/Window2.h"
+
+// extern HINSTANCE g_hInstance;
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+#ifndef _UNICODE
+ATOM MyRegisterClass(CONST WNDCLASSW *wndClass);
+#endif
+
+namespace NControl {
+
+#ifdef _WIN32
+static LRESULT CALLBACK WindowProcedure(HWND aHWND, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ CWindow tempWindow(aHWND);
+ if (message == WM_NCCREATE)
+ tempWindow.SetUserDataLongPtr(
+ LONG_PTR(((LPCREATESTRUCT)lParam)->lpCreateParams));
+ CWindow2 *window = (CWindow2*)(tempWindow.GetUserDataLongPtr());
+ if (window != NULL && message == WM_NCCREATE)
+ window->Attach(aHWND);
+ if (window == 0)
+ {
+ #ifndef _UNICODE
+ if (g_IsNT)
+ return DefWindowProcW(aHWND, message, wParam, lParam);
+ else
+ #endif
+ return DefWindowProc(aHWND, message, wParam, lParam);
+ }
+ return window->OnMessage(message, wParam, lParam);
+}
+
+bool CWindow2::CreateEx(DWORD exStyle, LPCTSTR className,
+ LPCTSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance)
+{
+ WNDCLASS windowClass;
+ if(!::GetClassInfo(instance, className, &windowClass))
+ {
+ // windowClass.style = CS_HREDRAW | CS_VREDRAW;
+ windowClass.style = 0;
+
+ windowClass.lpfnWndProc = WindowProcedure;
+ windowClass.cbClsExtra = NULL;
+ windowClass.cbWndExtra = NULL;
+ windowClass.hInstance = instance;
+ windowClass.hIcon = NULL;
+ windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ windowClass.lpszMenuName = NULL;
+ windowClass.lpszClassName = className;
+ if (::RegisterClass(&windowClass) == 0)
+ return false;
+ }
+ return CWindow::CreateEx(exStyle, className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, this);
+}
+
+#ifndef _UNICODE
+
+bool CWindow2::CreateEx(DWORD exStyle, LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance)
+{
+ bool needRegister;
+ if(g_IsNT)
+ {
+ WNDCLASSW windowClass;
+ needRegister = ::GetClassInfoW(instance, className, &windowClass) == 0;
+ }
+ else
+ {
+ WNDCLASSA windowClassA;
+ AString classNameA;
+ LPCSTR classNameP;
+ if (IS_INTRESOURCE(className))
+ classNameP = (LPCSTR)className;
+ else
+ {
+ classNameA = GetSystemString(className);
+ classNameP = classNameA;
+ }
+ needRegister = ::GetClassInfoA(instance, classNameP, &windowClassA) == 0;
+ }
+ if (needRegister)
+ {
+ WNDCLASSW windowClass;
+ // windowClass.style = CS_HREDRAW | CS_VREDRAW;
+ windowClass.style = 0;
+ windowClass.lpfnWndProc = WindowProcedure;
+ windowClass.cbClsExtra = NULL;
+ windowClass.cbWndExtra = NULL;
+ windowClass.hInstance = instance;
+ windowClass.hIcon = NULL;
+ windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ windowClass.lpszMenuName = NULL;
+ windowClass.lpszClassName = className;
+ if (MyRegisterClass(&windowClass) == 0)
+ return false;
+ }
+ return CWindow::CreateEx(exStyle, className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, this);
+
+}
+#endif
+
+LRESULT CWindow2::DefProc(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ #ifndef _UNICODE
+ if (g_IsNT)
+ return DefWindowProcW(_window, message, wParam, lParam);
+ else
+ #endif
+ return DefWindowProc(_window, message, wParam, lParam);
+}
+#endif
+
+LRESULT CWindow2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result;
+ switch (message)
+ {
+ case WM_CREATE:
+ if (!OnCreate((CREATESTRUCT *)lParam))
+ return -1;
+ break;
+ case WM_COMMAND:
+ if (OnCommand(wParam, lParam, result))
+ return result;
+ break;
+ case WM_NOTIFY:
+ if (OnNotify((UINT)wParam, (LPNMHDR) lParam, result))
+ return result;
+ break;
+ case WM_DESTROY:
+ OnDestroy();
+ break;
+ case WM_CLOSE:
+ OnClose();
+ return 0;
+#ifdef _WIN32
+ case WM_SIZE:
+ if (OnSize(wParam, LOWORD(lParam), HIWORD(lParam)))
+ return 0;
+#endif
+ }
+#ifdef _WIN32
+ return DefProc(message, wParam, lParam);
+#else
+ return 0;
+#endif
+}
+
+bool CWindow2::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT &result)
+{
+ return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result);
+}
+
+bool CWindow2::OnCommand(int /* code */, int /* itemID */, LPARAM /* lParam */, LRESULT & /* result */)
+{
+ return false;
+ // return DefProc(message, wParam, lParam);
+ /*
+ if (code == BN_CLICKED)
+ return OnButtonClicked(itemID, (HWND)lParam);
+ */
+}
+
+/*
+bool CDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
+{
+ switch(aButtonID)
+ {
+ case IDOK:
+ OnOK();
+ break;
+ case IDCANCEL:
+ OnCancel();
+ break;
+ case IDHELP:
+ OnHelp();
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+*/
+
+}}
diff --git a/src/libs/7zip/unix/CPP/Windows/Control/Window2.h b/src/libs/7zip/unix/CPP/Windows/Control/Window2.h
new file mode 100644
index 000000000..48c890640
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Control/Window2.h
@@ -0,0 +1,111 @@
+// Windows/Control/Window2.h
+
+#ifndef __WINDOWS_CONTROL_WINDOW2_H
+#define __WINDOWS_CONTROL_WINDOW2_H
+
+#include "Windows/Window.h"
+#include "Windows/Defs.h"
+
+#ifndef _WIN32
+typedef void * WNDPROC;
+typedef void * CREATESTRUCT;
+typedef struct
+{
+ HWND hwndFrom;
+
+ UINT code;
+#define NM_DBLCLK 1
+#define LVN_ITEMCHANGED 2
+#define LVN_COLUMNCLICK 3
+#define CBEN_BEGINEDIT 10
+#define CBEN_ENDEDITW 11
+
+
+} NMHDR;
+typedef NMHDR * LPNMHDR;
+
+typedef struct tagNMLISTVIEW
+{
+ NMHDR hdr;
+ INT iItem;
+ INT iSubItem;
+ UINT uNewState;
+ UINT uOldState;
+ // UINT uChanged;
+ // POINT ptAction;
+ LPARAM lParam;
+} NMLISTVIEW, *LPNMLISTVIEW;
+
+typedef void * LPNMITEMACTIVATE;
+
+#define NM_RCLICK 1234 /* FIXME */
+
+// FIXME
+#define WM_CREATE 1
+#define WM_COMMAND 2
+#define WM_NOTIFY 3
+#define WM_DESTROY 4
+#define WM_CLOSE 5
+
+#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16))
+#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xFFFF))
+
+
+#endif
+
+namespace NWindows {
+namespace NControl {
+
+class CWindow2 // : public CWindow
+{
+ // LRESULT DefProc(UINT message, WPARAM wParam, LPARAM lParam);
+public:
+ // CWindow2(HWND newWindow = NULL): CWindow(newWindow){};
+ CWindow2() {}
+ virtual ~CWindow2() {}
+
+#ifdef _WIN32
+ bool CreateEx(DWORD exStyle, LPCTSTR className,
+ LPCTSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance);
+
+ #ifndef _UNICODE
+ bool CreateEx(DWORD exStyle, LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance);
+ #endif
+#endif
+
+ virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
+ virtual bool OnCreate(CREATESTRUCT * /* createStruct */) { return true; }
+ // virtual LRESULT OnCommand(WPARAM wParam, LPARAM lParam);
+ virtual bool OnCommand(WPARAM wParam, LPARAM lParam, LRESULT &result);
+ virtual bool OnCommand(int code, int itemID, LPARAM lParam, LRESULT &result);
+ virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; }
+ virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */, LRESULT & /* result */) { return false; }
+ virtual void OnDestroy() { /* FIXME PostQuitMessage(0); */ }
+ virtual void OnClose() { /* FIXME Destroy(); */ }
+ /*
+ virtual LRESULT OnHelp(LPHELPINFO helpInfo) { OnHelp(); };
+ virtual LRESULT OnHelp() {};
+ virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
+ virtual void OnOK() {};
+ virtual void OnCancel() {};
+ */
+
+#ifdef _WIN32
+ LONG_PTR SetMsgResult(LONG_PTR newLongPtr )
+ { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); }
+ LONG_PTR GetMsgResult() const
+ { return GetLongPtr(DWLP_MSGRESULT); }
+#endif
+};
+
+}}
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/DLL.cpp b/src/libs/7zip/unix/CPP/Windows/DLL.cpp
new file mode 100644
index 000000000..5f76cc5e2
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/DLL.cpp
@@ -0,0 +1,193 @@
+// Windows/DLL.cpp
+
+#include "StdAfx.h"
+
+#ifdef __APPLE_CC__
+#include <mach-o/dyld.h>
+#elif ENV_BEOS
+#include <kernel/image.h>
+#include <Path.h>
+#else
+#define UINT64 DLL_UINT64 // HP-UX , dlfcn.h defines UINT64 but p7zip also defines UINT64
+#include <dlfcn.h> // dlopen ...
+#undef UINT64
+#endif
+
+#include "DLL.h"
+#include "Defs.h"
+#ifdef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#define NEED_NAME_WINDOWS_TO_UNIX
+#include "myPrivate.h"
+
+// #define TRACEN(u) u;
+#define TRACEN(u) /* */
+
+namespace NWindows {
+namespace NDLL {
+
+CLibrary::~CLibrary()
+{
+ Free();
+}
+
+bool CLibrary::Free()
+{
+TRACEN((printf("CLibrary::Free(%p)\n",(void *)_module)))
+ if (_module == 0)
+ return true;
+
+#ifdef __APPLE_CC__
+ int ret = NSUnLinkModule ((NSModule)_module, 0);
+#elif ENV_BEOS
+ int ret = unload_add_on((image_id)_module);
+#else
+ int ret = dlclose(_module);
+#endif
+TRACEN((printf("CLibrary::Free dlclose(%p)=%d\n",(void *)_module,ret)))
+ if (ret != 0) return false;
+ _module = 0;
+ return true;
+}
+
+static FARPROC local_GetProcAddress(HMODULE module,LPCSTR lpProcName)
+{
+ void *ptr = 0;
+ TRACEN((printf("local_GetProcAddress(%p,%s)\n",(void *)module,lpProcName)))
+ if (module) {
+#ifdef __APPLE_CC__
+ char name[MAX_PATHNAME_LEN];
+ snprintf(name,sizeof(name),"_%s",lpProcName);
+ name[sizeof(name)-1] = 0;
+ TRACEN((printf("NSLookupSymbolInModule(%p,%s)\n",(void *)module,name)))
+ NSSymbol sym;
+ sym = NSLookupSymbolInModule((NSModule)module, name);
+ if (sym) {
+ ptr = NSAddressOfSymbol(sym);
+ } else {
+ ptr = 0;
+ }
+#elif ENV_BEOS
+ if (get_image_symbol((image_id)module, lpProcName, B_SYMBOL_TYPE_TEXT, &ptr) != B_OK)
+ ptr = 0;
+#else
+ ptr = dlsym (module, lpProcName);
+#endif
+ TRACEN((printf("CLibrary::GetProc : dlsym(%p,%s)=%p\n",(void *)module,lpProcName,ptr)))
+ }
+ return (FARPROC)ptr;
+}
+
+FARPROC CLibrary::GetProc(LPCSTR lpProcName) const
+{
+ TRACEN((printf("CLibrary::GetProc(%p,%s)\n",(void *)_module,lpProcName)))
+ return local_GetProcAddress(_module,lpProcName);
+}
+
+bool CLibrary::LoadOperations(HMODULE newModule)
+{
+ if (newModule == NULL)
+ return false;
+ if(!Free())
+ return false;
+ _module = newModule;
+ return true;
+}
+
+bool CLibrary::Load(LPCTSTR lpLibFileName)
+{
+ void *handler = 0;
+ char name[MAX_PATHNAME_LEN+1];
+#ifdef _UNICODE
+ AString name2 = UnicodeStringToMultiByte(lpLibFileName);
+ strcpy(name,nameWindowToUnix((const char *)name2));
+#else
+ strcpy(name,nameWindowToUnix(lpLibFileName));
+#endif
+
+ // replace ".dll" with ".so"
+ size_t len = strlen(name);
+ if ((len >=4) && (strcmp(name+len-4,".dll") == 0)) {
+ strcpy(name+len-4,".so");
+ }
+
+ TRACEN((printf("CLibrary::Load(%ls) => %s\n",lpLibFileName,name)))
+
+#ifdef __APPLE_CC__
+ NSObjectFileImage image;
+ NSObjectFileImageReturnCode nsret;
+
+ nsret = NSCreateObjectFileImageFromFile (name, &image);
+ if (nsret == NSObjectFileImageSuccess) {
+ TRACEN((printf("NSCreateObjectFileImageFromFile(%s) : OK\n",name)))
+ handler = (HMODULE)NSLinkModule(image,name,NSLINKMODULE_OPTION_RETURN_ON_ERROR
+ | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_BINDNOW);
+ } else {
+ TRACEN((printf("NSCreateObjectFileImageFromFile(%s) : ERROR\n",name)))
+ }
+#elif ENV_BEOS
+ // normalize path (remove things like "./", "..", etc..), otherwise it won't work
+ BPath p(name, NULL, true);
+ status_t err = B_OK;
+ image_id image = load_add_on(p.Path());
+TRACEN((printf("load_add_on(%s)=%d\n",p.Path(),(int)image)))
+ if (image < 0) {
+ err = (image_id)handler;
+ handler = 0;
+ } else {
+ err = 0;
+ handler = (HMODULE)image;
+ }
+#else
+ int options_dlopen = 0;
+#ifdef RTLD_LOCAL
+ options_dlopen |= RTLD_LOCAL;
+#endif
+#ifdef RTLD_NOW
+ options_dlopen |= RTLD_NOW;
+#endif
+#ifdef RTLD_GROUP
+ #if ! (defined(hpux) || defined(__hpux))
+ options_dlopen |= RTLD_GROUP; // mainly for solaris but not for HPUX
+ #endif
+#endif
+ TRACEN((printf("CLibrary::Load - dlopen(%s,0x%d)\n",name,options_dlopen)))
+ handler = dlopen(name,options_dlopen);
+#endif // __APPLE_CC__
+ TRACEN((printf("CLibrary::Load(%s) => %p\n",name,handler)))
+ if (handler) {
+
+ // Call DllMain() like in Windows : useless now
+
+ // Propagate the value of global_use_utf16_conversion into the plugins
+ int *tmp = (int *)local_GetProcAddress(handler,"global_use_utf16_conversion");
+ if (tmp) *tmp = global_use_utf16_conversion;
+
+ tmp = (int *)local_GetProcAddress(handler,"global_use_lstat");
+ if (tmp) *tmp = global_use_lstat;
+
+ // test construtors calls
+ void (*fctTest)(void) = (void (*)(void))local_GetProcAddress(handler,"sync_TestConstructor");
+ if (fctTest) fctTest();
+
+ } else {
+#ifdef __APPLE_CC__
+ NSLinkEditErrors c;
+ int num_err;
+ const char *file,*err;
+ NSLinkEditError(&c,&num_err,&file,&err);
+ printf("Can't load '%ls' (%s)\n", lpLibFileName,err);
+#elif ENV_BEOS
+ printf("Can't load '%ls' (%s)\n", lpLibFileName,strerror(err));
+#else
+ printf("Can't load '%ls' (%s)\n", lpLibFileName,dlerror());
+#endif
+ }
+
+ return LoadOperations(handler);
+}
+
+}}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/DLL.h b/src/libs/7zip/unix/CPP/Windows/DLL.h
new file mode 100644
index 000000000..9b57bec8a
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/DLL.h
@@ -0,0 +1,48 @@
+// Windows/DLL.h
+
+#ifndef __WINDOWS_DLL_H
+#define __WINDOWS_DLL_H
+
+#include "../Common/MyString.h"
+
+typedef void * HMODULE;
+
+typedef int (*FARPROC)();
+
+namespace NWindows {
+namespace NDLL {
+
+class CLibrary
+{
+ bool LoadOperations(HMODULE newModule);
+ HMODULE _module;
+public:
+ operator HMODULE() const { return _module; }
+ HMODULE* operator&() { return &_module; }
+
+
+ CLibrary():_module(NULL) {};
+ ~CLibrary();
+
+ bool Free();
+
+ void Attach(HMODULE m)
+ {
+ Free();
+ _module = m;
+ }
+ HMODULE Detach()
+ {
+ HMODULE m = _module;
+ _module = NULL;
+ return m;
+ }
+
+
+ bool Load(LPCTSTR fileName);
+ FARPROC GetProc(LPCSTR procName) const;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Defs.h b/src/libs/7zip/unix/CPP/Windows/Defs.h
new file mode 100644
index 000000000..bad4e3552
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Defs.h
@@ -0,0 +1,17 @@
+// Windows/Defs.h
+
+#ifndef __WINDOWS_DEFS_H
+#define __WINDOWS_DEFS_H
+
+#include "../Common/MyWindows.h"
+
+// #ifdef _WIN32
+inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); }
+inline bool BOOLToBool(BOOL v) { return (v != FALSE); }
+inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); }
+// #endif
+
+inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); }
+inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); }
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Error.cpp b/src/libs/7zip/unix/CPP/Windows/Error.cpp
new file mode 100644
index 000000000..88008d711
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Error.cpp
@@ -0,0 +1,58 @@
+// Windows/Error.h
+
+#include "StdAfx.h"
+
+#include "Windows/Error.h"
+#include "Common/StringConvert.h"
+
+namespace NWindows {
+namespace NError {
+
+bool MyFormatMessage(DWORD messageID, CSysString &message)
+{
+ const char * txt = 0;
+ AString msg;
+
+ switch(messageID) {
+ case ERROR_NO_MORE_FILES : txt = "No more files"; break ;
+ case E_NOTIMPL : txt = "E_NOTIMPL"; break ;
+ case E_NOINTERFACE : txt = "E_NOINTERFACE"; break ;
+ case E_ABORT : txt = "E_ABORT"; break ;
+ case E_FAIL : txt = "E_FAIL"; break ;
+ case STG_E_INVALIDFUNCTION : txt = "STG_E_INVALIDFUNCTION"; break ;
+ case E_OUTOFMEMORY : txt = "E_OUTOFMEMORY"; break ;
+ case E_INVALIDARG : txt = "E_INVALIDARG"; break ;
+ default:
+ txt = strerror(messageID);
+ }
+ if (txt) {
+ msg = txt;
+ } else {
+ char msgBuf[256];
+ snprintf(msgBuf,sizeof(msgBuf),"error #%x",(unsigned)messageID);
+ msgBuf[sizeof(msgBuf)-1] = 0;
+ msg = msgBuf;
+ }
+
+ msg += " ";
+
+#ifdef _UNICODE
+ message = MultiByteToUnicodeString(msg);
+#else
+ message = msg;
+#endif
+ return true;
+}
+
+#ifndef _UNICODE
+bool MyFormatMessage(DWORD messageID, UString &message)
+{
+ CSysString messageSys;
+ bool result = MyFormatMessage(messageID, messageSys);
+ message = GetUnicodeString(messageSys);
+ return result;
+}
+#endif
+
+}}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Error.h b/src/libs/7zip/unix/CPP/Windows/Error.h
new file mode 100644
index 000000000..05b5cd0ea
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Error.h
@@ -0,0 +1,33 @@
+// Windows/Error.h
+
+#ifndef __WINDOWS_ERROR_H
+#define __WINDOWS_ERROR_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+namespace NError {
+
+bool MyFormatMessage(DWORD messageID, CSysString &message);
+inline CSysString MyFormatMessage(DWORD messageID)
+{
+ CSysString message;
+ MyFormatMessage(messageID, message);
+ return message;
+}
+#ifdef _UNICODE
+inline UString MyFormatMessageW(DWORD messageID)
+ { return MyFormatMessage(messageID); }
+#else
+bool MyFormatMessage(DWORD messageID, UString &message);
+inline UString MyFormatMessageW(DWORD messageID)
+{
+ UString message;
+ MyFormatMessage(messageID, message);
+ return message;
+}
+#endif
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/FileDir.cpp b/src/libs/7zip/unix/CPP/Windows/FileDir.cpp
new file mode 100644
index 000000000..838f92d5b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileDir.cpp
@@ -0,0 +1,927 @@
+// Windows/FileDir.cpp
+
+#include "StdAfx.h"
+
+#include "FileDir.h"
+#include "FileName.h"
+#include "FileFind.h"
+#include "Defs.h"
+#include "../Common/StringConvert.h"
+#include "../Common/IntToString.h"
+
+#define NEED_NAME_WINDOWS_TO_UNIX
+#include "myPrivate.h"
+#include "Windows/Synchronization.h"
+
+#include <unistd.h> // rmdir
+#include <errno.h>
+
+#include <sys/stat.h> // mkdir
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <utime.h>
+
+// #define TRACEN(u) u;
+#define TRACEN(u) /* */
+
+class Umask
+{
+ public:
+ mode_t current_umask;
+ mode_t mask;
+ Umask() {
+ current_umask = umask (0); /* get and set the umask */
+ umask(current_umask); /* restore the umask */
+ mask = 0777 & (~current_umask);
+ }
+};
+
+static Umask gbl_umask;
+
+#ifdef _UNICODE
+AString nameWindowToUnix2(LPCWSTR name) // FIXME : optimization ?
+{
+ AString astr = UnicodeStringToMultiByte(name);
+ return AString(nameWindowToUnix((const char *)astr));
+}
+#endif
+
+extern BOOLEAN WINAPI RtlTimeToSecondsSince1970( const LARGE_INTEGER *Time, DWORD *Seconds );
+
+#ifdef _UNICODE
+DWORD WINAPI GetFullPathName( LPCTSTR name, DWORD len, LPTSTR buffer, LPTSTR *lastpart ) { // FIXME
+ if (name == 0) return 0;
+
+ DWORD name_len = lstrlen(name);
+
+ if (name[0] == '/') {
+ DWORD ret = name_len+2;
+ if (ret >= len) {
+ TRACEN((printf("GetFullPathNameA(%ls,%d,)=0000 (case 0)\n",name, (int)len)))
+ return 0;
+ }
+ lstrcpy(buffer,L"c:");
+ lstrcat(buffer,name);
+
+ *lastpart=buffer;
+ TCHAR *ptr=buffer;
+ while (*ptr) {
+ if (*ptr == '/')
+ *lastpart=ptr+1;
+ ptr++;
+ }
+ TRACEN((printf("GetFullPathNameA(%s,%d,%ls,%ls)=%d\n",name, (int)len,buffer, *lastpart,(int)ret)))
+ return ret;
+ }
+ if (isascii(name[0]) && (name[1] == ':')) { // FIXME isascii
+ DWORD ret = name_len;
+ if (ret >= len) {
+ TRACEN((printf("GetFullPathNameA(%ls,%d,)=0000 (case 1)\n",name, (int)len)))
+ return 0;
+ }
+ lstrcpy(buffer,name);
+
+ *lastpart=buffer;
+ TCHAR *ptr=buffer;
+ while (*ptr) {
+ if (*ptr == '/')
+ *lastpart=ptr+1;
+ ptr++;
+ }
+ TRACEN((printf("GetFullPathNameA(%sl,%d,%ls,%ls)=%d\n",name, (int)len,buffer, *lastpart,(int)ret)))
+ return ret;
+ }
+
+ // name is a relative pathname.
+ //
+ if (len < 2) {
+ TRACEN((printf("GetFullPathNameA(%s,%d,)=0000 (case 2)\n",name, (int)len)))
+ return 0;
+ }
+
+ DWORD ret = 0;
+ char begin[MAX_PATHNAME_LEN];
+ /* DWORD begin_len = GetCurrentDirectoryA(MAX_PATHNAME_LEN,begin); */
+ DWORD begin_len = 0;
+ begin[0]='c';
+ begin[1]=':';
+ char * cret = getcwd(begin+2, MAX_PATHNAME_LEN - 3);
+ if (cret) {
+ begin_len = strlen(begin);
+ }
+
+ if (begin_len >= 1) {
+ // strlen(begin) + strlen("/") + strlen(name)
+ ret = begin_len + 1 + name_len;
+
+ if (ret >= len) {
+ TRACEN((printf("GetFullPathNameA(%s,%d,)=0000 (case 4)\n",name, (int)len)))
+ return 0;
+ }
+ UString wbegin = GetUnicodeString(begin);
+ lstrcpy(buffer,wbegin);
+ lstrcat(buffer,L"/");
+ lstrcat(buffer,name);
+
+ *lastpart=buffer + begin_len + 1;
+ TCHAR *ptr=buffer;
+ while (*ptr) {
+ if (*ptr == '/')
+ *lastpart=ptr+1;
+ ptr++;
+ }
+ TRACEN((printf("GetFullPathNameA(%s,%d,%s,%s)=%d\n",name, (int)len,buffer, *lastpart,(int)ret)))
+ } else {
+ ret = 0;
+ TRACEN((printf("GetFullPathNameA(%s,%d,)=0000 (case 5)\n",name, (int)len)))
+ }
+ return ret;
+}
+
+#endif
+
+#if 0
+DWORD WINAPI GetFullPathName( LPCSTR name, DWORD len, LPSTR buffer, LPSTR *lastpart ) {
+ if (name == 0) return 0;
+
+ DWORD name_len = strlen(name);
+
+ if (name[0] == '/') {
+ DWORD ret = name_len+2;
+ if (ret >= len) {
+ TRACEN((printf("GetFullPathNameA(%s,%d,)=0000 (case 0)\n",name, (int)len)))
+ return 0;
+ }
+ strcpy(buffer,"c:");
+ strcat(buffer,name);
+
+ *lastpart=buffer;
+ char *ptr=buffer;
+ while (*ptr) {
+ if (*ptr == '/')
+ *lastpart=ptr+1;
+ ptr++;
+ }
+ TRACEN((printf("GetFullPathNameA(%s,%d,%s,%s)=%d\n",name, (int)len,buffer, *lastpart,(int)ret)))
+ return ret;
+ }
+ if (isascii(name[0]) && (name[1] == ':')) {
+ DWORD ret = name_len;
+ if (ret >= len) {
+ TRACEN((printf("GetFullPathNameA(%s,%d,)=0000 (case 1)\n",name, (int)len)))
+ return 0;
+ }
+ strcpy(buffer,name);
+
+ *lastpart=buffer;
+ char *ptr=buffer;
+ while (*ptr) {
+ if (*ptr == '/')
+ *lastpart=ptr+1;
+ ptr++;
+ }
+ TRACEN((printf("GetFullPathNameA(%s,%d,%s,%s)=%d\n",name, (int)len,buffer, *lastpart,(int)ret)))
+ return ret;
+ }
+
+ // name is a relative pathname.
+ //
+ if (len < 2) {
+ TRACEN((printf("GetFullPathNameA(%s,%d,)=0000 (case 2)\n",name, (int)len)))
+ return 0;
+ }
+
+ DWORD ret = 0;
+ char begin[MAX_PATHNAME_LEN];
+ /* DWORD begin_len = GetCurrentDirectoryA(MAX_PATHNAME_LEN,begin); */
+ DWORD begin_len = 0;
+ begin[0]='c';
+ begin[1]=':';
+ char * cret = getcwd(begin+2, MAX_PATHNAME_LEN - 3);
+ if (cret) {
+ begin_len = strlen(begin);
+ }
+
+ if (begin_len >= 1) {
+ // strlen(begin) + strlen("/") + strlen(name)
+ ret = begin_len + 1 + name_len;
+
+ if (ret >= len) {
+ TRACEN((printf("GetFullPathNameA(%s,%d,)=0000 (case 4)\n",name, (int)len)))
+ return 0;
+ }
+ strcpy(buffer,begin);
+ strcat(buffer,"/");
+ strcat(buffer,name);
+
+ *lastpart=buffer + begin_len + 1;
+ char *ptr=buffer;
+ while (*ptr) {
+ if (*ptr == '/')
+ *lastpart=ptr+1;
+ ptr++;
+ }
+ TRACEN((printf("GetFullPathNameA(%s,%d,%s,%s)=%d\n",name, (int)len,buffer, *lastpart,(int)ret)))
+ } else {
+ ret = 0;
+ TRACEN((printf("GetFullPathNameA(%s,%d,)=0000 (case 5)\n",name, (int)len)))
+ }
+ return ret;
+}
+
+static BOOL WINAPI RemoveDirectory(LPCSTR path) {
+ if (!path || !*path) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+ const char * name = nameWindowToUnix(path);
+ TRACEN((printf("RemoveDirectoryA(%s)\n",name)))
+
+ if (rmdir( name ) != 0) {
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif
+
+#ifdef _UNICODE
+static BOOL WINAPI RemoveDirectory(LPCWSTR path) {
+ if (!path || !*path) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+ AString name = nameWindowToUnix2(path);
+ TRACEN((printf("RemoveDirectoryA(%s)\n",(const char *)name)))
+
+ if (rmdir( (const char *)name ) != 0) {
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif
+
+static int copy_fd(int fin,int fout)
+{
+ char buffer[16384];
+ ssize_t ret_in;
+ ssize_t ret_out;
+
+ do {
+ ret_out = -1;
+ do {
+ ret_in = read(fin, buffer,sizeof(buffer));
+ } while (ret_in < 0 && (errno == EINTR));
+ if (ret_in >= 1) {
+ do {
+ ret_out = write (fout, buffer, ret_in);
+ } while (ret_out < 0 && (errno == EINTR));
+ } else if (ret_in == 0) {
+ ret_out = 0;
+ }
+ } while (ret_out >= 1);
+ return ret_out;
+}
+
+static BOOL CopyFile(const char *src,const char *dst)
+{
+ int ret = -1;
+
+#ifdef O_BINARY
+ int flags = O_BINARY;
+#else
+ int flags = 0;
+#endif
+
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+
+ int fout = open(dst,O_CREAT | O_WRONLY | O_EXCL | flags, 0600);
+ if (fout != -1)
+ {
+ int fin = open(src,O_RDONLY | flags , 0600);
+ if (fin != -1)
+ {
+ ret = copy_fd(fin,fout);
+ if (ret == 0) ret = close(fin);
+ else close(fin);
+ }
+ if (ret == 0) ret = close(fout);
+ else close(fout);
+ }
+ if (ret == 0) return TRUE;
+ return FALSE;
+}
+
+/*****************************************************************************************/
+
+
+namespace NWindows {
+namespace NFile {
+namespace NDirectory {
+
+
+bool MySetCurrentDirectory(LPCWSTR wpath)
+{
+ AString path = UnicodeStringToMultiByte(wpath);
+
+ return chdir((const char*)path) == 0;
+}
+
+#ifdef _UNICODE
+bool GetOnlyName(LPCTSTR fileName, CSysString &resultName)
+{
+ int index;
+ if (!MyGetFullPathName(fileName, resultName, index))
+ return false;
+ resultName = resultName.Mid(index);
+ return true;
+}
+
+bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName)
+{
+ int index;
+ if (!MyGetFullPathName(fileName, resultName, index))
+ return false;
+ resultName = resultName.Left(index);
+ return true;
+}
+#endif
+
+
+bool MyGetCurrentDirectory(CSysString &resultPath)
+{
+ char begin[MAX_PATHNAME_LEN];
+ begin[0]='c';
+ begin[1]=':';
+ char * cret = getcwd(begin+2, MAX_PATHNAME_LEN - 3);
+ if (cret)
+ {
+#ifdef _UNICODE
+ resultPath = GetUnicodeString(begin);
+#else
+ resultPath = begin;
+#endif
+ return true;
+ }
+ return false;
+}
+
+bool MyMoveFile( LPCTSTR fn1, LPCTSTR fn2 ) {
+#ifdef _UNICODE
+ AString src = nameWindowToUnix2(fn1);
+ AString dst = nameWindowToUnix2(fn2);
+#else
+ const char * src = nameWindowToUnix(fn1);
+ const char * dst = nameWindowToUnix(fn2);
+#endif
+
+ TRACEN((printf("MoveFileW(%s,%s)\n",src,dst)))
+
+ int ret = rename(src,dst);
+ if (ret != 0)
+ {
+ if (errno == EXDEV) // FIXED : bug #1112167 (Temporary directory must be on same partition as target)
+ {
+ BOOL bret = CopyFile(src,dst);
+ if (bret == FALSE) return false;
+
+ struct stat info_file;
+ ret = stat(src,&info_file);
+ if (ret == 0) {
+ TRACEN((printf("##DBG chmod-1(%s,%o)\n",dst,(unsigned)info_file.st_mode & gbl_umask.mask)))
+ ret = chmod(dst,info_file.st_mode & gbl_umask.mask);
+ }
+ if (ret == 0) {
+ ret = unlink(src);
+ }
+ if (ret == 0) return true;
+ }
+ return false;
+ }
+ return true;
+}
+
+bool MyRemoveDirectory(LPCTSTR pathName)
+{
+ return BOOLToBool(::RemoveDirectory(pathName));
+}
+
+bool SetDirTime(LPCWSTR fileName, const FILETIME * /* creationTime */ ,
+ const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime)
+{
+ AString cfilename = UnicodeStringToMultiByte(fileName);
+ const char * unix_filename = nameWindowToUnix((const char *)cfilename);
+
+ struct utimbuf buf;
+
+ struct stat oldbuf;
+ int ret = stat(unix_filename,&oldbuf);
+ if (ret == 0) {
+ buf.actime = oldbuf.st_atime;
+ buf.modtime = oldbuf.st_mtime;
+ } else {
+ time_t current_time = time(0);
+ buf.actime = current_time;
+ buf.modtime = current_time;
+ }
+
+ if (lpLastAccessTime)
+ {
+ LARGE_INTEGER ltime;
+ DWORD dw;
+ ltime.QuadPart = lpLastAccessTime->dwHighDateTime;
+ ltime.QuadPart = (ltime.QuadPart << 32) | lpLastAccessTime->dwLowDateTime;
+ RtlTimeToSecondsSince1970( &ltime, &dw );
+ buf.actime = dw;
+ }
+
+ if (lpLastWriteTime)
+ {
+ LARGE_INTEGER ltime;
+ DWORD dw;
+ ltime.QuadPart = lpLastWriteTime->dwHighDateTime;
+ ltime.QuadPart = (ltime.QuadPart << 32) | lpLastWriteTime->dwLowDateTime;
+ RtlTimeToSecondsSince1970( &ltime, &dw );
+ buf.modtime = dw;
+ }
+
+ /* ret = */ utime(unix_filename, &buf);
+
+ return true;
+}
+
+#ifndef _UNICODE
+bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes)
+{
+ return MySetFileAttributes(UnicodeStringToMultiByte(fileName, CP_ACP), fileAttributes);
+}
+
+bool MyRemoveDirectory(LPCWSTR pathName)
+{
+ return MyRemoveDirectory(UnicodeStringToMultiByte(pathName, CP_ACP));
+}
+
+bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName)
+{
+ UINT codePage = CP_ACP;
+ return MyMoveFile(UnicodeStringToMultiByte(existFileName, codePage), UnicodeStringToMultiByte(newFileName, codePage));
+}
+#endif
+
+
+static int convert_to_symlink(const char * name) {
+ FILE *file = fopen(name,"rb");
+ if (file) {
+ char buf[MAX_PATHNAME_LEN+1];
+ char * ret = fgets(buf,sizeof(buf)-1,file);
+ fclose(file);
+ if (ret) {
+ int ir = unlink(name);
+ if (ir == 0) {
+ ir = symlink(buf,name);
+ }
+ return ir;
+ }
+ }
+ return -1;
+}
+
+bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes)
+{
+ if (!fileName) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ TRACEN((printf("MySetFileAttributes(NULL,%d) : false-1\n",fileAttributes)))
+ return false;
+ }
+#ifdef _UNICODE
+ AString name = nameWindowToUnix2(fileName);
+#else
+ const char * name = nameWindowToUnix(fileName);
+#endif
+ struct stat stat_info;
+#ifdef ENV_HAVE_LSTAT
+ if (global_use_lstat) {
+ if(lstat(name,&stat_info)!=0) {
+ TRACEN((printf("MySetFileAttributes(%s,%d) : false-2-1\n",name,fileAttributes)))
+ return false;
+ }
+ } else
+#endif
+ {
+ if(stat(name,&stat_info)!=0) {
+ TRACEN((printf("MySetFileAttributes(%s,%d) : false-2-2\n",name,fileAttributes)))
+ return false;
+ }
+ }
+
+ if (fileAttributes & FILE_ATTRIBUTE_UNIX_EXTENSION) {
+ stat_info.st_mode = fileAttributes >> 16;
+#ifdef ENV_HAVE_LSTAT
+ if (S_ISLNK(stat_info.st_mode)) {
+ if ( convert_to_symlink(name) != 0) {
+ TRACEN((printf("MySetFileAttributes(%s,%d) : false-3\n",name,fileAttributes)))
+ return false;
+ }
+ } else
+#endif
+ if (S_ISREG(stat_info.st_mode)) {
+ TRACEN((printf("##DBG chmod-2(%s,%o)\n",name,(unsigned)stat_info.st_mode & gbl_umask.mask)))
+ chmod(name,stat_info.st_mode & gbl_umask.mask);
+ } else if (S_ISDIR(stat_info.st_mode)) {
+ // user/7za must be able to create files in this directory
+ stat_info.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR);
+ TRACEN((printf("##DBG chmod-3(%s,%o)\n",name,(unsigned)stat_info.st_mode & gbl_umask.mask)))
+ chmod(name,stat_info.st_mode & gbl_umask.mask);
+ }
+#ifdef ENV_HAVE_LSTAT
+ } else if (!S_ISLNK(stat_info.st_mode)) {
+ // do not use chmod on a link
+#else
+ } else {
+#endif
+
+ /* Only Windows Attributes */
+ if( S_ISDIR(stat_info.st_mode)) {
+ /* Remark : FILE_ATTRIBUTE_READONLY ignored for directory. */
+ TRACEN((printf("##DBG chmod-4(%s,%o)\n",name,(unsigned)stat_info.st_mode & gbl_umask.mask)))
+ chmod(name,stat_info.st_mode & gbl_umask.mask);
+ } else {
+ if (fileAttributes & FILE_ATTRIBUTE_READONLY) stat_info.st_mode &= ~0222; /* octal!, clear write permission bits */
+ TRACEN((printf("##DBG chmod-5(%s,%o)\n",name,(unsigned)stat_info.st_mode & gbl_umask.mask)))
+ chmod(name,stat_info.st_mode & gbl_umask.mask);
+ }
+ }
+ TRACEN((printf("MySetFileAttributes(%s,%d) : true\n",name,fileAttributes)))
+
+ return true;
+}
+
+bool MyCreateDirectory(LPCTSTR pathName)
+{
+ if (!pathName || !*pathName) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return false;
+ }
+
+#ifdef _UNICODE
+ AString name = nameWindowToUnix2(pathName);
+#else
+ const char * name = nameWindowToUnix(pathName);
+#endif
+ bool bret = false;
+ if (mkdir( name, 0700 ) == 0) bret = true;
+
+ TRACEN((printf("MyCreateDirectory(%s)=%d\n",name,(int)bret)))
+ return bret;
+}
+
+#ifndef _UNICODE
+bool MyCreateDirectory(LPCWSTR pathName)
+{
+ return MyCreateDirectory(UnicodeStringToMultiByte(pathName, CP_ACP));
+}
+#endif
+
+bool CreateComplexDirectory(LPCTSTR _aPathName)
+{
+ CSysString pathName = _aPathName;
+ int pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+ if (pos > 0 && pos == pathName.Length() - 1)
+ {
+ if (pathName.Length() == 3 && pathName[1] == ':')
+ return true; // Disk folder;
+ pathName.Delete(pos);
+ }
+ CSysString pathName2 = pathName;
+ pos = pathName.Length();
+ while(true)
+ {
+ if(MyCreateDirectory(pathName))
+ break;
+ if(::GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+#ifdef _WIN32 // FIXED for supporting symbolic link instead of a directory
+ NFind::CFileInfo fileInfo;
+ if (!NFind::FindFile(pathName, fileInfo)) // For network folders
+ return true;
+ if (!fileInfo.IsDir())
+ return false;
+#endif
+ break;
+ }
+ pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+ if (pos < 0 || pos == 0)
+ return false;
+ if (pathName[pos - 1] == ':')
+ return false;
+ pathName = pathName.Left(pos);
+ }
+ pathName = pathName2;
+ while(pos < pathName.Length())
+ {
+ pos = pathName.Find(TEXT(CHAR_PATH_SEPARATOR), pos + 1);
+ if (pos < 0)
+ pos = pathName.Length();
+ if(!MyCreateDirectory(pathName.Left(pos)))
+ return false;
+ }
+ return true;
+}
+
+#ifndef _UNICODE
+
+bool CreateComplexDirectory(LPCWSTR _aPathName)
+{
+ UString pathName = _aPathName;
+ int pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
+ if (pos > 0 && pos == pathName.Length() - 1)
+ {
+ if (pathName.Length() == 3 && pathName[1] == L':')
+ return true; // Disk folder;
+ pathName.Delete(pos);
+ }
+ UString pathName2 = pathName;
+ pos = pathName.Length();
+ while(true)
+ {
+ if(MyCreateDirectory(pathName))
+ break;
+ if(::GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+#ifdef _WIN32 // FIXED for supporting symbolic link instead of a directory
+ NFind::CFileInfoW fileInfo;
+ if (!NFind::FindFile(pathName, fileInfo)) // For network folders
+ return true;
+ if (!fileInfo.IsDir())
+ return false;
+#endif
+ break;
+ }
+ pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
+ if (pos < 0 || pos == 0)
+ return false;
+ if (pathName[pos - 1] == L':')
+ return false;
+ pathName = pathName.Left(pos);
+ }
+ pathName = pathName2;
+ while(pos < pathName.Length())
+ {
+ pos = pathName.Find(WCHAR_PATH_SEPARATOR, pos + 1);
+ if (pos < 0)
+ pos = pathName.Length();
+ if(!MyCreateDirectory(pathName.Left(pos)))
+ return false;
+ }
+ return true;
+}
+
+#endif
+
+bool DeleteFileAlways(LPCTSTR name)
+{
+ if (!name || !*name) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return false;
+ }
+#ifdef _UNICODE
+ AString unixname = nameWindowToUnix2(name);
+#else
+ const char * unixname = nameWindowToUnix(name);
+#endif
+ bool bret = false;
+ if (remove(unixname) == 0) bret = true;
+ TRACEN((printf("DeleteFileAlways(%s)=%d\n",unixname,(int)bret)))
+ return bret;
+}
+
+#ifndef _UNICODE
+bool DeleteFileAlways(LPCWSTR name)
+{
+ return DeleteFileAlways(UnicodeStringToMultiByte(name, CP_ACP));
+}
+#endif
+
+
+static bool RemoveDirectorySubItems2(const UString &pathPrefix, const NFind::CFileInfoW &fileInfo)
+{
+ if (fileInfo.IsDir())
+ return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
+ return DeleteFileAlways(pathPrefix + fileInfo.Name);
+}
+
+bool RemoveDirectoryWithSubItems(const UString &path)
+{
+ NFind::CFileInfoW fileInfo;
+ UString pathPrefix = path + NName::kDirDelimiter;
+ {
+ NFind::CEnumeratorW enumerator(pathPrefix + TCHAR(NName::kAnyStringWildcard));
+ while (enumerator.Next(fileInfo))
+ if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
+ return false;
+ }
+ if (!MySetFileAttributes(path, 0))
+ return false;
+ return MyRemoveDirectory(path);
+}
+
+#ifndef _WIN32_WCE
+
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath,
+ int &fileNamePartStartIndex)
+{
+ LPTSTR fileNamePointer = 0;
+ LPTSTR buffer = resultPath.GetBuffer(MAX_PATH);
+ DWORD needLength = ::GetFullPathName(fileName, MAX_PATH + 1,
+ buffer, &fileNamePointer);
+ resultPath.ReleaseBuffer();
+ if (needLength == 0 || needLength >= MAX_PATH)
+ return false;
+ if (fileNamePointer == 0)
+ fileNamePartStartIndex = lstrlen(fileName);
+ else
+ fileNamePartStartIndex = fileNamePointer - buffer;
+ return true;
+}
+
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath,
+ int &fileNamePartStartIndex)
+{
+ const UINT currentPage = CP_ACP;
+ CSysString sysPath;
+ if (!MyGetFullPathName(UnicodeStringToMultiByte(fileName,
+ currentPage), sysPath, fileNamePartStartIndex))
+ return false;
+ UString resultPath1 = MultiByteToUnicodeString(
+ sysPath.Left(fileNamePartStartIndex), currentPage);
+ UString resultPath2 = MultiByteToUnicodeString(
+ sysPath.Mid(fileNamePartStartIndex), currentPage);
+ fileNamePartStartIndex = resultPath1.Length();
+ resultPath = resultPath1 + resultPath2;
+ return true;
+}
+#endif
+
+
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &path)
+{
+ int index;
+ return MyGetFullPathName(fileName, path, index);
+}
+
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &path)
+{
+ int index;
+ return MyGetFullPathName(fileName, path, index);
+}
+#endif
+
+#endif
+
+/* needed to find .DLL/.so and SFX */
+bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, UString &resultPath)
+{
+ if (path != 0) {
+ printf("NOT EXPECTED : MySearchPath : path != NULL\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (extension != 0) {
+ printf("NOT EXPECTED : MySearchPath : extension != NULL\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fileName == 0) {
+ printf("NOT EXPECTED : MySearchPath : fileName == NULL\n");
+ exit(EXIT_FAILURE);
+ }
+
+ const char *p7zip_home_dir = getenv("P7ZIP_HOME_DIR");
+ if (p7zip_home_dir) {
+ AString file_path = p7zip_home_dir;
+ file_path += UnicodeStringToMultiByte(fileName, CP_ACP);
+
+ TRACEN((printf("MySearchPath() fopen(%s)\n",(const char *)file_path)))
+ FILE *file = fopen((const char *)file_path,"r");
+ if (file) {
+ // file is found
+ fclose(file);
+ resultPath = MultiByteToUnicodeString(file_path, CP_ACP);
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifndef _UNICODE
+bool MyGetTempPath(CSysString &path)
+{
+ path = "c:/tmp/"; // final '/' is needed
+ return true;
+}
+#endif
+
+bool MyGetTempPath(UString &path)
+{
+ path = L"c:/tmp/"; // final '/' is needed
+ return true;
+}
+
+static NSynchronization::CCriticalSection g_CountCriticalSection;
+
+static CSysString CSysConvertUInt32ToString(UInt32 value)
+{
+ TCHAR buffer[32];
+ ConvertUInt32ToString(value, buffer);
+ return buffer;
+}
+
+UINT CTempFile::Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath)
+{
+ static UInt32 memo_count = 0;
+ UInt32 count;
+
+ g_CountCriticalSection.Enter();
+ count = memo_count++;
+ g_CountCriticalSection.Leave();
+
+ Remove();
+/* UINT number = ::GetTempFileName(dirPath, prefix, 0, path.GetBuffer(MAX_PATH)); */
+ UINT number = (UINT)getpid();
+
+ resultPath = dirPath;
+ resultPath += prefix;
+ resultPath += TEXT('#');
+ resultPath += CSysConvertUInt32ToString(number);
+ resultPath += TEXT('@');
+ resultPath += CSysConvertUInt32ToString(count);
+ resultPath += TEXT(".tmp");
+
+ _fileName = resultPath;
+ _mustBeDeleted = true;
+
+ return number;
+}
+
+bool CTempFile::Create(LPCTSTR prefix, CSysString &resultPath)
+{
+ CSysString tempPath;
+ if (!MyGetTempPath(tempPath))
+ return false;
+ if (Create(tempPath, prefix, resultPath) != 0)
+ return true;
+ return false;
+}
+
+
+bool CTempFile::Remove()
+{
+ if (!_mustBeDeleted)
+ return true;
+ _mustBeDeleted = !DeleteFileAlways(_fileName);
+ return !_mustBeDeleted;
+}
+
+bool CreateTempDirectory(LPCWSTR prefix, UString &dirName)
+{
+ /*
+ CSysString prefix = tempPath + prefixChars;
+ CRandom random;
+ random.Init();
+ */
+ for (;;)
+ {
+ {
+ CTempFileW tempFile;
+ if (!tempFile.Create(prefix, dirName))
+ return false;
+ if (!tempFile.Remove())
+ return false;
+ }
+ /*
+ UINT32 randomNumber = random.Generate();
+ TCHAR randomNumberString[32];
+ _stprintf(randomNumberString, _T("%04X"), randomNumber);
+ dirName = prefix + randomNumberString;
+ */
+ if (NFind::DoesFileOrDirExist(dirName))
+ continue;
+ if (MyCreateDirectory(dirName))
+ return true;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ return false;
+ }
+}
+
+bool CTempDirectory::Create(LPCTSTR prefix)
+{
+ Remove();
+ return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));
+}
+
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/Windows/FileDir.h b/src/libs/7zip/unix/CPP/Windows/FileDir.h
new file mode 100644
index 000000000..a7cfbaf8d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileDir.h
@@ -0,0 +1,115 @@
+// Windows/FileDir.h
+
+#ifndef __WINDOWS_FILEDIR_H
+#define __WINDOWS_FILEDIR_H
+
+#include "../Common/MyString.h"
+#include "Defs.h"
+
+/* GetFullPathName for 7zAES.cpp */
+DWORD WINAPI GetFullPathName( LPCSTR name, DWORD len, LPSTR buffer, LPSTR *lastpart );
+
+namespace NWindows {
+namespace NFile {
+namespace NDirectory {
+
+bool SetDirTime(LPCWSTR fileName, const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime);
+
+bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes);
+#ifndef _UNICODE
+bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes);
+#endif
+
+bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName);
+#ifndef _UNICODE
+bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName);
+#endif
+
+bool MyRemoveDirectory(LPCTSTR pathName);
+#ifndef _UNICODE
+bool MyRemoveDirectory(LPCWSTR pathName);
+#endif
+
+bool MyCreateDirectory(LPCTSTR pathName);
+bool CreateComplexDirectory(LPCTSTR pathName);
+#ifndef _UNICODE
+bool MyCreateDirectory(LPCWSTR pathName);
+bool CreateComplexDirectory(LPCWSTR pathName);
+#endif
+
+bool DeleteFileAlways(LPCTSTR name);
+#ifndef _UNICODE
+bool DeleteFileAlways(LPCWSTR name);
+#endif
+bool RemoveDirectoryWithSubItems(const UString &path);
+
+#ifndef _WIN32_WCE
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath,
+ int &fileNamePartStartIndex);
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath);
+bool GetOnlyName(LPCTSTR fileName, CSysString &resultName);
+bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName);
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath,
+ int &fileNamePartStartIndex);
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath);
+#endif
+
+#endif
+
+bool MySetCurrentDirectory(LPCWSTR path);
+bool MyGetCurrentDirectory(CSysString &resultPath);
+
+bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, UString &resultPath);
+
+bool MyGetTempPath(CSysString &resultPath);
+#ifndef _UNICODE
+bool MyGetTempPath(UString &resultPath);
+#endif
+
+class CTempFile
+{
+ bool _mustBeDeleted;
+ CSysString _fileName;
+public:
+ CTempFile(): _mustBeDeleted(false) {}
+ ~CTempFile() { Remove(); }
+ void DisableDeleting() { _mustBeDeleted = false; }
+ UINT Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath);
+ bool Create(LPCTSTR prefix, CSysString &resultPath);
+ bool Remove();
+};
+
+#ifdef _UNICODE
+typedef CTempFile CTempFileW;
+#endif
+
+bool CreateTempDirectory(LPCWSTR prefixChars, UString &dirName);
+
+class CTempDirectory
+{
+ bool _mustBeDeleted;
+ CSysString _tempDir;
+public:
+ const CSysString &GetPath() const { return _tempDir; }
+ CTempDirectory(): _mustBeDeleted(false) {}
+ ~CTempDirectory() { Remove(); }
+ bool Create(LPCTSTR prefix) ;
+ bool Remove()
+ {
+ if (!_mustBeDeleted)
+ return true;
+ _mustBeDeleted = !RemoveDirectoryWithSubItems(_tempDir);
+ return (!_mustBeDeleted);
+ }
+ void DisableDeleting() { _mustBeDeleted = false; }
+};
+
+#ifdef _UNICODE
+typedef CTempDirectory CTempDirectoryW;
+#endif
+
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/FileFind.cpp b/src/libs/7zip/unix/CPP/Windows/FileFind.cpp
new file mode 100644
index 000000000..9e526a233
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileFind.cpp
@@ -0,0 +1,604 @@
+// Windows/FileFind.cpp
+
+#include "StdAfx.h"
+
+#include "FileFind.h"
+#include "../Common/StringConvert.h"
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifdef ENV_HAVE_LSTAT
+extern "C"
+{
+
+int global_use_lstat=1; // default behaviour : p7zip stores symlinks instead of dumping the files they point to
+}
+#endif
+
+#define NEED_NAME_WINDOWS_TO_UNIX
+#include "myPrivate.h"
+
+// #define TRACEN(u) u;
+#define TRACEN(u) /* */
+
+void my_windows_split_path(const AString &p_path, AString &dir , AString &base) {
+ int pos = p_path.ReverseFind('/');
+ if (pos == -1) {
+ // no separator
+ dir = ".";
+ if (p_path.IsEmpty())
+ base = ".";
+ else
+ base = p_path;
+ } else if ((pos+1) < p_path.Length()) {
+ // true separator
+ base = p_path.Mid(pos+1);
+ while ((pos >= 1) && (p_path[pos-1] == '/'))
+ pos--;
+ if (pos == 0)
+ dir = "/";
+ else
+ dir = p_path.Left(pos);
+ } else {
+ // separator at the end of the path
+ // pos = p_path.find_last_not_of("/");
+ pos = -1;
+ int ind = 0;
+ while (p_path[ind]) {
+ if (p_path[ind] != '/')
+ pos = ind;
+ ind++;
+ }
+ if (pos == -1) {
+ base = "/";
+ dir = "/";
+ } else {
+ my_windows_split_path(p_path.Left(pos+1),dir,base);
+ }
+ }
+}
+
+static void my_windows_split_path(const UString &p_path, UString &dir , UString &base) {
+ int pos = p_path.ReverseFind(L'/');
+ if (pos == -1) {
+ // no separator
+ dir = L".";
+ if (p_path.IsEmpty())
+ base = L".";
+ else
+ base = p_path;
+ } else if ((pos+1) < p_path.Length()) {
+ // true separator
+ base = p_path.Mid(pos+1);
+ while ((pos >= 1) && (p_path[pos-1] == L'/'))
+ pos--;
+ if (pos == 0)
+ dir = L"/";
+ else
+ dir = p_path.Left(pos);
+ } else {
+ // separator at the end of the path
+ // pos = p_path.find_last_not_of("/");
+ pos = -1;
+ int ind = 0;
+ while (p_path[ind]) {
+ if (p_path[ind] != L'/')
+ pos = ind;
+ ind++;
+ }
+ if (pos == -1) {
+ base = L"/";
+ dir = L"/";
+ } else {
+ my_windows_split_path(p_path.Left(pos+1),dir,base);
+ }
+ }
+}
+
+static int filter_pattern(const char *string , const char *pattern , int flags_nocase) {
+ if ((string == 0) || (*string==0)) {
+ if (pattern == 0)
+ return 1;
+ while (*pattern=='*')
+ ++pattern;
+ return (!*pattern);
+ }
+
+ switch (*pattern) {
+ case '*':
+ if (!filter_pattern(string+1,pattern,flags_nocase))
+ return filter_pattern(string,pattern+1,flags_nocase);
+ return 1;
+ case 0:
+ if (*string==0)
+ return 1;
+ break;
+ case '?':
+ return filter_pattern(string+1,pattern+1,flags_nocase);
+ default:
+ if ( ((flags_nocase) && (tolower(*pattern)==tolower(*string)))
+ || (*pattern == *string)
+ ) {
+ return filter_pattern(string+1,pattern+1,flags_nocase);
+ }
+ break;
+ }
+ return 0;
+}
+
+
+namespace NWindows {
+namespace NFile {
+namespace NFind {
+
+static const TCHAR kDot = TEXT('.');
+
+bool CFileInfo::IsDots() const
+{
+ if (!IsDir() || Name.IsEmpty())
+ return false;
+ if (Name[0] != kDot)
+ return false;
+ return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2);
+}
+
+bool CFileInfoW::IsDots() const
+{
+ if (!IsDir() || Name.IsEmpty())
+ return false;
+ if (Name[0] != kDot)
+ return false;
+ return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2);
+}
+
+static bool originalFilename(const UString & src, AString & res)
+{
+ // Try to recover the original filename
+ res = "";
+ int i=0;
+ while (src[i])
+ {
+ if (src[i] >= 256) {
+ return false;
+ } else {
+ res += char(src[i]);
+ }
+ i++;
+ }
+ return true;
+}
+
+
+
+// Warning this function cannot update "fileInfo.Name"
+static int fillin_CFileInfo(CFileInfo &fileInfo,const char *filename) {
+ struct stat stat_info;
+
+ int ret;
+#ifdef ENV_HAVE_LSTAT
+ if (global_use_lstat) {
+ ret = lstat(filename,&stat_info);
+ } else
+#endif
+ {
+ ret = stat(filename,&stat_info);
+ }
+
+ if (ret != 0) return ret;
+
+ /* FIXME : FILE_ATTRIBUTE_HIDDEN ? */
+ if (S_ISDIR(stat_info.st_mode)) {
+ fileInfo.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+ } else {
+ fileInfo.Attrib = FILE_ATTRIBUTE_ARCHIVE;
+ }
+
+ if (!(stat_info.st_mode & S_IWUSR))
+ fileInfo.Attrib |= FILE_ATTRIBUTE_READONLY;
+
+ fileInfo.Attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((stat_info.st_mode & 0xFFFF) << 16);
+
+ RtlSecondsSince1970ToFileTime( stat_info.st_ctime, &fileInfo.CTime );
+ RtlSecondsSince1970ToFileTime( stat_info.st_mtime, &fileInfo.MTime );
+ RtlSecondsSince1970ToFileTime( stat_info.st_atime, &fileInfo.ATime );
+
+ fileInfo.IsDevice = false;
+
+ if (S_ISDIR(stat_info.st_mode)) {
+ fileInfo.Size = 0;
+ } else { // file or symbolic link
+ fileInfo.Size = stat_info.st_size; // for a symbolic link, size = size of filename
+ }
+ return 0;
+}
+
+static int fillin_CFileInfo(CFileInfo &fileInfo,const char *dir,const char *name) {
+ char filename[MAX_PATHNAME_LEN];
+ size_t dir_len = strlen(dir);
+ size_t name_len = strlen(name);
+ size_t total = dir_len + 1 + name_len + 1; // 1 = strlen("/"); + le zero character
+ if (total >= MAX_PATHNAME_LEN) throw "fillin_CFileInfo - internal error - MAX_PATHNAME_LEN";
+ memcpy(filename,dir,dir_len);
+ if (dir_len >= 1)
+ {
+ if (filename[dir_len-1] == CHAR_PATH_SEPARATOR)
+ { // delete the '/'
+ dir_len--;
+ }
+ }
+ filename[dir_len] = CHAR_PATH_SEPARATOR;
+ memcpy(filename+(dir_len+1),name,name_len+1); // copy also final '\0'
+
+ fileInfo.Name = name;
+
+ int ret = fillin_CFileInfo(fileInfo,filename);
+ if (ret != 0) {
+ AString err_msg = "stat error for ";
+ err_msg += filename;
+ err_msg += " (";
+ err_msg += strerror(errno);
+ err_msg += ")";
+ throw err_msg;
+ }
+ return ret;
+}
+
+////////////////////////////////
+// CFindFile
+
+bool CFindFile::Close()
+{
+
+ if(_dirp == 0)
+ return true;
+ int ret = closedir(_dirp);
+ if (ret == 0)
+ {
+ _dirp = 0;
+ return true;
+ }
+ return false;
+}
+
+// bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo)
+bool CFindFile::FindFirst(LPCSTR wildcard, CFileInfo &fileInfo)
+{
+ if (!Close())
+ return false;
+
+ if ((!wildcard) || (wildcard[0]==0)) {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return false;
+ }
+
+ my_windows_split_path(nameWindowToUnix(wildcard),_directory,_pattern);
+
+ TRACEN((printf("CFindFile::FindFirst : %s (dirname=%s,pattern=%s)\n",wildcard,(const char *)_directory,(const char *)_pattern)))
+
+ _dirp = ::opendir((const char *)_directory);
+ TRACEN((printf("CFindFile::FindFirst : opendir=%p\n",_dirp)))
+
+ if ((_dirp == 0) && (global_use_utf16_conversion)) {
+ // Try to recover the original filename
+ UString ustr = MultiByteToUnicodeString(_directory, 0);
+ AString resultString;
+ bool is_good = originalFilename(ustr, resultString);
+ if (is_good) {
+ _dirp = ::opendir((const char *)resultString);
+ _directory = resultString;
+ }
+ }
+
+ if (_dirp == 0) return false;
+
+ struct dirent *dp;
+ while ((dp = readdir(_dirp)) != NULL) {
+ if (filter_pattern(dp->d_name,(const char *)_pattern,0) == 1) {
+ int retf = fillin_CFileInfo(fileInfo,(const char *)_directory,dp->d_name);
+ if (retf)
+ {
+ TRACEN((printf("CFindFile::FindFirst : closedir-1(dirp=%p)\n",_dirp)))
+ closedir(_dirp);
+ _dirp = 0;
+ SetLastError( ERROR_NO_MORE_FILES );
+ return false;
+ }
+ TRACEN((printf("CFindFile::FindFirst -%s- true\n",dp->d_name)))
+ return true;
+ }
+ }
+
+ TRACEN((printf("CFindFile::FindFirst : closedir-2(dirp=%p)\n",_dirp)))
+ closedir(_dirp);
+ _dirp = 0;
+ SetLastError( ERROR_NO_MORE_FILES );
+ return false;
+}
+
+bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo)
+{
+ if (!Close())
+ return false;
+ CFileInfo fileInfo0;
+ AString Awildcard = UnicodeStringToMultiByte(wildcard, CP_ACP);
+ bool bret = FindFirst((LPCSTR)Awildcard, fileInfo0);
+ if (bret)
+ {
+ fileInfo.Attrib = fileInfo0.Attrib;
+ fileInfo.CTime = fileInfo0.CTime;
+ fileInfo.ATime = fileInfo0.ATime;
+ fileInfo.MTime = fileInfo0.MTime;
+ fileInfo.Size = fileInfo0.Size;
+ fileInfo.IsDevice = fileInfo0.IsDevice;
+ fileInfo.Name = GetUnicodeString(fileInfo0.Name, CP_ACP);
+ }
+ return bret;
+}
+
+bool CFindFile::FindNext(CFileInfo &fileInfo)
+{
+ if (_dirp == 0)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return false;
+ }
+
+ struct dirent *dp;
+ while ((dp = readdir(_dirp)) != NULL) {
+ if (filter_pattern(dp->d_name,(const char *)_pattern,0) == 1) {
+ int retf = fillin_CFileInfo(fileInfo,(const char *)_directory,dp->d_name);
+ if (retf)
+ {
+ TRACEN((printf("FindNextFileA -%s- ret_handle=FALSE (errno=%d)\n",dp->d_name,errno)))
+ return false;
+
+ }
+ TRACEN((printf("FindNextFileA -%s- true\n",dp->d_name)))
+ return true;
+ }
+ }
+ TRACEN((printf("FindNextFileA ret_handle=FALSE (ERROR_NO_MORE_FILES)\n")))
+ SetLastError( ERROR_NO_MORE_FILES );
+ return false;
+}
+
+bool CFindFile::FindNext(CFileInfoW &fileInfo)
+{
+ CFileInfo fileInfo0;
+ bool bret = FindNext(fileInfo0);
+ if (bret)
+ {
+ fileInfo.Attrib = fileInfo0.Attrib;
+ fileInfo.CTime = fileInfo0.CTime;
+ fileInfo.ATime = fileInfo0.ATime;
+ fileInfo.MTime = fileInfo0.MTime;
+ fileInfo.Size = fileInfo0.Size;
+ fileInfo.IsDevice = fileInfo0.IsDevice;
+ fileInfo.Name = GetUnicodeString(fileInfo0.Name, CP_ACP);
+ }
+ return bret;
+}
+
+bool CFileInfo::Find(LPCSTR wildcard)
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDeviceName(wildcard))
+ {
+ Clear();
+ IsDevice = true;
+ NIO::CInFile inFile;
+ if (!inFile.Open(wildcard))
+ return false;
+ Name = wildcard + 4;
+ if (inFile.LengthDefined)
+ Size = inFile.Length;
+ return true;
+ }
+ #endif
+ CFindFile finder;
+ return finder.FindFirst(wildcard, *this);
+}
+
+
+// #ifndef _UNICODE
+bool CFileInfoW::Find(LPCWSTR wildcard)
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDeviceName(wildcard))
+ {
+ Clear();
+ IsDevice = true;
+ NIO::CInFile inFile;
+ if (!inFile.Open(wildcard))
+ return false;
+ Name = wildcard + 4;
+ if (inFile.LengthDefined)
+ Size = inFile.Length;
+ return true;
+ }
+ #endif
+ CFindFile finder;
+ return finder.FindFirst(wildcard, *this);
+}
+// #endif
+
+bool FindFile(LPCSTR wildcard, CFileInfo &fileInfo)
+{
+ // CFindFile finder;
+ // return finder.FindFirst(wildcard, fileInfo);
+ AString dir,base;
+ my_windows_split_path(wildcard, dir , base);
+ int ret = fillin_CFileInfo(fileInfo,nameWindowToUnix(wildcard));
+ fileInfo.Name = base;
+ TRACEN((printf("FindFile(%s,CFileInfo) ret=%d\n",wildcard,ret)))
+ return (ret == 0);
+}
+
+bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo)
+{
+ // CFindFile finder;
+ // return finder.FindFirst(wildcard, fileInfo);
+ AString name = UnicodeStringToMultiByte(wildcard, CP_ACP);
+ CFileInfo fileInfo0;
+ int ret = fillin_CFileInfo(fileInfo0,nameWindowToUnix((const char *)name));
+ TRACEN((printf("FindFile-1(%s,CFileInfo) ret=%d\n",(const char *)name,ret)))
+ if (ret != 0)
+ {
+ // Try to recover the original filename
+ AString resultString;
+ bool is_good = originalFilename(wildcard, resultString);
+ if (is_good) {
+ ret = fillin_CFileInfo(fileInfo0,nameWindowToUnix((const char *)resultString));
+ TRACEN((printf("FindFile-2(%s,CFileInfo) ret=%d\n",(const char *)resultString,ret)))
+ }
+ }
+ if (ret == 0)
+ {
+ UString dir,base;
+ my_windows_split_path(wildcard, dir , base);
+ fileInfo.Attrib = fileInfo0.Attrib;
+ fileInfo.CTime = fileInfo0.CTime;
+ fileInfo.ATime = fileInfo0.ATime;
+ fileInfo.MTime = fileInfo0.MTime;
+ fileInfo.Size = fileInfo0.Size;
+ fileInfo.Name = base;
+ }
+ return (ret == 0);
+}
+
+bool DoesFileExist(LPCSTR name) // FIXME
+{
+ CFileInfo fi;
+ int ret = fillin_CFileInfo(fi,nameWindowToUnix(name));
+ TRACEN((printf("DoesFileExist(%s) ret=%d\n",name,ret)))
+ return (ret == 0) && !fi.IsDir();;
+}
+
+bool DoesDirExist(LPCSTR name) // FIXME
+{
+ CFileInfo fi;
+ int ret = fillin_CFileInfo(fi,nameWindowToUnix(name));
+ TRACEN((printf("DoesDirExist(%s) ret=%d\n",name,ret)))
+ return (ret == 0) && fi.IsDir();;
+}
+
+bool DoesFileOrDirExist(LPCSTR name)
+{
+ CFileInfo fileInfo;
+ int ret = fillin_CFileInfo(fileInfo,nameWindowToUnix(name));
+ TRACEN((printf("DoesFileOrDirExist(%s) ret=%d\n",name,ret)))
+ return (ret == 0);
+}
+
+bool DoesFileExist(LPCWSTR name)
+{
+ AString Aname = UnicodeStringToMultiByte(name, CP_ACP);
+ bool bret = DoesFileExist((LPCSTR)Aname);
+ if (bret) return bret;
+
+ // Try to recover the original filename
+ AString resultString;
+ bool is_good = originalFilename(name, resultString);
+ if (is_good) {
+ bret = DoesFileExist((const char *)resultString);
+ }
+ return bret;
+}
+
+bool DoesDirExist(LPCWSTR name)
+{
+ AString Aname = UnicodeStringToMultiByte(name, CP_ACP);
+ bool bret = DoesDirExist((LPCSTR)Aname);
+ if (bret) return bret;
+
+ // Try to recover the original filename
+ AString resultString;
+ bool is_good = originalFilename(name, resultString);
+ if (is_good) {
+ bret = DoesDirExist((const char *)resultString);
+ }
+ return bret;
+}
+
+bool DoesFileOrDirExist(LPCWSTR name)
+{
+ AString Aname = UnicodeStringToMultiByte(name, CP_ACP);
+ bool bret = DoesFileOrDirExist((LPCSTR)Aname);
+ if (bret) return bret;
+
+ // Try to recover the original filename
+ AString resultString;
+ bool is_good = originalFilename(name, resultString);
+ if (is_good) {
+ bret = DoesFileOrDirExist((const char *)resultString);
+ }
+ return bret;
+}
+
+/////////////////////////////////////
+// CEnumerator
+
+bool CEnumerator::NextAny(CFileInfo &fileInfo)
+{
+ if(_findFile.IsHandleAllocated())
+ return _findFile.FindNext(fileInfo);
+ else
+ return _findFile.FindFirst(_wildcard, fileInfo);
+}
+
+bool CEnumerator::Next(CFileInfo &fileInfo)
+{
+ while(true)
+ {
+ if(!NextAny(fileInfo))
+ return false;
+ if(!fileInfo.IsDots())
+ return true;
+ }
+}
+
+bool CEnumerator::Next(CFileInfo &fileInfo, bool &found)
+{
+ if (Next(fileInfo))
+ {
+ found = true;
+ return true;
+ }
+ found = false;
+ return (::GetLastError() == ERROR_NO_MORE_FILES);
+}
+
+bool CEnumeratorW::NextAny(CFileInfoW &fileInfo)
+{
+ if(_findFile.IsHandleAllocated())
+ return _findFile.FindNext(fileInfo);
+ else
+ return _findFile.FindFirst(_wildcard, fileInfo);
+}
+
+bool CEnumeratorW::Next(CFileInfoW &fileInfo)
+{
+ while(true)
+ {
+ if(!NextAny(fileInfo))
+ return false;
+ if(!fileInfo.IsDots())
+ return true;
+ }
+}
+
+bool CEnumeratorW::Next(CFileInfoW &fileInfo, bool &found)
+{
+ if (Next(fileInfo))
+ {
+ found = true;
+ return true;
+ }
+ found = false;
+ return (::GetLastError() == ERROR_NO_MORE_FILES);
+}
+
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/Windows/FileFind.h b/src/libs/7zip/unix/CPP/Windows/FileFind.h
new file mode 100644
index 000000000..a1fd0f072
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileFind.h
@@ -0,0 +1,126 @@
+// Windows/FileFind.h
+
+#ifndef __WINDOWS_FILEFIND_H
+#define __WINDOWS_FILEFIND_H
+
+#include "../Common/MyString.h"
+#include "FileName.h"
+#include "Defs.h"
+
+#include <sys/types.h> /* for DIR */
+#include <dirent.h>
+
+namespace NWindows {
+namespace NFile {
+namespace NFind {
+
+namespace NAttributes
+{
+ inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; }
+ inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; }
+ inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; }
+ inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; }
+ inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; }
+ inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; }
+ inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; }
+}
+
+class CFileInfoBase
+{
+ bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); }
+public:
+ UInt64 Size;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ DWORD Attrib;
+ bool IsDevice;
+
+ bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); }
+};
+
+class CFileInfo: public CFileInfoBase
+{
+public:
+ AString Name; // FIXME CSysString Name;
+ bool IsDots() const;
+ bool Find(LPCSTR wildcard);
+};
+
+// FIXME #ifdef _UNICODE
+// typedef CFileInfo CFileInfoW;
+// #else
+class CFileInfoW: public CFileInfoBase
+{
+public:
+ UString Name;
+ bool IsDots() const;
+ bool Find(LPCWSTR wildcard);
+};
+// #endif
+
+class CFindFile
+{
+ friend class CEnumerator;
+ DIR *_dirp;
+ AString _pattern;
+ AString _directory;
+public:
+ bool IsHandleAllocated() const { return (_dirp != 0); }
+ CFindFile(): _dirp(0) {}
+ ~CFindFile() { Close(); }
+ // bool FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo);
+ bool FindFirst(LPCSTR wildcard, CFileInfo &fileInfo);
+ bool FindNext(CFileInfo &fileInfo);
+ // FIXME #ifndef _UNICODE
+ bool FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo);
+ bool FindNext(CFileInfoW &fileInfo);
+ // FIXME #endif
+ bool Close();
+};
+
+bool FindFile(LPCSTR wildcard, CFileInfo &fileInfo);
+
+bool DoesFileExist(LPCSTR name);
+bool DoesDirExist(LPCTSTR name);
+bool DoesFileOrDirExist(LPCSTR name);
+// #ifndef _UNICODE
+bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo);
+bool DoesFileExist(LPCWSTR name);
+bool DoesDirExist(LPCWSTR name);
+bool DoesFileOrDirExist(LPCWSTR name);
+// #endif
+
+class CEnumerator
+{
+ CFindFile _findFile;
+ AString _wildcard; // FIXME CSysString _wildcard;
+ bool NextAny(CFileInfo &fileInfo);
+public:
+ CEnumerator(): _wildcard(NName::kAnyStringWildcard) {}
+ // FIXME CEnumerator(const CSysString &wildcard): _wildcard(wildcard) {}
+ CEnumerator(const AString &wildcard): _wildcard(wildcard) {}
+ bool Next(CFileInfo &fileInfo);
+ bool Next(CFileInfo &fileInfo, bool &found);
+};
+
+// FIXME #ifdef _UNICODE
+// typedef CEnumerator CEnumeratorW;
+// #else
+class CEnumeratorW
+{
+ CFindFile _findFile;
+ UString _wildcard;
+ bool NextAny(CFileInfoW &fileInfo);
+public:
+ CEnumeratorW(): _wildcard(NName::kAnyStringWildcard) {}
+ CEnumeratorW(const UString &wildcard): _wildcard(wildcard) {}
+ bool Next(CFileInfoW &fileInfo);
+ bool Next(CFileInfoW &fileInfo, bool &found);
+};
+// FIXME #endif
+
+}}}
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/FileIO.cpp b/src/libs/7zip/unix/CPP/Windows/FileIO.cpp
new file mode 100644
index 000000000..a731813f3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileIO.cpp
@@ -0,0 +1,475 @@
+// Windows/FileIO.cpp
+
+#include "StdAfx.h"
+
+#include "FileIO.h"
+#include "Defs.h"
+#include "../Common/StringConvert.h"
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define NEED_NAME_WINDOWS_TO_UNIX
+#include "myPrivate.h"
+
+#include <sys/types.h>
+#include <utime.h>
+
+#ifdef ENV_HAVE_LSTAT
+#define FD_LINK (-2)
+#endif
+
+#define GENERIC_READ 0x80000000
+#define GENERIC_WRITE 0x40000000
+
+extern BOOLEAN WINAPI RtlTimeToSecondsSince1970( const LARGE_INTEGER *Time, DWORD *Seconds );
+
+namespace NWindows {
+namespace NFile {
+namespace NIO {
+
+CFileBase::~CFileBase()
+{
+ Close();
+}
+
+bool CFileBase::Create(LPCSTR filename, DWORD dwDesiredAccess,
+ DWORD dwShareMode, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,bool ignoreSymbolicLink)
+{
+ Close();
+
+ int flags = 0;
+ const char * name = nameWindowToUnix(filename);
+
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+
+ /* now use the umask value */
+ int mask = umask(0);
+ (void)umask(mask);
+ int mode = 0666 & ~(mask & 066); /* keep the R/W for the user */
+
+ if (dwDesiredAccess & GENERIC_WRITE) flags |= O_WRONLY;
+ if (dwDesiredAccess & GENERIC_READ) flags |= O_RDONLY;
+
+
+ switch (dwCreationDisposition)
+ {
+ case CREATE_NEW : flags |= O_CREAT | O_EXCL; break;
+ case CREATE_ALWAYS : flags |= O_CREAT; break;
+ case OPEN_EXISTING : break;
+ case OPEN_ALWAYS : flags |= O_CREAT; break;
+ // case TRUNCATE_EXISTING : flags |= O_TRUNC; break;
+ }
+ // printf("##DBG open(%s,0x%x,%o)##\n",name,flags,(unsigned)mode);
+
+ _fd = -1;
+#ifdef ENV_HAVE_LSTAT
+ if ((global_use_lstat) && (ignoreSymbolicLink == false))
+ {
+ _size = readlink(name, _buffer, sizeof(_buffer)-1);
+ if (_size > 0) {
+ if (dwDesiredAccess & GENERIC_READ) {
+ _fd = FD_LINK;
+ _offset = 0;
+ _buffer[_size]=0;
+ } else if (dwDesiredAccess & GENERIC_WRITE) {
+ // does not overwrite the file pointed by symbolic link
+ if (!unlink(name)) return false;
+ }
+ }
+ }
+#endif
+
+ if (_fd == -1) {
+ _fd = open(name,flags, mode);
+ }
+
+ if ((_fd == -1) && (global_use_utf16_conversion)) {
+ // bug #1204993 - Try to recover the original filename
+ UString ustr = MultiByteToUnicodeString(AString(name), 0);
+ AString resultString;
+ int is_good = 1;
+ for (int i = 0; i < ustr.Length(); i++)
+ {
+ if (ustr[i] >= 256) {
+ is_good = 0;
+ break;
+ } else {
+ resultString += char(ustr[i]);
+ }
+ }
+ if (is_good) {
+ _fd = open((const char *)resultString,flags, mode);
+ }
+ }
+
+ if (_fd == -1) {
+ /* !ENV_HAVE_LSTAT : an invalid symbolic link => errno == ENOENT */
+ return false;
+ } else {
+ _unix_filename = name;
+ }
+
+ return true;
+}
+
+bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes,bool ignoreSymbolicLink)
+{
+ Close();
+ return Create(UnicodeStringToMultiByte(fileName, CP_ACP),
+ desiredAccess, shareMode, creationDisposition, flagsAndAttributes,ignoreSymbolicLink);
+}
+
+bool CFileBase::Close()
+{
+ struct utimbuf buf;
+
+ buf.actime = _lastAccessTime;
+ buf.modtime = _lastWriteTime;
+
+ _lastAccessTime = _lastWriteTime = (time_t)-1;
+
+ if(_fd == -1)
+ return true;
+
+#ifdef ENV_HAVE_LSTAT
+ if(_fd == FD_LINK) {
+ _fd = -1;
+ return true;
+ }
+#endif
+
+ int ret = ::close(_fd);
+ if (ret == 0) {
+ _fd = -1;
+
+ /* On some OS (mingwin, MacOSX ...), you must close the file before updating times */
+ if ((buf.actime != (time_t)-1) || (buf.modtime != (time_t)-1)) {
+ struct stat oldbuf;
+ int ret = stat((const char*)(_unix_filename),&oldbuf);
+ if (ret == 0) {
+ if (buf.actime == (time_t)-1) buf.actime = oldbuf.st_atime;
+ if (buf.modtime == (time_t)-1) buf.modtime = oldbuf.st_mtime;
+ } else {
+ time_t current_time = time(0);
+ if (buf.actime == (time_t)-1) buf.actime = current_time;
+ if (buf.modtime == (time_t)-1) buf.modtime = current_time;
+ }
+ /* ret = */ utime((const char *)(_unix_filename), &buf);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool CFileBase::GetLength(UINT64 &length) const
+{
+ if (_fd == -1)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return false;
+ }
+
+#ifdef ENV_HAVE_LSTAT
+ if (_fd == FD_LINK) {
+ length = _size;
+ return true;
+ }
+#endif
+
+ off_t pos_cur = ::lseek(_fd, 0, SEEK_CUR);
+ if (pos_cur == (off_t)-1)
+ return false;
+
+ off_t pos_end = ::lseek(_fd, 0, SEEK_END);
+ if (pos_end == (off_t)-1)
+ return false;
+
+ off_t pos_cur2 = ::lseek(_fd, pos_cur, SEEK_SET);
+ if (pos_cur2 == (off_t)-1)
+ return false;
+
+ length = (UINT64)pos_end;
+
+ return true;
+}
+
+bool CFileBase::Seek(INT64 distanceToMove, DWORD moveMethod, UINT64 &newPosition)
+{
+ if (_fd == -1)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return false;
+ }
+
+#ifdef ENV_HAVE_LSTAT
+ if (_fd == FD_LINK) {
+ INT64 offset;
+ switch (moveMethod) {
+ case STREAM_SEEK_SET : offset = distanceToMove; break;
+ case STREAM_SEEK_CUR : offset = _offset + distanceToMove; break;
+ case STREAM_SEEK_END : offset = _size + distanceToMove; break;
+ default : offset = -1;
+ }
+ if (offset < 0) {
+ SetLastError( EINVAL );
+ return false;
+ }
+ if (offset > _size) offset = _size;
+ newPosition = _offset = offset;
+ return true;
+ }
+#endif
+
+ bool ret = true;
+
+ off_t pos = (off_t)distanceToMove;
+
+ off_t newpos = ::lseek(_fd,pos,moveMethod);
+
+ if (newpos == ((off_t)-1)) {
+ ret = false;
+ } else {
+ newPosition = (UINT64)newpos;
+ }
+
+ return ret;
+}
+
+bool CFileBase::Seek(UINT64 position, UINT64 &newPosition)
+{
+ return Seek(position, FILE_BEGIN, newPosition);
+}
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(LPCTSTR fileName, DWORD shareMode,
+ DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ return Create(fileName, GENERIC_READ, shareMode,
+ creationDisposition, flagsAndAttributes);
+}
+
+bool CInFile::Open(LPCTSTR fileName,bool ignoreSymbolicLink)
+{
+ return Create(fileName, GENERIC_READ , FILE_SHARE_READ, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,ignoreSymbolicLink);
+}
+
+#ifndef _UNICODE
+bool CInFile::Open(LPCWSTR fileName, DWORD shareMode,
+ DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ return Create(fileName, GENERIC_READ, shareMode,
+ creationDisposition, flagsAndAttributes);
+}
+
+bool CInFile::Open(LPCWSTR fileName,bool ignoreSymbolicLink)
+{
+ return Create(fileName, GENERIC_READ , FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,ignoreSymbolicLink);
+}
+#endif
+
+// ReadFile and WriteFile functions in Windows have BUG:
+// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
+// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
+// (Insufficient system resources exist to complete the requested service).
+
+// static UINT32 kChunkSizeMax = (1 << 24);
+
+bool CInFile::ReadPart(void *data, UINT32 size, UINT32 &processedSize)
+{
+ // if (size > kChunkSizeMax)
+ // size = kChunkSizeMax;
+ return Read(data,size,processedSize);
+}
+
+bool CInFile::Read(void *buffer, UINT32 bytesToRead, UINT32 &bytesRead)
+{
+ if (_fd == -1)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return false;
+ }
+
+ if (bytesToRead == 0) {
+ bytesRead =0;
+ return TRUE;
+ }
+
+#ifdef ENV_HAVE_LSTAT
+ if (_fd == FD_LINK) {
+ if (_offset >= _size) {
+ bytesRead = 0;
+ return TRUE;
+ }
+ int len = (_size - _offset);
+ if (len > bytesToRead) len = bytesToRead;
+ memcpy(buffer,_buffer+_offset,len);
+ bytesRead = len;
+ _offset += len;
+ return TRUE;
+ }
+#endif
+
+ ssize_t ret;
+ do {
+ ret = read(_fd,buffer,bytesToRead);
+ } while (ret < 0 && (errno == EINTR));
+
+ if (ret != -1) {
+ bytesRead = ret;
+ return TRUE;
+ }
+ bytesRead =0;
+ return FALSE;
+}
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Open(LPCTSTR fileName, DWORD shareMode,
+ DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ return CFileBase::Create(fileName, GENERIC_WRITE, shareMode,
+ creationDisposition, flagsAndAttributes);
+}
+
+static inline DWORD GetCreationDisposition(bool createAlways)
+ { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
+
+bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition)
+{
+ return Open(fileName, FILE_SHARE_READ,
+ creationDisposition, FILE_ATTRIBUTE_NORMAL);
+}
+
+bool COutFile::Create(LPCTSTR fileName, bool createAlways)
+{
+ return Open(fileName, GetCreationDisposition(createAlways));
+}
+
+#ifndef _UNICODE
+
+bool COutFile::Open(LPCWSTR fileName, DWORD shareMode,
+ DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ return CFileBase::Create(fileName, GENERIC_WRITE, shareMode,
+ creationDisposition, flagsAndAttributes);
+}
+
+bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition)
+{
+ return Open(fileName, FILE_SHARE_READ,
+ creationDisposition, FILE_ATTRIBUTE_NORMAL);
+}
+
+bool COutFile::Create(LPCWSTR fileName, bool createAlways)
+{
+ return Open(fileName, GetCreationDisposition(createAlways));
+}
+
+#endif
+
+bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
+{
+ LARGE_INTEGER ltime;
+ DWORD dw;
+
+ if (_fd == -1) {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return false;
+ }
+
+ /* On some OS (cygwin, MacOSX ...), you must close the file before updating times */
+ if (aTime) {
+ ltime.QuadPart = aTime->dwHighDateTime;
+ ltime.QuadPart = (ltime.QuadPart << 32) | aTime->dwLowDateTime;
+ RtlTimeToSecondsSince1970( &ltime, &dw );
+ _lastAccessTime = dw;
+ }
+ if (mTime) {
+ ltime.QuadPart = mTime->dwHighDateTime;
+ ltime.QuadPart = (ltime.QuadPart << 32) | mTime->dwLowDateTime;
+ RtlTimeToSecondsSince1970( &ltime, &dw );
+ _lastWriteTime = dw;
+ }
+
+ return true;
+}
+
+bool COutFile::SetMTime(const FILETIME *mTime)
+{
+ return SetTime(NULL, NULL, mTime);
+}
+
+bool COutFile::WritePart(const void *data, UINT32 size, UINT32 &processedSize)
+{
+// if (size > kChunkSizeMax)
+// size = kChunkSizeMax;
+
+ return Write(data,size,processedSize);
+}
+
+bool COutFile::Write(const void *buffer, UINT32 bytesToWrite, UINT32 &bytesWritten)
+{
+ if (_fd == -1)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return false;
+ }
+
+ ssize_t ret;
+ do {
+ ret = write(_fd,buffer, bytesToWrite);
+ } while (ret < 0 && (errno == EINTR));
+
+ if (ret != -1) {
+ bytesWritten = ret;
+ return TRUE;
+ }
+ bytesWritten =0;
+ return FALSE;
+}
+
+bool COutFile::SetEndOfFile()
+{
+ if (_fd == -1)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return false;
+ }
+
+ bool bret = false;
+
+ off_t pos_cur = lseek(_fd, 0, SEEK_CUR);
+ if (pos_cur != (off_t)-1) {
+ int iret = ftruncate(_fd, pos_cur);
+ if (iret == 0) bret = true;
+ }
+
+ return bret;
+}
+
+bool COutFile::SetLength(UINT64 length)
+{
+ UINT64 newPosition;
+ if(!Seek(length, newPosition))
+ return false;
+ if(newPosition != length)
+ return false;
+ return SetEndOfFile();
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/Windows/FileIO.h b/src/libs/7zip/unix/CPP/Windows/FileIO.h
new file mode 100644
index 000000000..4aa84c053
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileIO.h
@@ -0,0 +1,110 @@
+// Windows/FileIO.h
+
+#ifndef __WINDOWS_FILEIO_H
+#define __WINDOWS_FILEIO_H
+
+#include <Common/MyString.h>
+
+#ifndef _WIN32
+
+#define FILE_SHARE_READ 1
+#define FILE_SHARE_WRITE 2
+
+#define FILE_BEGIN SEEK_SET
+#define FILE_CURRENT SEEK_CUR
+#define FILE_END SEEK_END
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+
+#define CREATE_NEW 1
+#define CREATE_ALWAYS 2
+#define OPEN_EXISTING 3
+#define OPEN_ALWAYS 4
+/* #define TRUNCATE_EXISTING 5 */
+
+#endif
+
+namespace NWindows {
+namespace NFile {
+namespace NIO {
+
+
+class CFileBase
+{
+protected:
+ int _fd;
+ AString _unix_filename;
+ time_t _lastAccessTime;
+ time_t _lastWriteTime;
+#ifdef ENV_HAVE_LSTAT
+ int _size;
+ char _buffer[MAX_PATHNAME_LEN+1];
+ int _offset;
+#endif
+
+ bool Create(LPCSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes,bool ignoreSymbolicLink=false);
+ bool Create(LPCWSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes,bool ignoreSymbolicLink=false);
+
+public:
+ CFileBase(): _fd(-1) {};
+ virtual ~CFileBase();
+
+ virtual bool Close();
+
+ bool GetLength(UINT64 &length) const;
+
+ bool Seek(INT64 distanceToMove, DWORD moveMethod, UINT64 &newPosition);
+ bool Seek(UINT64 position, UINT64 &newPosition);
+};
+
+class CInFile: public CFileBase
+{
+public:
+ bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool OpenShared(LPCTSTR fileName, bool /* shareForWrite */ ,bool ignoreSymbolicLink=false) {
+ return Open(fileName,ignoreSymbolicLink);
+ }
+ bool Open(LPCTSTR fileName,bool ignoreSymbolicLink=false);
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool OpenShared(LPCWSTR fileName, bool /* shareForWrite */ ,bool ignoreSymbolicLink=false) {
+ return Open(fileName,ignoreSymbolicLink);
+ }
+ bool Open(LPCWSTR fileName,bool ignoreSymbolicLink=false);
+ #endif
+ bool ReadPart(void *data, UINT32 size, UINT32 &processedSize);
+ bool Read(void *data, UINT32 size, UINT32 &processedSize);
+};
+
+class COutFile: public CFileBase
+{
+public:
+ bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(LPCTSTR fileName, DWORD creationDisposition);
+ bool Create(LPCTSTR fileName, bool createAlways);
+
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(LPCWSTR fileName, DWORD creationDisposition);
+ bool Create(LPCWSTR fileName, bool createAlways);
+ #endif
+
+ /*
+ void SetOpenCreationDisposition(DWORD creationDisposition)
+ { m_CreationDisposition = creationDisposition; }
+ void SetOpenCreationDispositionCreateAlways()
+ { m_CreationDisposition = CREATE_ALWAYS; }
+ */
+
+ bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime);
+ bool SetMTime(const FILETIME *mTime);
+ bool WritePart(const void *data, UINT32 size, UINT32 &processedSize);
+ bool Write(const void *data, UINT32 size, UINT32 &processedSize);
+ bool SetEndOfFile();
+ bool SetLength(UINT64 length);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/FileName.cpp b/src/libs/7zip/unix/CPP/Windows/FileName.cpp
new file mode 100644
index 000000000..8443a4af9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileName.cpp
@@ -0,0 +1,50 @@
+// Windows/FileName.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileName.h"
+#include "Common/Wildcard.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+void NormalizeDirPathPrefix(CSysString &dirPath)
+{
+ if (dirPath.IsEmpty())
+ return;
+ if (dirPath.ReverseFind(kDirDelimiter) != dirPath.Length() - 1)
+ dirPath += kDirDelimiter;
+}
+
+#ifndef _UNICODE
+void NormalizeDirPathPrefix(UString &dirPath)
+{
+ if (dirPath.IsEmpty())
+ return;
+ if (dirPath.ReverseFind(wchar_t(kDirDelimiter)) != dirPath.Length() - 1)
+ dirPath += wchar_t(kDirDelimiter);
+}
+#endif
+
+const wchar_t kExtensionDelimiter = L'.';
+
+void SplitNameToPureNameAndExtension(const UString &fullName,
+ UString &pureName, UString &extensionDelimiter, UString &extension)
+{
+ int index = fullName.ReverseFind(kExtensionDelimiter);
+ if (index < 0)
+ {
+ pureName = fullName;
+ extensionDelimiter.Empty();
+ extension.Empty();
+ }
+ else
+ {
+ pureName = fullName.Left(index);
+ extensionDelimiter = kExtensionDelimiter;
+ extension = fullName.Mid(index + 1);
+ }
+}
+
+}}}
diff --git a/src/libs/7zip/unix/CPP/Windows/FileName.h b/src/libs/7zip/unix/CPP/Windows/FileName.h
new file mode 100644
index 000000000..d98079026
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/FileName.h
@@ -0,0 +1,27 @@
+// Windows/FileName.h
+
+#ifndef __WINDOWS_FILENAME_H
+#define __WINDOWS_FILENAME_H
+
+#include "../../C/Types.h"
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+const TCHAR kDirDelimiter = CHAR_PATH_SEPARATOR;
+const TCHAR kAnyStringWildcard = '*';
+
+void NormalizeDirPathPrefix(CSysString &dirPath); // ensures that it ended with '\\'
+#ifndef _UNICODE
+void NormalizeDirPathPrefix(UString &dirPath); // ensures that it ended with '\\'
+#endif
+
+void SplitNameToPureNameAndExtension(const UString &fullName,
+ UString &pureName, UString &extensionDelimiter, UString &extension);
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Handle.h b/src/libs/7zip/unix/CPP/Windows/Handle.h
new file mode 100644
index 000000000..0791b4acd
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Handle.h
@@ -0,0 +1,37 @@
+// Windows/Handle.h
+
+#ifndef __WINDOWS_HANDLE_H
+#define __WINDOWS_HANDLE_H
+
+namespace NWindows {
+
+class CHandle
+{
+protected:
+ HANDLE _handle;
+public:
+ operator HANDLE() { return _handle; }
+ CHandle(): _handle(NULL) {}
+ ~CHandle() { Close(); }
+ bool Close()
+ {
+ if (_handle == NULL)
+ return true;
+ if (!::CloseHandle(_handle))
+ return false;
+ _handle = NULL;
+ return true;
+ }
+ void Attach(HANDLE handle)
+ { _handle = handle; }
+ HANDLE Detach()
+ {
+ HANDLE handle = _handle;
+ _handle = NULL;
+ return handle;
+ }
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Menu.h b/src/libs/7zip/unix/CPP/Windows/Menu.h
new file mode 100644
index 000000000..2f753c237
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Menu.h
@@ -0,0 +1,4 @@
+
+/* TODO */
+
+
diff --git a/src/libs/7zip/unix/CPP/Windows/NtCheck.h b/src/libs/7zip/unix/CPP/Windows/NtCheck.h
new file mode 100644
index 000000000..e56318f00
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/NtCheck.h
@@ -0,0 +1,44 @@
+// Windows/NtCheck.h
+
+#ifndef __WINDOWS_NT_CHECK_H
+#define __WINDOWS_NT_CHECK_H
+
+#ifdef _WIN32
+
+#if !defined(_WIN64) && !defined(UNDER_CE)
+static inline bool IsItWindowsNT()
+{
+ OSVERSIONINFO vi;
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+
+#ifndef _UNICODE
+ #if defined(_WIN64) || defined(UNDER_CE)
+ bool g_IsNT = true;
+ #define SET_IS_NT
+ #else
+ bool g_IsNT = false;
+ #define SET_IS_NT g_IsNT = IsItWindowsNT();
+ #endif
+ #define NT_CHECK_ACTION
+ // #define NT_CHECK_ACTION { NT_CHECK_FAIL_ACTION }
+#else
+ #if !defined(_WIN64) && !defined(UNDER_CE)
+ #define NT_CHECK_ACTION if (!IsItWindowsNT()) { NT_CHECK_FAIL_ACTION }
+ #else
+ #define NT_CHECK_ACTION
+ #endif
+ #define SET_IS_NT
+#endif
+
+#define NT_CHECK NT_CHECK_ACTION SET_IS_NT
+
+#else
+
+#define NT_CHECK
+
+#endif
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/PropVariant.cpp b/src/libs/7zip/unix/CPP/Windows/PropVariant.cpp
new file mode 100644
index 000000000..90212e08f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/PropVariant.cpp
@@ -0,0 +1,243 @@
+// Windows/PropVariant.cpp
+
+#include "StdAfx.h"
+
+#include "PropVariant.h"
+
+#include "../Common/Defs.h"
+
+namespace NWindows {
+namespace NCOM {
+
+CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
+{
+ vt = VT_EMPTY;
+ InternalCopy(&varSrc);
+}
+
+CPropVariant::CPropVariant(const CPropVariant &varSrc)
+{
+ vt = VT_EMPTY;
+ InternalCopy(&varSrc);
+}
+
+CPropVariant::CPropVariant(BSTR bstrSrc)
+{
+ vt = VT_EMPTY;
+ *this = bstrSrc;
+}
+
+CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
+{
+ vt = VT_EMPTY;
+ *this = lpszSrc;
+}
+
+CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
+{
+ InternalCopy(&varSrc);
+ return *this;
+}
+CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
+{
+ InternalCopy(&varSrc);
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
+{
+ *this = (LPCOLESTR)bstrSrc;
+ return *this;
+}
+
+static const char *kMemException = "out of memory";
+
+CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc)
+{
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ bstrVal = ::SysAllocString(lpszSrc);
+ if (bstrVal == NULL && lpszSrc != NULL)
+ {
+ throw kMemException;
+ // vt = VT_ERROR;
+ // scode = E_OUTOFMEMORY;
+ }
+ return *this;
+}
+
+
+CPropVariant& CPropVariant::operator=(const char *s)
+{
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ UINT len = (UINT)strlen(s);
+ bstrVal = ::SysAllocStringByteLen(0, (UINT)len * sizeof(OLECHAR));
+ if (bstrVal == NULL)
+ {
+ throw kMemException;
+ // vt = VT_ERROR;
+ // scode = E_OUTOFMEMORY;
+ }
+ else
+ {
+ for (UINT i = 0; i <= len; i++)
+ bstrVal[i] = s[i];
+ }
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(bool bSrc)
+{
+ if (vt != VT_BOOL)
+ {
+ InternalClear();
+ vt = VT_BOOL;
+ }
+ boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
+ return *this;
+}
+
+#define SET_PROP_FUNC(type, id, dest) \
+ CPropVariant& CPropVariant::operator=(type value) \
+ { if (vt != id) { InternalClear(); vt = id; } \
+ dest = value; return *this; }
+
+SET_PROP_FUNC(Byte, VT_UI1, bVal)
+SET_PROP_FUNC(Int16, VT_I2, iVal)
+SET_PROP_FUNC(Int32, VT_I4, lVal)
+SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
+SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
+SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime)
+
+static HRESULT MyPropVariantClear(PROPVARIANT *prop)
+{
+ switch(prop->vt)
+ {
+ case VT_UI1:
+ case VT_I1:
+ case VT_I2:
+ case VT_UI2:
+ case VT_BOOL:
+ case VT_I4:
+ case VT_UI4:
+ case VT_R4:
+ case VT_INT:
+ case VT_UINT:
+ case VT_ERROR:
+ case VT_FILETIME:
+ case VT_UI8:
+ case VT_R8:
+ case VT_CY:
+ case VT_DATE:
+ prop->vt = VT_EMPTY;
+ prop->wReserved1 = 0;
+ return S_OK;
+ }
+ return ::VariantClear((VARIANTARG *)prop);
+}
+
+HRESULT CPropVariant::Clear()
+{
+ return MyPropVariantClear(this);
+}
+
+HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc)
+{
+ ::VariantClear((tagVARIANT *)this);
+ switch(pSrc->vt)
+ {
+ case VT_UI1:
+ case VT_I1:
+ case VT_I2:
+ case VT_UI2:
+ case VT_BOOL:
+ case VT_I4:
+ case VT_UI4:
+ case VT_R4:
+ case VT_INT:
+ case VT_UINT:
+ case VT_ERROR:
+ case VT_FILETIME:
+ case VT_UI8:
+ case VT_R8:
+ case VT_CY:
+ case VT_DATE:
+ memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
+ return S_OK;
+ }
+ return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
+}
+
+
+HRESULT CPropVariant::Attach(PROPVARIANT *pSrc)
+{
+ HRESULT hr = Clear();
+ if (FAILED(hr))
+ return hr;
+ memcpy(this, pSrc, sizeof(PROPVARIANT));
+ pSrc->vt = VT_EMPTY;
+ return S_OK;
+}
+
+HRESULT CPropVariant::Detach(PROPVARIANT *pDest)
+{
+ HRESULT hr = MyPropVariantClear(pDest);
+ if (FAILED(hr))
+ return hr;
+ memcpy(pDest, this, sizeof(PROPVARIANT));
+ vt = VT_EMPTY;
+ return S_OK;
+}
+
+HRESULT CPropVariant::InternalClear()
+{
+ HRESULT hr = Clear();
+ if (FAILED(hr))
+ {
+ vt = VT_ERROR;
+ scode = hr;
+ }
+ return hr;
+}
+
+void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
+{
+ HRESULT hr = Copy(pSrc);
+ if (FAILED(hr))
+ {
+ if (hr == E_OUTOFMEMORY)
+ throw kMemException;
+ vt = VT_ERROR;
+ scode = hr;
+ }
+}
+
+int CPropVariant::Compare(const CPropVariant &a)
+{
+ if (vt != a.vt)
+ return MyCompare(vt, a.vt);
+ switch (vt)
+ {
+ case VT_EMPTY: return 0;
+ // case VT_I1: return MyCompare(cVal, a.cVal);
+ case VT_UI1: return MyCompare(bVal, a.bVal);
+ case VT_I2: return MyCompare(iVal, a.iVal);
+ case VT_UI2: return MyCompare(uiVal, a.uiVal);
+ case VT_I4: return MyCompare(lVal, a.lVal);
+ case VT_UI4: return MyCompare(ulVal, a.ulVal);
+ // case VT_UINT: return MyCompare(uintVal, a.uintVal);
+ case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
+ case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
+ case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
+ case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime);
+ case VT_BSTR:
+ return 0; // Not implemented
+ // return MyCompare(aPropVarint.cVal);
+ default: return 0;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/Windows/PropVariant.h b/src/libs/7zip/unix/CPP/Windows/PropVariant.h
new file mode 100644
index 000000000..d018034eb
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/PropVariant.h
@@ -0,0 +1,56 @@
+// Windows/PropVariant.h
+
+#ifndef __WINDOWS_PROPVARIANT_H
+#define __WINDOWS_PROPVARIANT_H
+
+#include "../Common/MyWindows.h"
+#include "../Common/Types.h"
+
+namespace NWindows {
+namespace NCOM {
+
+class CPropVariant : public tagPROPVARIANT
+{
+public:
+ CPropVariant() { vt = VT_EMPTY; wReserved1 = 0; }
+ ~CPropVariant() { Clear(); }
+ CPropVariant(const PROPVARIANT &varSrc);
+ CPropVariant(const CPropVariant &varSrc);
+ CPropVariant(BSTR bstrSrc);
+ CPropVariant(LPCOLESTR lpszSrc);
+ CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); };
+ CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; }
+ CPropVariant(Int16 value) { vt = VT_I2; wReserved1 = 0; iVal = value; }
+ CPropVariant(Int32 value) { vt = VT_I4; wReserved1 = 0; lVal = value; }
+ CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; }
+ CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; }
+ CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; }
+
+ CPropVariant& operator=(const CPropVariant &varSrc);
+ CPropVariant& operator=(const PROPVARIANT &varSrc);
+ CPropVariant& operator=(BSTR bstrSrc);
+ CPropVariant& operator=(LPCOLESTR lpszSrc);
+ CPropVariant& operator=(const char *s);
+ CPropVariant& operator=(bool bSrc);
+ CPropVariant& operator=(Byte value);
+ CPropVariant& operator=(Int16 value);
+ CPropVariant& operator=(Int32 value);
+ CPropVariant& operator=(UInt32 value);
+ CPropVariant& operator=(Int64 value);
+ CPropVariant& operator=(UInt64 value);
+ CPropVariant& operator=(const FILETIME &value);
+
+ HRESULT Clear();
+ HRESULT Copy(const PROPVARIANT *pSrc);
+ HRESULT Attach(PROPVARIANT *pSrc);
+ HRESULT Detach(PROPVARIANT *pDest);
+
+ HRESULT InternalClear();
+ void InternalCopy(const PROPVARIANT *pSrc);
+
+ int Compare(const CPropVariant &a1);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/PropVariantConversions.cpp b/src/libs/7zip/unix/CPP/Windows/PropVariantConversions.cpp
new file mode 100644
index 000000000..61d524d07
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/PropVariantConversions.cpp
@@ -0,0 +1,142 @@
+// PropVariantConversions.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Defs.h"
+
+#include "PropVariantConversions.h"
+
+static UString ConvertUInt64ToString(UInt64 value)
+{
+ wchar_t buffer[32];
+ ConvertUInt64ToString(value, buffer);
+ return buffer;
+}
+
+static UString ConvertInt64ToString(Int64 value)
+{
+ wchar_t buffer[32];
+ ConvertInt64ToString(value, buffer);
+ return buffer;
+}
+
+#ifdef _WIN32
+static char *UIntToStringSpec(char c, UInt32 value, char *s, int numPos)
+{
+ if (c != 0)
+ *s++ = c;
+ char temp[16];
+ int pos = 0;
+ do
+ {
+ temp[pos++] = (char)('0' + value % 10);
+ value /= 10;
+ }
+ while (value != 0);
+ int i;
+ for (i = 0; i < numPos - pos; i++)
+ *s++ = '0';
+ do
+ *s++ = temp[--pos];
+ while (pos > 0);
+ *s = '\0';
+ return s;
+}
+#endif
+
+bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime, bool includeSeconds)
+{
+#ifdef _WIN32
+ s[0] = '\0';
+ SYSTEMTIME st;
+ if (!BOOLToBool(FileTimeToSystemTime(&ft, &st)))
+ return false;
+ s = UIntToStringSpec(0, st.wYear, s, 4);
+ s = UIntToStringSpec('-', st.wMonth, s, 2);
+ s = UIntToStringSpec('-', st.wDay, s, 2);
+ if (includeTime)
+ {
+ s = UIntToStringSpec(' ', st.wHour, s, 2);
+ s = UIntToStringSpec(':', st.wMinute, s, 2);
+ if (includeSeconds)
+ UIntToStringSpec(':', st.wSecond, s, 2);
+ }
+ /*
+ sprintf(s, "%04d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
+ if (includeTime)
+ {
+ sprintf(s + strlen(s), " %02d:%02d", st.wHour, st.wMinute);
+ if (includeSeconds)
+ sprintf(s + strlen(s), ":%02d", st.wSecond);
+ }
+ */
+#else
+ BOOLEAN WINAPI RtlTimeToSecondsSince1970( const LARGE_INTEGER *Time, DWORD *Seconds );
+
+ FILETIME filetime;
+ LocalFileTimeToFileTime(&ft, &filetime);
+
+ LARGE_INTEGER ltime;
+
+ ltime.QuadPart = filetime.dwHighDateTime;
+ ltime.QuadPart = (ltime.QuadPart << 32) | filetime.dwLowDateTime;
+
+ DWORD dw;
+ RtlTimeToSecondsSince1970(&ltime, &dw );
+ time_t timep = (time_t)dw;
+
+ struct tm * date = localtime(&timep);
+
+ sprintf(s, "%04d-%02d-%02d", date->tm_year+1900, date->tm_mon+1,date->tm_mday);
+ if (includeTime)
+ {
+ sprintf(s + strlen(s), " %02d:%02d", date->tm_hour,date->tm_min);
+ if (includeSeconds)
+ sprintf(s + strlen(s), ":%02d", date->tm_sec);
+ }
+#endif
+ return true;
+}
+
+UString ConvertFileTimeToString(const FILETIME &ft, bool includeTime, bool includeSeconds)
+{
+ char s[32];
+ ConvertFileTimeToString(ft, s, includeTime, includeSeconds);
+ return GetUnicodeString(s);
+}
+
+
+UString ConvertPropVariantToString(const PROPVARIANT &prop)
+{
+ switch (prop.vt)
+ {
+ case VT_EMPTY: return UString();
+ case VT_BSTR: return prop.bstrVal;
+ case VT_UI1: return ConvertUInt64ToString(prop.bVal);
+ case VT_UI2: return ConvertUInt64ToString(prop.uiVal);
+ case VT_UI4: return ConvertUInt64ToString(prop.ulVal);
+ case VT_UI8: return ConvertUInt64ToString(prop.uhVal.QuadPart);
+ case VT_FILETIME: return ConvertFileTimeToString(prop.filetime, true, true);
+ // case VT_I1: return ConvertInt64ToString(prop.cVal);
+ case VT_I2: return ConvertInt64ToString(prop.iVal);
+ case VT_I4: return ConvertInt64ToString(prop.lVal);
+ case VT_I8: return ConvertInt64ToString(prop.hVal.QuadPart);
+ case VT_BOOL: return VARIANT_BOOLToBool(prop.boolVal) ? L"+" : L"-";
+ default: throw 150245;
+ }
+}
+
+UInt64 ConvertPropVariantToUInt64(const PROPVARIANT &prop)
+{
+ switch (prop.vt)
+ {
+ case VT_UI1: return prop.bVal;
+ case VT_UI2: return prop.uiVal;
+ case VT_UI4: return prop.ulVal;
+ case VT_UI8: return (UInt64)prop.uhVal.QuadPart;
+ default: throw 151199;
+ }
+}
diff --git a/src/libs/7zip/unix/CPP/Windows/PropVariantConversions.h b/src/libs/7zip/unix/CPP/Windows/PropVariantConversions.h
new file mode 100644
index 000000000..3de4dedb3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/PropVariantConversions.h
@@ -0,0 +1,14 @@
+// Windows/PropVariantConversions.h
+
+#ifndef __PROP_VARIANT_CONVERSIONS_H
+#define __PROP_VARIANT_CONVERSIONS_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime = true, bool includeSeconds = true);
+UString ConvertFileTimeToString(const FILETIME &ft, bool includeTime = true, bool includeSeconds = true);
+UString ConvertPropVariantToString(const PROPVARIANT &prop);
+UInt64 ConvertPropVariantToUInt64(const PROPVARIANT &prop);
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/PropVariantUtils.cpp b/src/libs/7zip/unix/CPP/Windows/PropVariantUtils.cpp
new file mode 100644
index 000000000..0a9cfab7f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/PropVariantUtils.cpp
@@ -0,0 +1,78 @@
+// PropVariantUtils.cpp
+
+#include "StdAfx.h"
+
+#include "PropVariantUtils.h"
+#include "Common/StringConvert.h"
+#include "Common/IntToString.h"
+
+using namespace NWindows;
+
+static AString GetHex(UInt32 v)
+{
+ char sz[32] = { '0', 'x' };
+ ConvertUInt64ToString(v, sz + 2, 16);
+ return sz;
+}
+
+void StringToProp(const AString &s, NCOM::CPropVariant &prop)
+{
+ prop = MultiByteToUnicodeString(s);
+}
+
+void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NCOM::CPropVariant &prop)
+{
+ AString s;
+ for (unsigned i = 0; i < num; i++)
+ {
+ const CUInt32PCharPair &p = pairs[i];
+ if (p.Value == value)
+ s = p.Name;
+ }
+ if (s.IsEmpty())
+ s = GetHex(value);
+ StringToProp(s, prop);
+}
+
+AString TypeToString(const char *table[], unsigned num, UInt32 value)
+{
+ if (value < num)
+ return table[value];
+ return GetHex(value);
+}
+
+void TypeToProp(const char *table[], unsigned num, UInt32 value, NCOM::CPropVariant &prop)
+{
+ StringToProp(TypeToString(table, num, value), prop);
+}
+
+
+AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags)
+{
+ AString s;
+ for (unsigned i = 0; i < num; i++)
+ {
+ const CUInt32PCharPair &p = pairs[i];
+ UInt32 flag = (UInt32)1 << (unsigned)p.Value;
+ if ((flags & flag) != 0)
+ {
+ if (!s.IsEmpty())
+ s += ' ';
+ s += p.Name;
+ }
+ flags &= ~flag;
+ }
+ if (flags != 0)
+ {
+ if (!s.IsEmpty())
+ s += ' ';
+ s += GetHex(flags);
+ }
+ return s;
+}
+
+void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM::CPropVariant &prop)
+{
+ StringToProp(FlagsToString(pairs, num, flags), prop);
+}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/PropVariantUtils.h b/src/libs/7zip/unix/CPP/Windows/PropVariantUtils.h
new file mode 100644
index 000000000..5aaf65cb9
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/PropVariantUtils.h
@@ -0,0 +1,28 @@
+// Windows/PropVariantUtils.h
+
+#ifndef __PROP_VARIANT_UTILS_H
+#define __PROP_VARIANT_UTILS_H
+
+#include "Common/MyString.h"
+#include "PropVariant.h"
+
+struct CUInt32PCharPair
+{
+ UInt32 Value;
+ const char *Name;
+};
+
+void StringToProp(const AString &s, NWindows::NCOM::CPropVariant &prop);
+void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop);
+
+AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags);
+void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop);
+
+AString TypeToString(const char *table[], unsigned num, UInt32 value);
+void TypeToProp(const char *table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop);
+
+#define PAIR_TO_PROP(pairs, value, prop) PairToProp(pairs, sizeof(pairs) / sizeof(pairs[0]), value, prop)
+#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, sizeof(pairs) / sizeof(pairs[0]), value, prop)
+#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, sizeof(table) / sizeof(table[0]), value, prop)
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Registry.cpp b/src/libs/7zip/unix/CPP/Windows/Registry.cpp
new file mode 100644
index 000000000..74e255df4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Registry.cpp
@@ -0,0 +1,313 @@
+// Windows/Registry.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+#include "Windows/Registry.h"
+
+#include <wx/config.h>
+
+class HKEY_Impl
+{
+ public:
+ wxString path;
+ HKEY_Impl(wxString a) : path(a) {}
+};
+
+namespace NWindows {
+namespace NRegistry {
+
+#define ERROR_SET_VALUE (E_INVALIDARG) // FIXME
+#define ERROR_GET_VALUE (E_INVALIDARG) // FIXME
+#define PROGRAM_NAME L"p7zip"
+
+static wxConfig * g_config = 0;
+static int g_config_ref = 0;
+
+static void configAddRef() {
+ if (g_config == 0) {
+ g_config = new wxConfig(PROGRAM_NAME);
+ g_config->Flush(true);
+ wxConfigBase::Set(g_config);
+ }
+ g_config_ref++;
+}
+
+static void configSubRef() {
+ if (g_config_ref >= 1)
+ {
+ g_config_ref--;
+ if (g_config_ref == 0) {
+ delete g_config;
+ g_config = 0;
+ wxConfigBase::Set(NULL);
+ } else {
+ g_config->Flush(true);
+ }
+ }
+}
+
+ LONG CKey::Close()
+ {
+ if (_object)
+ {
+ configSubRef();
+ delete _object;
+ }
+ _object = 0;
+ return ERROR_SUCCESS;
+ }
+
+ LONG CKey::Create(HKEY parentKey, LPCTSTR keyName)
+ {
+ Close();
+
+ configAddRef();
+
+ wxString path;
+
+ if (parentKey == HKEY_CURRENT_USER) {
+ path=L"/" + wxString(keyName);
+ } else {
+ path = parentKey->path + L"/" + wxString(keyName);
+ }
+ _object = new HKEY_Impl(path);
+ return ERROR_SUCCESS;
+ }
+ LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask)
+ {
+ Close();
+
+ configAddRef();
+
+ wxString path;
+
+ if (parentKey == HKEY_CURRENT_USER) {
+ path=L"/" + wxString(keyName);
+ } else {
+ path = parentKey->path + L"/" + wxString(keyName);
+ }
+ _object = new HKEY_Impl(path);
+ return ERROR_SUCCESS;
+ }
+
+ LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName)
+ {
+ g_config->SetPath(_object->path);
+ bool ret = g_config->DeleteGroup(subKeyName);
+ if (ret) return ERROR_SUCCESS;
+ return ERROR_GET_VALUE;
+ }
+
+ LONG CKey::DeleteValue(LPCTSTR name)
+ {
+ g_config->SetPath(_object->path);
+ bool ret = g_config->DeleteEntry(name);
+ if (ret) return ERROR_SUCCESS;
+ return ERROR_GET_VALUE;
+ }
+
+ LONG CKey::QueryValue(LPCTSTR name, UInt32 &value)
+ {
+ g_config->SetPath(_object->path);
+ long val;
+ bool ret = g_config->Read(name,&val);
+ if (ret) {
+ value = (UInt32)val;
+ return ERROR_SUCCESS;
+ }
+ return ERROR_GET_VALUE;
+ }
+
+ LONG CKey::QueryValue(LPCTSTR name, bool &value)
+ {
+ g_config->SetPath(_object->path);
+ bool ret = g_config->Read(name,&value);
+ if (ret) return ERROR_SUCCESS;
+ return ERROR_GET_VALUE;
+ }
+
+ LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
+ {
+ g_config->SetPath(_object->path);
+ wxString val;
+ bool ret = g_config->Read(name,&val);
+ if (ret) {
+ value = val;
+ return ERROR_SUCCESS;
+ }
+ return ERROR_GET_VALUE;
+ }
+
+LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value)
+{
+ UInt32 newVal;
+ LONG res = QueryValue(name, newVal);
+ if (res == ERROR_SUCCESS)
+ value = newVal;
+ return res;
+}
+
+LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value)
+{
+ bool newVal;
+ LONG res = QueryValue(name, newVal);
+ if (res == ERROR_SUCCESS)
+ value = newVal;
+ return res;
+}
+
+
+ LONG CKey::SetValue(LPCTSTR valueName, UInt32 value)
+ {
+ g_config->SetPath(_object->path);
+ bool ret = g_config->Write(valueName,(long)value);
+ if (ret == true) return ERROR_SUCCESS;
+ return ERROR_SET_VALUE;
+ }
+ LONG CKey::SetValue(LPCTSTR valueName, bool value)
+ {
+ g_config->SetPath(_object->path);
+ bool ret = g_config->Write(valueName,value);
+ if (ret == true) return ERROR_SUCCESS;
+ return ERROR_SET_VALUE;
+ }
+ LONG CKey::SetValue(LPCTSTR valueName, LPCTSTR value)
+ {
+ g_config->SetPath(_object->path);
+ bool ret = g_config->Write(valueName,value);
+ if (ret == true) return ERROR_SUCCESS;
+ return ERROR_SET_VALUE;
+ }
+
+ LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size)
+ {
+ static char hexa[] = "0123456789ABCDEF";
+ /* FIXME
+ MYASSERT(value != NULL);
+ MYASSERT(_object != NULL);
+ return RegSetValueEx(_object, name, NULL, REG_BINARY, (const BYTE *)value, size);
+ */
+ BYTE *buf = (BYTE *)value;
+ wxString str;
+ for(UInt32 i=0;i<size;i++)
+ {
+ str += hexa[ (buf[i]>>4) & 0x0f];
+ str += hexa[ buf[i] & 0x0f];
+ }
+ return SetValue(name,(LPCTSTR)str);
+ }
+
+ LONG CKey::EnumKeys(CSysStringVector &keyNames)
+ {
+ g_config->SetPath(_object->path);
+ keyNames.Clear();
+ // enumeration variables
+ wxString str;
+ long dummy;
+ bool bCont = g_config->GetFirstEntry(str, dummy);
+ while ( bCont ) {
+ keyNames.Add((const TCHAR *)str);
+ bCont = g_config->GetNextEntry(str, dummy);
+ }
+
+ // now all groups...
+ bCont = g_config->GetFirstGroup(str, dummy);
+ while ( bCont ) {
+ keyNames.Add((const TCHAR *)str);
+ bCont = g_config->GetNextGroup(str, dummy);
+ }
+ return ERROR_SUCCESS;
+ }
+
+ LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &dataSize)
+ {
+ g_config->SetPath(_object->path);
+ wxString str;
+ bool ret = g_config->Read(name,&str);
+ if (ret == false) return ERROR_GET_VALUE;
+
+ size_t l = str.Len() / 2;
+ if (l > dataSize) l = dataSize;
+ else dataSize=l;
+
+ BYTE *buf = (BYTE *)value;
+ for(UInt32 i=0;i<dataSize;i++)
+ {
+ char cval[3];
+ cval[0] = (char)str[2*i];
+ cval[1] = (char)str[2*i+1];
+ cval[2] = 0;
+ unsigned uval = 0;
+ sscanf(cval,"%x",&uval);
+ buf[i]=(BYTE)uval;
+ }
+
+ return ERROR_SUCCESS;
+ }
+
+
+ LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize)
+ {
+ g_config->SetPath(_object->path);
+ wxString str;
+ bool ret = g_config->Read(name,&str);
+ if (ret == false) return ERROR_GET_VALUE;
+
+ dataSize = str.Len() / 2;
+ value.SetCapacity(dataSize);
+ return QueryValue(name, (BYTE *)value, dataSize);
+ }
+
+
+LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
+{
+ UInt32 numChars = 0;
+ int i;
+ for (i = 0; i < strings.Size(); i++)
+ numChars += strings[i].Length() + 1;
+ CBuffer<wchar_t> buffer;
+ buffer.SetCapacity(numChars);
+ int pos = 0;
+ for (i = 0; i < strings.Size(); i++)
+ {
+ const UString &s = strings[i];
+ MyStringCopy((wchar_t *)buffer + pos, (const wchar_t *)s);
+ pos += s.Length() + 1;
+ }
+ return SetValue(valueName, buffer, numChars * sizeof(wchar_t));
+}
+
+LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
+{
+ strings.Clear();
+ CByteBuffer buffer;
+ UInt32 dataSize;
+ LONG res = QueryValue(valueName, buffer, dataSize);
+ if (res != ERROR_SUCCESS)
+ return res;
+ if (dataSize % sizeof(wchar_t) != 0)
+ return E_FAIL;
+ const wchar_t *data = (const wchar_t *)(const Byte *)buffer;
+ int numChars = dataSize / sizeof(wchar_t);
+ UString s;
+ for (int i = 0; i < numChars; i++)
+ {
+ wchar_t c = data[i];
+ if (c == 0)
+ {
+ strings.Add(s);
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ return res;
+}
+
+
+}
+}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Registry.h b/src/libs/7zip/unix/CPP/Windows/Registry.h
new file mode 100644
index 000000000..a9078751f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Registry.h
@@ -0,0 +1,113 @@
+// Windows/Registry.h
+
+#ifndef __WINDOWS_REGISTRY_H
+#define __WINDOWS_REGISTRY_H
+
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+#ifndef _WIN32
+class HKEY_Impl;
+
+typedef HKEY_Impl * HKEY;
+
+/*
+#define HKEY_CLASSES_ROOT ((HKEY) 0x80000000)
+#define HKEY_LOCAL_MACHINE ((HKEY) 0x80000002)
+#define HKEY_USERS ((HKEY) 0x80000003)
+#define HKEY_PERFORMANCE_DATA ((HKEY) 0x80000004)
+#define HKEY_CURRENT_CONFIG ((HKEY) 0x80000005)
+#define HKEY_DYN_DATA ((HKEY) 0x80000006)
+*/
+#define HKEY_CURRENT_USER ((HKEY) 0x80000001)
+
+
+typedef DWORD REGSAM;
+#define ERROR_SUCCESS (0)
+#define KEY_READ (0x1234) // FIXME
+#define KEY_ALL_ACCESS (~0) // FIXME
+
+/* ------------------------------ end registry ------------------------------ */
+
+#endif
+
+namespace NWindows {
+namespace NRegistry {
+
+const TCHAR kKeyNameDelimiter = TEXT(CHAR_PATH_SEPARATOR);
+
+// LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value);
+
+class CKey
+{
+ HKEY _object;
+public:
+ CKey(): _object(NULL) {}
+ ~CKey() { Close(); }
+
+ operator HKEY() const { return _object; }
+
+ #if 0
+ HKEY Detach();
+ void Attach(HKEY key);
+ LONG Create(HKEY parentKey, LPCTSTR keyName,
+ LPTSTR keyClass = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,
+ REGSAM accessMask = KEY_ALL_ACCESS,
+ LPSECURITY_ATTRIBUTES securityAttributes = NULL,
+ LPDWORD disposition = NULL);
+ LONG Open(HKEY parentKey, LPCTSTR keyName,
+ REGSAM accessMask = KEY_ALL_ACCESS);
+#endif // #if 0
+ LONG Create(HKEY parentKey, LPCTSTR keyName);
+ LONG Open(HKEY parentKey, LPCTSTR keyName,
+ REGSAM accessMask = KEY_ALL_ACCESS);
+
+ LONG Close();
+
+ LONG DeleteSubKey(LPCTSTR subKeyName);
+ LONG RecurseDeleteKey(LPCTSTR subKeyName);
+
+ LONG DeleteValue(LPCTSTR name);
+ #ifndef _UNICODE
+ LONG DeleteValue(LPCWSTR name);
+ #endif
+
+ LONG SetValue(LPCTSTR valueName, UInt32 value);
+ LONG SetValue(LPCTSTR valueName, bool value);
+ LONG SetValue(LPCTSTR valueName, LPCTSTR value);
+ // LONG SetValue(LPCTSTR valueName, const CSysString &value);
+ #ifndef _UNICODE
+ LONG SetValue(LPCWSTR name, LPCWSTR value);
+ // LONG SetValue(LPCWSTR name, const UString &value);
+ #endif
+
+ LONG SetValue(LPCTSTR name, const void *value, UInt32 size);
+
+ LONG SetValue_Strings(LPCTSTR valueName, const UStringVector &strings);
+ LONG GetValue_Strings(LPCTSTR valueName, UStringVector &strings);
+
+ LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value);
+
+ LONG QueryValue(LPCTSTR name, UInt32 &value);
+ LONG QueryValue(LPCTSTR name, bool &value);
+ LONG QueryValue(LPCTSTR name, LPTSTR value, UInt32 &dataSize);
+ LONG QueryValue(LPCTSTR name, CSysString &value);
+
+ LONG GetValue_IfOk(LPCTSTR name, UInt32 &value);
+ LONG GetValue_IfOk(LPCTSTR name, bool &value);
+
+ #ifndef _UNICODE
+ LONG QueryValue(LPCWSTR name, LPWSTR value, UInt32 &dataSize);
+ LONG QueryValue(LPCWSTR name, UString &value);
+ #endif
+
+ LONG QueryValue(LPCTSTR name, void *value, UInt32 &dataSize);
+ LONG QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize);
+
+ LONG EnumKeys(CSysStringVector &keyNames);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/ResourceString.h b/src/libs/7zip/unix/CPP/Windows/ResourceString.h
new file mode 100644
index 000000000..ac9c5cd5d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/ResourceString.h
@@ -0,0 +1,22 @@
+// Windows/ResourceString.h
+
+#ifndef __WINDOWS_RESOURCESTRING_H
+#define __WINDOWS_RESOURCESTRING_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+
+CSysString MyLoadString(HINSTANCE hInstance, UINT resourceID);
+CSysString MyLoadString(UINT resourceID);
+#ifdef _UNICODE
+inline UString MyLoadStringW(HINSTANCE hInstance, UINT resourceID) { return MyLoadString(hInstance, resourceID); }
+inline UString MyLoadStringW(UINT resourceID) { return MyLoadString(resourceID); }
+#else
+UString MyLoadStringW(HINSTANCE hInstance, UINT resourceID);
+UString MyLoadStringW(UINT resourceID);
+#endif
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Shell.h b/src/libs/7zip/unix/CPP/Windows/Shell.h
new file mode 100644
index 000000000..f116b772b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Shell.h
@@ -0,0 +1,21 @@
+// Windows/Shell.h
+
+#ifndef __WINDOWS_SHELL_H
+#define __WINDOWS_SHELL_H
+
+#include <windows.h>
+// #include <shlobj.h>
+
+#include "Common/MyString.h"
+#include "Windows/Defs.h"
+
+
+namespace NWindows{
+namespace NShell{
+
+bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath);
+
+}}
+
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Synchronization.cpp b/src/libs/7zip/unix/CPP/Windows/Synchronization.cpp
new file mode 100644
index 000000000..8130f9ac3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Synchronization.cpp
@@ -0,0 +1,157 @@
+// Windows/Synchronization.cpp
+
+#include "StdAfx.h"
+
+#include "Synchronization.h"
+
+// #define TRACEN(u) u;
+#define TRACEN(u) /* */
+
+#define MAGIC 0x1234CAFE
+class CSynchroTest
+{
+ int _magic;
+ public:
+ CSynchroTest() {
+ _magic = MAGIC;
+ }
+ void testConstructor() {
+ if (_magic != MAGIC) {
+ printf("ERROR : no constructors called during loading of plugins (please look at LINK_SHARED in makefile.machine)\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+};
+
+static CSynchroTest gbl_synchroTest;
+
+extern "C" void sync_TestConstructor(void) {
+ gbl_synchroTest.testConstructor();
+}
+
+
+namespace NWindows {
+namespace NSynchronization {
+
+
+#ifndef ENV_BEOS
+#ifdef DEBUG_SYNCHRO
+ void CSynchro::dump_error(int ligne,int ret,const char *text,void *param)
+ {
+ printf("\n##T%d#ERROR2 (l=%d) %s : param=%p ret = %d (%s)##\n",(int)pthread_self(),ligne,text,param,ret,strerror(ret));
+ // abort();
+ }
+ CSynchro::CSynchro() {
+ TRACEN((printf("\nT%d : E1-CSynchro(this=%p,m=%p,cond=%p)\n",(int)pthread_self(),(void *)this,(void *)&_object,(void *)&_cond)))
+ _isValid = false;
+ }
+
+ void CSynchro::Create() {
+ TRACEN((printf("\nT%d : E1-CSynchro::Create(this=%p,m=%p,cond=%p)\n",(int)pthread_self(),(void *)this,(void *)&_object,(void *)&_cond)))
+ pthread_mutexattr_t mutexattr;
+ memset(&mutexattr,0,sizeof(mutexattr));
+ int ret = pthread_mutexattr_init(&mutexattr);
+ if (ret != 0) {
+ dump_error(__LINE__,ret,"pthread_mutexattr_init",&mutexattr);
+ }
+ ret = pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK);
+ if (ret != 0) dump_error(__LINE__,ret,"pthread_mutexattr_settype",&mutexattr);
+ ret = ::pthread_mutex_init(&_object,&mutexattr);
+ if (ret != 0) dump_error(__LINE__,ret,"pthread_mutex_init",&_object);
+ ret = ::pthread_cond_init(&_cond,0);
+ if (ret != 0) dump_error(__LINE__,ret,"pthread_cond_init",&_cond);
+ TRACEN((printf("\nT%d : E2-CSynchro::Create(m=%p,cond=%p)\n",(int)pthread_self(),(void *)&_object,(void *)&_cond)))
+ }
+ CSynchro::~CSynchro() {
+ TRACEN((printf("\nT%d : E1-~CSynchro(this=%p,m=%p,cond=%p)\n",(int)pthread_self(),(void *)this,(void *)&_object,(void *)&_cond)))
+ if (_isValid) {
+ int ret = ::pthread_mutex_destroy(&_object);
+ if (ret != 0) dump_error(__LINE__,ret,"pthread_mutex_destroy",&_object);
+ ret = ::pthread_cond_destroy(&_cond);
+ if (ret != 0) dump_error(__LINE__,ret,"pthread_cond_destroy",&_cond);
+ TRACEN((printf("\nT%d : E2-~CSynchro(m=%p,cond=%p)\n",(int)pthread_self(),(void *)&_object,(void *)&_cond)))
+ }
+ _isValid = false;
+ }
+ void CSynchro::Enter() {
+ TRACEN((printf("\nT%d : E1-CSynchro::Enter(%p)\n",(int)pthread_self(),(void *)&_object)))
+ int ret = ::pthread_mutex_lock(&_object);
+ if (ret != 0) {
+ dump_error(__LINE__,ret,"CSynchro::Enter-pthread_mutex_lock",&_object);
+ }
+ TRACEN((printf("\nT%d : E2-CSynchro::Enter(%p)\n",(int)pthread_self(),(void *)&_object)))
+ }
+ void CSynchro::Leave() {
+ TRACEN((printf("\nT%d : E1-CSynchro::Leave(%p)\n",(int)pthread_self(),(void *)&_object)))
+ int ret = ::pthread_mutex_unlock(&_object);
+ if (ret != 0) dump_error(__LINE__,ret,"Leave::pthread_mutex_unlock",&_object);
+ TRACEN((printf("\nT%d : E2-CSynchro::Leave(%p)\n",(int)pthread_self(),(void *)&_object)))
+ }
+ void CSynchro::WaitCond() {
+ TRACEN((printf("\nT%d : E1-CSynchro::WaitCond(%p,%p)\n",(int)pthread_self(),(void *)&_cond,(void *)&_object)))
+ int ret = ::pthread_cond_wait(&_cond, &_object);
+ if (ret != 0) dump_error(__LINE__,ret,"pthread_cond_wait",&_cond);
+ TRACEN((printf("\nT%d : E2-CSynchro::WaitCond(%p,%p)\n",(int)pthread_self(),(void *)&_cond,(void *)&_object)))
+ }
+ void CSynchro::LeaveAndSignal() {
+ TRACEN((printf("\nT%d : E1-CSynchro::LeaveAndSignal(%p)\n",(int)pthread_self(),(void *)&_cond)))
+ int ret = ::pthread_cond_broadcast(&_cond);
+ if (ret != 0) dump_error(__LINE__,ret,"pthread_cond_broadcast",&_cond);
+ TRACEN((printf("\nT%d : E2-CSynchro::LeaveAndSignal(%p)\n",(int)pthread_self(),(void *)&_object)))
+ ret = ::pthread_mutex_unlock(&_object);
+ if (ret != 0) dump_error(__LINE__,ret,"LeaveAndSignal::pthread_mutex_unlock",&_object);
+ TRACEN((printf("\nT%d : E3-CSynchro::LeaveAndSignal(%p)\n",(int)pthread_self(),(void *)&_cond)))
+ }
+#endif
+#endif
+
+}}
+
+DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout )
+{
+ TRACEN((printf("\nT%d : E1-WaitForMultipleObjects(%d)\n",(int)pthread_self(),(int)count)))
+ if (wait_all != FALSE) {
+ printf("\n\n INTERNAL ERROR - WaitForMultipleObjects(...) wait_all(%d) != FALSE\n\n",(unsigned)wait_all);
+ abort();
+ }
+
+ if (timeout != INFINITE) {
+ printf("\n\n INTERNAL ERROR - WaitForMultipleObjects(...) timeout(%u) != INFINITE\n\n",(unsigned)timeout);
+ abort();
+ }
+
+ if (count < 1) {
+ printf("\n\n INTERNAL ERROR - WaitForMultipleObjects(...) count(%u) < 1\n\n",(unsigned)count);
+ abort();
+ }
+
+ NWindows::NSynchronization::CSynchro *synchro = handles[0]->_sync;
+
+ TRACEN((printf("\nT%d : E2-WaitForMultipleObjects(%d)\n",(int)pthread_self(),(int)count)))
+ synchro->Enter();
+ TRACEN((printf("\nT%d : E3-WaitForMultipleObjects(%d)\n",(int)pthread_self(),(int)count)))
+
+#ifdef DEBUG_SYNCHRO
+ for(DWORD i=1;i<count;i++) {
+ if (synchro != handles[i]->_sync) {
+ printf("\n\n INTERNAL ERROR - WaitForMultipleObjects(...) synchro(%p) != handles[%d]->_sync(%p)\n\n",
+ synchro,(unsigned)i,handles[i]->_sync);
+ abort();
+ }
+ }
+#endif
+
+ while(1) {
+ for(DWORD i=0;i<count;i++) {
+ if (handles[i]->IsSignaledAndUpdate()) {
+ synchro->Leave();
+ TRACEN((printf("\nT%d : E4-WaitForMultipleObjects(%d)\n",(int)pthread_self(),(int)count)))
+ return WAIT_OBJECT_0+i;
+ }
+ }
+ synchro->WaitCond();
+ }
+ synchro->Leave();
+ return ETIMEDOUT; // WAIT_TIMEOUT;
+}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Synchronization.h b/src/libs/7zip/unix/CPP/Windows/Synchronization.h
new file mode 100644
index 000000000..df3c693a7
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Synchronization.h
@@ -0,0 +1,187 @@
+// Windows/Synchronization.h
+
+#ifndef __WINDOWS_SYNCHRONIZATION_H
+#define __WINDOWS_SYNCHRONIZATION_H
+
+#include "Defs.h"
+
+extern "C"
+{
+#include "../../C/Threads.h"
+}
+
+#ifdef _WIN32
+#include "Handle.h"
+#endif
+
+namespace NWindows {
+namespace NSynchronization {
+
+class Uncopyable {
+protected:
+ Uncopyable() {} // allow construction
+ ~Uncopyable() {} // and destruction of derived objects...
+private:
+ Uncopyable(const Uncopyable&); // ...but prevent copying
+ Uncopyable& operator=(const Uncopyable&);
+};
+
+
+class CBaseEvent // FIXME : private Uncopyable
+{
+protected:
+ ::CEvent _object;
+public:
+ bool IsCreated() { return Event_IsCreated(&_object) != 0; }
+#ifdef _WIN32
+ operator HANDLE() { return _object.handle; }
+#endif
+ CBaseEvent() { Event_Construct(&_object); }
+ ~CBaseEvent() { Close(); }
+ WRes Close() { return Event_Close(&_object); }
+ #ifdef _WIN32
+ WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL,
+ LPSECURITY_ATTRIBUTES securityAttributes = NULL)
+ {
+ _object.handle = ::CreateEvent(securityAttributes, BoolToBOOL(manualReset),
+ BoolToBOOL(initiallyOwn), name);
+ if (_object.handle != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+ {
+ _object.handle = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);
+ if (_object.handle != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ #endif
+
+ WRes Set() { return Event_Set(&_object); }
+ // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); }
+ WRes Reset() { return Event_Reset(&_object); }
+ WRes Lock() { return Event_Wait(&_object); }
+};
+
+class CManualResetEvent: public CBaseEvent
+{
+public:
+ WRes Create(bool initiallyOwn = false)
+ {
+ return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0);
+ }
+ WRes CreateIfNotCreated()
+ {
+ if (IsCreated())
+ return 0;
+ return ManualResetEvent_CreateNotSignaled(&_object);
+ }
+ #ifdef _WIN32
+ WRes CreateWithName(bool initiallyOwn, LPCTSTR name)
+ {
+ return CBaseEvent::Create(true, initiallyOwn, name);
+ }
+ #endif
+};
+
+class CAutoResetEvent: public CBaseEvent
+{
+public:
+ WRes Create()
+ {
+ return AutoResetEvent_CreateNotSignaled(&_object);
+ }
+ WRes CreateIfNotCreated()
+ {
+ if (IsCreated())
+ return 0;
+ return AutoResetEvent_CreateNotSignaled(&_object);
+ }
+};
+
+#ifdef _WIN32
+class CObject: public CHandle
+{
+public:
+ WRes Lock(DWORD timeoutInterval = INFINITE)
+ { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); }
+};
+class CMutex: public CObject
+{
+public:
+ WRes Create(bool initiallyOwn, LPCTSTR name = NULL,
+ LPSECURITY_ATTRIBUTES securityAttributes = NULL)
+ {
+ _handle = ::CreateMutex(securityAttributes, BoolToBOOL(initiallyOwn), name);
+ if (_handle != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+ {
+ _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name);
+ if (_handle != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ WRes Release()
+ {
+ return ::ReleaseMutex(_handle) ? 0 : ::GetLastError();
+ }
+};
+class CMutexLock
+{
+ CMutex *_object;
+public:
+ CMutexLock(CMutex &object): _object(&object) { _object->Lock(); }
+ ~CMutexLock() { _object->Release(); }
+};
+#endif
+
+class CSemaphore : private Uncopyable
+{
+ ::CSemaphore _object;
+public:
+ CSemaphore() { Semaphore_Construct(&_object); }
+ ~CSemaphore() { Close(); }
+ WRes Close() { return Semaphore_Close(&_object); }
+#ifdef _WIN32
+ operator HANDLE() { return _object.handle; }
+#endif
+ WRes Create(UInt32 initiallyCount, UInt32 maxCount)
+ {
+ return Semaphore_Create(&_object, initiallyCount, maxCount);
+ }
+ WRes Release() { return Semaphore_Release1(&_object); }
+ WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }
+ WRes Lock() { return Semaphore_Wait(&_object); }
+};
+
+class CCriticalSection : private Uncopyable
+{
+ ::CCriticalSection _object;
+public:
+ CCriticalSection() { CriticalSection_Init(&_object); }
+ ~CCriticalSection() { CriticalSection_Delete(&_object); }
+ void Enter() { CriticalSection_Enter(&_object); }
+ void Leave() { CriticalSection_Leave(&_object); }
+};
+
+class CCriticalSectionLock : private Uncopyable
+{
+ CCriticalSection *_object;
+ void Unlock() { _object->Leave(); }
+public:
+ CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }
+ ~CCriticalSectionLock() { Unlock(); }
+};
+
+}}
+
+#ifndef _WIN32
+#include "Synchronization2.h"
+#endif
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Synchronization2.h b/src/libs/7zip/unix/CPP/Windows/Synchronization2.h
new file mode 100644
index 000000000..d86b49dee
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Synchronization2.h
@@ -0,0 +1,218 @@
+// Windows/Synchronization.h
+
+#ifdef ENV_BEOS
+#include <Locker.h>
+#include <kernel/OS.h>
+#include <list>
+#endif
+
+/* Remark : WFMO = WaitForMultipleObjects */
+
+namespace NWindows { namespace NSynchronization { struct CBaseHandleWFMO; } }
+
+typedef NWindows::NSynchronization::CBaseHandleWFMO *HANDLE;
+
+DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout );
+
+namespace NWindows {
+namespace NSynchronization {
+
+#ifdef ENV_BEOS
+class CSynchro : BLocker, private Uncopyable
+{
+#define MAX_THREAD 256
+ thread_id _waiting[MAX_THREAD]; // std::list<thread_id> _waiting;
+ int index_waiting;
+public:
+ CSynchro() { index_waiting = 0; }
+ void Create() { index_waiting = 0; }
+ ~CSynchro() {}
+ void Enter() { Lock(); }
+ void Leave() { Unlock(); }
+ void WaitCond() {
+ _waiting[index_waiting++] = find_thread(NULL); // _waiting.push_back(find_thread(NULL));
+ thread_id sender;
+ Unlock();
+ int msg = receive_data(&sender, NULL, 0);
+ Lock();
+ }
+ void LeaveAndSignal() {
+ // Unlock();
+ // Lock();
+ // for (std::list<thread_id>::iterator index = _waiting.begin(); index != _waiting.end(); index++)
+ for(int index = 0 ; index < index_waiting ; index++)
+ {
+ send_data(_waiting[index], '7zCN', NULL, 0);
+ }
+ index_waiting = 0; // _waiting.clear();
+ Unlock();
+ }
+};
+#else // #ifdef ENV_BEOS
+#ifdef DEBUG_SYNCHRO
+class CSynchro: private Uncopyable
+{
+ pthread_mutex_t _object;
+ pthread_cond_t _cond;
+ bool _isValid;
+ void dump_error(int ligne,int ret,const char *text,void *param);
+public:
+ CSynchro();
+ ~CSynchro();
+ void Create();
+ void Enter();
+ void Leave();
+ void WaitCond();
+ void LeaveAndSignal();
+};
+#else // #ifdef DEBUG_SYNCHRO
+class CSynchro : private Uncopyable
+{
+ pthread_mutex_t _object;
+ pthread_cond_t _cond;
+ bool _isValid;
+public:
+ CSynchro() { _isValid = false; }
+ ~CSynchro() {
+ if (_isValid) {
+ ::pthread_mutex_destroy(&_object);
+ ::pthread_cond_destroy(&_cond);
+ }
+ _isValid = false;
+ }
+ void Create() {
+ ::pthread_mutex_init(&_object,0);
+ ::pthread_cond_init(&_cond,0);
+ }
+ void Enter() {
+ ::pthread_mutex_lock(&_object);
+ }
+ void Leave() {
+ ::pthread_mutex_unlock(&_object);
+ }
+ void WaitCond() {
+ ::pthread_cond_wait(&_cond, &_object);
+ }
+ void LeaveAndSignal() {
+ ::pthread_cond_broadcast(&_cond);
+ ::pthread_mutex_unlock(&_object);
+ }
+};
+#endif // #ifdef DEBUG_SYNCHRO
+#endif // #ifdef ENV_BEOS
+
+struct CBaseHandleWFMO // FIXME : private Uncopyable
+{
+ CSynchro *_sync;
+
+ CBaseHandleWFMO() { }
+
+ operator HANDLE() { return this; }
+ virtual bool IsSignaledAndUpdate() = 0;
+};
+
+class CBaseEventWFMO : public CBaseHandleWFMO
+{
+ bool _manual_reset;
+ bool _state;
+
+public:
+
+ bool IsCreated() { return (this->_sync != 0); }
+ CBaseEventWFMO() { this->_sync = 0; }
+ ~CBaseEventWFMO() { Close(); }
+
+ WRes Close() { this->_sync = 0; return S_OK; }
+
+ WRes Create(CSynchro *sync,bool manualReset, bool initiallyOwn)
+ {
+ this->_sync = sync;
+ this->_manual_reset = manualReset;
+ this->_state = initiallyOwn;
+ return S_OK;
+ }
+
+ WRes Set() {
+ this->_sync->Enter();
+ this->_state = true;
+ this->_sync->LeaveAndSignal();
+ return S_OK;
+ }
+
+ WRes Reset() {
+ this->_sync->Enter();
+ this->_state = false;
+ this->_sync->Leave();
+ return S_OK;
+ }
+ virtual bool IsSignaledAndUpdate() {
+ if (this->_state == true) {
+ if (this->_manual_reset == false) this->_state = false;
+ return true;
+ }
+ return false;
+ }
+};
+
+class CManualResetEventWFMO: public CBaseEventWFMO
+{
+public:
+ WRes Create(CSynchro *sync,bool initiallyOwn = false) { return CBaseEventWFMO::Create(sync,true, initiallyOwn); }
+};
+
+class CAutoResetEventWFMO: public CBaseEventWFMO
+{
+public:
+ WRes Create(CSynchro *sync) { return CBaseEventWFMO::Create(sync,false, false); }
+ WRes CreateIfNotCreated(CSynchro *sync)
+ {
+ if (IsCreated())
+ return 0;
+ return CBaseEventWFMO::Create(sync,false, false);
+ }
+};
+
+class CSemaphoreWFMO : public CBaseHandleWFMO
+{
+ LONG _count;
+ LONG _maxCount;
+
+public:
+ CSemaphoreWFMO() : _count(0), _maxCount(0) { this->_sync=0;}
+ WRes Create(CSynchro *sync,LONG initiallyCount, LONG maxCount)
+ {
+ if ((initiallyCount < 0) || (initiallyCount > maxCount) || (maxCount < 1)) return S_FALSE;
+ this->_sync = sync;
+ this->_count = initiallyCount;
+ this->_maxCount = maxCount;
+ return S_OK;
+ }
+ WRes Release(LONG releaseCount = 1) {
+ if (releaseCount < 1) return S_FALSE;
+
+ this->_sync->Enter();
+ LONG newCount = this->_count + releaseCount;
+ if (newCount > this->_maxCount)
+ {
+ this->_sync->Leave();
+ return S_FALSE;
+ }
+ this->_count = newCount;
+
+ this->_sync->LeaveAndSignal();
+
+ return S_OK;
+ }
+ WRes Close() { this->_sync=0; return S_OK; }
+
+ virtual bool IsSignaledAndUpdate() {
+ if (this->_count > 0) {
+ this->_count--;
+ return true;
+ }
+ return false;
+ }
+};
+
+}}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/System.cpp b/src/libs/7zip/unix/CPP/Windows/System.cpp
new file mode 100644
index 000000000..b63ebec79
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/System.cpp
@@ -0,0 +1,166 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined (__NetBSD__) || defined(__OpenBSD__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#elif defined(__linux__) || defined(__CYGWIN__) || defined(sun) || defined(__NETWARE__)
+#include <unistd.h>
+#elif defined(hpux) || defined(__hpux)
+#include <sys/param.h>
+#include <sys/pstat.h>
+#endif
+
+#if defined(__NETWARE__)
+#include <sys/sysinfo.h>
+#endif
+
+#if defined(ENV_BEOS)
+#include <be/kernel/OS.h>
+#endif
+
+
+#include "Common/Types.h"
+
+namespace NWindows
+{
+ namespace NSystem
+ {
+ /************************ GetNumberOfProcessors ************************/
+
+ #if defined (__NetBSD__) || defined(__OpenBSD__)
+ UInt32 GetNumberOfProcessors() {
+ int mib[2], value;
+ int nbcpu = 1;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ size_t len = sizeof(size_t);
+ if (sysctl(mib, 2, &value, &len, NULL, 0) >= 0)
+ if (value > nbcpu)
+ nbcpu = value;
+ return nbcpu;
+ }
+ #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+ UInt32 GetNumberOfProcessors() {
+ int nbcpu = 1;
+ size_t value;
+ size_t len = sizeof(value);
+ if (sysctlbyname("hw.ncpu", &value, &len, NULL, 0) == 0)
+ nbcpu = value;
+ return nbcpu;
+ }
+ #elif defined (__APPLE__)
+ UInt32 GetNumberOfProcessors() {
+ int nbcpu = 1,value;
+ size_t valSize = sizeof(value);
+ if (sysctlbyname ("hw.ncpu", &value, &valSize, NULL, 0) == 0)
+ nbcpu = value;
+ return nbcpu;
+ }
+
+ #elif defined(__linux__) || defined(__CYGWIN__) || defined(sun)
+ UInt32 GetNumberOfProcessors() {
+ int nbcpu = sysconf (_SC_NPROCESSORS_CONF);
+ if (nbcpu < 1) nbcpu = 1;
+ return nbcpu;
+ }
+ #elif defined(hpux) || defined(__hpux)
+ UInt32 GetNumberOfProcessors() {
+ struct pst_dynamic psd;
+ if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1)
+ return (UInt32)psd.psd_proc_cnt;
+ return 1;
+ }
+ #elif defined(__NETWARE__)
+ UInt32 GetNumberOfProcessors() {
+ // int nbcpu = get_nprocs_conf();
+ int nbcpu = get_nprocs();
+ if (nbcpu < 1) nbcpu = 1;
+ return nbcpu;
+ }
+ #elif defined(ENV_BEOS)
+ UInt32 GetNumberOfProcessors() {
+ system_info info;
+ get_system_info(&info);
+ int nbcpu = info.cpu_count;
+ if (nbcpu < 1) nbcpu = 1;
+ return nbcpu;
+ }
+ #else
+ #warning Generic GetNumberOfProcessors
+ UInt32 GetNumberOfProcessors() {
+ return 1;
+ }
+ #endif
+
+ /************************ GetRamSize ************************/
+ UInt64 GetRamSize() {
+ UInt64 ullTotalPhys = 128 * 1024 * 1024; // default : 128MB
+
+#ifdef linux
+ FILE * f = fopen( "/proc/meminfo", "r" );
+ if (f)
+ {
+ char buffer[256];
+ unsigned long total;
+
+ ullTotalPhys = 0;
+
+ while (fgets( buffer, sizeof(buffer), f ))
+ {
+ /* old style /proc/meminfo ... */
+ if (sscanf( buffer, "Mem: %lu", &total))
+ {
+ ullTotalPhys += total;
+ }
+
+ /* new style /proc/meminfo ... */
+ if (sscanf(buffer, "MemTotal: %lu", &total))
+ ullTotalPhys = ((UInt64)total)*1024;
+ }
+ fclose( f );
+ }
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__APPLE__)
+#ifdef HW_MEMSIZE
+ uint64_t val = 0; // support 2Gb+ RAM
+ int mib[2] = { CTL_HW, HW_MEMSIZE };
+#else // HW_MEMSIZE
+ unsigned int val = 0; // For old system
+ int mib[2] = { CTL_HW, HW_PHYSMEM };
+#endif // HW_MEMSIZE
+ size_t size_sys = sizeof(val);
+
+ sysctl(mib, 2, &val, &size_sys, NULL, 0);
+ if (val) ullTotalPhys = val;
+#elif defined(__CYGWIN__)
+ unsigned long pagesize=4096; // FIXME - sysconf(_SC_PAGESIZE) returns 65536 !?
+ // see http://readlist.com/lists/cygwin.com/cygwin/0/3313.html
+ unsigned long maxpages=sysconf(_SC_PHYS_PAGES);
+ ullTotalPhys = ((UInt64)pagesize)*maxpages;
+#elif defined ( sun ) || defined(__NETWARE__)
+ unsigned long pagesize=sysconf(_SC_PAGESIZE);
+ unsigned long maxpages=sysconf(_SC_PHYS_PAGES);
+ ullTotalPhys = ((UInt64)pagesize)*maxpages;
+#elif defined(hpux) || defined(__hpux)
+ struct pst_static pst;
+ union pstun pu;
+
+ pu.pst_static = &pst;
+ if ( pstat( PSTAT_STATIC, pu, (size_t)sizeof(pst), (size_t)0, 0 ) != -1 ) {
+ ullTotalPhys = ((UInt64)pst.physical_memory)*pst.page_size;
+ }
+#elif defined(ENV_BEOS)
+ system_info info;
+ get_system_info(&info);
+ ullTotalPhys = info.max_pages;
+ ullTotalPhys *= 4096;
+#else
+#warning Generic GetRamSize
+#endif
+ return ullTotalPhys;
+ }
+
+ }
+}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/System.h b/src/libs/7zip/unix/CPP/Windows/System.h
new file mode 100644
index 000000000..e0067158f
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/System.h
@@ -0,0 +1,16 @@
+// Windows/System.h
+
+#ifndef __WINDOWS_SYSTEM_H
+#define __WINDOWS_SYSTEM_H
+
+#include "../Common/Types.h"
+
+namespace NWindows {
+namespace NSystem {
+
+UInt32 GetNumberOfProcessors();
+UInt64 GetRamSize();
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Thread.h b/src/libs/7zip/unix/CPP/Windows/Thread.h
new file mode 100644
index 000000000..ed72507f4
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Thread.h
@@ -0,0 +1,41 @@
+// Windows/Thread.h
+
+#ifndef __WINDOWS_THREAD_H
+#define __WINDOWS_THREAD_H
+
+#include "Defs.h"
+
+extern "C"
+{
+#include "../../C/Threads.h"
+}
+
+namespace NWindows {
+
+class CThread
+{
+ ::CThread thread;
+public:
+ CThread() { Thread_Construct(&thread); }
+ ~CThread() { Close(); }
+ bool IsCreated() { return Thread_WasCreated(&thread) != 0; }
+ WRes Close() { return Thread_Close(&thread); }
+ WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
+ { return Thread_Create(&thread, startAddress, parameter); }
+ WRes Wait() { return Thread_Wait(&thread); }
+
+ #ifdef _WIN32
+ operator HANDLE() { return thread; }
+ void Attach(HANDLE handle) { thread = handle; }
+ HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; }
+ DWORD Resume() { return ::ResumeThread(thread); }
+ DWORD Suspend() { return ::SuspendThread(thread); }
+ bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); }
+ int GetPriority() { return ::GetThreadPriority(thread); }
+ bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); }
+ #endif
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Time.cpp b/src/libs/7zip/unix/CPP/Windows/Time.cpp
new file mode 100644
index 000000000..dfa0938b5
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Time.cpp
@@ -0,0 +1,88 @@
+// Windows/Time.cpp
+
+#include "StdAfx.h"
+
+#include "Time.h"
+#include "Windows/Defs.h"
+
+namespace NWindows {
+namespace NTime {
+
+static const UInt32 kFileTimeStartYear = 1601;
+
+bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime)
+{
+ return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &fileTime));
+}
+
+static const UInt32 kHighDosTime = 0xFF9FBF7D;
+static const UInt32 kLowDosTime = 0x210000;
+
+bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime)
+{
+ WORD datePart, timePart;
+ if (!::FileTimeToDosDateTime(&fileTime, &datePart, &timePart))
+ {
+ dosTime = (fileTime.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime;
+ return false;
+ }
+ dosTime = (((UInt32)datePart) << 16) + timePart;
+ return true;
+}
+
+static const UInt32 kNumTimeQuantumsInSecond = 10000000;
+static const UInt64 kUnixTimeStartValue = ((UInt64)kNumTimeQuantumsInSecond) * 60 * 60 * 24 * 134774;
+
+void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime)
+{
+ UInt64 v = kUnixTimeStartValue + ((UInt64)unixTime) * kNumTimeQuantumsInSecond;
+ fileTime.dwLowDateTime = (DWORD)v;
+ fileTime.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime)
+{
+ UInt64 winTime = (((UInt64)fileTime.dwHighDateTime) << 32) + fileTime.dwLowDateTime;
+ if (winTime < kUnixTimeStartValue)
+ {
+ unixTime = 0;
+ return false;
+ }
+ winTime = (winTime - kUnixTimeStartValue) / kNumTimeQuantumsInSecond;
+ if (winTime > 0xFFFFFFFF)
+ {
+ unixTime = 0xFFFFFFFF;
+ return false;
+ }
+ unixTime = (UInt32)winTime;
+ return true;
+}
+
+bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
+ unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds)
+{
+ resSeconds = 0;
+ if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 ||
+ day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59)
+ return false;
+ UInt32 numYears = year - kFileTimeStartYear;
+ UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400;
+ Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+ ms[1] = 29;
+ month--;
+ for (unsigned i = 0; i < month; i++)
+ numDays += ms[i];
+ numDays += day - 1;
+ resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec;
+ return true;
+}
+
+void GetCurUtcFileTime(FILETIME &ft)
+{
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+}
+
+}}
diff --git a/src/libs/7zip/unix/CPP/Windows/Time.h b/src/libs/7zip/unix/CPP/Windows/Time.h
new file mode 100644
index 000000000..6f510b22b
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Time.h
@@ -0,0 +1,21 @@
+// Windows/Time.h
+
+#ifndef __WINDOWS_TIME_H
+#define __WINDOWS_TIME_H
+
+#include "Common/Types.h"
+
+namespace NWindows {
+namespace NTime {
+
+bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime);
+bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime);
+void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime);
+bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime);
+bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
+ unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds);
+void GetCurUtcFileTime(FILETIME &ft);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/unix/CPP/Windows/Window.cpp b/src/libs/7zip/unix/CPP/Windows/Window.cpp
new file mode 100644
index 000000000..e92228c70
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Window.cpp
@@ -0,0 +1,101 @@
+// Windows/Window.cpp
+
+#include "StdAfx.h"
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWidgets headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#undef _WIN32
+
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+#include "Windows/Window.h"
+
+void verify_main_thread(void);
+
+class LockGUI
+{
+ bool _IsMain;
+ public:
+ LockGUI() {
+ verify_main_thread();
+
+ _IsMain = wxThread::IsMain();
+ if (!_IsMain) {
+ printf("LockGUI-Windows\n");
+ abort(); // FIXME wxMutexGuiEnter();
+ }
+ }
+ ~LockGUI() { if (!_IsMain) wxMutexGuiLeave(); }
+};
+
+namespace NWindows {
+
+HWND GetDlgItem(HWND dialogWindow, int ControlID)
+{
+ LockGUI lock;
+ if (dialogWindow) return dialogWindow->FindWindow(ControlID);
+ return 0;
+}
+
+void MySetWindowText(HWND wnd, LPCWSTR s)
+{
+ if (wnd == 0) return;
+
+ LockGUI lock;
+
+ wxString str = s;
+ /*
+ int id = wnd->GetId();
+ if ( (id != wxID_OK) && (id != wxID_CANCEL) && (id != wxID_HELP) && (id != wxID_YES) && (id != wxID_NO))
+ */
+ {
+ wnd->SetLabel(str);
+ }
+}
+
+ bool CWindow::GetText(CSysString &s)
+ {
+ wxString str;
+ {
+ LockGUI lock;
+ str = _window->GetLabel();
+ }
+ s = str;
+ return true;
+ }
+
+ bool CWindow::IsEnabled()
+ {
+ LockGUI lock;
+ return _window->IsEnabled();
+ }
+}
+
+////////////////////////////////// Windows Compatibility
+#include <sys/resource.h>
+
+void Sleep(unsigned millisec)
+{
+ wxMilliSleep(millisec);
+}
+
+t_processID GetCurrentProcess(void) {
+ return getpid();
+}
+
+void SetPriorityClass(t_processID pid , int priority) {
+ setpriority(PRIO_PROCESS,pid,priority);
+}
+
diff --git a/src/libs/7zip/unix/CPP/Windows/Window.h b/src/libs/7zip/unix/CPP/Windows/Window.h
new file mode 100644
index 000000000..1970fe62d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/Windows/Window.h
@@ -0,0 +1,43 @@
+// Windows/Window.h
+
+#ifndef __WINDOWS_WINDOW_H
+#define __WINDOWS_WINDOW_H
+
+#include "Windows/Defs.h"
+#include "Common/MyString.h"
+
+namespace NWindows {
+
+HWND GetDlgItem(HWND dialogWindow, int ControlID);
+void MySetWindowText(HWND wnd, LPCWSTR s);
+
+class CWindow
+{
+private:
+ // bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags);
+protected:
+ HWND _window;
+public:
+ CWindow(HWND newWindow = NULL): _window(newWindow){};
+ CWindow& operator=(HWND newWindow)
+ {
+ _window = newWindow;
+ return *this;
+ }
+ operator HWND() const { return _window; }
+ void Attach(HWND newWindow) { _window = newWindow; }
+ HWND Detach()
+ {
+ HWND window = _window;
+ _window = NULL;
+ return window;
+ }
+ virtual void SetText(LPCWSTR s) { MySetWindowText(_window, s); }
+ virtual bool GetText(CSysString &s);
+ bool IsEnabled();
+};
+
+}
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/include_windows/basetyps.h b/src/libs/7zip/unix/CPP/include_windows/basetyps.h
new file mode 100644
index 000000000..d761e74b0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/include_windows/basetyps.h
@@ -0,0 +1,19 @@
+#ifndef _BASETYPS_H
+#define _BASETYPS_H
+
+#ifdef ENV_HAVE_GCCVISIBILITYPATCH
+ #define DLLEXPORT __attribute__ ((visibility("default")))
+ #else
+ #define DLLEXPORT
+ #endif
+
+#ifdef __cplusplus
+#define STDAPI extern "C" DLLEXPORT HRESULT
+#else
+#define STDAPI extern DLLEXPORT HRESULT
+#endif /* __cplusplus */
+
+typedef GUID IID;
+typedef GUID CLSID;
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/include_windows/tchar.h b/src/libs/7zip/unix/CPP/include_windows/tchar.h
new file mode 100644
index 000000000..4aa1a4f8e
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/include_windows/tchar.h
@@ -0,0 +1,89 @@
+/*
+ * tchar.h
+ *
+ * Unicode mapping layer for the standard C library. By including this
+ * file and using the 't' names for string functions
+ * (eg. _tprintf) you can make code which can be easily adapted to both
+ * Unicode and non-unicode environments. In a unicode enabled compile define
+ * _UNICODE before including tchar.h, otherwise the standard non-unicode
+ * library functions will be used.
+ *
+ * Note that you still need to include string.h or stdlib.h etc. to define
+ * the appropriate functions. Also note that there are several defines
+ * included for non-ANSI functions which are commonly available (but using
+ * the convention of prepending an underscore to non-ANSI library function
+ * names).
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ * Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAIMED. This includes but is not limited to warranties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.11 $
+ * $Author: earnie $
+ * $Date: 2003/05/03 13:48:46 $
+ *
+ */
+
+#ifndef _TCHAR_H_
+#define _TCHAR_H_
+
+/* All the headers include this file. */
+#ifndef __int64
+#define __int64 long long
+#endif
+
+#ifndef __cdecl
+#define __cdecl /* */
+#endif
+
+/*
+ * NOTE: This tests _UNICODE, which is different from the UNICODE define
+ * used to differentiate Win32 API calls.
+ */
+#ifdef _UNICODE
+
+
+/*
+ * Use TCHAR instead of char or wchar_t. It will be appropriately translated
+ * if _UNICODE is correctly defined (or not).
+ */
+#ifndef _TCHAR_DEFINED
+typedef wchar_t TCHAR;
+#define _TCHAR_DEFINED
+#endif
+
+/*
+ * Unicode functions
+ */
+/*
+#define _tfopen _wfopen
+FILE *_wfopen( const wchar_t *filename, const wchar_t *mode );
+*/
+
+#else /* Not _UNICODE */
+
+#define _tfopen fopen
+
+/*
+ * TCHAR, the type you should use instead of char.
+ */
+#ifndef _TCHAR_DEFINED
+typedef char TCHAR;
+#define _TCHAR_DEFINED
+#endif
+
+#endif /* Not _UNICODE */
+
+#endif /* Not _TCHAR_H_ */
+
diff --git a/src/libs/7zip/unix/CPP/include_windows/windows.h b/src/libs/7zip/unix/CPP/include_windows/windows.h
new file mode 100644
index 000000000..ef0ca3d19
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/include_windows/windows.h
@@ -0,0 +1,194 @@
+/*
+ windows.h - main header file for the Win32 API
+
+ Written by Anders Norlander <anorland@hem2.passagen.se>
+
+ This file is part of a free library for the Win32 API.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+#ifndef _WINDOWS_H
+#define _WINDOWS_H
+
+#include <stdarg.h>
+
+/* BEGIN #include <windef.h> */
+
+#include "Common/MyWindows.h" // FIXED
+
+#ifndef CONST
+#define CONST const
+#endif
+
+#undef MAX_PATH
+#define MAX_PATH 4096 /* Linux : 4096 - Windows : 260 */
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define WINAPI
+
+#undef BOOL
+typedef int BOOL;
+
+/* BEGIN #include <winnt.h> */
+/* BEGIN <winerror.h> */
+#define NO_ERROR 0L
+#define ERROR_ALREADY_EXISTS EEXIST
+#define ERROR_FILE_EXISTS EEXIST
+#define ERROR_INVALID_HANDLE EBADF
+#define ERROR_PATH_NOT_FOUND ENOENT
+#define ERROR_DISK_FULL ENOSPC
+#define ERROR_NO_MORE_FILES 0x100123 // FIXME
+
+/* see Common/WyWindows.h
+#define S_OK ((HRESULT)0x00000000L)
+#define S_FALSE ((HRESULT)0x00000001L)
+#define E_INVALIDARG ((HRESULT)0x80070057L)
+#define E_NOTIMPL ((HRESULT)0x80004001L)
+#define E_NOINTERFACE ((HRESULT)0x80004002L)
+#define E_ABORT ((HRESULT)0x80004004L)
+#define E_FAIL ((HRESULT)0x80004005L)
+#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
+#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L)
+#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
+#define FAILED(Status) ((HRESULT)(Status)<0)
+*/
+#ifndef VOID
+#define VOID void
+#endif
+typedef void *PVOID,*LPVOID;
+typedef WCHAR *LPWSTR;
+typedef CHAR *LPSTR;
+typedef TCHAR *LPTSTR;
+
+#ifdef UNICODE
+/*
+ * P7ZIP_TEXT is a private macro whose specific use is to force the expansion of a
+ * macro passed as an argument to the macro TEXT. DO NOT use this
+ * macro within your programs. It's name and function could change without
+ * notice.
+ */
+#define P7ZIP_TEXT(q) L##q
+#else
+#define P7ZIP_TEXT(q) q
+#endif
+/*
+ * UNICODE a constant string when UNICODE is defined, else returns the string
+ * unmodified.
+ * The corresponding macros _TEXT() and _T() for mapping _UNICODE strings
+ * passed to C runtime functions are defined in mingw/tchar.h
+ */
+#define TEXT(q) P7ZIP_TEXT(q)
+
+typedef BYTE BOOLEAN;
+
+/* BEGIN #include <basetsd.h> */
+#ifndef __int64
+#define __int64 long long
+#endif
+typedef unsigned __int64 UINT64;
+typedef __int64 INT64;
+/* END #include <basetsd.h> */
+
+#define FILE_ATTRIBUTE_READONLY 1
+#define FILE_ATTRIBUTE_HIDDEN 2
+#define FILE_ATTRIBUTE_SYSTEM 4
+#define FILE_ATTRIBUTE_DIRECTORY 16
+#define FILE_ATTRIBUTE_ARCHIVE 32
+#define FILE_ATTRIBUTE_DEVICE 64
+#define FILE_ATTRIBUTE_NORMAL 128
+#define FILE_ATTRIBUTE_TEMPORARY 256
+#define FILE_ATTRIBUTE_SPARSE_FILE 512
+#define FILE_ATTRIBUTE_REPARSE_POINT 1024
+#define FILE_ATTRIBUTE_COMPRESSED 2048
+#define FILE_ATTRIBUTE_OFFLINE 0x1000
+#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
+#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */
+
+/* END <winerror.h> */
+
+#include <string.h>
+#include <stddef.h>
+
+/* END #include <winnt.h> */
+
+/* END #include <windef.h> */
+
+/* BEGIN #include <winbase.h> */
+
+#define WAIT_OBJECT_0 0
+#define INFINITE 0xFFFFFFFF
+
+typedef struct _SYSTEMTIME {
+ WORD wYear;
+ WORD wMonth;
+ WORD wDayOfWeek;
+ WORD wDay;
+ WORD wHour;
+ WORD wMinute;
+ WORD wSecond;
+ WORD wMilliseconds;
+} SYSTEMTIME;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BOOL WINAPI DosDateTimeToFileTime(WORD,WORD,FILETIME *);
+BOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *,WORD *, WORD *);
+BOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *,FILETIME *);
+BOOL WINAPI FileTimeToSystemTime(CONST FILETIME *,SYSTEMTIME *);
+BOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *,FILETIME *);
+VOID WINAPI GetSystemTime(SYSTEMTIME *);
+BOOL WINAPI SystemTimeToFileTime(const SYSTEMTIME*,FILETIME *);
+
+DWORD WINAPI GetTickCount(VOID);
+
+#ifdef __cplusplus
+}
+#endif
+/* END #include <winbase.h> */
+
+/* BEGIN #include <winnls.h> */
+
+#define CP_ACP 0
+#define CP_OEMCP 1
+#define CP_UTF8 65001
+
+/* #include <unknwn.h> */
+#include <basetyps.h>
+struct IEnumSTATPROPSTG;
+
+typedef struct tagSTATPROPSTG {
+ LPOLESTR lpwstrName;
+ PROPID propid;
+ VARTYPE vt;
+} STATPROPSTG;
+
+#ifdef __cplusplus
+extern "C" const IID IID_ISequentialStream;
+struct ISequentialStream : public IUnknown
+{
+ STDMETHOD(QueryInterface)(REFIID,PVOID*) PURE;
+ STDMETHOD_(ULONG,AddRef)(void) PURE;
+ STDMETHOD_(ULONG,Release)(void) PURE;
+ STDMETHOD(Read)(void*,ULONG,ULONG*) PURE;
+ STDMETHOD(Write)(void const*,ULONG,ULONG*) PURE;
+};
+#else
+extern const IID IID_ISequentialStream;
+#endif /* __cplusplus */
+
+
+/* END #include <ole2.h> */
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/StdAfx.h b/src/libs/7zip/unix/CPP/myWindows/StdAfx.h
new file mode 100644
index 000000000..629529dcf
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/StdAfx.h
@@ -0,0 +1,124 @@
+// stdafx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+
+#include "config.h"
+
+
+#define NO_INLINE /* FIXME */
+
+#ifdef ENV_HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+#include "Common/MyWindows.h"
+#include "Common/Types.h"
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <tchar.h>
+#include <wchar.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+
+#ifdef __NETWARE__
+#include <sys/types.h>
+#endif
+
+#undef CS /* fix for Solaris 10 x86 */
+
+
+/***************************/
+
+#ifndef ENV_HAVE_WCHAR__H
+
+EXTERN_C_BEGIN
+
+size_t wcslen(const wchar_t *);
+wchar_t *wcscpy(wchar_t * , const wchar_t * );
+wchar_t *wcscat(wchar_t * , const wchar_t * );
+
+EXTERN_C_END
+
+#endif
+
+/***************************/
+
+#define CLASS_E_CLASSNOTAVAILABLE ((HRESULT)0x80040111L)
+
+/************************* LastError *************************/
+inline DWORD WINAPI GetLastError(void) { return errno; }
+inline void WINAPI SetLastError( DWORD err ) { errno = err; }
+
+#define AreFileApisANSI() (1)
+
+void Sleep(unsigned millisleep);
+
+typedef pid_t t_processID;
+
+t_processID GetCurrentProcess(void);
+
+#define NORMAL_PRIORITY_CLASS (0)
+#define IDLE_PRIORITY_CLASS (10)
+void SetPriorityClass(t_processID , int priority);
+
+#ifdef __cplusplus
+class wxWindow;
+typedef wxWindow *HWND;
+
+#define MB_ICONERROR (0x00000200) // wxICON_ERROR
+#define MB_YESNOCANCEL (0x00000002 | 0x00000008 | 0x00000010) // wxYES | wxNO | wxCANCEL
+#define MB_ICONQUESTION (0x00000400) // wxICON_QUESTION
+#define MB_TASKMODAL (0) // FIXME
+#define MB_SYSTEMMODAL (0) // FIXME
+
+#define MB_OK (0x00000004) // wxOK
+#define MB_ICONSTOP (0x00000200) // wxICON_STOP
+#define MB_OKCANCEL (0x00000004 | 0x00000010) // wxOK | wxCANCEL
+
+#define MessageBox MessageBoxW
+int MessageBoxW(wxWindow * parent, const TCHAR * mes, const TCHAR * title,int flag);
+
+typedef void *HINSTANCE;
+
+typedef int INT_PTR; // FIXME 64 bits ?
+typedef unsigned int UINT_PTR; // FIXME 64 bits ?
+typedef long LONG_PTR; // FIXME 64 bits ?
+typedef long DWORD_PTR; // FIXME 64 bits ?
+typedef UINT_PTR WPARAM;
+
+/* WARNING
+ LPARAM shall be 'long' because of CListView::SortItems and wxListCtrl::SortItems :
+*/
+typedef LONG_PTR LPARAM;
+typedef LONG_PTR LRESULT;
+
+#define CALLBACK /* */
+
+/************ LANG ***********/
+typedef WORD LANGID;
+
+LANGID GetUserDefaultLangID(void);
+LANGID GetSystemDefaultLangID(void);
+
+#define PRIMARYLANGID(l) ((WORD)(l) & 0x3ff)
+#define SUBLANGID(l) ((WORD)(l) >> 10)
+
+#if defined( __x86_64__ )
+
+#define _WIN64 1
+
+#endif
+
+#endif
+
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/config.h b/src/libs/7zip/unix/CPP/myWindows/config.h
new file mode 100644
index 000000000..54332aad0
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/config.h
@@ -0,0 +1,67 @@
+
+#if !defined(__DJGPP__)
+
+#ifndef __CYGWIN__
+ #define FILESYSTEM_IS_CASE_SENSITIVE 1
+#endif
+
+ #if !defined(ENV_MACOSX) && !defined(ENV_BEOS)
+
+ /* <wchar.h> */
+ /* ENV_HAVE_WCHAR__H and not ENV_HAVE_WCHAR_H to avoid warning with wxWidgets */
+ #define ENV_HAVE_WCHAR__H
+
+ /* <wctype.h> */
+ #define ENV_HAVE_WCTYPE_H
+
+ /* mbrtowc */
+/* #ifndef __hpux */
+/* #define ENV_HAVE_MBRTOWC */
+/* #endif */
+
+ /* towupper */
+ #define ENV_HAVE_TOWUPPER
+
+ #endif /* !ENV_MACOSX && !ENV_BEOS */
+
+ #if !defined(ENV_BEOS)
+ #define ENV_HAVE_GETPASS
+
+ #if !defined(sun)
+ #define ENV_HAVE_TIMEGM
+ #endif
+
+
+ #endif
+
+ /* lstat, readlink and S_ISLNK */
+ #define ENV_HAVE_LSTAT
+
+ /* <locale.h> */
+ #define ENV_HAVE_LOCALE
+
+ /* mbstowcs */
+ #define ENV_HAVE_MBSTOWCS
+
+ /* wcstombs */
+ #define ENV_HAVE_WCSTOMBS
+
+#endif /* !__DJGPP__ */
+
+#ifndef ENV_BEOS
+#define ENV_HAVE_PTHREAD
+#endif
+
+#if defined(ENV_MACOSX)
+#define LOCALE_IS_UTF8
+#endif
+
+#ifdef LOCALE_IS_UTF8
+#undef ENV_HAVE_LOCALE
+#undef ENV_HAVE_MBSTOWCS
+#undef ENV_HAVE_WCSTOMBS
+/* #undef ENV_HAVE_MBRTOWC */
+#endif
+
+#define MAX_PATHNAME_LEN 1024
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/initguid.h b/src/libs/7zip/unix/CPP/myWindows/initguid.h
new file mode 100644
index 000000000..f7580d571
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/initguid.h
@@ -0,0 +1,4 @@
+// initguid.h
+
+#include "Common/MyInitGuid.h"
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/myAddExeFlag.cpp b/src/libs/7zip/unix/CPP/myWindows/myAddExeFlag.cpp
new file mode 100644
index 000000000..6bdc34ac3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/myAddExeFlag.cpp
@@ -0,0 +1,20 @@
+#include "StdAfx.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <windows.h>
+
+#define NEED_NAME_WINDOWS_TO_UNIX
+#include "myPrivate.h"
+
+#include "Common/StringConvert.h"
+
+void myAddExeFlag(const UString &u_name)
+{
+ AString filename = UnicodeStringToMultiByte(u_name, CP_ACP); // FIXME
+ const char * name = nameWindowToUnix(filename);
+ // printf("myAddExeFlag(%s)\n",name);
+ chmod(name,0700);
+}
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/myGetTickCount.cpp b/src/libs/7zip/unix/CPP/myWindows/myGetTickCount.cpp
new file mode 100644
index 000000000..6a6080b35
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/myGetTickCount.cpp
@@ -0,0 +1,8 @@
+#include "StdAfx.h"
+
+#include <time.h>
+
+DWORD WINAPI GetTickCount(VOID) {
+ return (DWORD)time(0); // FIXME : but only for the seed of the random generator
+}
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/myPrivate.h b/src/libs/7zip/unix/CPP/myWindows/myPrivate.h
new file mode 100644
index 000000000..73739d095
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/myPrivate.h
@@ -0,0 +1,17 @@
+
+void WINAPI RtlSecondsSince1970ToFileTime( DWORD Seconds, FILETIME * ft );
+
+extern "C" int global_use_utf16_conversion;
+#ifdef ENV_HAVE_LSTAT
+extern "C" int global_use_lstat;
+#endif
+
+const char *my_getlocale(void);
+
+#ifdef NEED_NAME_WINDOWS_TO_UNIX
+static inline const char * nameWindowToUnix(const char * lpFileName) {
+ if ((lpFileName[0] == 'c') && (lpFileName[1] == ':')) return lpFileName+2;
+ return lpFileName;
+}
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/mySplitCommandLine.cpp b/src/libs/7zip/unix/CPP/myWindows/mySplitCommandLine.cpp
new file mode 100644
index 000000000..9e0791992
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/mySplitCommandLine.cpp
@@ -0,0 +1,82 @@
+#include "StdAfx.h"
+
+#include "../Common/StringConvert.h"
+
+#include "myPrivate.h"
+
+#ifdef ENV_HAVE_LOCALE
+#include <locale.h>
+#endif
+
+extern void my_windows_split_path(const AString &p_path, AString &dir , AString &base);
+
+void mySplitCommandLine(int numArguments,const char *arguments[],UStringVector &parts) {
+
+ { // define P7ZIP_HOME_DIR
+ static char p7zip_home_dir[MAX_PATH];
+ AString dir,name;
+ my_windows_split_path(arguments[0],dir,name);
+ snprintf(p7zip_home_dir,sizeof(p7zip_home_dir),"P7ZIP_HOME_DIR=%s/",(const char *)dir);
+ p7zip_home_dir[sizeof(p7zip_home_dir)-1] = 0;
+ putenv(p7zip_home_dir);
+ }
+
+#ifdef ENV_HAVE_LOCALE
+ // set the program's current locale from the user's environment variables
+ setlocale(LC_ALL,"");
+
+
+ // auto-detect which conversion p7zip should use
+ char *locale = setlocale(LC_CTYPE,0);
+ if (locale) {
+ size_t len = strlen(locale);
+ char *locale_upper = (char *)malloc(len+1);
+ if (locale_upper) {
+ strcpy(locale_upper,locale);
+
+ for(size_t i=0;i<len;i++)
+ locale_upper[i] = toupper(locale_upper[i] & 255);
+
+ if ( (strcmp(locale_upper,"") != 0)
+ && (strcmp(locale_upper,"C") != 0)
+ && (strcmp(locale_upper,"POSIX") != 0) ) {
+ global_use_utf16_conversion = 1;
+ }
+ free(locale_upper);
+ }
+ }
+#elif defined(LOCALE_IS_UTF8)
+ global_use_utf16_conversion = 1; // assume LC_CTYPE="utf8"
+#else
+ global_use_utf16_conversion = 0; // assume LC_CTYPE="C"
+#endif
+
+ parts.Clear();
+ for(int ind=0;ind < numArguments; ind++) {
+ if ((ind <= 2) && (strcmp(arguments[ind],"-no-utf16") == 0)) {
+ global_use_utf16_conversion = 0;
+ } else if ((ind <= 2) && (strcmp(arguments[ind],"-utf16") == 0)) {
+ global_use_utf16_conversion = 1;
+ } else {
+ UString tmp = MultiByteToUnicodeString(arguments[ind]);
+ // tmp.Trim(); " " is a valid filename ...
+ if (!tmp.IsEmpty()) {
+ parts.Add(tmp);
+ }
+ }
+ }
+}
+
+const char *my_getlocale(void) {
+#ifdef ENV_HAVE_LOCALE
+ const char* ret = setlocale(LC_CTYPE,0);
+ if (ret == 0)
+ ret ="C";
+ return ret;
+#elif defined(LOCALE_IS_UTF8)
+ return "utf8";
+#else
+ return "C";
+#endif
+}
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/test_emul.cpp b/src/libs/7zip/unix/CPP/myWindows/test_emul.cpp
new file mode 100644
index 000000000..1c8d3261d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/test_emul.cpp
@@ -0,0 +1,745 @@
+#undef BIG_ENDIAN
+#undef LITTLE_ENDIAN
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#ifdef __APPLE_CC__
+#define UInt32 macUIn32
+#include <CoreFoundation/CoreFoundation.h>
+#undef UInt32
+#endif
+
+#ifdef ENV_HAVE_WCHAR__H
+#include <wchar.h>
+#endif
+#ifdef ENV_HAVE_LOCALE
+#include <locale.h>
+#endif
+
+#include <windows.h>
+
+#define NEED_NAME_WINDOWS_TO_UNIX
+// #include "myPrivate.h"
+
+#include "Common/StringConvert.h"
+#include "Common/StdOutStream.h"
+
+#undef NDEBUG
+#include <assert.h>
+
+#include "Common/StringConvert.cpp"
+#include "Common/StdOutStream.cpp"
+#include "Common/IntToString.cpp"
+
+#include "Windows/Synchronization.cpp"
+#include "Windows/FileFind.cpp"
+#include "Windows/Time.cpp"
+#include "../C/Threads.c"
+#include "../../C/Ppmd.h"
+
+using namespace NWindows;
+
+#if defined(ENV_HAVE_WCHAR__H) && defined(ENV_HAVE_MBSTOWCS) && defined(ENV_HAVE_WCSTOMBS)
+void test_mbs(void) {
+ wchar_t wstr1[256] = {
+ L'e',
+ 0xE8, // latin small letter e with grave
+ 0xE9, // latin small letter e with acute
+ L'a',
+ 0xE0, // latin small letter a with grave
+ 0x20AC, // euro sign
+ L'b',
+ 0 };
+ wchar_t wstr2[256];
+ char astr[256];
+
+ global_use_utf16_conversion = 1;
+
+ size_t len1 = wcslen(wstr1);
+
+ printf("wstr1 - %d - '%ls'\n",(int)len1,wstr1);
+
+ size_t len0 = wcstombs(astr,wstr1,sizeof(astr));
+ printf("astr - %d - '%s'\n",(int)len0,astr);
+
+ size_t len2 = mbstowcs(wstr2,astr,sizeof(wstr2)/sizeof(*wstr2));
+ printf("wstr - %d - '%ls'\n",(int)len2,wstr2);
+
+ if (wcscmp(wstr1,wstr2) != 0) {
+ printf("ERROR during conversions wcs -> mbs -> wcs\n");
+ exit(EXIT_FAILURE);
+ }
+
+ char *ptr = astr;
+ size_t len = 0;
+ while (*ptr) {
+ ptr = CharNextA(ptr);
+ len += 1;
+ }
+ if ((len != len1) && (len != 12)) { // 12 = when locale is UTF8 instead of ISO8859-15
+ printf("ERROR CharNextA : len=%d, len1=%d\n",(int)len,(int)len1);
+ exit(EXIT_FAILURE);
+ }
+
+ UString ustr(wstr1);
+ assert(ustr.Length() == (int)len1);
+
+ AString ansistr(astr);
+ assert(ansistr.Length() == (int)len0);
+
+ ansistr = UnicodeStringToMultiByte(ustr);
+ assert(ansistr.Length() == (int)len0);
+
+ assert(strcmp(ansistr,astr) == 0);
+ assert(wcscmp(ustr,wstr1) == 0);
+
+ UString ustr2 = MultiByteToUnicodeString(astr);
+ assert(ustr2.Length() == (int)len1);
+ assert(wcscmp(ustr2,wstr1) == 0);
+}
+#endif
+
+static void test_astring(int num) {
+ AString strResult;
+
+ strResult = "first part : ";
+ char number[256];
+ sprintf(number,"%d",num);
+ strResult += AString(number);
+
+ strResult += " : last part";
+
+ printf("strResult -%s-\n",(const char *)strResult);
+
+}
+
+
+extern void my_windows_split_path(const AString &p_path, AString &dir , AString &base);
+
+static struct {
+ const char *path;
+ const char *dir;
+ const char *base;
+}
+tabSplit[]=
+ {
+ { "",".","." },
+ { "/","/","/" },
+ { ".",".","." },
+ { "//","/","/" },
+ { "///","/","/" },
+ { "dir",".","dir" },
+ { "/dir","/","dir" },
+ { "/dir/","/","dir" },
+ { "/dir/base","/dir","base" },
+ { "/dir//base","/dir","base" },
+ { "/dir///base","/dir","base" },
+ { "//dir/base","//dir","base" },
+ { "///dir/base","///dir","base" },
+ { "/dir/base/","/dir","base" },
+ { 0,0,0 }
+ };
+
+static void test_split_astring() {
+ int ind = 0;
+ while (tabSplit[ind].path) {
+ AString path(tabSplit[ind].path);
+ AString dir;
+ AString base;
+
+ my_windows_split_path(path,dir,base);
+
+ if ((dir != tabSplit[ind].dir) || (base != tabSplit[ind].base)) {
+ printf("ERROR : '%s' '%s' '%s'\n",(const char *)path,(const char *)dir,(const char *)base);
+ }
+ ind++;
+ }
+ printf("test_split_astring : done\n");
+}
+
+ // Number of 100 nanosecond units from 1/1/1601 to 1/1/1970
+#define EPOCH_BIAS 116444736000000000LL
+static LARGE_INTEGER UnixTimeToUL(time_t tps_unx)
+{
+ LARGE_INTEGER ul;
+ ul.QuadPart = tps_unx * 10000000LL + EPOCH_BIAS;
+ return ul;
+}
+
+static LARGE_INTEGER FileTimeToUL(FILETIME fileTime)
+{
+ LARGE_INTEGER lFileTime;
+ lFileTime.QuadPart = fileTime.dwHighDateTime;
+ lFileTime.QuadPart = (lFileTime.QuadPart << 32) | fileTime.dwLowDateTime;
+ return lFileTime;
+}
+
+static void display(const char *txt,SYSTEMTIME systime)
+{
+ FILETIME fileTime;
+ BOOL ret = SystemTimeToFileTime(&systime,&fileTime);
+ assert(ret == TRUE);
+ LARGE_INTEGER ulFileTime = FileTimeToUL(fileTime);
+
+ const char * day="";
+ switch (systime.wDayOfWeek)
+ {
+ case 0:day = "Sunday";break;
+ case 1:day = "Monday";break;
+ case 2:day = "Tuesday";break;
+ case 3:day = "Wednesday";break;
+ case 4:day = "Thursday";break;
+ case 5:day = "Friday";break;
+ case 6:day = "Saturday";break;
+ }
+ g_StdOut<< txt << day << " "
+ << (int)systime.wYear << "/" << (int)systime.wMonth << "/" << (int)systime.wDay << " "
+ << (int)systime.wHour << ":" << (int)systime.wMinute << ":" << (int)systime.wSecond << ":"
+ << (int)systime.wMilliseconds
+ << " (" << (UInt64)ulFileTime.QuadPart << ")\n";
+}
+
+static void test_time()
+{
+ time_t tps_unx = time(0);
+
+ printf("Test Time (1):\n");
+ printf("===========\n");
+ SYSTEMTIME systimeGM;
+ GetSystemTime(&systimeGM);
+
+ LARGE_INTEGER ul = UnixTimeToUL(tps_unx);
+ g_StdOut<<" unix time = " << (UInt64)tps_unx << " (" << (UInt64)ul.QuadPart << ")\n";
+
+ g_StdOut<<" gmtime : " << asctime(gmtime(&tps_unx))<<"\n";
+ g_StdOut<<" localtime : " << asctime(localtime(&tps_unx))<<"\n";
+
+ display(" GetSystemTime : ", systimeGM);
+}
+
+static void test_time2()
+{
+ UInt32 dosTime = 0x30d0094C;
+ FILETIME utcFileTime;
+ FILETIME localFileTime;
+ FILETIME localFileTime2;
+ UInt32 dosTime2 = 0;
+
+ printf("Test Time (2):\n");
+ printf("===========\n");
+ NTime::DosTimeToFileTime(dosTime, localFileTime);
+ NTime::FileTimeToDosTime(localFileTime, dosTime2);
+ assert(dosTime == dosTime2);
+
+ printf("Test Time (3):\n");
+ printf("===========\n");
+ /* DosTime To utcFileTime */
+
+ if (NTime::DosTimeToFileTime(dosTime, localFileTime)) /* DosDateTimeToFileTime */
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ }
+
+ printf(" - 0x%x => 0x%x 0x%x => 0x%x 0x%x\n",(unsigned)dosTime,
+ (unsigned)localFileTime.dwHighDateTime,(unsigned)localFileTime.dwLowDateTime,
+ (unsigned)utcFileTime.dwHighDateTime,(unsigned)utcFileTime.dwLowDateTime);
+
+
+ /* utcFileTime to DosTime */
+
+ FileTimeToLocalFileTime(&utcFileTime, &localFileTime2);
+ NTime::FileTimeToDosTime(localFileTime2, dosTime2); /* FileTimeToDosDateTime */
+
+ printf(" - 0x%x <= 0x%x 0x%x <= 0x%x 0x%x\n",(unsigned)dosTime2,
+ (unsigned)localFileTime2.dwHighDateTime,(unsigned)localFileTime2.dwLowDateTime,
+ (unsigned)utcFileTime.dwHighDateTime,(unsigned)utcFileTime.dwLowDateTime);
+
+ assert(dosTime == dosTime2);
+ assert(localFileTime.dwHighDateTime == localFileTime2.dwHighDateTime);
+ assert(localFileTime.dwLowDateTime == localFileTime2.dwLowDateTime);
+}
+
+static void test_semaphore()
+{
+ g_StdOut << "\nTEST SEMAPHORE :\n";
+
+ NWindows::NSynchronization::CSynchro sync;
+ NWindows::NSynchronization::CSemaphoreWFMO sema;
+ bool bres;
+ DWORD waitResult;
+ int i;
+
+ sync.Create();
+ sema.Create(&sync,2,10);
+
+ g_StdOut << " - Release(1)\n";
+ for(i = 0 ;i < 8;i++)
+ {
+ // g_StdOut << " - Release(1) : "<< i << "\n";
+ bres = sema.Release(1);
+ assert(bres == S_OK);
+ }
+ // g_StdOut << " - Release(1) : done\n";
+ bres = sema.Release(1);
+ assert(bres == S_FALSE);
+
+ g_StdOut << " - WaitForMultipleObjects(INFINITE)\n";
+ HANDLE events[1] = { sema };
+ for(i=0;i<10;i++)
+ {
+ waitResult = ::WaitForMultipleObjects(1, events, FALSE, INFINITE);
+ assert(waitResult == WAIT_OBJECT_0);
+ }
+
+ g_StdOut << " Done\n";
+}
+
+
+/****************************************************************************************/
+
+
+static int threads_count = 0;
+
+static THREAD_FUNC_RET_TYPE thread_fct(void * /* param */ ) {
+ threads_count++;
+ return 0;
+}
+
+#define MAX_THREADS 100000
+
+int test_thread(void) {
+ ::CThread thread;
+
+ Thread_Construct(&thread);
+
+ threads_count = 0;
+
+ printf("test_thread : %d threads\n",MAX_THREADS);
+
+ for(int i=0;i<MAX_THREADS;i++) {
+ Thread_Create(&thread, thread_fct, 0);
+
+ Thread_Wait(&thread);
+
+ Thread_Close(&thread);
+ }
+
+ assert(threads_count == MAX_THREADS);
+
+ return 0;
+}
+
+
+void dumpStr(const char *title,const char *txt)
+{
+ size_t i,len = strlen(txt);
+
+ printf("%s - %d :",title,(int)len);
+
+ for(i = 0 ; i<len;i++) {
+ printf(" 0x%02x",(unsigned)(txt[i] & 255));
+ }
+
+ printf("\n");
+}
+
+
+void dumpWStr(const char *title,const wchar_t *txt)
+{
+ size_t i,len = wcslen(txt);
+
+ printf("%s - %d :",title,(int)len);
+
+ for(i = 0 ; i<len;i++) {
+ printf(" 0x%02x",(unsigned)(txt[i]));
+ }
+
+ printf("\n");
+}
+
+#ifdef __APPLE_CC__
+
+void testMaxOSX_stringConvert()
+{
+/*
+ 0xE8, // latin small letter e with grave
+ 0xE9, // latin small letter e with acute
+ L'a',
+ 0xE0, // latin small letter a with grave
+ 0x20AC, // euro sign
+*/
+ struct
+ {
+ char astr [256];
+ wchar_t ustr [256];
+ }
+ tab [] =
+ {
+ {
+ // 'a' , 'e with acute' , 'e with grave' , 'a with grave' , 'u with grave' , 'b' , '.' , 't' , 'x' , 't'
+ { 0x61, 0x65, 0xcc, 0x81 , 0x65, 0xcc, 0x80, 0x61, 0xcc, 0x80, 0x75, 0xcc, 0x80, 0x62, 0x2e, 0x74, 0x78, 0x74, 0 },
+ { 0x61, 0xe9, 0xe8, 0xe0, 0xf9, 0x62, 0x2e, 0x74, 0x78, 0x74, 0 }
+ },
+ {
+ // 'a' , 'euro sign' , 'b' , '.' , 't' , 'x' , 't' , '\n'
+ { 0x61, 0xe2, 0x82, 0xac, 0x62, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0 },
+ { 0x61, 0x20AC, 0x62, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0 }
+ },
+ {
+ { 0 },
+ { 0 }
+ }
+ };
+
+ int i;
+
+ printf("testMaxOSX_stringConvert : \n");
+
+ i = 0;
+ while (tab[i].astr[0])
+ {
+ printf(" %s\n",tab[i].astr);
+
+ UString ustr = GetUnicodeString(tab[i].astr);
+
+ // dumpWStr("1",&ustr[0]);
+
+ assert(MyStringCompare(&ustr[0],tab[i].ustr) == 0);
+ assert(ustr.Length() == wcslen(tab[i].ustr) );
+
+
+ AString astr = GetAnsiString(ustr);
+ assert(MyStringCompare(&astr[0],tab[i].astr) == 0);
+ assert(astr.Length() == strlen(tab[i].astr) );
+
+ i++;
+ }
+}
+
+void testMacOSX()
+{
+// char texte1[]= { 0xc3 , 0xa9 , 0xc3, 0xa0, 0};
+
+ wchar_t wpath1[4096] = {
+ 0xE9, // latin small letter e with acute
+ 0xE0,
+ 0xc7,
+ 0x25cc,
+ 0x327,
+ 0xe4,
+ 0xe2,
+ 0xc2,
+ 0xc3,
+ 0x2e,
+ 0x74,
+ 0x78,
+ 0x74,
+/*
+ L'e',
+ 0xE8, // latin small letter e with grave
+ 0xE9, // latin small letter e with acute
+ L'a',
+ 0xE0, // latin small letter a with grave
+ 0x20AC, // euro sign
+ L'b',
+*/
+ 0 };
+
+ char utf8[4096];
+ wchar_t wpath2[4096];
+
+
+
+ // dumpStr("UTF8 standart",texte1);
+
+ dumpWStr("UCS32 standard",wpath1);
+
+// Translate into FS pathname
+ {
+ const wchar_t * wcs = wpath1;
+
+ UniChar unipath[4096];
+
+ long n = wcslen(wcs);
+
+ for(long i = 0 ; i<= n ;i++) {
+ unipath[i] = wcs[i];
+ }
+
+ CFStringRef cfpath = CFStringCreateWithCharacters(NULL,unipath,n);
+
+ CFMutableStringRef cfpath2 = CFStringCreateMutableCopy(NULL,0,cfpath);
+ CFRelease(cfpath);
+ CFStringNormalize(cfpath2,kCFStringNormalizationFormD);
+
+ CFStringGetCString(cfpath2,(char *)utf8,4096,kCFStringEncodingUTF8);
+
+ CFRelease(cfpath2);
+ }
+
+ dumpStr("UTF8 MacOSX",utf8);
+
+// Translate from FS pathname
+ {
+ const char * path = utf8;
+
+ long n = strlen(path);
+
+ CFStringRef cfpath = CFStringCreateWithCString(NULL,path,kCFStringEncodingUTF8);
+
+ if (cfpath)
+ {
+
+ CFMutableStringRef cfpath2 = CFStringCreateMutableCopy(NULL,0,cfpath);
+ CFRelease(cfpath);
+ CFStringNormalize(cfpath2,kCFStringNormalizationFormC);
+
+ n = CFStringGetLength(cfpath2);
+ for(long i = 0 ; i<= n ;i++) {
+ wpath2[i] = CFStringGetCharacterAtIndex(cfpath2,i);
+ }
+ wpath2[n] = 0;
+
+ CFRelease(cfpath2);
+ }
+ else
+ {
+ wpath2[0] = 0;
+ }
+ }
+
+ dumpWStr("UCS32 standard (2)",wpath2);
+
+/*
+ {
+ CFStringRef cfpath;
+
+ cfpath = CFStringCreateWithCString(kCFAllocatorDefault, texte1, kCFStringEncodingUTF8);
+
+ // TODO str = null ?
+
+ CFMutableStringRef cfpath2 = CFStringCreateMutableCopy(NULL,0,cfpaht);
+ CFRealease(cfpath);
+
+
+
+
+ }
+*/
+
+
+}
+#endif // __APPLE_CC__
+
+
+static const TCHAR *kMainDll = TEXT("7z.dll");
+
+static CSysString ConvertUInt32ToString(UInt32 value)
+{
+ TCHAR buffer[32];
+ ConvertUInt32ToString(value, buffer);
+ return buffer;
+}
+
+
+void test_csystring(void)
+{
+ {
+ const CSysString baseFolder = TEXT("bin/");
+ const CSysString b2 = baseFolder + kMainDll;
+
+ assert(MyStringCompare(&b2[0],TEXT("bin/7z.dll")) == 0);
+ }
+
+ {
+ LPCTSTR dirPath=TEXT("/tmp/");
+ LPCTSTR prefix=TEXT("foo");
+ CSysString resultPath;
+
+ UINT number = 12345;
+ UInt32 count = 6789;
+
+/*
+ TCHAR * buf = resultPath.GetBuffer(MAX_PATH);
+ ::swprintf(buf,MAX_PATH,L"%ls%ls#%d@%d.tmp",dirPath,prefix,(unsigned)number,count);
+ buf[MAX_PATH-1]=0;
+ resultPath.ReleaseBuffer();
+*/
+ resultPath = dirPath;
+ resultPath += prefix;
+ resultPath += TEXT('#');
+ resultPath += ConvertUInt32ToString(number);
+ resultPath += TEXT('@');
+ resultPath += ConvertUInt32ToString(count);
+ resultPath += TEXT(".tmp");
+
+ // printf("##%ls##\n",&resultPath[0]);
+
+ assert(MyStringCompare(&resultPath[0],TEXT("/tmp/foo#12345@6789.tmp")) == 0);
+ }
+
+}
+
+static void test_AString()
+{
+ AString a;
+
+ a = "abc";
+ assert(MyStringCompare(&a[0],"abc") == 0);
+ assert(a.Length() == 3);
+
+ a = GetAnsiString(L"abc");
+ assert(MyStringCompare(&a[0],"abc") == 0);
+ assert(a.Length() == 3);
+}
+
+
+const TCHAR kAnyStringWildcard = '*';
+
+static void test_UString2(const UString &phyPrefix)
+{
+ UString tmp = phyPrefix + wchar_t(kAnyStringWildcard);
+ printf("Enum(%ls-%ls-%lc)\n",&tmp[0],&phyPrefix[0],wchar_t(kAnyStringWildcard));
+}
+
+
+
+static void test_UString()
+{
+ UString us = L"7za433_tar";
+
+ test_UString2(L"7za433_tar");
+
+ UString u1(us);
+ test_UString2(u1);
+ u1 = L"";
+ test_UString2(u1);
+ u1 = us;
+ test_UString2(u1);
+
+ UString u2 = us;
+ test_UString2(u2);
+ u2 = L"";
+ test_UString2(u2);
+ u2 = u1;
+ test_UString2(u2);
+
+ u1 = L"abc";
+ assert(MyStringCompare(&u1[0],L"abc") == 0);
+ assert(u1.Length() == 3);
+
+ u1 = GetUnicodeString("abc");
+ assert(MyStringCompare(&u1[0],L"abc") == 0);
+ assert(u1.Length() == 3);
+}
+
+/****************************************************************************************/
+int main() {
+
+ // return test_thread();
+
+
+#ifdef ENV_HAVE_LOCALE
+ setlocale(LC_ALL,"");
+#endif
+
+#if defined(BIG_ENDIAN)
+ printf("BIG_ENDIAN : %d\n",(int)BIG_ENDIAN);
+#endif
+#if defined(LITTLE_ENDIAN)
+ printf("LITTLE_ENDIAN : %d\n",(int)LITTLE_ENDIAN);
+#endif
+
+ printf("sizeof(Byte) : %d\n",(int)sizeof(Byte));
+ printf("sizeof(UInt16) : %d\n",(int)sizeof(UInt16));
+ printf("sizeof(UInt32) : %d\n",(int)sizeof(UInt32));
+ printf("sizeof(UINT32) : %d\n",(int)sizeof(UINT32));
+ printf("sizeof(UInt64) : %d\n",(int)sizeof(UInt64));
+ printf("sizeof(UINT64) : %d\n",(int)sizeof(UINT64));
+ printf("sizeof(void *) : %d\n",(int)sizeof(void *));
+ printf("sizeof(size_t) : %d\n",(int)sizeof(size_t));
+ printf("sizeof(ptrdiff_t) : %d\n",(int)sizeof(ptrdiff_t));
+ printf("sizeof(off_t) : %d\n",(int)sizeof(off_t));
+ printf("sizeof(wchar_t) : %d\n",(int)sizeof(wchar_t));
+#ifdef __APPLE_CC__
+ printf("sizeof(UniChar) : %d\n",(int)sizeof(UniChar));
+#endif
+ printf("sizeof(CPpmd_See) : %d\n",(int)sizeof(CPpmd_See));
+ printf("sizeof(CPpmd_State) : %d\n",(int)sizeof(CPpmd_State));
+
+ // size tests
+ assert(sizeof(Byte)==1);
+ assert(sizeof(UInt16)==2);
+ assert(sizeof(UInt32)==4);
+ assert(sizeof(UINT32)==4);
+ assert(sizeof(UInt64)==8);
+ assert(sizeof(UINT64)==8);
+
+ // alignement tests
+ assert(sizeof(CPpmd_See)==4);
+ assert(sizeof(CPpmd_State)==6);
+
+ union {
+ Byte b[2];
+ UInt16 s;
+ } u;
+ u.s = 0x1234;
+
+ if ((u.b[0] == 0x12) && (u.b[1] == 0x34)) {
+ printf("CPU : big endian\n");
+ } else if ((u.b[0] == 0x34) && (u.b[1] == 0x12)) {
+ printf("CPU : little endian\n");
+ } else {
+ printf("CPU : unknown endianess\n");
+ }
+
+#if defined(ENV_HAVE_WCHAR__H) && defined(ENV_HAVE_MBSTOWCS) && defined(ENV_HAVE_WCSTOMBS)
+ test_mbs();
+#endif
+
+ test_astring(12345);
+ test_split_astring();
+
+ test_csystring();
+ test_AString();
+ test_UString();
+
+ test_time();
+
+ test_time2();
+
+ test_semaphore();
+
+#ifdef __APPLE_CC__
+ testMacOSX();
+ testMaxOSX_stringConvert();
+#endif
+
+
+{
+ LANGID langID;
+ WORD primLang;
+ WORD subLang;
+
+ langID = GetUserDefaultLangID();
+ printf("langID=0x%x\n",langID);
+
+ primLang = (WORD)(PRIMARYLANGID(langID));
+ subLang = (WORD)(SUBLANGID(langID));
+
+ printf("primLang=%d subLang=%d\n",(unsigned)primLang,(unsigned)subLang);
+}
+
+ printf("\n### All Done ###\n\n");
+
+ return 0;
+}
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/wine_GetXXXDefaultLangID.cpp b/src/libs/7zip/unix/CPP/myWindows/wine_GetXXXDefaultLangID.cpp
new file mode 100644
index 000000000..918c4372c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/wine_GetXXXDefaultLangID.cpp
@@ -0,0 +1,741 @@
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <wchar.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef __APPLE__
+#define UInt32 mac_UInt32
+#include <CoreFoundation/CoreFoundation.h>
+#undef UInt32
+#endif // __APPLE__
+
+
+// #define TRACE printf
+
+typedef DWORD LCID;
+typedef void * ULONG_PTR; /* typedef unsigned long ULONG_PTR; */
+
+#define SORT_DEFAULT 0x0
+
+#define LANG_NEUTRAL 0x00
+#define LANG_ENGLISH 0x09
+
+#define SUBLANG_DEFAULT 0x01 /* user default */
+
+#define MAKELCID(l, s) ( (l & 0xFFFF) | ((s & 0xFFFF)<<16))
+#define MAKELANGID(p, s) ((((WORD)(s))<<10) | (WORD)(p))
+
+#define LANGIDFROMLCID(lcid) ((WORD)(lcid))
+
+static LCID lcid_LC_MESSAGES = 0;
+static LCID lcid_LC_CTYPE = 0;
+
+struct locale_name
+{
+ WCHAR win_name[128]; /* Windows name ("en-US") */
+ WCHAR lang[128]; /* language ("en") (note: buffer contains the other strings too) */
+ WCHAR *country; /* country ("US") */
+ WCHAR *charset; /* charset ("UTF-8") for Unix format only */
+ WCHAR *script; /* script ("Latn") for Windows format only */
+ WCHAR *modifier; /* modifier or sort order */
+ LCID lcid; /* corresponding LCID */
+ int matches; /* number of elements matching LCID (0..4) */
+ UINT codepage; /* codepage corresponding to charset */
+};
+#define WINE_UNICODE_INLINE static
+
+/***********************************************************/
+typedef struct {
+ const WCHAR * LOCALE_SNAME;
+ const WCHAR * LOCALE_SISO639LANGNAME;
+ const WCHAR * LOCALE_SISO3166CTRYNAME;
+ unsigned int LOCALE_IDEFAULTUNIXCODEPAGE;
+ unsigned int LOCALE_ILANGUAGE;
+} t_info;
+
+static t_info g_langInfo[] = {
+ { L"af-ZA" , L"af" , L"ZA" , 28591 , 0x0436 }, /* afk.nls */
+ { L"ar-SA" , L"ar" , L"SA" , 28596 , 0x0401 }, /* ara.nls */
+ { L"ar-LB" , L"ar" , L"LB" , 28596 , 0x3001 }, /* arb.nls */
+ { L"ar-EG" , L"ar" , L"EG" , 28596 , 0x0c01 }, /* are.nls */
+ { L"ar-DZ" , L"ar" , L"DZ" , 28596 , 0x1401 }, /* arg.nls */
+ { L"ar-BH" , L"ar" , L"BH" , 28596 , 0x3c01 }, /* arh.nls */
+ { L"ar-IQ" , L"ar" , L"IQ" , 28596 , 0x0801 }, /* ari.nls */
+ { L"ar-JO" , L"ar" , L"JO" , 28596 , 0x2c01 }, /* arj.nls */
+ { L"ar-KW" , L"ar" , L"KW" , 28596 , 0x3401 }, /* ark.nls */
+ { L"ar-LY" , L"ar" , L"LY" , 28596 , 0x1001 }, /* arl.nls */
+ { L"ar-MA" , L"ar" , L"MA" , 28596 , 0x1801 }, /* arm.nls */
+ { L"ar-OM" , L"ar" , L"OM" , 28596 , 0x2001 }, /* aro.nls */
+ { L"ar-QA" , L"ar" , L"QA" , 28596 , 0x4001 }, /* arq.nls */
+ { L"ar-SY" , L"ar" , L"SY" , 28596 , 0x2801 }, /* ars.nls */
+ { L"ar-TN" , L"ar" , L"TN" , 28596 , 0x1c01 }, /* art.nls */
+ { L"ar-AE" , L"ar" , L"AE" , 28596 , 0x3801 }, /* aru.nls */
+ { L"ar-YE" , L"ar" , L"YE" , 28596 , 0x2401 }, /* ary.nls */
+ { L"az-AZ" , L"az" , L"AZ" , 28595 , 0x082c }, /* aze.nls */
+ { L"az-Latn-AZ" , L"az" , L"AZ" , 28599 , 0x042c }, /* azl.nls */
+ { L"be-BY" , L"be" , L"BY" , 1251 , 0x0423 }, /* bel.nls */
+ { L"bg-BG" , L"bg" , L"BG" , 1251 , 0x0402 }, /* bgr.nls */
+ { L"br-FR" , L"br" , L"FR" , 28605 , 0x0493 }, /* brf.nls */
+ { L"ca-ES" , L"ca" , L"ES" , 28605 , 0x0403 }, /* cat.nls */
+ { L"zh-CN" , L"zh" , L"CN" , 936 , 0x0804 }, /* chs.nls */
+ { L"zh-TW" , L"zh" , L"TW" , 950 , 0x0404 }, /* cht.nls */
+ { L"kw-GB" , L"kw" , L"GB" , 28605 , 0x04891 }, /* cor.nls */
+ { L"cs-CZ" , L"cs" , L"CZ" , 28592 , 0x0405 }, /* csy.nls */
+ { L"cy-GB" , L"cy" , L"GB" , 28604 , 0x0492 }, /* cym.nls */
+ { L"da-DK" , L"da" , L"DK" , 28605 , 0x0406 }, /* dan.nls */
+ { L"de-AT" , L"de" , L"AT" , 28605 , 0x0c07 }, /* dea.nls */
+ { L"de-LI" , L"de" , L"LI" , 28605 , 0x1407 }, /* dec.nls */
+ { L"de-LU" , L"de" , L"LU" , 28605 , 0x1007 }, /* del.nls */
+ { L"de-CH" , L"de" , L"CH" , 28605 , 0x0807 }, /* des.nls */
+ { L"de-DE" , L"de" , L"DE" , 28605 , 0x0407 }, /* deu.nls */
+ { L"dv-MV" , L"dv" , L"MV" , 65001 , 0x0465 }, /* div.nls */
+ { L"el-GR" , L"el" , L"GR" , 28597 , 0x0408 }, /* ell.nls */
+ { L"en-AU" , L"en" , L"AU" , 28591 , 0x0c09 }, /* ena.nls */
+ { L"en-CB" , L"en" , L"CB" , 28591 , 0x2409 }, /* enb.nls */
+ { L"en-CA" , L"en" , L"CA" , 28591 , 0x1009 }, /* enc.nls */
+ { L"en-GB" , L"en" , L"GB" , 28605 , 0x0809 }, /* eng.nls */
+ { L"en-IE" , L"en" , L"IE" , 28605 , 0x1809 }, /* eni.nls */
+ { L"en-JM" , L"en" , L"JM" , 28591 , 0x2009 }, /* enj.nls */
+ { L"en-BZ" , L"en" , L"BZ" , 28591 , 0x2809 }, /* enl.nls */
+ { L"en-PH" , L"en" , L"PH" , 28591 , 0x3409 }, /* enp.nls */
+ { L"en-ZA" , L"en" , L"ZA" , 28591 , 0x1c09 }, /* ens.nls */
+ { L"en-TT" , L"en" , L"TT" , 28591 , 0x2c09 }, /* ent.nls */
+ { L"en-US" , L"en" , L"US" , 28591 , 0x0409 }, /* enu.nls */
+ { L"en-ZW" , L"en" , L"ZW" , 28591 , 0x3009 }, /* enw.nls */
+ { L"en-NZ" , L"en" , L"NZ" , 28591 , 0x1409 }, /* enz.nls */
+ { L"eo" , L"eo" , L"" , 65001 , 0x048f }, /* eox.nls */
+ { L"es-PA" , L"es" , L"PA" , 28591 , 0x180a }, /* esa.nls */
+ { L"es-BO" , L"es" , L"BO" , 28591 , 0x400a }, /* esb.nls */
+ { L"es-CR" , L"es" , L"CR" , 28591 , 0x140a }, /* esc.nls */
+ { L"es-DO" , L"es" , L"DO" , 28591 , 0x1c0a }, /* esd.nls */
+ { L"es-SV" , L"es" , L"SV" , 28591 , 0x440a }, /* ese.nls */
+ { L"es-EC" , L"es" , L"EC" , 28591 , 0x300a }, /* esf.nls */
+ { L"es-GT" , L"es" , L"GT" , 28591 , 0x100a }, /* esg.nls */
+ { L"es-HN" , L"es" , L"HN" , 28591 , 0x480a }, /* esh.nls */
+ { L"es-NI" , L"es" , L"NI" , 28591 , 0x4c0a }, /* esi.nls */
+ { L"es-C" , L"es" , L"C" , 28591 , 0x340a }, /* esl.nls */
+ { L"es-MX" , L"es" , L"MX" , 28591 , 0x080a }, /* esm.nls */
+ { L"es-ES_modern" , L"es" , L"ES" , 28605 , 0x0c0a }, /* esn.nls */
+ { L"es-CO" , L"es" , L"CO" , 28591 , 0x240a }, /* eso.nls */
+ { L"es-ES" , L"es" , L"ES" , 28605 , 0x040a }, /* esp.nls */
+ { L"es-PE" , L"es" , L"PE" , 28591 , 0x280a }, /* esr.nls */
+ { L"es-AR" , L"es" , L"AR" , 28591 , 0x2c0a }, /* ess.nls */
+ { L"es-PR" , L"es" , L"PR" , 28591 , 0x500a }, /* esu.nls */
+ { L"es-VE" , L"es" , L"VE" , 28591 , 0x200a }, /* esv.nls */
+ { L"es-UY" , L"es" , L"UY" , 28591 , 0x380a }, /* esy.nls */
+ { L"es-PY" , L"es" , L"PY" , 28591 , 0x3c0a }, /* esz.nls */
+ { L"et-EE" , L"et" , L"EE" , 28605 , 0x0425 }, /* eti.nls */
+ { L"eu-ES" , L"eu" , L"ES" , 28605 , 0x042d }, /* euq.nls */
+ { L"fa-IR" , L"fa" , L"IR" , 65001 , 0x0429 }, /* far.nls */
+ { L"fi-FI" , L"fi" , L"FI" , 28605 , 0x040b }, /* fin.nls */
+ { L"fo-FO" , L"fo" , L"FO" , 28605 , 0x0438 }, /* fos.nls */
+ { L"fr-FR" , L"fr" , L"FR" , 28605 , 0x040c }, /* fra.nls */
+ { L"fr-BE" , L"fr" , L"BE" , 28605 , 0x080c }, /* frb.nls */
+ { L"fr-CA" , L"fr" , L"CA" , 28591 , 0x0c0c }, /* frc.nls */
+ { L"fr-LU" , L"fr" , L"LU" , 28605 , 0x140c }, /* frl.nls */
+ { L"fr-MC" , L"fr" , L"MC" , 28605 , 0x180c }, /* frm.nls */
+ { L"fr-CH" , L"fr" , L"CH" , 28605 , 0x100c }, /* frs.nls */
+ { L"ga-IE" , L"ga" , L"IE" , 28605 , 0x043c }, /* gae.nls */
+ { L"gd-GB" , L"gd" , L"GB" , 28605 , 0x083c }, /* gdh.nls */
+ { L"gv-GB" , L"gv" , L"GB" , 28605 , 0x0c3c }, /* gdv.nls */
+ { L"gl-ES" , L"gl" , L"ES" , 28605 , 0x0456 }, /* glc.nls */
+ { L"gu-IN" , L"gu" , L"IN" , 65001 , 0x0447 }, /* guj.nls */
+ { L"he-I" , L"he" , L"I" , 28598 , 0x040d }, /* heb.nls */
+ { L"hi-IN" , L"hi" , L"IN" , 65001 , 0x0439 }, /* hin.nls */
+ { L"hr-HR" , L"hr" , L"HR" , 28592 , 0x041a }, /* hrv.nls */
+ { L"hu-HU" , L"hu" , L"HU" , 28592 , 0x040e }, /* hun.nls */
+ { L"hy-AM" , L"hy" , L"AM" , 65001 , 0x042b }, /* hye.nls */
+ { L"id-ID" , L"id" , L"ID" , 28591 , 0x0421 }, /* ind.nls */
+ { L"is-IS" , L"is" , L"IS" , 28605 , 0x040f }, /* isl.nls */
+ { L"it-IT" , L"it" , L"IT" , 28605 , 0x0410 }, /* ita.nls */
+ { L"it-CH" , L"it" , L"CH" , 28605 , 0x0810 }, /* its.nls */
+ { L"ja-JP" , L"ja" , L"JP" , 20932 , 0x0411 }, /* jpn.nls */
+ { L"kn-IN" , L"kn" , L"IN" , 65001 , 0x044b }, /* kan.nls */
+ { L"ka-GE" , L"ka" , L"GE" , 65001 , 0x0437 }, /* kat.nls */
+ { L"kk-KZ" , L"kk" , L"KZ" , 28595 , 0x043f }, /* kkz.nls */
+ { L"kok-IN" , L"kok" , L"IN" , 65001 , 0x0457 }, /* knk.nls */
+ { L"ko-KR" , L"ko" , L"KR" , 949 , 0x0412 }, /* kor.nls */
+ { L"ky-KG" , L"ky" , L"KG" , 28595 , 0x0440 }, /* kyr.nls */
+ { L"lt-LT" , L"lt" , L"LT" , 28603 , 0x0427 }, /* lth.nls */
+ { L"lv-LV" , L"lv" , L"LV" , 28603 , 0x0426 }, /* lvi.nls */
+ { L"mr-IN" , L"mr" , L"IN" , 65001 , 0x044e }, /* mar.nls */
+ { L"mk-MK" , L"mk" , L"MK" , 28595 , 0x042f }, /* mki.nls */
+ { L"mn-MN" , L"mn" , L"MN" , 28595 , 0x0450 }, /* mon.nls */
+ { L"ms-BN" , L"ms" , L"BN" , 28591 , 0x083e }, /* msb.nls */
+ { L"ms-MY" , L"ms" , L"MY" , 28591 , 0x043e }, /* msl.nls */
+ { L"nl-BE" , L"nl" , L"BE" , 28605 , 0x0813 }, /* nlb.nls */
+ { L"nl-N" , L"nl" , L"N" , 28605 , 0x0413 }, /* nld.nls */
+ { L"nl-SR" , L"nl" , L"SR" , 28605 , 0x0c13 }, /* nls.nls */
+ { L"nn-NO" , L"nn" , L"NO" , 28605 , 0x0814 }, /* non.nls */
+ { L"nb-NO" , L"nb" , L"NO" , 28605 , 0x0414 }, /* nor.nls */
+ { L"pa-IN" , L"pa" , L"IN" , 65001 , 0x0446 }, /* pan.nls */
+ { L"pl-P" , L"pl" , L"P" , 28592 , 0x0415 }, /* plk.nls */
+ { L"pt-BR" , L"pt" , L"BR" , 28591 , 0x0416 }, /* ptb.nls */
+ { L"pt-PT" , L"pt" , L"PT" , 28605 , 0x0816 }, /* ptg.nls */
+ { L"rm-CH" , L"rm" , L"CH" , 28605 , 0x0417 }, /* rmc.nls */
+ { L"ro-RO" , L"ro" , L"RO" , 28592 , 0x0418 }, /* rom.nls */
+ { L"ru-RU" , L"ru" , L"RU" , 20866 , 0x0419 }, /* rus.nls */
+ { L"sa-IN" , L"sa" , L"IN" , 65001 , 0x044f }, /* san.nls */
+ { L"sk-SK" , L"sk" , L"SK" , 28592 , 0x041b }, /* sky.nls */
+ { L"sl-SI" , L"sl" , L"SI" , 28592 , 0x0424 }, /* slv.nls */
+ { L"sq-A" , L"sq" , L"A" , 28592 , 0x041c }, /* sqi.nls */
+ { L"sr-SP" , L"sr" , L"SP" , 28595 , 0x0c1a }, /* srb.nls */
+ { L"sr-Latn-SP" , L"sr" , L"SP" , 28592 , 0x081a }, /* srl.nls */
+ { L"sv-SE" , L"sv" , L"SE" , 28605 , 0x041d }, /* sve.nls */
+ { L"sv-FI" , L"sv" , L"FI" , 28605 , 0x081d }, /* svf.nls */
+ { L"sw-KE" , L"sw" , L"KE" , 28591 , 0x0441 }, /* swk.nls */
+ { L"syr-SY" , L"syr" , L"SY" , 65001 , 0x045a }, /* syr.nls */
+ { L"ta-IN" , L"ta" , L"IN" , 65001 , 0x0449 }, /* tam.nls */
+ { L"te-IN" , L"te" , L"IN" , 65001 , 0x044a }, /* tel.nls */
+ { L"th-TH" , L"th" , L"TH" , 874 , 0x041e }, /* tha.nls */
+ { L"tr-TR" , L"tr" , L"TR" , 28599 , 0x041f }, /* trk.nls */
+ { L"tt-TA" , L"tt" , L"TA" , 28595 , 0x0444 }, /* ttt.nls */
+ { L"uk-UA" , L"uk" , L"UA" , 21866 , 0x0422 }, /* ukr.nls */
+ { L"ur-PK" , L"ur" , L"PK" , 1256 , 0x0420 }, /* urd.nls */
+ { L"uz-UZ" , L"uz" , L"UZ" , 28595 , 0x0843 }, /* uzb.nls */
+ { L"uz-Latn-UZ" , L"uz" , L"UZ" , 28605 , 0x0443 }, /* uzl.nls */
+ { L"vi-VN" , L"vi" , L"VN" , 1258 , 0x042a }, /* vit.nls */
+ { L"wa-BE" , L"wa" , L"BE" , 28605 , 0x0490 }, /* wal.nls */
+ { L"zh-HK" , L"zh" , L"HK" , 950 , 0x0c04 }, /* zhh.nls */
+ { L"zh-SG" , L"zh" , L"SG" , 936 , 0x1004 }, /* zhi.nls */
+ { L"zh-MO" , L"zh" , L"MO" , 950 , 0x1404 }, /* zhm.nls */
+ { 0 , 0 , 0 , 0, 0 }
+};
+
+/***********************************************************/
+WINE_UNICODE_INLINE WCHAR *strchrW( const WCHAR *str, WCHAR ch )
+{
+ do { if (*str == ch) return (WCHAR *)(ULONG_PTR)str; } while (*str++);
+ return NULL;
+}
+
+WINE_UNICODE_INLINE WCHAR *strpbrkW( const WCHAR *str, const WCHAR *accept )
+{
+ for ( ; *str; str++) if (strchrW( accept, *str )) return (WCHAR *)(ULONG_PTR)str;
+ return NULL;
+}
+
+
+/***********************************************************/
+
+WINE_UNICODE_INLINE unsigned int strlenW( const WCHAR *str )
+{
+ const WCHAR *s = str;
+ while (*s) s++;
+ return s - str;
+}
+
+WINE_UNICODE_INLINE WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
+{
+ WCHAR *p = dst;
+ while ((*p++ = *src++));
+ return dst;
+}
+
+WINE_UNICODE_INLINE WCHAR *strcatW( WCHAR *dst, const WCHAR *src )
+{
+ strcpyW( dst + strlenW(dst), src );
+ return dst;
+}
+
+WINE_UNICODE_INLINE int strcmpW( const WCHAR *str1, const WCHAR *str2 )
+{
+ while (*str1 && (*str1 == *str2)) { str1++; str2++; }
+ return *str1 - *str2;
+}
+
+
+WINE_UNICODE_INLINE LPWSTR lstrcpynW( LPWSTR dst, LPCWSTR src, int n )
+{
+ {
+ LPWSTR d = dst;
+ LPCWSTR s = src;
+ UINT count = n;
+
+ while ((count > 1) && *s)
+ {
+ count--;
+ *d++ = *s++;
+ }
+ if (count) *d = 0;
+ }
+ return dst;
+}
+
+/* Copy Ascii string to Unicode without using codepages */
+static inline void strcpynAtoW( WCHAR *dst, const char *src, size_t n )
+{
+ while (n > 1 && *src)
+ {
+ *dst++ = (unsigned char)*src++;
+ n--;
+ }
+ if (n) *dst = 0;
+}
+
+/*******************************************************/
+
+/* Charset to codepage map, sorted by name. */
+static const struct charset_entry
+{
+ const char *charset_name;
+ UINT codepage;
+} charset_names[] =
+{
+ { "BIG5", 950 },
+ { "CP1250", 1250 },
+ { "CP1251", 1251 },
+ { "CP1252", 1252 },
+ { "CP1253", 1253 },
+ { "CP1254", 1254 },
+ { "CP1255", 1255 },
+ { "CP1256", 1256 },
+ { "CP1257", 1257 },
+ { "CP1258", 1258 },
+ { "CP932", 932 },
+ { "CP936", 936 },
+ { "CP949", 949 },
+ { "CP950", 950 },
+ { "EUCJP", 20932 },
+ { "GB2312", 936 },
+ { "IBM037", 37 },
+ { "IBM1026", 1026 },
+ { "IBM424", 424 },
+ { "IBM437", 437 },
+ { "IBM500", 500 },
+ { "IBM850", 850 },
+ { "IBM852", 852 },
+ { "IBM855", 855 },
+ { "IBM857", 857 },
+ { "IBM860", 860 },
+ { "IBM861", 861 },
+ { "IBM862", 862 },
+ { "IBM863", 863 },
+ { "IBM864", 864 },
+ { "IBM865", 865 },
+ { "IBM866", 866 },
+ { "IBM869", 869 },
+ { "IBM874", 874 },
+ { "IBM875", 875 },
+ { "ISO88591", 28591 },
+ { "ISO885910", 28600 },
+ { "ISO885913", 28603 },
+ { "ISO885914", 28604 },
+ { "ISO885915", 28605 },
+ { "ISO885916", 28606 },
+ { "ISO88592", 28592 },
+ { "ISO88593", 28593 },
+ { "ISO88594", 28594 },
+ { "ISO88595", 28595 },
+ { "ISO88596", 28596 },
+ { "ISO88597", 28597 },
+ { "ISO88598", 28598 },
+ { "ISO88599", 28599 },
+ { "KOI8R", 20866 },
+ { "KOI8U", 21866 },
+ { "UTF8", CP_UTF8 }
+};
+
+static int charset_cmp( const void *name, const void *entry )
+{
+ const struct charset_entry *charset = (const struct charset_entry *)entry;
+ return strcasecmp( (const char *)name, charset->charset_name );
+}
+
+static UINT find_charset( const WCHAR *name )
+{
+ const struct charset_entry *entry;
+ char charset_name[16];
+ size_t i, j;
+
+ /* remove punctuation characters from charset name */
+ for (i = j = 0; name[i] && j < sizeof(charset_name)-1; i++)
+ if (isalnum((unsigned char)name[i])) charset_name[j++] = name[i];
+ charset_name[j] = 0;
+
+ entry = (const struct charset_entry *)bsearch( charset_name, charset_names,
+ sizeof(charset_names)/sizeof(charset_names[0]),
+ sizeof(charset_names[0]), charset_cmp );
+ if (entry) return entry->codepage;
+
+ return 0;
+}
+/*******************************************************/
+
+static BOOL find_locale_id_callback(/* LPCWSTR name, ? */ const t_info * tab, struct locale_name *data)
+{
+ // WCHAR buffer[128];
+ int matches = 0;
+ WORD LangID = tab->LOCALE_ILANGUAGE & 0xFFFF; /* FIXME */
+ LCID lcid = MAKELCID( LangID, SORT_DEFAULT ); /* FIXME: handle sort order */
+
+ if (PRIMARYLANGID(LangID) == LANG_NEUTRAL) return TRUE; /* continue search */
+
+ /* first check exact name */
+ if (data->win_name[0] && tab->LOCALE_SNAME[0])
+ /* GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE,
+ buffer, sizeof(buffer)/sizeof(WCHAR) )) */
+ {
+ if (!strcmpW( data->win_name, tab->LOCALE_SNAME ))
+ {
+ matches = 4; /* everything matches */
+ goto done;
+ }
+ }
+
+ /*if (!GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME | LOCALE_NOUSEROVERRIDE,
+ buffer, sizeof(buffer)/sizeof(WCHAR) )) */
+ if (tab->LOCALE_SISO639LANGNAME[0] == 0)
+ return TRUE;
+
+ if (strcmpW( tab->LOCALE_SISO639LANGNAME , data->lang )) return TRUE;
+ matches++; /* language name matched */
+
+ if (data->country)
+ {
+ /* if (GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE,
+ buffer, sizeof(buffer)/sizeof(WCHAR) )) */
+ if (tab->LOCALE_SISO3166CTRYNAME[0])
+ {
+ if (strcmpW(tab->LOCALE_SISO3166CTRYNAME , data->country )) goto done;
+ matches++; /* country name matched */
+ }
+ }
+ else /* match default language */
+ {
+ if (SUBLANGID(LangID) == SUBLANG_DEFAULT) matches++;
+ }
+
+ if (data->codepage)
+ {
+ UINT unix_cp;
+ /* if (GetLocaleInfoW( lcid, LOCALE_IDEFAULTUNIXCODEPAGE | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&unix_cp, sizeof(unix_cp)/sizeof(WCHAR) )) */
+ unix_cp = tab->LOCALE_IDEFAULTUNIXCODEPAGE;
+ {
+ if (unix_cp == data->codepage) matches++;
+ }
+ }
+
+ /* FIXME: check sort order */
+
+done:
+ if (matches > data->matches)
+ {
+ data->lcid = lcid;
+ data->matches = matches;
+ }
+ return (data->matches < 4); /* no need to continue for perfect match */
+}
+
+
+/***********************************************************************
+ * parse_locale_name
+ *
+ * Parse a locale name into a struct locale_name, handling both Windows and Unix formats.
+ * Unix format is: lang[_country][.charset][@modifier]
+ * Windows format is: lang[-script][-country][_modifier]
+ */
+static void parse_locale_name( const WCHAR *str, struct locale_name *name )
+{
+ static const WCHAR sepW[] = {'-','_','.','@',0};
+ static const WCHAR winsepW[] = {'-','_',0};
+ static const WCHAR posixW[] = {'P','O','S','I','X',0};
+ static const WCHAR cW[] = {'C',0};
+ static const WCHAR latinW[] = {'l','a','t','i','n',0};
+ static const WCHAR latnW[] = {'-','L','a','t','n',0};
+ WCHAR *p;
+ int ind;
+
+ // TRACE("%s\n", debugstr_w(str));
+
+ name->country = name->charset = name->script = name->modifier = NULL;
+ name->lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
+ name->matches = 0;
+ name->codepage = 0;
+ name->win_name[0] = 0;
+ lstrcpynW( name->lang, str, sizeof(name->lang)/sizeof(WCHAR) );
+
+ if (!(p = strpbrkW( name->lang, sepW )))
+ {
+ if (!strcmpW( name->lang, posixW ) || !strcmpW( name->lang, cW ))
+ {
+ name->matches = 4; /* perfect match for default English lcid */
+ return;
+ }
+ strcpyW( name->win_name, name->lang );
+ }
+ else if (*p == '-') /* Windows format */
+ {
+ strcpyW( name->win_name, name->lang );
+ *p++ = 0;
+ name->country = p;
+ if (!(p = strpbrkW( p, winsepW ))) goto done;
+ if (*p == '-')
+ {
+ *p++ = 0;
+ name->script = name->country;
+ name->country = p;
+ if (!(p = strpbrkW( p, winsepW ))) goto done;
+ }
+ *p++ = 0;
+ name->modifier = p;
+ }
+ else /* Unix format */
+ {
+ if (*p == '_')
+ {
+ *p++ = 0;
+ name->country = p;
+ p = strpbrkW( p, sepW + 2 );
+ }
+ if (p && *p == '.')
+ {
+ *p++ = 0;
+ name->charset = p;
+ p = strchrW( p, '@' );
+ }
+ if (p)
+ {
+ *p++ = 0;
+ name->modifier = p;
+ }
+
+ if (name->charset)
+ name->codepage = find_charset( name->charset );
+
+ /* rebuild a Windows name if possible */
+
+ if (name->charset) goto done; /* can't specify charset in Windows format */
+ if (name->modifier && strcmpW( name->modifier, latinW ))
+ goto done; /* only Latn script supported for now */
+ strcpyW( name->win_name, name->lang );
+ if (name->modifier) strcatW( name->win_name, latnW );
+ if (name->country)
+ {
+ p = name->win_name + strlenW(name->win_name);
+ *p++ = '-';
+ strcpyW( p, name->country );
+ }
+ }
+done:
+ ;
+
+/* DEBUG
+ printf("EnumResourceLanguagesW(...):\n");
+ printf(" name->win_name=%ls\n", name->win_name);
+ printf(" name->lang=%ls\n", name->lang);
+ printf(" name->country=%ls\n", name->country);
+ printf(" name->codepage=%d\n", name->codepage);
+*/
+// EnumResourceLanguagesW( kernel32_handle, (LPCWSTR)RT_STRING, (LPCWSTR)LOCALE_ILANGUAGE,
+// find_locale_id_callback, (LPARAM)name );
+
+ ind = 0;
+ while (g_langInfo[ind].LOCALE_SNAME)
+ {
+ BOOL ret = find_locale_id_callback(&g_langInfo[ind],name);
+ if (ret == FALSE)
+ break;
+
+ ind++;
+ }
+}
+
+
+
+
+/********************************/
+
+static UINT setup_unix_locales(void)
+{
+ struct locale_name locale_name;
+ // WCHAR buffer[128];
+ WCHAR ctype_buff[128];
+ char *locale;
+ UINT unix_cp = 0;
+
+ if ((locale = setlocale( LC_CTYPE, NULL )))
+ {
+ strcpynAtoW( ctype_buff, locale, sizeof(ctype_buff)/sizeof(WCHAR) );
+ parse_locale_name( ctype_buff, &locale_name );
+ lcid_LC_CTYPE = locale_name.lcid;
+ unix_cp = locale_name.codepage;
+ }
+ if (!lcid_LC_CTYPE) /* this one needs a default value */
+ lcid_LC_CTYPE = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
+
+#if 0
+ TRACE( "got lcid %04x (%d matches) for LC_CTYPE=%s\n",
+ locale_name.lcid, locale_name.matches, debugstr_a(locale) );
+
+#define GET_UNIX_LOCALE(cat) do \
+ if ((locale = setlocale( cat, NULL ))) \
+ { \
+ strcpynAtoW( buffer, locale, sizeof(buffer)/sizeof(WCHAR) ); \
+ if (!strcmpW( buffer, ctype_buff )) lcid_##cat = lcid_LC_CTYPE; \
+ else { \
+ parse_locale_name( buffer, &locale_name ); \
+ lcid_##cat = locale_name.lcid; \
+ TRACE( "got lcid %04x (%d matches) for " #cat "=%s\n", \
+ locale_name.lcid, locale_name.matches, debugstr_a(locale) ); \
+ } \
+ } while (0)
+
+ GET_UNIX_LOCALE( LC_COLLATE );
+ GET_UNIX_LOCALE( LC_MESSAGES );
+ GET_UNIX_LOCALE( LC_MONETARY );
+ GET_UNIX_LOCALE( LC_NUMERIC );
+ GET_UNIX_LOCALE( LC_TIME );
+#ifdef LC_PAPER
+ GET_UNIX_LOCALE( LC_PAPER );
+#endif
+#ifdef LC_MEASUREMENT
+ GET_UNIX_LOCALE( LC_MEASUREMENT );
+#endif
+#ifdef LC_TELEPHONE
+ GET_UNIX_LOCALE( LC_TELEPHONE );
+#endif
+
+#undef GET_UNIX_LOCALE
+
+#endif // #if 0
+
+ return unix_cp;
+}
+
+/********************************/
+
+static void LOCALE_Init(void)
+{
+ /*
+ extern void __wine_init_codepages( const union cptable *ansi_cp, const union cptable *oem_cp,
+ const union cptable *unix_cp );
+ */
+
+ // UINT ansi_cp = 1252, oem_cp = 437, mac_cp = 10000, unix_cp;
+ UINT unix_cp = 0;
+
+#ifdef __APPLE__
+ /* MacOS doesn't set the locale environment variables so we have to do it ourselves */
+ CFArrayRef preferred_locales, all_locales;
+ CFStringRef user_language_string_ref = NULL;
+ char user_locale[50];
+
+ CFLocaleRef user_locale_ref = CFLocaleCopyCurrent();
+ CFStringRef user_locale_string_ref = CFLocaleGetIdentifier( user_locale_ref );
+
+ CFStringGetCString( user_locale_string_ref, user_locale, sizeof(user_locale), kCFStringEncodingUTF8 );
+ CFRelease( user_locale_ref );
+ if (!strchr( user_locale, '.' )) strcat( user_locale, ".UTF-8" );
+ unix_cp = CP_UTF8; /* default to utf-8 even if we don't get a valid locale */
+ setenv( "LANG", user_locale, 0 );
+ // TRACE( "setting locale to '%s'\n", user_locale );
+
+ /* We still want to set the retrieve the preferred language as chosen in
+ System Preferences.app, because it can differ from CFLocaleCopyCurrent().
+ */
+ all_locales = CFLocaleCopyAvailableLocaleIdentifiers();
+ preferred_locales = CFBundleCopyLocalizationsForPreferences( all_locales, NULL );
+ if (preferred_locales && CFArrayGetCount( preferred_locales ))
+ user_language_string_ref = (CFStringRef)CFArrayGetValueAtIndex( preferred_locales, 0 ); // FIXME
+ CFRelease( all_locales );
+#endif /* __APPLE__ */
+
+ // FIXME setlocale( LC_ALL, "" );
+
+ unix_cp = setup_unix_locales();
+ if (!lcid_LC_MESSAGES) lcid_LC_MESSAGES = lcid_LC_CTYPE;
+
+#ifdef __APPLE__
+ /* Override lcid_LC_MESSAGES with user_language if LC_MESSAGES is set to default */
+ if (lcid_LC_MESSAGES == lcid_LC_CTYPE && user_language_string_ref)
+ {
+ struct locale_name locale_name;
+ WCHAR buffer[128];
+ CFStringGetCString( user_language_string_ref, user_locale, sizeof(user_locale), kCFStringEncodingUTF8 );
+ strcpynAtoW( buffer, user_locale, sizeof(buffer)/sizeof(WCHAR) );
+ parse_locale_name( buffer, &locale_name );
+ lcid_LC_MESSAGES = locale_name.lcid;
+ // TRACE( "setting lcid_LC_MESSAGES to '%s'\n", user_locale );
+ }
+ if (preferred_locales)
+ CFRelease( preferred_locales );
+#endif
+
+#if 0 // FIXME
+ NtSetDefaultUILanguage( LANGIDFROMLCID(lcid_LC_MESSAGES) );
+ NtSetDefaultLocale( TRUE, lcid_LC_MESSAGES );
+ NtSetDefaultLocale( FALSE, lcid_LC_CTYPE );
+
+ ansi_cp = get_lcid_codepage( LOCALE_USER_DEFAULT );
+ GetLocaleInfoW( LOCALE_USER_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&mac_cp, sizeof(mac_cp)/sizeof(WCHAR) );
+ GetLocaleInfoW( LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR) );
+ if (!unix_cp)
+ GetLocaleInfoW( LOCALE_USER_DEFAULT, LOCALE_IDEFAULTUNIXCODEPAGE | LOCALE_RETURN_NUMBER,
+ (LPWSTR)&unix_cp, sizeof(unix_cp)/sizeof(WCHAR) );
+
+ if (!(ansi_cptable = wine_cp_get_table( ansi_cp )))
+ ansi_cptable = wine_cp_get_table( 1252 );
+ if (!(oem_cptable = wine_cp_get_table( oem_cp )))
+ oem_cptable = wine_cp_get_table( 437 );
+ if (!(mac_cptable = wine_cp_get_table( mac_cp )))
+ mac_cptable = wine_cp_get_table( 10000 );
+ if (unix_cp != CP_UTF8)
+ {
+ if (!(unix_cptable = wine_cp_get_table( unix_cp )))
+ unix_cptable = wine_cp_get_table( 28591 );
+ }
+
+ __wine_init_codepages( ansi_cptable, oem_cptable, unix_cptable );
+
+ TRACE( "ansi=%03d oem=%03d mac=%03d unix=%03d\n",
+ ansi_cptable->info.codepage, oem_cptable->info.codepage,
+ mac_cptable->info.codepage, unix_cp );
+
+ setlocale(LC_NUMERIC, "C"); /* FIXME: oleaut32 depends on this */
+#endif
+}
+
+LANGID GetUserDefaultLangID(void)
+{
+ // return LANGIDFROMLCID(GetUserDefaultLCID());
+ if (lcid_LC_MESSAGES == 0) LOCALE_Init();
+ return LANGIDFROMLCID(lcid_LC_MESSAGES);
+}
+
+LANGID GetSystemDefaultLangID(void)
+{
+ // return LANGIDFROMLCID(GetSystemDefaultLCID());
+ if (lcid_LC_MESSAGES == 0) LOCALE_Init();
+ return LANGIDFROMLCID(lcid_LC_MESSAGES);
+}
+
+#ifdef TEST
+int main()
+{
+ LANGID langID;
+ WORD primLang;
+ WORD subLang;
+
+ setlocale( LC_ALL, "" );
+
+ langID = GetUserDefaultLangID();
+ printf("langID=0x%x\n",langID);
+
+ primLang = (WORD)(PRIMARYLANGID(langID));
+ subLang = (WORD)(SUBLANGID(langID));
+
+ printf("primLang=%d subLang=%d\n",(unsigned)primLang,(unsigned)subLang);
+
+ return 0;
+}
+#endif
+
diff --git a/src/libs/7zip/unix/CPP/myWindows/wine_date_and_time.cpp b/src/libs/7zip/unix/CPP/myWindows/wine_date_and_time.cpp
new file mode 100644
index 000000000..6d7f83a0c
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/myWindows/wine_date_and_time.cpp
@@ -0,0 +1,434 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h> /* gettimeofday */
+#include <dirent.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <windows.h>
+
+// #define TRACEN(u) u;
+#define TRACEN(u) /* */
+
+typedef LONG NTSTATUS;
+#define STATUS_SUCCESS 0x00000000
+
+#define TICKSPERSEC 10000000
+#define TICKSPERMSEC 10000
+#define SECSPERDAY 86400
+#define SECSPERHOUR 3600
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define EPOCHWEEKDAY 1 /* Jan 1, 1601 was Monday */
+#define DAYSPERWEEK 7
+#define EPOCHYEAR 1601
+#define DAYSPERNORMALYEAR 365
+#define DAYSPERLEAPYEAR 366
+#define MONSPERYEAR 12
+#define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
+#define DAYSPERNORMALCENTURY (365 * 100 + 24)
+#define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
+
+/* 1601 to 1970 is 369 years plus 89 leap days */
+#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
+#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
+/* 1601 to 1980 is 379 years plus 91 leap days */
+#define SECS_1601_TO_1980 ((379 * 365 + 91) * (ULONGLONG)SECSPERDAY)
+#define TICKS_1601_TO_1980 (SECS_1601_TO_1980 * TICKSPERSEC)
+typedef short CSHORT;
+
+static LONG TIME_GetBias() {
+ time_t utc = time(NULL);
+ struct tm *ptm = localtime(&utc);
+ int localdaylight = ptm->tm_isdst; /* daylight for local timezone */
+ ptm = gmtime(&utc);
+ ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */
+ LONG bias = (int)(mktime(ptm)-utc);
+ TRACEN((printf("TIME_GetBias %ld\n",(long)bias)))
+ return bias;
+}
+
+static inline void RtlSystemTimeToLocalTime( const LARGE_INTEGER *SystemTime,
+ LARGE_INTEGER *LocalTime ) {
+ LONG bias = TIME_GetBias();
+ LocalTime->QuadPart = SystemTime->QuadPart - bias * (LONGLONG)TICKSPERSEC;
+}
+
+void WINAPI RtlSecondsSince1970ToFileTime( DWORD Seconds, FILETIME * ft ) {
+ ULONGLONG secs = Seconds * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
+ ft->dwLowDateTime = (DWORD)secs;
+ ft->dwHighDateTime = (DWORD)(secs >> 32);
+ TRACEN((printf("RtlSecondsSince1970ToFileTime %lx => %lx %lx\n",(long)Seconds,(long)ft->dwHighDateTime,(long)ft->dwLowDateTime)))
+}
+
+/*
+void WINAPI RtlSecondsSince1970ToTime( DWORD Seconds, LARGE_INTEGER *Time )
+{
+ ULONGLONG secs = Seconds * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
+ // Time->u.LowPart = (DWORD)secs; Time->u.HighPart = (DWORD)(secs >> 32);
+ Time->QuadPart = secs;
+}
+ */
+
+BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, FILETIME * ft)
+{
+ struct tm newtm;
+#ifndef ENV_HAVE_TIMEGM
+ struct tm *gtm;
+ time_t time1, time2;
+#endif
+
+ TRACEN((printf("DosDateTimeToFileTime\n")))
+
+ newtm.tm_sec = (fattime & 0x1f) * 2;
+ newtm.tm_min = (fattime >> 5) & 0x3f;
+ newtm.tm_hour = (fattime >> 11);
+ newtm.tm_mday = (fatdate & 0x1f);
+ newtm.tm_mon = ((fatdate >> 5) & 0x0f) - 1;
+ newtm.tm_year = (fatdate >> 9) + 80;
+ newtm.tm_isdst = -1;
+#ifdef ENV_HAVE_TIMEGM
+ RtlSecondsSince1970ToFileTime( timegm(&newtm), ft );
+#else
+ newtm.tm_isdst = 0;
+ time1 = mktime(&newtm);
+ gtm = gmtime(&time1);
+ time2 = mktime(gtm);
+ RtlSecondsSince1970ToFileTime( 2*time1-time2, ft );
+#endif
+ TRACEN((printf("DosDateTimeToFileTime(%ld,%ld) => %lx %lx\n",
+ (long)fatdate,(long)fattime,
+ (long)ft->dwHighDateTime,(long)ft->dwLowDateTime)))
+
+ return TRUE;
+}
+
+/*
+BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, FILETIME * ft) {
+ struct tm newtm;
+
+ TRACEN((printf("DosDateTimeToFileTime\n")))
+
+ memset(&newtm,0,sizeof(newtm));
+ newtm.tm_sec = (fattime & 0x1f) * 2;
+ newtm.tm_min = (fattime >> 5) & 0x3f;
+ newtm.tm_hour = (fattime >> 11);
+ newtm.tm_mday = (fatdate & 0x1f);
+ newtm.tm_mon = ((fatdate >> 5) & 0x0f) - 1;
+ newtm.tm_year = (fatdate >> 9) + 80;
+ newtm.tm_isdst = -1;
+
+ time_t time1 = mktime(&newtm);
+ LONG bias = TIME_GetBias();
+ RtlSecondsSince1970ToFileTime( time1 - bias, ft );
+
+
+ TRACEN((printf("DosDateTimeToFileTime(%ld,%ld) t1=%ld => %lx %lx\n",
+ (long)fatdate,(long)fattime,(long)time1,
+ (long)ft->dwHighDateTime,(long)ft->dwLowDateTime)))
+
+ return TRUE;
+}
+*/
+
+BOOLEAN WINAPI RtlTimeToSecondsSince1970( const LARGE_INTEGER *Time, DWORD *Seconds ) {
+ ULONGLONG tmp = Time->QuadPart;
+ TRACEN((printf("RtlTimeToSecondsSince1970-1 %llx\n",tmp)))
+ tmp /= TICKSPERSEC;
+ tmp -= SECS_1601_TO_1970;
+ TRACEN((printf("RtlTimeToSecondsSince1970-2 %llx\n",tmp)))
+ if (tmp > 0xffffffff) return FALSE;
+ *Seconds = (DWORD)tmp;
+ return TRUE;
+}
+
+BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, WORD *fatdate, WORD *fattime ) {
+ LARGE_INTEGER li;
+ ULONG t;
+ time_t unixtime;
+ struct tm* tm;
+ WORD fat_d,fat_t;
+
+ TRACEN((printf("FileTimeToDosDateTime\n")))
+ li.QuadPart = ft->dwHighDateTime;
+ li.QuadPart = (li.QuadPart << 32) | ft->dwLowDateTime;
+ RtlTimeToSecondsSince1970( &li, &t );
+ unixtime = t; /* unixtime = t; * FIXME unixtime = t - TIME_GetBias(); */
+
+ tm = gmtime( &unixtime );
+
+ fat_t = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2);
+ fat_d = ((tm->tm_year - 80) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday;
+ if (fattime)
+ *fattime = fat_t;
+ if (fatdate)
+ *fatdate = fat_d;
+
+ TRACEN((printf("FileTimeToDosDateTime : %lx %lx => %d %d\n",
+ (long)ft->dwHighDateTime,(long)ft->dwLowDateTime,(unsigned)fat_d,(unsigned)fat_t)))
+
+ return TRUE;
+}
+
+BOOL WINAPI FileTimeToLocalFileTime( const FILETIME *utcft, FILETIME * localft ) {
+ LARGE_INTEGER local, utc;
+
+ TRACEN((printf("FileTimeToLocalFileTime\n")))
+ utc.QuadPart = utcft->dwHighDateTime;
+ utc.QuadPart = (utc.QuadPart << 32) | utcft->dwLowDateTime;
+ RtlSystemTimeToLocalTime( &utc, &local );
+ localft->dwLowDateTime = (DWORD)local.QuadPart;
+ localft->dwHighDateTime = (DWORD)(local.QuadPart >> 32);
+
+ return TRUE;
+}
+
+typedef struct _TIME_FIELDS {
+ CSHORT Year;
+ CSHORT Month;
+ CSHORT Day;
+ CSHORT Hour;
+ CSHORT Minute;
+ CSHORT Second;
+ CSHORT Milliseconds;
+ CSHORT Weekday;
+} TIME_FIELDS;
+
+static const int MonthLengths[2][MONSPERYEAR] =
+{
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static inline int IsLeapYear(int Year) {
+ return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
+}
+
+static inline VOID WINAPI RtlTimeToTimeFields(
+ const LARGE_INTEGER *liTime,
+ TIME_FIELDS * TimeFields) {
+ int SecondsInDay;
+ long int cleaps, years, yearday, months;
+ long int Days;
+ LONGLONG Time;
+
+ /* Extract millisecond from time and convert time into seconds */
+ TimeFields->Milliseconds =
+ (CSHORT) (( liTime->QuadPart % TICKSPERSEC) / TICKSPERMSEC);
+ Time = liTime->QuadPart / TICKSPERSEC;
+
+ /* The native version of RtlTimeToTimeFields does not take leap seconds
+ * into account */
+
+ /* Split the time into days and seconds within the day */
+ Days = Time / SECSPERDAY;
+ SecondsInDay = Time % SECSPERDAY;
+
+ /* compute time of day */
+ TimeFields->Hour = (CSHORT) (SecondsInDay / SECSPERHOUR);
+ SecondsInDay = SecondsInDay % SECSPERHOUR;
+ TimeFields->Minute = (CSHORT) (SecondsInDay / SECSPERMIN);
+ TimeFields->Second = (CSHORT) (SecondsInDay % SECSPERMIN);
+
+ /* compute day of week */
+ TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
+
+ /* compute year, month and day of month. */
+ cleaps=( 3 * ((4 * Days + 1227) / DAYSPERQUADRICENTENNIUM) + 3 ) / 4;
+ Days += 28188 + cleaps;
+ years = (20 * Days - 2442) / (5 * DAYSPERNORMALQUADRENNIUM);
+ yearday = Days - (years * DAYSPERNORMALQUADRENNIUM)/4;
+ months = (64 * yearday) / 1959;
+ /* the result is based on a year starting on March.
+ * To convert take 12 from Januari and Februari and
+ * increase the year by one. */
+ if( months < 14 ) {
+ TimeFields->Month = months - 1;
+ TimeFields->Year = years + 1524;
+ } else {
+ TimeFields->Month = months - 13;
+ TimeFields->Year = years + 1525;
+ }
+ /* calculation of day of month is based on the wonderful
+ * sequence of INT( n * 30.6): it reproduces the
+ * 31-30-31-30-31-31 month lengths exactly for small n's */
+ TimeFields->Day = yearday - (1959 * months) / 64 ;
+}
+
+
+BOOL WINAPI FileTimeToSystemTime( const FILETIME *ft, SYSTEMTIME * syst ) {
+ TIME_FIELDS tf;
+ LARGE_INTEGER t;
+
+ TRACEN((printf("FileTimeToSystemTime\n")))
+ t.QuadPart = ft->dwHighDateTime;
+ t.QuadPart = (t.QuadPart << 32) | ft->dwLowDateTime;
+ RtlTimeToTimeFields(&t, &tf);
+
+ syst->wYear = tf.Year;
+ syst->wMonth = tf.Month;
+ syst->wDay = tf.Day;
+ syst->wHour = tf.Hour;
+ syst->wMinute = tf.Minute;
+ syst->wSecond = tf.Second;
+ syst->wMilliseconds = tf.Milliseconds;
+ syst->wDayOfWeek = tf.Weekday;
+ return TRUE;
+}
+
+
+static inline NTSTATUS WINAPI RtlLocalTimeToSystemTime( const LARGE_INTEGER *LocalTime,
+ LARGE_INTEGER *SystemTime) {
+
+ TRACEN((printf("RtlLocalTimeToSystemTime\n")))
+ LONG bias = TIME_GetBias();
+ SystemTime->QuadPart = LocalTime->QuadPart + bias * (LONGLONG)TICKSPERSEC;
+ return STATUS_SUCCESS;
+}
+
+BOOL WINAPI LocalFileTimeToFileTime( const FILETIME *localft, FILETIME * utcft ) {
+ LARGE_INTEGER local, utc;
+
+ TRACEN((printf("LocalFileTimeToFileTime\n")))
+ local.QuadPart = localft->dwHighDateTime;
+ local.QuadPart = (local.QuadPart << 32) | localft->dwLowDateTime;
+ RtlLocalTimeToSystemTime( &local, &utc );
+ utcft->dwLowDateTime = (DWORD)utc.QuadPart;
+ utcft->dwHighDateTime = (DWORD)(utc.QuadPart >> 32);
+
+ return TRUE;
+}
+
+/*********************************************************************
+ * GetSystemTime (KERNEL32.@)
+ *
+ * Get the current system time.
+ *
+ * RETURNS
+ * Nothing.
+ */
+VOID WINAPI GetSystemTime(SYSTEMTIME * systime) /* [O] Destination for current time */
+{
+ FILETIME ft;
+ LARGE_INTEGER t;
+
+ TRACEN((printf("GetSystemTime\n")))
+
+ struct timeval now;
+ gettimeofday( &now, 0 );
+ t.QuadPart = now.tv_sec * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
+ t.QuadPart += now.tv_usec * 10;
+
+ ft.dwLowDateTime = (DWORD)(t.QuadPart);
+ ft.dwHighDateTime = (DWORD)(t.QuadPart >> 32);
+ FileTimeToSystemTime(&ft, systime);
+}
+
+/******************************************************************************
+ * RtlTimeFieldsToTime [NTDLL.@]
+ *
+ * Convert a TIME_FIELDS structure into a time.
+ *
+ * PARAMS
+ * ftTimeFields [I] TIME_FIELDS structure to convert.
+ * Time [O] Destination for the converted time.
+ *
+ * RETURNS
+ * Success: TRUE.
+ * Failure: FALSE.
+ */
+static BOOLEAN WINAPI RtlTimeFieldsToTime(
+ TIME_FIELDS * tfTimeFields,
+ LARGE_INTEGER *Time)
+{
+ int month, year, cleaps, day;
+
+ TRACEN((printf("RtlTimeFieldsToTime\n")))
+
+ /* FIXME: normalize the TIME_FIELDS structure here */
+ /* No, native just returns 0 (error) if the fields are not */
+ if( tfTimeFields->Milliseconds< 0 || tfTimeFields->Milliseconds > 999 ||
+ tfTimeFields->Second < 0 || tfTimeFields->Second > 59 ||
+ tfTimeFields->Minute < 0 || tfTimeFields->Minute > 59 ||
+ tfTimeFields->Hour < 0 || tfTimeFields->Hour > 23 ||
+ tfTimeFields->Month < 1 || tfTimeFields->Month > 12 ||
+ tfTimeFields->Day < 1 ||
+ tfTimeFields->Day > MonthLengths
+ [ tfTimeFields->Month ==2 || IsLeapYear(tfTimeFields->Year)]
+ [ tfTimeFields->Month - 1] ||
+ tfTimeFields->Year < 1601 )
+ return FALSE;
+
+ /* now calculate a day count from the date
+ * First start counting years from March. This way the leap days
+ * are added at the end of the year, not somewhere in the middle.
+ * Formula's become so much less complicate that way.
+ * To convert: add 12 to the month numbers of Jan and Feb, and
+ * take 1 from the year */
+ if(tfTimeFields->Month < 3) {
+ month = tfTimeFields->Month + 13;
+ year = tfTimeFields->Year - 1;
+ } else {
+ month = tfTimeFields->Month + 1;
+ year = tfTimeFields->Year;
+ }
+ cleaps = (3 * (year / 100) + 3) / 4; /* nr of "century leap years"*/
+ day = (36525 * year) / 100 - cleaps + /* year * dayperyr, corrected */
+ (1959 * month) / 64 + /* months * daypermonth */
+ tfTimeFields->Day - /* day of the month */
+ 584817 ; /* zero that on 1601-01-01 */
+ /* done */
+
+ Time->QuadPart = (((((LONGLONG) day * HOURSPERDAY +
+ tfTimeFields->Hour) * MINSPERHOUR +
+ tfTimeFields->Minute) * SECSPERMIN +
+ tfTimeFields->Second ) * 1000 +
+ tfTimeFields->Milliseconds ) * TICKSPERMSEC;
+
+ return TRUE;
+}
+
+/*********************************************************************
+ * SystemTimeToFileTime (KERNEL32.@)
+ */
+BOOL WINAPI SystemTimeToFileTime( const SYSTEMTIME *syst, FILETIME * ft ) {
+ TIME_FIELDS tf;
+ LARGE_INTEGER t;
+
+ TRACEN((printf("SystemTimeToFileTime\n")))
+
+ tf.Year = syst->wYear;
+ tf.Month = syst->wMonth;
+ tf.Day = syst->wDay;
+ tf.Hour = syst->wHour;
+ tf.Minute = syst->wMinute;
+ tf.Second = syst->wSecond;
+ tf.Milliseconds = syst->wMilliseconds;
+
+ RtlTimeFieldsToTime(&tf, &t);
+ ft->dwLowDateTime = (DWORD)t.QuadPart;
+ ft->dwHighDateTime = (DWORD)(t.QuadPart>>32);
+ return TRUE;
+}
+
diff --git a/src/libs/7zip/unix/ChangeLog b/src/libs/7zip/unix/ChangeLog
new file mode 100644
index 000000000..5887d43f1
--- /dev/null
+++ b/src/libs/7zip/unix/ChangeLog
@@ -0,0 +1,914 @@
+
+Version 9.20.1
+==============
+
+ - #3211479 "p7zip 9.20 - "unsupported method" with RAR files - " fixed
+ "install.sh" installs again "bin/Codecs/Rar29.so"
+
+Version 9.20
+============
+
+ - From Windows version of 7-zip 9.20, What's new after 7-Zip 4.65 (2009-02-03):
+ - 7-Zip now supports LZMA2 compression method.
+ - 7-Zip now can update solid .7z archives.
+ - 7-Zip now supports XZ archives.
+ - 7-Zip now supports PPMd compression in ZIP archives.
+ - 7-Zip now can unpack NTFS, FAT, VHD, MBR, APM, SquashFS, CramFS, MSLZ archives.
+ - 7-Zip now can unpack GZip, BZip2, LZMA, XZ and TAR archives from stdin.
+ - 7-Zip now can unpack some TAR and ISO archives with incorrect headers.
+ - 7-Zip now supports files that are larger than 8 GB in TAR archives.
+ - NSIS and WIM support was improved.
+ - Partial parsing for EXE resources, SWF and FLV.
+ - The support for archives in installers was improved.
+ - 7-Zip now can stores NTFS file timestamps to ZIP archives.
+ - Speed optimizations in PPMd codec.
+ - Speed optimizations in CRC calculation code for Intel's Atom CPUs.
+ - New -scrc switch to calculate total CRC-32 during extracting / testing.
+ - 7-Zip File Manager now doesn't use temp files to open nested archives stored without compression.
+ - Disk fragmentation problem for ZIP archives created by 7-Zip was fixed.
+ - Some bugs were fixed.
+ - New localizations: Hindi, Gujarati, Sanskrit, Tatar, Uyghur, Kazakh.
+ - Not in p7zip : Speed optimizations in AES code for Intel's 32nm CPUs.
+
+
+
+
+Version 9.18
+============
+ - From Windows version of 7-zip 9.17
+ - Disk fragmentation problem for ZIP archives created by 7-Zip was fixed.
+ Notes: 7-Zip now uses 4 MB RAM buffer as file cache, when you create ZIP archives.
+ It reduces the number of Move_File_Position and Write_to_File operations.
+
+ - From Windows version of 7-zip 9.18
+ - 7-Zip now can unpack SquashFS and CramFS filesystem images.
+ - 7-Zip now can unpack some TAR and ISO archives with incorrect headers.
+ - Some bugs were fixed.
+
+ - Some bugs were fixed in 7zG and 7zFM on MacOSX
+
+
+Version 9.16
+============
+ - From Windows version of 7-zip 9.16
+ - 7-Zip now supports files that are larger than 8 GB in TAR archives.
+ - NSIS support was improved :
+ - 7-Zip now supports BZip2 method in NSIS installers.
+ - 7-Zip now can extract identical files from NSIS installers.
+ - Some bugs were fixed.
+ - New localizations: Hindi, Gujarati, Sanskrit.
+
+ - From Windows version of 7-zip 9.15
+ - Some bugs were fixed.
+ - New localization: Tatar
+
+ - From Windows version of 7-zip 9.14
+ - WIM support was improved. 7-Zip now can create WIM archives without compression.
+
+
+ - #3069545 "kSignatureDummy?" fixed
+
+
+
+
+Version 9.13
+============
+ - From Windows version of 7-zip 9.12
+ - Some bugs were fixed.
+
+
+ - #2863580 "Crash in Rar decoder on a corrupted file" fixed
+
+ - #2860898 "Dereferencing a zero pointer in cab handler" fixed
+
+ - #2860679 "Division by zero in cab decoder" fixed
+
+
+
+Version 9.12
+============
+ - From Windows version of 7-zip 9.12
+ - ZIP / PPMd compression ratio was improved in Maximum and Ultra modes.
+ - The BUG in 7-Zip 9.* beta was fixed: LZMA2 codec didn't work,
+ if more than 10 threads were used (or more than 20 threads in some modes).
+
+ - makefile.openbsd is now compatible with OpenBSD ports tree.
+ (thanks to jggimi)
+
+ - cmake projects added.
+
+ - 7zFM and 7zG can be built on MacOSX but these ports are in very alpha stage.
+ make app to build p7zip.app (p7zip for MacOSX)
+
+
+Version 9.11 (never published)
+============
+ - From Windows version of 7-zip 9.11
+ - 7-Zip now supports PPMd compression in .ZIP archives.
+ - Speed optimizations in PPMd codec.
+ - The support for archives in installers was improved.
+ - Some bugs were fixed.
+
+
+Version 9.10 (never published)
+============
+
+ - From Windows version of 7-zip 9.05 to 9.10
+ - 7-Zip now can unpack Apple Partition Map (APM) disk images.
+ - 7-Zip now can unpack MSLZ archives.
+ - Partial parsing for EXE resources, SWF and FLV.
+ - Some bugs were fixed.
+
+ - p7zip can now use hugetlbfs on Linux (thank to Joachim Henke)
+ Like with the Windows large pages, this gives a nice speedup,
+ when running memory intensive operations.
+
+ - p7zip now uses UTF8 (kCFStringNormalizationFormD) On MacOSX
+ fixes #2831266 "p7zip can't find NFC Unicode filename in OSX Terminal"
+ and #2976169 "German Umlauts Failure"
+
+
+Version 9.05 (never published)
+============
+
+ - p7zip now uses precompiled header with gcc 4
+
+
+Version 9.04 (Major bugfixes and Major enhancements)
+============
+
+ - From Windows version of 7-zip 9.04 :
+ - 7-Zip now can update solid .7z archives.
+ - 7-Zip now supports LZMA2 compression method.
+ - 7-Zip now supports XZ archives.
+ - 7-Zip now can unpack NTFS, FAT, VHD and MBR archives.
+ - 7-Zip now can unpack GZip, BZip2, LZMA, XZ and TAR archives from stdin.
+ - New -scrc switch to calculate total CRC-32 during extracting / testing.
+ - Some bugs were fixed.
+
+ - #2799966 " A newly created 7z archive (by p7zip 4.65) is broken and cannot be unpacked / listed / tested"
+ Fixed : now "7za a -mx=9 archive.7z directory" creates a good archive even
+ if there are a lot of executable files.
+
+ - Fixed : the RAM size was reported incorrectly on MacOSX 64bits (with 2Gb+ RAM)
+
+ - #2798023 "segfault handling very large multivolume .7z file"
+ p7zip now displays the following error "Error: Too many open files"
+ if you don't have enough rights to open all the splitted files
+ ( on Linux : ulimit -n)
+
+
+Version 4.65
+============
+ - From Windows version of 7-zip 4.62 to 4.65
+ - The bug in 7-Zip 4.63 was fixed: 7-Zip could not decrypt .ZIP archives encrypted with WinZip-AES method.
+ - 7-Zip now can unpack ZIP archives encrypted with PKWARE-AES.
+ - Some bugs were fixed.
+
+ - Fixed : the RAM size was reported incorrectly on MacOSX 64bits
+
+ - Fixed : makefile.linux_amd64_asm_icc
+
+ - DJGPP :
+ makefile.djgpp becomes makefile.djgpp_old
+ makefile.djgpp_watt added (thank to Rugxulo)
+
+
+ - you can now compile 7za with a cmake project (see README)
+ the cmake project can build a codeblock project ;)
+ Remark : the kdevelop3 or Eclipse/CDT4 project don't work :(
+
+Version 4.61
+============
+ - From Windows version of 7-zip 4.61 :
+ - 7-Zip now supports LZMA compression for .ZIP archives.
+ - Some bugs were fixed.
+
+ - #2199036 : Ask for password twice when creating encrypted archive
+
+ - 7zG added (read GUI/readme.txt)
+
+
+Version 4.60 (never published)
+============
+
+ - From Windows version of 7-zip 4.60 :
+ - Some bugs were fixed
+
+ - p7zip didn't use the BCJ /BCJ2 filters for executables (:
+ - makefile.linux_amd64_asm_icc added (tested with Intel Compiler 11 on Ubuntu 8.04 x64)
+
+
+Version 4.59 (never published)
+============
+
+ - From Windows version of 7-zip 4.59 :
+ - 7-Zip now can unpack UDF, XAR and DMG/HFS archives.
+ - It's allowed to use -t switch for "list" and "extract" commands.
+ - Some bugs were fixed.
+
+ - Bug : wrong timestamp for files extracted from .zip or .rar archives
+
+
+Version 4.58
+============
+ - From Windows version of 7-zip 4.58 :
+ - Some speed optimizations.
+ - 7-Zip now can unpack .lzma archives.
+ - Unicode (UTF-8) support for filenames in .ZIP archives. Now there are 3 modes:
+ 1) Default mode: 7-Zip uses UTF-8, if the local code page doesn't contain required symbols.
+ 2) -mcu switch: 7-Zip uses UTF-8, if there are non-ASCII symbols.
+ 3) -mcl switch: 7-Zip uses local code page.
+ - Now it's possible to store file creation time in 7z and ZIP archives (-mtc switch).
+ - 7-Zip now can unpack multivolume RAR archives created with
+ "old style volume names" scheme and names *.001, *.002, ...
+ - Now it's possible to use -mSW- and -mSW+ switches instead of -mSW=off and -mSW=on
+ - Some bugs were fixed.
+
+ - Bug #1898410 : Timestamp error in archive listing
+ now "7za l .." and "ls -l just_extracted_file" give the same date and time.
+
+ - Bug #1860938 : unix file rights only 600 instead of 644
+
+ - Bug #1941574 : gzip files always marked as OS FAT, Now p7zip uses "Unix".
+
+ - Bug #1947700 : file containing excluded files not read
+ When using the -xr <filename> flag to list files not to be included in the
+ archive the file <filename> is not read if it is a symbolic link.
+
+ - Feature Requests #1868080 : add support to compile for NetWare (makefile.netware_asm_gcc_3.X)
+
+ - Patch #1883893 : Incorrect path ref to docs in man pages (When using the last ($DEST_DIR) argument with install.sh)
+
+ - now "install.sh" supports filenames with spaces.
+
+ - some code cleanup (Synchronization)
+
+ - some minor fix in the BZip2 codec.
+
+ - fix with the define "__TEXT" for s390
+
+
+Version 4.57
+============
+ - From Windows version of 7-zip 4.57 :
+ - The BUG in command line version was fixed: -up3 switch could work incorrectly.
+ - Minor improvement in ZIP compression.
+
+
+Version 4.56 (never published)
+============
+ - From Windows version of 7-zip 4.56 :
+ - Some bugs were fixed
+
+ - On HPUX : fixed "Can't load '../bin/7z.dll'"
+ (Unsatisfied data symbol '_ZTVN10__cxxabiv121__vmi_class_type_infoE' in load module '../bin/7z.so'.)
+
+ - bug : p7zip used to build a zip file with an "FAT" header instead of "Unix" header
+ If LANG was set, "unzip" tried to translate the filenames from "FAT" to locale ...
+
+ - On AIX : fixed "HugeFiles=off" (thank kuriath)
+
+ - bug #1800180 : LZMAlone compilation error in COutFile
+
+ - Patch #1796569 : Fix FreeBSD FTBFS
+
+ - Patch #1796575 : fix man1/7za.1 man1/7zr.1 man1/7z.1
+
+
+Version 4.55
+============
+ - From Windows version of 7-zip 4.55 :
+ - Some bugs were fixed
+
+ - fixed #1783007 : when make p7-zip 4.51 under hp-ux 11.11 error
+
+ - fixed #1789154 : 7z use default or -m0=LZMA runtime error under HP-UX IA11.23
+
+ - support added for HPUX on Itanium.
+ (makefile.hpux-acc and makefile.hpux-acc_64)
+
+
+Version 4.54 (never published)
+============
+ - From Windows version of 7-zip 4.54 :
+ - Decompression speed was increased
+
+Version 4.53
+============
+ - From Windows version of 7-zip 4.53 :
+ - The bug in 7-Zip 4.48 - 4.52 beta was fixed:
+ 7-Zip could create .ZIP archives with broken files.
+ - Some bugs were fixed.
+
+Version 4.52 (never published)
+============
+ - From Windows version of 7-zip 4.52 :
+ - 7z now can unpack Compound files (msi, doc, ...).
+ - Some bugs were fixed (CAB decompressing)
+
+ - lzma (CPP/7zip/Compress/LZMA_Alone) is now multi-threaded.
+
+ - fixed #632912 : Extracting large directories takes quadratic time
+ (this bug was not fully fixed ...)
+
+ - fixed : "7za x -odirectory archive.7z" now works even if "directory" is a symbolic link.
+
+ - makefile.linux_s390x added : support for Linux on IBM z/Series Mainframe with s390x CPU
+ (thank y_stephen)
+
+ - fixed crashes on BeOs with the flag "@filename"
+
+ - cleanup in the makefile : defining LITTLE_ENDIAN or BIG_ENDIAN is not needed anymore
+
+ - ppmd.exe added (CPP/7zip/Compress/PPMD_Alone)
+
+Version 4.51
+============
+ - From Windows version of 7-zip 4.51 :
+ - Bug was fixed: 7-Zip 4.50 beta could not open some .7z archives.
+
+ - fix built of test_emul
+
+Version 4.50 (never published)
+============
+ - From Windows version of 7-zip 4.50 :
+ - New switch for command line version:
+ -ssc[-] enables/disables case-sensitive mode for file names.
+ - Speed optimizations for AES encryption.
+ - Some bugs were fixed.
+
+ - contrib/gzip-like_CLI_wrapper_for_7z/p7zip now supports commands like :
+ p7zip -- -name
+ p7zip "file name"
+ p7zip file1 file2 file3
+ p7zip -d file1.7z file2.7z file3.7z
+
+ never published because this version does not pass my tests.
+
+Version 4.49
+============
+ - From Windows version of 7-zip 4.49 :
+ - 7-Zip (7z) now can unpack WIM archives
+
+ - fixed : On Sparc Solaris, core dump during "7z a -sfx exe.x dir" with p7zip compiled with makefile.solaris_sparc_CC_32
+
+ - some code cleanup
+
+ - On HPUX, p7zip can get the number of CPU and the size of the memory.
+
+
+Version 4.48
+============
+ - From Windows version of 7-zip 4.48 :
+ - Encryption strength for .7z format was increased.
+ Now it uses random initialization vectors.
+ - Some bugs were fixed.
+
+ - fixed #1729236 : Makefile infrastructure not safe for parallel compilation
+ (if your make command understands -C and -j4, copy makefile.parallel_jobs over makefile)
+
+ - Now the executables are not built with the PIC (position-independent code) flag.
+ 7z.so are still built with the PIC flag.
+ 7za and 7zr are now faster than 7z with 7z.so.
+ 7za, 7zr and 7r are now smaller.
+
+ - contrib/gzip-like_CLI_wrapper_for_7z/p7zip now supports spaces in filename
+ and use 7za instead of 7z.
+
+ - contrib/qnx630sp3 added to support QNX built (thank termterm)
+
+
+Version 4.47
+============
+ - From Windows version of 7-zip 4.47 :
+ - Bugs of 7-Zip 4.46 beta were fixed: BZip2 could work incorrectly
+
+Version 4.46 (never published)
+============
+
+ - From Windows version of 7-zip 4.46 :
+ - New fast compression mode for Deflate method in Zip and GZip.
+ - Some bugs were fixed.
+
+ - LZMA Benchmark :
+ - cygwin : RAM size detection
+ - computation of the CPU %
+
+ - fixed #1721827 : install.sh now copies 7z.so
+
+ - Client7z now uses 7z.so instead of 7za.so
+
+ - new target : cygwin with asm
+
+ - LZMA SDK added in the source package (CPP/7zip/Compress/LZMA_Alone)
+
+ - fixed #1716987 : 7zr removed from 4.45 binary distribution
+
+ - fixed #1706002 : make and install.sh use the same variables in the same order.
+
+
+Version 4.45
+============
+
+ - From Windows version of 7-zip 4.45 :
+ - Default dictionary size was increased: Normal: 16 MB, Max: 32 MB.
+ - Speed optimizations.
+ - Benchmark was improved (new "b" command in command line version).
+ - The number of DLL files was reduced.
+ - switch -mhcf=off is not supported now.
+ - If -t{Type} switch is not specified, 7-Zip now uses extension of archive to detect the type of archive.
+ - Some bugs were fixed (BZip2 in multithread)
+ - x86 or x86_64 : ASM version of crc32 available
+
+ - better detection of executable file (scripts do not need BCJ/BCJ2 filter)
+
+ - default permissions are now :
+ - for a file : -rw-------
+ - for a directory : drwx------
+
+ - on MacOSX, locale is always utf8 (because the MacOSX filesystem supports only utf8 filenames)
+
+ - makefile.qnx_static and makefile.qnx_shared added (Thank to termterm)
+
+
+Version 4.44
+============
+
+ - From Windows version of 7-zip 4.44 :
+ - 7za : Cab support
+ - Speed optimizations for LZMA, Deflate, BZip2 and unRAR.
+ - fix : now, updating a crypted header archive keeps the crypted header
+
+ - fixes in the help displayed by 7za/7z/7zr.
+
+ - code cleanup
+ - remove of mySetModuleFileNameA (and its memory leak), GetModuleFileName ...
+
+ - fixed : p7zip for DJGPP can now update an archive (thank stranix)
+
+ - fixed : in the plugins of 7z, the "Utf16" state was always off.
+
+ - fixed : support for directory names that are not encoded with the current locale.
+ (ex : directory name is in "iso 8859-15" whereas the locale is "utf8")
+
+ - patch #1581907 : fix for FreeBSD in contrib/gzip-like_CLI_wrapper_for_7z/p7zip
+
+ - fixed : p7zip can now restore a symbolic link from a Zip archive (archive.zip made with "zip -y")
+ remark/todo : p7zip stores, in a zip archive, the linked file instead of the symbolic link
+
+ - fixed #1630452 : small fix in the output of the script install.sh
+
+ - fixed #632912 : Extracting large directories takes quadratic time
+
+ - preliminary support of HP-UX : remove of RTLD_GROUP for dlopen in DLL.cpp
+ makefile.hpux-acc should be able to build 7za for HP-UX (thank furiol)
+
+ - Client7z added.
+
+Version 4.43
+============
+ - From Windows version of 7-zip 4.43 :
+ - 7-Zip now can use multi-threading mode for compressing to .ZIP archives.
+ - ZIP format supporting was improved.
+ - 7-Zip now supports WinZip-compatible AES-256 encryption for .ZIP archives.
+ - 7-Zip now uses order list (list of extensions) for files sorting for compressing
+ to .7z archives. It can slightly increase compression ratio in some cases.
+ - 7-Zip now restores modification time of folders during .7z archives extracting.
+ - Some bugs were fixed.
+
+ - fixed : the user can now see the percentage indicator.
+
+ - fix "Bugs item #1612285" : doesn't preserve directory timestamps
+
+ - support added for Tru64 / OSF 5.1 (makefile.tru64)
+
+ - small fix "Bugs item #1533765" in install.sh (7zr install)
+
+ - fix "Bugs item #1507913" : "make all" now build 7za and 7zCon.sfx
+ following the README.
+
+ - manpage updated "bugs item #1509098" : exit codes added
+
+ - manpage updated :-mhe=on (Header encryption) added
+
+ - install.sh now can install the file README, ChangeLog and the directory DOCS
+
+
+Version 4.42
+============
+ - From Windows version of 7-zip 4.42 :
+ - Some bugs were fixed
+
+ - the binaries provided by p7zip_4.XY_x86_linux_bin.tar.bz2
+ can now run on Fedora x86_64,
+ and should now run on any 64bits Linux.
+
+ - patch #1473746 - gzip-like CLI wrapper (for 7z)
+ see the directory "contrib/gzip-like_CLI_wrapper_for_7z".
+
+ - patch #471478 - Support for OPTFLAGS
+ This patch allows to use system specific opt flags.
+ example : make OPTFLAGS="-O2 -march=athlon-xp"
+
+ - the djgpp and cygwin makefile now build "7za" with case insensitive filenames
+ (Windows filesystem is case insensitive).
+
+
+Version 4.41
+============
+ - From Windows version of 7-zip 4.41 :
+ - Some bugs were fixed
+
+
+Version 4.40
+============
+
+ - From Windows version of 7-zip 4.40 :
+ - 7-Zip now can unpack some installers created by NSIS
+ - Some bugs were fixed
+
+ - format LZH/LHA : fixed directory display during listing or extracting
+ (a directory does not end with the path separator)
+
+ - patch #1470817 - Handle 7zr in install.sh
+
+ - code cleanup
+
+
+Version 4.39
+============
+
+ - From Windows version of 7-zip 4.39 :
+ - Bug in versions 4.33:4.38 was fixed:
+ 7-Zip could not correctly compress files larger than 2 GB
+ to 7z archive in fast/fastest modes (HC4 match finder).
+
+
+Version 4.38
+============
+
+ - From Windows version of 7-zip 4.38 :
+ - Some bugs were fixed.
+
+ - new manpage : 7zr.1
+ - update manpages : 7z.1 and 7za.1
+ - new switch : --help
+
+ - patch #1465026 - Patch for install.sh for packagers
+
+ - DosDateTimeToFileTime fixed (rar format)
+
+ - contrib/VirtualFileSystemForMidnightCommander/u7z updated
+ (thank sgh_punk)
+
+
+Version 4.37
+============
+ - From Windows version of 7-zip 4.37 :
+ - Some bugs were fixed.
+
+ - fix build for Solaris sparc with CC instead of g++.
+
+ - fix build for Solaris 9 x86
+ - fix build for Solaris 10 x86
+ - fix build for OpenBSD
+ - p7zip can now be build with djgpp.
+ - new target : 7zr (light version of 7za)
+ - new machine : IBM AIX
+
+Version 4.36
+============
+ - From Windows version of 7-zip 4.36 :
+ - 7-zip now can unpack ISO archives
+
+ - GCC 4.X : add C++ visibility support to reduce the size of the *.so
+ (see makefile.linux_x86_ppc_alpha__gcc_4.X)
+
+ - cygwin now supports '-o/tmp'
+
+Version 4.35
+============
+ - From Windows version of 7-zip 4.35 :
+ - New switch : -slt ("l" (list) command with -slt shows technical information for archive).
+ - Some bugs were fixed.
+
+ - From Windows version of 7-zip 4.34 :
+ - BZip2 compressing / decompressing now can work in multi-threading mode
+ - Multi-threading mode now is default for multi-processor systems
+
+Version 4.33
+============
+ - From Windows version of 7-zip 4.33 :
+ - Compressing speed and Memory requirements were increased.
+ Default dictionary size was increased: Fastest: 64 KB, Fast: 1 MB,
+ Normal: 4 MB, Max: 16 MB, Ultra: 64 MB.
+ - 64-bit version now supports 1 GB dictionary
+ - 7z/LZMA now can use only these match finders: HC4, BT2, BT3, BT4
+ - Compression ratio in Zip/GZip/Deflate in Ultra mode was increased
+ - Some bugs were fixed
+
+ - fix "Bugs item #1407358" : Passwords entered are not visible on command line
+ if the target has the system function "getpass".
+
+ - fix "BCJ2" : now p7zip uses the "BCJ2" filter when the file has execute permission
+ (7-zip uses the "BCJ2" filter when the filename ends with ".dll", ".exe", ".ocx", ".sfx" or ".sys")
+
+ - patch #1390722 : no new line at end of file
+
+ - patch #1390716 : allow compiling with gcc-4.1
+
+ - patch #1425862 : allow other make programs than GNU make
+
+ - Testing framework added ("make test" and "make test_7z")
+
+ - fix 'lstat' : p7zip can compile if 'lstat' is not available
+
+Version 4.30
+============
+ - From Windows version of 7-zip 4.30 :
+ - Speed optimizations in LZMA maximum/ultra compressing.
+ - LZMA now supports word size up to 273
+ - 7-Zip now reduces dictionary size for LZMA, if you compress files
+ smaller than specified dictionary size.
+ - Some bugs were fixed
+
+ - fix minor build trouble with MacOS X
+ - fix "Bugs item #1349229" : 7-zip now displays "e: Extract files from archive (without using directory names)"
+
+Version 4.29
+============
+
+ - fix "Bugs item #1305781" : "7z a -sfx" sets the execute-flag
+ and does not add ".exe" extension.
+
+ - fix "Bugs item #1306783" : "7za a /tmp/t.7z /etc/passwd"
+
+ - fix "Bugs item #1304797" : @lists don't handle files starting with ./
+
+ - fix "Bugs item #1309287" : man 7za fails after install
+
+Version 4.27
+============
+ - From Windows version of 7-zip 4.27 :
+ - new plugin for 7z : 7-Zip can unpack CHM/HXS (MS HTML HELP) archives
+ - cab plugin for 7z : 7-Zip can unpack multivolume CAB archives
+ - Some bugs were fixed
+ - better support for 64bits (PPMD coder/decoder)
+
+Version 4.26
+============
+ - From Windows version of 7-zip 4.26 :
+ - new plugin for 7z : LZH format support (extracting only)
+
+ - fix (courtesy from Robert Millan) to make p7zip compile on GNU/kFreeBSD.
+
+ - fix "Bug item #1273057", now "7z -so -t7z a dummy.7z file >output.7z" does not
+ finish with a "Segmentation fault (core dumped)".
+
+ - fix "Bug item #1221056", now, makefile for p7zip use the flag "-O" to
+ support compilers that build invalid programs with the flag "-O2".
+
+Version 4.25
+============
+ - From Windows version of 7-zip 4.25 :
+ - Some bugs were fixed
+ - DOCS/MANUAL/exit_codes.htm added
+
+ - new plugin for 7z : RAR format support (extracting only)
+
+ - better dependencies in makefile
+
+Version 4.23
+============
+ - From Windows version of 7-zip 4.23 :
+ - Some bugs were fixed
+
+ - manpages for 7za and 7z updated by Mohammed Adnene Trojette.
+
+ - little fix for the help message of 7za or 7z.
+
+ - bug #1224304 : Files and directories with \ in name not handled properly.
+
+ - fix for tar archives that have pax header.
+
+Version 4.20
+============
+
+ - From Windows version of 7-zip 4.19 and 4.20 :
+ - BZip2 code was rewritten. Now it supports 3 modes: Normal, Maximum and
+ Ultra. In Normal mode it compresses almost as original BZip2 compressor.
+ Compression ratio in Maximum and Ultra modes is 1-3% better for some files,
+ but Maximum Mode is about 3 times slower and Ultra Mode is about 8 times
+ slower than Normal mode.
+ - Console version now prints all messages to stdout by default,
+ and if -so switch is specified, 7-Zip prints messages to stderr.
+ - Some bugs were fixed
+
+ - Updating "contrib/VirtualFileSystemForMidnightCommander/" with u7z-4.16beta.tar.bz2
+
+ - bug #1204993 (does not find broken filenames)
+
+ - bug #1201244 (Missing files in p7zip_4.18_x86_linux_bin.tar.bz2)
+
+ - makefile.linux_x86_ppc_alpha : flag "-fPIC" added
+
+ - flag "-l" added.
+ without : p7zip stores symlinks (like p7zip 4.18)
+ with "-l" : p7zip stores the files/directories pointed by symlinks (like before p7zip 4.18)
+ CAUTION : the scanning stage can never end because of symlinks like ".."
+ (ex: ln -s .. ldir)
+
+Version 4.18
+============
+
+ - From Windows version of 7-zip 4.18 and 4.17 :
+ - minor fixes
+
+ - p7zip can now store and restore :
+ - symbolic links,
+ - file permission bits
+ Remark : for directory, restored_perm = stored_perm | 0700 .
+
+ - fix in install.sh
+
+ - On MacOSX, p7zip now restore times of a file.
+
+ - more detailed errors during scanning stage.
+
+
+Version 4.16
+============
+
+ - From Windows version of 7-zip 4.16 :
+ - Speed optimization (5%) for 7z / LZMA
+ - 7za now supports .Z archives
+ - -r- switch in command line now is default for all commands
+ - Some bugs were fixed
+ - bug #1119193 (list mode output confusing/wrong)
+
+ - From Windows version of 7-zip 4.15 :
+ - Z format supporting (extracting only)
+ - 7-Zip now can extract ZIP archives compressed with "Shrink" method
+ - 7-Zip now doesn't interrupt the compressing when it can not open file.
+ 7-Zip just skips that file and shows warning.
+ - Some bugs were fixed
+
+ - man pages added (thank Mohammed Adnene Trojette)
+ - bug #1112167 fixed (Temporary directory must be on same partition as target)
+ p7zip failed moving the temporary file at the end of
+ compressing to target file if the directories don't reside
+ on the same partition (or network path).
+ - bug #1164659 fixed (Invalid file date for "big endian" machine)
+ - p7zip now uses ".so" instead of ".dll"
+ - p7zip now handles "ctrl-c" and "kill" to cleanup temporary files before exiting
+ - p7zip now runs on BeOS.
+ - better support of filenames with spaces.
+ - some code cleanup
+ - "myWindows/myFiles.cpp" is now in "Windows/FileIO.cpp"
+ - "myWindows/myFindFile.cpp" is now in "Windows/FileFind.cpp"
+ - "myWindows/myDirectoryAndPath.cpp" is now in "Windows/FileDir.cpp"
+ - "myWindows/myEvents.cpp" is now in "Windows/Synchronization.cpp"
+ - "myWindows/wine_strings.cpp" is now in "Windows/String.cpp"
+
+
+Version 4.14.01
+===============
+ - huge speed up for multi CPUs machines (Thanks to loderunner - http://sourceforge.net/users/loderunner/).
+ - some code cleanup
+ - Fix problems with link files or directories.
+ - "7z a dummy -tgzip -so Doc.txt > archive.gz" now works.
+ - in the messages, the path separator is now '/' instead of '\'.
+
+Version 4.14
+============
+
+ - From Windows version of 7-zip 4.14 :
+ - STL using was reduced
+ - 7za now supports Split(001) archives
+ - "7za | more" now works
+ - Bugs item #1093095 : Usage banner now says "7za" (instead of "7z") when the binary is "7za"
+
+ - use of AString instead of std::string (no more need of #include <string>")
+ - makefile.linux_gcc_2.95_no_need_for_libstdc added to build 7za for the
+ p7zip*_bin.tar.bz2 package.
+ 7za provided by p7zip*_bin.tar.bz2 is build on Debian 3.0 with gcc 2.95.4
+ and should now find the locale on all kinds of Linux (Debian, Fedora, Mandrake, ...).
+
+Version 4.13
+============
+ - new port of 7za from the source of 7za 4.13Beta for Windows
+
+ - From Windows version of 7-zip 4.13 :
+ - Switch "--" stops switches parsing
+ - Some bugs were fixed
+ - User's manual updated (DOCS/MANUAL/index.htm)
+
+ - makefile.netbsd_x86 added [Bug #1069055].
+
+ - new method to install 7z and its plugins (the "link" method do no work)
+
+ - installer added (install.sh).
+
+ - makefile.macosx_with_fink becomes makefile.macosx
+ and makefile.macosx uses c++ instead of CC
+ (on some MacOSX, CC is a link to gcc instead of g++)
+
+ - new flag "-utf16" to enable "utf16" conversion [Bug #1075229].
+
+ - new logic to automatically enable or disable "utf16" conversion :
+ no locale, locale=="C" or locale=="POSIX" implies utf16=off
+ else utf16=on
+ uses "-utf16" or "-no-utf16" to change this behaviour.
+ [Bug #1075229]
+
+ - 7z (compiled with -O2) works now on Sparc Solaris.
+
+Version 4.12
+============
+ - new port of 7za from the source of 7za 4.12Beta for Windows
+
+ - From Windows version of 7-zip 4.11 and 4.12 :
+ - 7-Zip now supports Zip64 extension of ZIP format. So now it's
+ possible to compress files bigger than 4 GB to ZIP archives.
+ - Some bugs were fixed
+
+ - fix "7za a archive.7z file" that added all the files and directories
+ with filename "file", "FILE", "File" ...
+
+ - p7zip now displays the locale (ex : en_US.UTF-8) in the banner.
+
+ - new flag "-no-utf16" to avoid lossly conversion in filenames.
+ CAUTION : use this flag when you do not plan to export your archive.
+
+ - support creation of self extracting archive.
+
+ - better support of symbolic link (now, an invalid symbolic link
+ do not stop archiving but displays a warning).
+
+ - better support of files that the user cannot read.
+ (now this kind of file is not added to the archive, and p7zip displays a warning).
+
+ - return of 7z and its plugins.
+
+ - support of listing/testing/extracting files from a splitted archive (only with 7z).
+
+ - support of MacOX X 10.X.
+
+ - creation of Gzip/Tar archives didn't work on Linux Alpha.
+
+ - see "contrib/VirtualFileSystemForMidnightCommander/readme" to use 7za with "mc".
+
+Version 4.10
+============
+ - new port of 7za from the source of 7za 4.10Beta for Windows
+ => p7zip now work on big endian CPU.
+
+ - 7z for Unix is not maintain anymore (because as the source of unrar plugin for 7z
+ is not available, 7z is unless on Unix).
+
+Version 0.91
+============
+ - add support for FreeBSD 5.2.1
+ In Windows/Time.h add "#include <time.h>"
+ and prototype change for FileTimeToUnixTime()
+
+ - bug 990684 Corrected : support of filesystem
+ that support case sensitive filenames.
+ Example, since version 0.91 :
+ "7z a glibc -r glibc-2.3.2"
+ does not terminate with error :
+ Duplicate filename:
+ glibc-2.3.2\sysdeps\m88k\m88100\add_n.S
+ glibc-2.3.2\sysdeps\m88k\m88100\add_n.s
+
+Version 0.90
+============
+ - build of 7z.exe and its DLL.
+ 7z.exe support more archive formats than 7za.exe
+ thanks to DLL in Formats and Codecs directories
+ - "#pragma once" is now in comments
+ - mainly For OpenBSD :
+ - add #include <wchar.h> in include_windows/winnt.h
+ - remove stuff for GUID_SECTION and GUID_SECT in include_windows/basetyps.h
+ and include_windows/initguid.h
+ - some changes in 7zip/Crypto/aesopt.h because of endian.h
+
+Version 0.81
+============
+ - add a copy of the help of 7-zip (see html directory)
+ - "7z a -r tmp.7z directory" works as expected.
+ no more need for commands like : 7z a -r tmp.7z "directory/*"
+ - 7z restores the date of each files (but not directories)
+ - 7z supports UNICODE filenames (version 0.80 supports only ASCII/Latin1 filenames)
+ - support of gcc 2.95
+ - support of gcc 3.4
+ - 7z needs no more libgen.h (dirname() and basename())
+ - less "Internal Error #7" during arguments parsing
+ - minor change in class CThread
+
+Version 0.80
+============
+ - First public release
+ - support of gcc 3.2 and 3.3
+
diff --git a/src/libs/7zip/unix/DOCS/7zC.txt b/src/libs/7zip/unix/DOCS/7zC.txt
new file mode 100644
index 000000000..5d5d06d7b
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/7zC.txt
@@ -0,0 +1,194 @@
+7z ANSI-C Decoder 4.62
+----------------------
+
+7z ANSI-C provides 7z/LZMA decoding.
+7z ANSI-C version is simplified version ported from C++ code.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+
+LICENSE
+-------
+
+7z ANSI-C Decoder is part of the LZMA SDK.
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+Files
+---------------------
+
+7zDecode.* - Low level 7z decoding
+7zExtract.* - High level 7z decoding
+7zHeader.* - .7z format constants
+7zIn.* - .7z archive opening
+7zItem.* - .7z structures
+7zMain.c - Test application
+
+
+How To Use
+----------
+
+You must download 7-Zip program from www.7-zip.org.
+
+You can create .7z archive with 7z.exe or 7za.exe:
+
+ 7za.exe a archive.7z *.htm -r -mx -m0fb=255
+
+If you have big number of files in archive, and you need fast extracting,
+you can use partly-solid archives:
+
+ 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
+
+In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
+512KB for extracting one file from such archive.
+
+
+Limitations of current version of 7z ANSI-C Decoder
+---------------------------------------------------
+
+ - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
+ - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
+ - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
+
+These limitations will be fixed in future versions.
+
+
+Using 7z ANSI-C Decoder Test application:
+-----------------------------------------
+
+Usage: 7zDec <command> <archive_name>
+
+<Command>:
+ e: Extract files from archive
+ l: List contents of archive
+ t: Test integrity of archive
+
+Example:
+
+ 7zDec l archive.7z
+
+lists contents of archive.7z
+
+ 7zDec e archive.7z
+
+extracts files from archive.7z to current folder.
+
+
+How to use .7z Decoder
+----------------------
+
+Memory allocation
+~~~~~~~~~~~~~~~~~
+
+7z Decoder uses two memory pools:
+1) Temporary pool
+2) Main pool
+Such scheme can allow you to avoid fragmentation of allocated blocks.
+
+
+Steps for using 7z decoder
+--------------------------
+
+Use code at 7zMain.c as example.
+
+1) Declare variables:
+ inStream /* implements ILookInStream interface */
+ CSzArEx db; /* 7z archive database structure */
+ ISzAlloc allocImp; /* memory functions for main pool */
+ ISzAlloc allocTempImp; /* memory functions for temporary pool */
+
+2) call CrcGenerateTable(); function to initialize CRC structures.
+
+3) call SzArEx_Init(&db); function to initialize db structures.
+
+4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive
+
+This function opens archive "inStream" and reads headers to "db".
+All items in "db" will be allocated with "allocMain" functions.
+SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
+
+5) List items or Extract items
+
+ Listing code:
+ ~~~~~~~~~~~~~
+ {
+ UInt32 i;
+ for (i = 0; i < db.db.NumFiles; i++)
+ {
+ CFileItem *f = db.db.Files + i;
+ printf("%10d %s\n", (int)f->Size, f->Name);
+ }
+ }
+
+ Extracting code:
+ ~~~~~~~~~~~~~~~~
+
+ SZ_RESULT SzAr_Extract(
+ CArchiveDatabaseEx *db,
+ ILookInStream *inStream,
+ UInt32 fileIndex, /* index of file */
+ UInt32 *blockIndex, /* index of solid block */
+ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
+ size_t *outBufferSize, /* buffer size for output buffer */
+ size_t *offset, /* offset of stream for required file in *outBuffer */
+ size_t *outSizeProcessed, /* size of file in *outBuffer */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp);
+
+ If you need to decompress more than one file, you can send these values from previous call:
+ blockIndex,
+ outBuffer,
+ outBufferSize,
+ You can consider "outBuffer" as cache of solid block. If your archive is solid,
+ it will increase decompression speed.
+
+ After decompressing you must free "outBuffer":
+ allocImp.Free(outBuffer);
+
+6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
+
+
+
+
+Memory requirements for .7z decoding
+------------------------------------
+
+Memory usage for Archive opening:
+ - Temporary pool:
+ - Memory for uncompressed .7z headers
+ - some other temporary blocks
+ - Main pool:
+ - Memory for database:
+ Estimated size of one file structures in solid archive:
+ - Size (4 or 8 Bytes)
+ - CRC32 (4 bytes)
+ - LastWriteTime (8 bytes)
+ - Some file information (4 bytes)
+ - File Name (variable length) + pointer + allocation structures
+
+Memory usage for archive Decompressing:
+ - Temporary pool:
+ - Memory for LZMA decompressing structures
+ - Main pool:
+ - Memory for decompressed solid block
+ - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
+ temprorary buffers can be about 15% of solid block size.
+
+
+7z Decoder doesn't allocate memory for compressed blocks.
+Instead of this, you must allocate buffer with desired
+size before calling 7z Decoder. Use 7zMain.c as example.
+
+
+Defines
+-------
+
+_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/src/libs/7zip/unix/DOCS/7zFormat.txt b/src/libs/7zip/unix/DOCS/7zFormat.txt
new file mode 100644
index 000000000..55b52b1b9
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/7zFormat.txt
@@ -0,0 +1,469 @@
+7z Format description (4.59)
+----------------------------
+
+This file contains description of 7z archive format.
+7z archive can contain files compressed with any method.
+See "Methods.txt" for description for defined compressing methods.
+
+
+Format structure Overview
+-------------------------
+
+Some fields can be optional.
+
+Archive structure
+~~~~~~~~~~~~~~~~~
+SignatureHeader
+[PackedStreams]
+[PackedStreamsForHeaders]
+[
+ Header
+ or
+ {
+ Packed Header
+ HeaderInfo
+ }
+]
+
+
+
+Header structure
+~~~~~~~~~~~~~~~~
+{
+ ArchiveProperties
+ AdditionalStreams
+ {
+ PackInfo
+ {
+ PackPos
+ NumPackStreams
+ Sizes[NumPackStreams]
+ CRCs[NumPackStreams]
+ }
+ CodersInfo
+ {
+ NumFolders
+ Folders[NumFolders]
+ {
+ NumCoders
+ CodersInfo[NumCoders]
+ {
+ ID
+ NumInStreams;
+ NumOutStreams;
+ PropertiesSize
+ Properties[PropertiesSize]
+ }
+ NumBindPairs
+ BindPairsInfo[NumBindPairs]
+ {
+ InIndex;
+ OutIndex;
+ }
+ PackedIndices
+ }
+ UnPackSize[Folders][Folders.NumOutstreams]
+ CRCs[NumFolders]
+ }
+ SubStreamsInfo
+ {
+ NumUnPackStreamsInFolders[NumFolders];
+ UnPackSizes[]
+ CRCs[]
+ }
+ }
+ MainStreamsInfo
+ {
+ (Same as in AdditionalStreams)
+ }
+ FilesInfo
+ {
+ NumFiles
+ Properties[]
+ {
+ ID
+ Size
+ Data
+ }
+ }
+}
+
+HeaderInfo structure
+~~~~~~~~~~~~~~~~~~~~
+{
+ (Same as in AdditionalStreams)
+}
+
+
+
+Notes about Notation and encoding
+---------------------------------
+
+7z uses little endian encoding.
+
+7z archive format has optional headers that are marked as
+[]
+Header
+[]
+
+REAL_UINT64 means real UINT64.
+
+UINT64 means real UINT64 encoded with the following scheme:
+
+ Size of encoding sequence depends from first byte:
+ First_Byte Extra_Bytes Value
+ (binary)
+ 0xxxxxxx : ( xxxxxxx )
+ 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
+ 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
+ ...
+ 1111110x BYTE y[6] : ( x << (8 * 6)) + y
+ 11111110 BYTE y[7] : y
+ 11111111 BYTE y[8] : y
+
+
+
+Property IDs
+------------
+
+0x00 = kEnd
+
+0x01 = kHeader
+
+0x02 = kArchiveProperties
+
+0x03 = kAdditionalStreamsInfo
+0x04 = kMainStreamsInfo
+0x05 = kFilesInfo
+
+0x06 = kPackInfo
+0x07 = kUnPackInfo
+0x08 = kSubStreamsInfo
+
+0x09 = kSize
+0x0A = kCRC
+
+0x0B = kFolder
+
+0x0C = kCodersUnPackSize
+0x0D = kNumUnPackStream
+
+0x0E = kEmptyStream
+0x0F = kEmptyFile
+0x10 = kAnti
+
+0x11 = kName
+0x12 = kCTime
+0x13 = kATime
+0x14 = kMTime
+0x15 = kWinAttributes
+0x16 = kComment
+
+0x17 = kEncodedHeader
+
+0x18 = kStartPos
+0x19 = kDummy
+
+
+7z format headers
+-----------------
+
+SignatureHeader
+~~~~~~~~~~~~~~~
+ BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+ ArchiveVersion
+ {
+ BYTE Major; // now = 0
+ BYTE Minor; // now = 2
+ };
+
+ UINT32 StartHeaderCRC;
+
+ StartHeader
+ {
+ REAL_UINT64 NextHeaderOffset
+ REAL_UINT64 NextHeaderSize
+ UINT32 NextHeaderCRC
+ }
+
+
+...........................
+
+
+ArchiveProperties
+~~~~~~~~~~~~~~~~~
+BYTE NID::kArchiveProperties (0x02)
+for (;;)
+{
+ BYTE PropertyType;
+ if (aType == 0)
+ break;
+ UINT64 PropertySize;
+ BYTE PropertyData[PropertySize];
+}
+
+
+Digests (NumStreams)
+~~~~~~~~~~~~~~~~~~~~~
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumStreams)
+ BIT Defined
+ }
+ UINT32 CRCs[NumDefined]
+
+
+PackInfo
+~~~~~~~~~~~~
+ BYTE NID::kPackInfo (0x06)
+ UINT64 PackPos
+ UINT64 NumPackStreams
+
+ []
+ BYTE NID::kSize (0x09)
+ UINT64 PackSizes[NumPackStreams]
+ []
+
+ []
+ BYTE NID::kCRC (0x0A)
+ PackStreamDigests[NumPackStreams]
+ []
+
+ BYTE NID::kEnd
+
+
+Folder
+~~~~~~
+ UINT64 NumCoders;
+ for (NumCoders)
+ {
+ BYTE
+ {
+ 0:3 CodecIdSize
+ 4: Is Complex Coder
+ 5: There Are Attributes
+ 6: Reserved
+ 7: There are more alternative methods. (Not used anymore, must be 0).
+ }
+ BYTE CodecId[CodecIdSize]
+ if (Is Complex Coder)
+ {
+ UINT64 NumInStreams;
+ UINT64 NumOutStreams;
+ }
+ if (There Are Attributes)
+ {
+ UINT64 PropertiesSize
+ BYTE Properties[PropertiesSize]
+ }
+ }
+
+ NumBindPairs = NumOutStreamsTotal - 1;
+
+ for (NumBindPairs)
+ {
+ UINT64 InIndex;
+ UINT64 OutIndex;
+ }
+
+ NumPackedStreams = NumInStreamsTotal - NumBindPairs;
+ if (NumPackedStreams > 1)
+ for(NumPackedStreams)
+ {
+ UINT64 Index;
+ };
+
+
+
+
+Coders Info
+~~~~~~~~~~~
+
+ BYTE NID::kUnPackInfo (0x07)
+
+
+ BYTE NID::kFolder (0x0B)
+ UINT64 NumFolders
+ BYTE External
+ switch(External)
+ {
+ case 0:
+ Folders[NumFolders]
+ case 1:
+ UINT64 DataStreamIndex
+ }
+
+
+ BYTE ID::kCodersUnPackSize (0x0C)
+ for(Folders)
+ for(Folder.NumOutStreams)
+ UINT64 UnPackSize;
+
+
+ []
+ BYTE NID::kCRC (0x0A)
+ UnPackDigests[NumFolders]
+ []
+
+
+
+ BYTE NID::kEnd
+
+
+
+SubStreams Info
+~~~~~~~~~~~~~~
+ BYTE NID::kSubStreamsInfo; (0x08)
+
+ []
+ BYTE NID::kNumUnPackStream; (0x0D)
+ UINT64 NumUnPackStreamsInFolders[NumFolders];
+ []
+
+
+ []
+ BYTE NID::kSize (0x09)
+ UINT64 UnPackSizes[]
+ []
+
+
+ []
+ BYTE NID::kCRC (0x0A)
+ Digests[Number of streams with unknown CRC]
+ []
+
+
+ BYTE NID::kEnd
+
+
+Streams Info
+~~~~~~~~~~~~
+
+ []
+ PackInfo
+ []
+
+
+ []
+ CodersInfo
+ []
+
+
+ []
+ SubStreamsInfo
+ []
+
+ BYTE NID::kEnd
+
+
+FilesInfo
+~~~~~~~~~
+ BYTE NID::kFilesInfo; (0x05)
+ UINT64 NumFiles
+
+ for (;;)
+ {
+ BYTE PropertyType;
+ if (aType == 0)
+ break;
+
+ UINT64 Size;
+
+ switch(PropertyType)
+ {
+ kEmptyStream: (0x0E)
+ for(NumFiles)
+ BIT IsEmptyStream
+
+ kEmptyFile: (0x0F)
+ for(EmptyStreams)
+ BIT IsEmptyFile
+
+ kAnti: (0x10)
+ for(EmptyStreams)
+ BIT IsAntiFile
+
+ case kCTime: (0x12)
+ case kATime: (0x13)
+ case kMTime: (0x14)
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumFiles)
+ BIT TimeDefined
+ }
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Definded Items)
+ UINT64 Time
+ []
+
+ kNames: (0x11)
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Files)
+ {
+ wchar_t Names[NameSize];
+ wchar_t 0;
+ }
+ []
+
+ kAttributes: (0x15)
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumFiles)
+ BIT AttributesAreDefined
+ }
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Definded Attributes)
+ UINT32 Attributes
+ []
+ }
+ }
+
+
+Header
+~~~~~~
+ BYTE NID::kHeader (0x01)
+
+ []
+ ArchiveProperties
+ []
+
+ []
+ BYTE NID::kAdditionalStreamsInfo; (0x03)
+ StreamsInfo
+ []
+
+ []
+ BYTE NID::kMainStreamsInfo; (0x04)
+ StreamsInfo
+ []
+
+ []
+ FilesInfo
+ []
+
+ BYTE NID::kEnd
+
+
+HeaderInfo
+~~~~~~~~~~
+ []
+ BYTE NID::kEncodedHeader; (0x17)
+ StreamsInfo for Encoded Header
+ []
+
+
+---
+End of document
diff --git a/src/libs/7zip/unix/DOCS/License.txt b/src/libs/7zip/unix/DOCS/License.txt
new file mode 100644
index 000000000..a6a721853
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/License.txt
@@ -0,0 +1,52 @@
+ 7-Zip source code
+ ~~~~~~~~~~~~~~~~~
+ License for use and distribution
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ 7-Zip Copyright (C) 1999-2010 Igor Pavlov.
+
+ Licenses for files are:
+
+ 1) CPP/7zip/Compress/Rar* files: GNU LGPL + unRAR restriction
+ 2) All other files: GNU LGPL
+
+ The GNU LGPL + unRAR restriction means that you must follow both
+ GNU LGPL rules and unRAR restriction rules.
+
+
+ GNU LGPL information
+ --------------------
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ unRAR restriction
+ -----------------
+
+ The decompression engine for RAR archives was developed using source
+ code of unRAR program.
+ All copyrights to original unRAR code are owned by Alexander Roshal.
+
+ The license for original unRAR code has the following restriction:
+
+ The unRAR sources cannot be used to re-create the RAR compression algorithm,
+ which is proprietary. Distribution of modified unRAR sources in separate form
+ or as a part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+
+ --
+ Igor Pavlov
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/add.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/add.htm
new file mode 100644
index 000000000..7bc5ea22f
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/add.htm
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>a (Add) command</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>a (Add) command</H1>
+
+<P>Adds files to archive.</P>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z a archive1.zip subdir\
+</PRE>
+
+<P>adds all files and subfolders from folder <SPAN class="filename">subdir</SPAN> to archive
+ <SPAN class="filename">archive1.zip</SPAN>.
+ The filenames in archive will contain <SPAN class="filename">subdir\</SPAN> prefix.</P>
+
+<PRE class="example">
+7z a archive2.zip .\subdir\*
+</PRE>
+
+<P>adds all files and subfolders from folder <SPAN class="filename">subdir</SPAN> to archive
+ <SPAN class="filename">archive2.zip</SPAN>.
+ The filenames in archive will not contain <SPAN class="filename">subdir\</SPAN> prefix.</P>
+
+
+<PRE class="example">
+cd /D c:\dir1\
+7z a c:\archive3.zip dir2\dir3\
+</PRE>
+
+The filenames in archive <SPAN class="filename">c:\archive3.zip</SPAN>
+will contain <SPAN class="filename">dir2\dir3\</SPAN> prefix,
+but they will not contain <SPAN class="filename">c:\dir1\</SPAN> prefix.
+
+<PRE class="example">
+7z a Files.7z *.txt -r
+</PRE>
+
+<P>adds all *.txt files from current folder and its subfolders to archive
+ <SPAN class="filename">Files.7z</SPAN>.</P>
+
+
+<H4>Notes</H4>
+
+<P>7-Zip doesn't uses the system wildcard parser. 7-Zip doesn't
+follow the archaic rule by which *.* means any file. 7-Zip treats
+*.* as matching the name of any file that has an extension. To process
+all files, you must use a * wildcard.</P>
+
+
+<H4>Switches that can be used with this command</H4>
+
+<P>
+ <A href="../switches/include.htm">-i (Include)</A><BR>
+ <A href="../switches/method.htm">-m (Method)</A><BR>
+ <A href="../switches/password.htm">-p (Set Password)</A><BR>
+ <A href="../switches/recurse.htm">-r (Recurse)</A><BR>
+ <A href="../switches/sfx.htm">-sfx (create SFX)</A><BR>
+ <A href="../switches/stdin.htm">-si (use StdIn)</A><BR>
+ <A href="../switches/stdout.htm">-so (use StdOut)</A><BR>
+ <A href="../switches/type.htm">-t (Type of archive)</A><BR>
+ <A href="../switches/update.htm">-u (Update)</A><BR>
+ <A href="../switches/volume.htm">-v (Volumes)</A><BR>
+ <A href="../switches/working_dir.htm">-w (Working Dir)</A><BR>
+ <A href="../switches/exclude.htm">-x (Exclude)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Commands:</B>
+ <A href="delete.htm">d (Delete)</A>,
+ <A href="update.htm">u (Update)</A><BR>
+ <B>Switches:</B>
+ <A href="../switches/update.htm">-u (Update)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/bench.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/bench.htm
new file mode 100644
index 000000000..14f456cd3
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/bench.htm
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>b (Benchmark) command</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>b (Benchmark) command</H1>
+
+<P>Measures speed of the CPU and checks RAM for errors.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+b [number_of_iterations] [-mmt{N}] [-md{N}] [-mm={Method}]
+</PRE>
+
+<P>There are two tests:<P>
+<OL>
+ <LI>Compressing with LZMA method
+ <LI>Decompressing with LZMA method
+</OL>
+
+<P>The benchmark shows a rating in MIPS (million instructions per second).
+The rating value is calculated from the measured CPU speed and it
+is normalized with results of Intel Core 2 CPU with multi-threading option
+switched off. So if you have Intel Core 2 Duo,
+rating values must be close to real CPU frequency.</P>
+
+<P>You can change the upper dictionary size to increase memory usage by -md{N} switch.
+Also, you can change the number of threads by -mmt{N} switch.</P>
+
+<P>The <B>Dict</B> column shows dictionary size. For example, 21 means 2^21 = 2 MB.</P>
+
+<P>The <B>Usage</B> column shows the percentage of time the processor is working.
+It's normalized for a one-thread load. For example, 180% CPU Usage for 2 threads
+can mean that average CPU usage is about 90% for each thread.</P>
+
+<P>The <B>R / U</B> column shows the rating normalized for 100% of CPU usage.
+That column shows the performance of one average CPU thread.</P>
+
+<P><B>Avr</B> shows averages for different dictionary sizes.</P>
+<P><B>Tot</B> shows averages of the compression and decompression ratings.</P>
+
+<P>Compression speed and rating strongly depend on memory (RAM) latency.
+
+<P>Decompression speed and rating strongly depend on the integer performance of the CPU.
+For example, the Intel Pentium 4 has big branch
+misprediction penalty (which is an effect of its long pipeline) and pretty slow
+multiply and shift operations. So, the Pentium 4 has pretty low decompressing ratings.</P>
+
+<P>You can run a CRC calculation benchmark by specifying -mm=crc.
+That test shows the speed of CRC calculation in MB/s. The first column shows the size of the block.
+The next column shows the speed of CRC calculation for one thread. The other columns are results
+for multi-threaded CRC calculation.</P>
+
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z b
+</PRE>
+runs benchmarking.
+
+<PRE class="example">
+7z b -mmt1 -md26
+</PRE>
+runs benchmarking with one thread and 64 MB dictionary.
+
+<PRE class="example">
+7z b 30
+</PRE>
+<P>runs benchmarking with default settings for 30 iterations.</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/delete.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/delete.htm
new file mode 100644
index 000000000..845b8d899
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/delete.htm
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>d (Delete) command</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>d (Delete) command</H1>
+
+<P>Deletes files from archive.</P>
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z d archive.zip *.bak -r
+</PRE>
+
+<P>deletes <SPAN class="filename">*.bak</SPAN> files from archive
+ <SPAN class="filename">archive.zip</SPAN>.</P>
+
+
+<H4>Notes</H4>
+
+<P>7-Zip doesn't uses the system wildcard parser. 7-Zip doesn't
+follow the archaic rule by which *.* means any file. 7-Zip treats
+*.* as matching the name of any file that has an extension. To process
+all files, you must use a * wildcard.</P>
+
+
+<H4>Switches that can be used with this command</H4>
+
+<P>
+ <A href="../switches/include.htm">-i (Include)</A><BR>
+ <A href="../switches/method.htm">-m (Method)</A><BR>
+ <A href="../switches/password.htm">-p (Set Password)</A><BR>
+ <A href="../switches/recurse.htm">-r (Recurse)</A><BR>
+ <A href="../switches/update.htm">-u (Update)</A><BR>
+ <A href="../switches/working_dir.htm">-w (Working Dir)</A><BR>
+ <A href="../switches/exclude.htm">-x (Exclude)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Commands:</B>
+ <A href="add.htm">a (Add)</A>,
+ <A href="update.htm">u (Update)</A>
+</P>
+
+<P>
+ <B>Switches:</B>
+ <A href="../switches/update.htm">-u (Update)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/extract.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/extract.htm
new file mode 100644
index 000000000..dad6b2b0b
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/extract.htm
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>e (Extract) command</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>e (Extract) command</H1>
+
+<P>Extracts files from an archive to the current
+directory or to the output directory. The output directory can be specified by
+<A href="../switches/output_dir.htm">-o (Set Output Directory)</A> switch.</P>
+
+<P>This command copies all extracted files to one directory.
+If you want extract files with full paths, you must use
+<A href="extract_full.htm">x (Extract with full paths)</A> command.
+
+<P>7-Zip will prompt the user before overwriting existing files unless
+the user specifies the <A href="../switches/yes.htm">-y (Assume Yes on all queries)</A>
+switch. If the user gives a <B>no</B> answer, 7-Zip will prompt for the file to be
+extracted to a new filename. Then a <B>no</B> answer skips that file; or, <B>yes</B>
+prompts for new filename.</P>
+
+<P>7-Zip accepts the following responses:</P>
+
+<TABLE>
+ <TR> <TH>Answer</TH> <TH>Abbr.</TH> <TH>Action</TH> </TR>
+ <TR> <TD>Yes</TD> <TD>y</TD> <TD>&nbsp;</TD> </TR>
+ <TR> <TD>No</TD> <TD>n</TD> <TD>&nbsp;</TD> </TR>
+ <TR> <TD>Always</TD> <TD>a</TD> <TD>Assume YES for ALL subsequent queries of the same class</TD> </TR>
+ <TR> <TD>Skip</TD> <TD>s</TD> <TD>Assume NO for ALL subsequent queries of the same class</TD> </TR>
+ <TR> <TD>Quit</TD> <TD>q</TD> <TD>Quit the program</TD> </TR>
+
+</TABLE>
+
+<P>Abbreviated responses are allowed.</P>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z e archive.zip
+</PRE>
+
+<P>extracts all files from archive
+ <SPAN class="filename">archive.zip</SPAN> to the current directory.</P>
+
+<PRE class="example">
+7z e archive.zip -oc:\soft *.cpp -r
+</PRE>
+
+<P>extracts all <SPAN class="filename">*.cpp</SPAN> files from archive
+ <SPAN class="filename">archive.zip</SPAN> to <SPAN class="filename">c:\soft</SPAN> folder.</P>
+
+
+<H4>Notes</H4>
+
+<P>7-Zip doesn't uses the system wildcard parser. 7-Zip doesn't
+follow the archaic rule by which *.* means any file. 7-Zip treats
+*.* as matching the name of any file that has an extension. To process
+all files, you must use a * wildcard.</P>
+
+
+<H4>Switches that can be used with this command</H4>
+
+<P>
+ <A href="../switches/ar_include.htm">-ai (Include archives)</A><BR>
+ <A href="../switches/ar_no.htm">-an (Disable parsing of archive_name)</A><BR>
+ <A href="../switches/overwrite.htm">-ao (Overwrite mode)</A><BR>
+ <A href="../switches/ar_exclude.htm">-ax (Exclude archives)</A><BR>
+ <A href="../switches/include.htm">-i (Include)</A><BR>
+ <A href="../switches/output_dir.htm">-o (Set Output Directory)</A><BR>
+ <A href="../switches/password.htm">-p (Set Password)</A><BR>
+ <A href="../switches/recurse.htm">-r (Recurse)</A><BR>
+ <A href="../switches/stdout.htm">-so (use StdOut)</A><BR>
+ <A href="../switches/type.htm">-t (Type of archive)</A><BR>
+ <A href="../switches/exclude.htm">-x (Exclude)</A><BR>
+ <A href="../switches/yes.htm">-y (Assume Yes on all queries)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Commands:</B>
+ <A href="extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/extract_full.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/extract_full.htm
new file mode 100644
index 000000000..3f857a6e4
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/extract_full.htm
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>x (Extract with full paths) command</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>x (Extract with full paths) command</H1>
+
+<P>Extracts files from an archive with their full
+paths in the current directory, or in an output directory if specified.</P>
+
+<P>See the <A href="extract.htm">e (Extract)</A> command description for more details.</P>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z x archive.zip
+</PRE>
+
+<P>extracts all files from the archive
+ <SPAN class="filename">archive.zip</SPAN> to the current directory.</P>
+
+<PRE class="example">
+7z x archive.zip -oc:\soft *.cpp -r
+</PRE>
+
+<P>extracts all <SPAN class="filename">*.cpp</SPAN> files from the archive
+ <SPAN class="filename">archive.zip</SPAN> to <SPAN class="filename">c:\soft</SPAN> folder.</P>
+
+
+<H4>Notes</H4>
+
+<P>7-Zip doesn't uses the system wildcard parser. 7-Zip doesn't
+follow the archaic rule by which *.* means any file. 7-Zip treats
+*.* as matching the name of any file that has an extension. To process
+all files, you must use a * wildcard.</P>
+
+
+<H4>Switches that can be used with this command</H4>
+
+<P>
+ <A href="../switches/ar_include.htm">-ai (Include archives)</A><BR>
+ <A href="../switches/ar_no.htm">-an (Disable parsing of archive_name)</A><BR>
+ <A href="../switches/overwrite.htm">-ao (Overwrite mode)</A><BR>
+ <A href="../switches/ar_exclude.htm">-ax (Exclude archives)</A><BR>
+ <A href="../switches/include.htm">-i (Include)</A><BR>
+ <A href="../switches/output_dir.htm">-o (Set Output Directory)</A><BR>
+ <A href="../switches/password.htm">-p (Set Password)</A><BR>
+ <A href="../switches/recurse.htm">-r (Recurse)</A><BR>
+ <A href="../switches/stdout.htm">-so (use StdOut)</A><BR>
+ <A href="../switches/type.htm">-t (Type of archive)</A><BR>
+ <A href="../switches/exclude.htm">-x (Exclude)</A><BR>
+ <A href="../switches/yes.htm">-y (Assume Yes on all queries)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Commands:</B>
+ <A href="extract.htm">e (Extract)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/index.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/index.htm
new file mode 100644
index 000000000..579ea2931
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/index.htm
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>Command Line Commands</TITLE>
+ <LINK href="style.css" rel=stylesheet type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>Command Line Commands</H1>
+
+<P>The command is the first non-switch argument on the command line.</P>
+<P>Command names are not case sensitive.</P>
+<P>See also <A href ="../syntax.htm">Command Line Syntax</A> for more details about using the command line.</P>
+
+<H2>Commands quick reference</H2>
+
+<TABLE border="1" cellpadding="3" cellspacing="0">
+<TR><TH>Command</TH><TH>Description</TH></TR>
+<TR> <TD><A href="add.htm">a</A></TD> <TD><A href="add.htm">Add</A></TD></TR>
+<TR> <TD><A href="bench.htm">b</A></TD> <TD><A href="bench.htm">Benchmark</A></TD></TR>
+<TR> <TD><A href="delete.htm">d</A></TD> <TD><A href="delete.htm">Delete</A></TD></TR>
+<TR> <TD><A href="extract.htm">e</A></TD> <TD><A href="extract.htm">Extract</A></TD></TR>
+<TR> <TD><A href="list.htm">l</A></TD> <TD><A href="list.htm">List</A></TD></TR>
+<TR> <TD><A href="test.htm">t</A></TD> <TD><A href="test.htm">Test</A></TD></TR>
+<TR> <TD><A href="update.htm">u</A></TD> <TD><A href="update.htm">Update</A></TD></TR>
+<TR> <TD><A href="extract_full.htm">x</A></TD> <TD><A href="extract_full.htm">eXtract with full paths</A></TD></TR>
+</TABLE>
+
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/list.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/list.htm
new file mode 100644
index 000000000..1eba758e9
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/list.htm
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>l (List contents of archive) command</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>l (List contents of archive) command</H1>
+
+
+
+<!--
+<H4>Syntax</H4>
+<P><PRE class="syntax">
+l[a | t][f]
+</PRE></P>
+
+-->
+
+<P>Lists contents of archive.</P>
+
+<!--
+<P>The following options can be used:</P>
+<TABLE>
+<TR> <TH>Option</TH> <TH>Description</TH> </TR>
+<TR> <TD>a</TD> <TD>List with Additional fields</TD> </TR>
+<TR> <TD>t</TD> <TD>List with all fields, including Technical</TD> </TR>
+<TR> <TD>f</TD> <TD>List with Full pathnames</TD> </TR>
+</TABLE>
+-->
+
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z l archive.zip
+</PRE>
+
+<P>lists all files from archive <SPAN class="filename">archive.zip</SPAN>.</P>
+
+<!--
+<PRE class="example">
+7z lf archive.zip *.txt
+</PRE>
+
+<P>lists <SPAN class="filename">*.txt</SPAN> files from archive
+ <SPAN class="filename">archive.zip</SPAN> with full pathnames.</P>
+-->
+
+
+<H4>Notes</H4>
+
+<P>7-Zip doesn't uses the system wildcard parser. 7-Zip doesn't
+follow the archaic rule by which *.* means any file. 7-Zip treats
+*.* as matching the name of any file that has an extension. To process
+all files, you must use a * wildcard.</P>
+
+
+<H4>Switches that can be used with this command</H4>
+
+<P>
+ <A href="../switches/ar_include.htm">-ai (Include archives)</A><BR>
+ <A href="../switches/ar_no.htm">-an (Disable parsing of archive_name)</A><BR>
+ <A href="../switches/ar_exclude.htm">-ax (Exclude archives)</A><BR>
+ <A href="../switches/include.htm">-i (Include)</A><BR>
+ <A href="../switches/list_tech.htm">-slt (Show technical information)</A><BR>
+ <A href="../switches/password.htm">-p (Set Password)</A><BR>
+ <A href="../switches/recurse.htm">-r (Recurse)</A><BR>
+ <A href="../switches/type.htm">-t (Type of archive)</A><BR>
+ <A href="../switches/exclude.htm">-x (Exclude)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/style.css b/src/libs/7zip/unix/DOCS/MANUAL/commands/style.css
new file mode 100644
index 000000000..13ebb79ce
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/style.css
@@ -0,0 +1,232 @@
+body
+ {
+ padding: 0px 0px 0px 26px;
+ background: #ffffff;
+ color: #000000;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 80%;
+ }
+
+div
+ {
+ width: 90%;
+ border: 2px solid #999999;
+ padding: 4px 8px;
+ background: #cccccc;
+ }
+
+h1, h2, h3, h4
+ {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ margin-left: -26px;
+ }
+
+h1
+ {
+ font-size: 145%;
+ margin-top: .5em;
+ margin-bottom: 1em;
+ }
+
+h2
+ {
+ font-size: 130%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+h3
+ {
+ font-size: 115%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+h4
+ {
+ font-size: 100%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+ul p, ol p, dl p
+ {
+ margin-left: 0em;
+ }
+
+p
+ {
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+
+dl
+ {
+ /*margin-top: 0em; */
+ }
+
+dt
+ {
+ margin-top: .76em;
+ margin-bottom: .5em;
+ font-weight: bold;
+ }
+
+dd
+ {
+ margin-top: .5em;
+ margin-bottom: .5em;
+ margin-left: 1.9em;
+ }
+
+
+ul, ol
+ {
+ margin-top: .6em;
+ margin-bottom: 0em;
+ }
+
+ol
+ {
+ margin-left: 3.6em;
+ }
+
+ul
+ {
+ list-style-type: disc;
+ margin-left: 1.9em;
+ }
+
+li
+ {
+ margin-bottom: .6em;
+ }
+
+ul ol, ol ol
+ {
+ list-style-type: lower-alpha;
+ {
+
+ /*
+pre
+ {
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+ */
+
+pre,code
+ {
+ font: 100% Courier New, Courier, mono;
+ color: #000000;
+ cursor: text;
+ }
+
+pre.syntax
+ {
+ background: #dddddd;
+ padding: 2pt,4pt
+ }
+
+pre.syntax
+ {
+ color: #000000;
+ }
+
+pre.example
+ {
+ margin-left: 2.0em;
+ /*margin-top: 12.0em;*/
+ /*margin-bottom: 1.0em;*/
+ color: #C00000;
+ /*padding: 10pt,20pt*/
+ }
+
+table
+ {
+ /* width: 90%; */
+ background: #999999;
+ margin-top: .6em;
+ margin-bottom: .3em;
+ }
+
+th
+ {
+ padding: 4px 8px;
+ background: #cccccc;
+ text-align: left;
+ font-size: 80%;
+ vertical-align: bottom;
+ }
+
+th.cc
+ {
+ text-align: center;
+ vertical-align: middle;
+ }
+
+td
+ {
+ padding: 4px 8px;
+ background: #ffffff;
+ vertical-align: top;
+ font-size: 80%;
+ }
+
+td.cc
+ {
+ text-align: center;
+ vertical-align: middle;
+ }
+
+
+blockquote
+ {
+ margin-left: 3.8em;
+ margin-right: 3.8em;
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+
+a:link
+ {
+ color: #0066ff;
+ }
+
+a:visited
+ {
+ color: #996600;
+ }
+
+a:hover
+ {
+ color: #cc9900;
+ }
+
+a.parameter:link
+ {
+ color: #0066ff;
+ text-decoration:none;
+ }
+
+a.parameter:visited
+ {
+ text-decoration:none;
+ }
+
+div.footer
+ {
+ width: 100%;
+ border: none;
+ background: #ffffff;
+ margin-top: 18pt;
+ padding-bottom: 12pt;
+ color: #228B22;
+ text-align: center;
+ font-size: 70%;
+ }
+
+span.filename
+{
+ color: #F00000;
+}
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/test.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/test.htm
new file mode 100644
index 000000000..b09f8a497
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/test.htm
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>t (Test integrity of archive) command</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>t (Test integrity of archive) command</H1>
+
+<P>Tests archive files.</P>
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z t archive.zip *.doc -r
+</PRE>
+
+<P>tests <SPAN class="filename">*.doc</SPAN> files in archive
+ <SPAN class="filename">archive.zip</SPAN>.</P>
+
+
+<H4>Notes</H4>
+
+<P>7-Zip doesn't uses the system wildcard parser. 7-Zip doesn't
+follow the archaic rule by which *.* means any file. 7-Zip treats
+*.* as matching the name of any file that has an extension. To process
+all files, you must use a * wildcard.</P>
+
+
+<H4>Switches that can be used with this command</H4>
+
+<P>
+ <A href="../switches/ar_include.htm">-ai (Include archives)</A><BR>
+ <A href="../switches/ar_no.htm">-an (Disable parsing of archive_name)</A><BR>
+ <A href="../switches/ar_exclude.htm">-ax (Exclude archives)</A><BR>
+ <A href="../switches/include.htm">-i (Include)</A><BR>
+ <A href="../switches/password.htm">-p (Set Password)</A><BR>
+ <A href="../switches/recurse.htm">-r (Recurse)</A><BR>
+ <A href="../switches/exclude.htm">-x (Exclude)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/commands/update.htm b/src/libs/7zip/unix/DOCS/MANUAL/commands/update.htm
new file mode 100644
index 000000000..860080109
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/commands/update.htm
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>u (Update) command</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>u (Update) command</H1>
+
+<P>Update older files in the archive and add files that are not already in the archive.</P>
+
+<P>Note: the updating of solid .7z archives can be slow, since it
+can require some recompression.</P>
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z u archive.zip *.doc
+</PRE>
+
+<P>updates <SPAN class="filename">*.doc</SPAN> files to archive
+ <SPAN class="filename">archive.zip</SPAN>.</P>
+
+
+<H4>Notes</H4>
+
+<P>7-Zip doesn't uses the system wildcard parser. 7-Zip doesn't
+follow the archaic rule by which *.* means any file. 7-Zip treats
+*.* as matching the name of any file that has an extension. To process
+all files, you must use a * wildcard.</P>
+
+
+<H4>Switches that can be used with this command</H4>
+
+<P>
+ <A href="../switches/include.htm">-i (Include)</A><BR>
+ <A href="../switches/method.htm">-m (Method)</A><BR>
+ <A href="../switches/password.htm">-p (Set Password)</A><BR>
+ <A href="../switches/recurse.htm">-r (Recurse)</A><BR>
+ <A href="../switches/sfx.htm">-sfx (create SFX)</A><BR>
+ <A href="../switches/stdin.htm">-si (use StdIn)</A><BR>
+ <A href="../switches/stdout.htm">-so (use StdOut)</A><BR>
+ <A href="../switches/type.htm">-t (Type of archive)</A><BR>
+ <A href="../switches/update.htm">-u (Update)</A><BR>
+ <A href="../switches/working_dir.htm">-w (Working Dir)</A><BR>
+ <A href="../switches/exclude.htm">-x (Exclude)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Commands:</B>
+ <A href="add.htm">a (Add)</A>,
+ <A href="delete.htm">d (Delete)</A>,
+</P>
+
+<P>
+ <B>Switches:</B>
+ <A href="../switches/update.htm">-u (Update)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/exit_codes.htm b/src/libs/7zip/unix/DOCS/MANUAL/exit_codes.htm
new file mode 100644
index 000000000..4cdc74a5b
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/exit_codes.htm
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>Exit Codes from 7-Zip</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>Exit Codes from 7-Zip</H1>
+
+<P>7-Zip returns the following exit codes:</P>
+
+<TABLE>
+ <TR><TH>Code</TH><TH>Meaning</TH></TR>
+ <TR><TD>0</TH><TD>No error</TD></TR>
+ <TR><TD>1</TH><TD>Warning (Non fatal error(s)). For example, one or more files were
+ locked by some other application, so they were not compressed.</TD></TR>
+ <TR><TD>2</TH><TD>Fatal error</TD></TR>
+ <TR><TD>7</TH><TD>Command line error</TD></TR>
+ <TR><TD>8</TH><TD>Not enough memory for operation</TD></TR>
+ <TR><TD>255</TH><TD>User stopped the process</TD></TR>
+</TABLE>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/index.htm b/src/libs/7zip/unix/DOCS/MANUAL/index.htm
new file mode 100644
index 000000000..5bf8aae61
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/index.htm
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>Command Line Version User's Guide</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>Command Line Version User's Guide</H1>
+
+
+<P>7z.exe is the command line version of 7-Zip. 7z.exe uses 7z.dll
+from the 7-Zip package. 7z.dll is used by the 7-Zip File Manager also.</LI>
+
+<P>7za.exe (a = alone) is a standalone version of 7-Zip.
+7za.exe supports only 7z, lzma, cab, zip, gzip, bzip2, Z and tar formats.
+7za.exe doesn't use external modules.</LI>
+
+<UL>
+ <LI><A href = "syntax.htm">Command Line syntax</A></LI>
+ <LI><A href = "exit_codes.htm">Exit Codes</A></LI>
+ <LI><A href = "commands/index.htm">Commands</A></LI>
+ <LI><A href = "switches/index.htm">Switches</A></LI>
+</UL>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/style.css b/src/libs/7zip/unix/DOCS/MANUAL/style.css
new file mode 100644
index 000000000..13ebb79ce
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/style.css
@@ -0,0 +1,232 @@
+body
+ {
+ padding: 0px 0px 0px 26px;
+ background: #ffffff;
+ color: #000000;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 80%;
+ }
+
+div
+ {
+ width: 90%;
+ border: 2px solid #999999;
+ padding: 4px 8px;
+ background: #cccccc;
+ }
+
+h1, h2, h3, h4
+ {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ margin-left: -26px;
+ }
+
+h1
+ {
+ font-size: 145%;
+ margin-top: .5em;
+ margin-bottom: 1em;
+ }
+
+h2
+ {
+ font-size: 130%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+h3
+ {
+ font-size: 115%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+h4
+ {
+ font-size: 100%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+ul p, ol p, dl p
+ {
+ margin-left: 0em;
+ }
+
+p
+ {
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+
+dl
+ {
+ /*margin-top: 0em; */
+ }
+
+dt
+ {
+ margin-top: .76em;
+ margin-bottom: .5em;
+ font-weight: bold;
+ }
+
+dd
+ {
+ margin-top: .5em;
+ margin-bottom: .5em;
+ margin-left: 1.9em;
+ }
+
+
+ul, ol
+ {
+ margin-top: .6em;
+ margin-bottom: 0em;
+ }
+
+ol
+ {
+ margin-left: 3.6em;
+ }
+
+ul
+ {
+ list-style-type: disc;
+ margin-left: 1.9em;
+ }
+
+li
+ {
+ margin-bottom: .6em;
+ }
+
+ul ol, ol ol
+ {
+ list-style-type: lower-alpha;
+ {
+
+ /*
+pre
+ {
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+ */
+
+pre,code
+ {
+ font: 100% Courier New, Courier, mono;
+ color: #000000;
+ cursor: text;
+ }
+
+pre.syntax
+ {
+ background: #dddddd;
+ padding: 2pt,4pt
+ }
+
+pre.syntax
+ {
+ color: #000000;
+ }
+
+pre.example
+ {
+ margin-left: 2.0em;
+ /*margin-top: 12.0em;*/
+ /*margin-bottom: 1.0em;*/
+ color: #C00000;
+ /*padding: 10pt,20pt*/
+ }
+
+table
+ {
+ /* width: 90%; */
+ background: #999999;
+ margin-top: .6em;
+ margin-bottom: .3em;
+ }
+
+th
+ {
+ padding: 4px 8px;
+ background: #cccccc;
+ text-align: left;
+ font-size: 80%;
+ vertical-align: bottom;
+ }
+
+th.cc
+ {
+ text-align: center;
+ vertical-align: middle;
+ }
+
+td
+ {
+ padding: 4px 8px;
+ background: #ffffff;
+ vertical-align: top;
+ font-size: 80%;
+ }
+
+td.cc
+ {
+ text-align: center;
+ vertical-align: middle;
+ }
+
+
+blockquote
+ {
+ margin-left: 3.8em;
+ margin-right: 3.8em;
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+
+a:link
+ {
+ color: #0066ff;
+ }
+
+a:visited
+ {
+ color: #996600;
+ }
+
+a:hover
+ {
+ color: #cc9900;
+ }
+
+a.parameter:link
+ {
+ color: #0066ff;
+ text-decoration:none;
+ }
+
+a.parameter:visited
+ {
+ text-decoration:none;
+ }
+
+div.footer
+ {
+ width: 100%;
+ border: none;
+ background: #ffffff;
+ margin-top: 18pt;
+ padding-bottom: 12pt;
+ color: #228B22;
+ text-align: center;
+ font-size: 70%;
+ }
+
+span.filename
+{
+ color: #F00000;
+}
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_exclude.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_exclude.htm
new file mode 100644
index 000000000..697891880
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_exclude.htm
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-ax (Exclude archive filenames) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-ax (Exclude archive filenames) switch</H1>
+
+<P>Specifies archives to be excluded from the operation.</P>
+<P>Multiple exclude archive switches are supported.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-ax[&lt;recurse_type>]&lt;file_ref>
+
+&lt;recurse_type> ::= r[- | 0]
+&lt;file_ref> ::= @{listfile} | !{wildcard}
+</PRE>
+
+<P>See <A href="include.htm">-xi (Include archive filenames)</A> switch description
+for information about option parameters.</P>
+
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z t -an -ai!*.7z -ax!a*.7z
+</PRE>
+
+<P>tests all <SPAN class="filename">*.7z</SPAN> archives,
+ except <SPAN class="filename">a*.7z</SPAN> archives.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/list.htm">l (List)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="include.htm">-ai (Include archives)</A>
+ <A href="ar_no.htm">-an (Disable parsing of archive_name)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_include.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_include.htm
new file mode 100644
index 000000000..30a5a9b69
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_include.htm
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-ai (Include archive filenames) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-ai (Include archive filenames) switch</H1>
+
+<P>Specifies additional include archive filenames and wildcards.</P>
+<P>Multiple include switches are supported.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-ai[<A class="parameter" href="#recurse_type">&lt;recurse_type></A>]<A class="parameter" href="#file_ref">&lt;file_ref></A>
+
+<A class="parameter" href="#recurse_type">&lt;recurse_type></A> ::= r[- | 0]
+<A class="parameter" href="#file_ref">&lt;file_ref></A> ::= @{listfile} | !{wildcard}
+</PRE>
+
+<H4>Parameters</H4>
+
+<DL>
+ <DT><A name="recurse_type"></A>&lt;recurse_type></DT>
+ <DD><P>Specifies how wildcards and file names in this switch must
+ be used. If this option is not given, recursion will be not used.
+ For more details see specification of the
+ <A href="recurse.htm">-r (Recurse)</A> switch.</P>
+<PRE class="syntax">
+&lt;recurse_type> ::= r[- | 0]
+</PRE>
+
+ </DD>
+ <DT><A name="file_ref"></A>&lt;file_ref></DT>
+ <DD>
+ <P>Specifies filenames and wildcards or list file that specify processed files.</P>
+<PRE class="syntax">
+&lt;file_ref> ::= @{listfile} | !{wildcard}
+</PRE>
+ <TABLE>
+ <TR> <TH width="120">Option</TH> <TH>Description</TH> </TR>
+ <TR> <TD>{listfile}</TD> <TD>Specifies name of list file. See
+ <A href = ../syntax.htm#ListFile>List file</A> description.</TD> </TR>
+ <TR> <TD>{wildcard}</TD> <TD>Specifies wildcard or filename.</TD> </TR>
+ </TABLE>
+ </DD>
+</DL>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z t -an -air!*.7z
+</PRE>
+
+<P>tests <SPAN class="filename">*.7z</SPAN> archives in current directory and all it's
+subdirectories.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/list.htm">l (List)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="ar_exclude.htm">-ax (Exclude archives)</A>
+ <A href="ar_no.htm">-an (Disable parsing of archive_name)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_no.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_no.htm
new file mode 100644
index 000000000..d925f13d3
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/ar_no.htm
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-an (Disable parsing of archive_name) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-an (Disable parsing of archive_name) switch</H1>
+
+<P>Disables parsing of the archive_name field on the command line.
+This switch must be used with the
+<A href="include.htm">-ai (Include archives) switch</A>.
+If you use a file list for your archives, you specify it with the -ai switch,
+so you need to disable parsing of archive_name field from command line.
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-an
+</PRE>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z t -an -ai!*.7z -ax!a*.7z
+</PRE>
+
+<P>tests all <SPAN class="filename">*.7z</SPAN> archives,
+ except <SPAN class="filename">a*.7z</SPAN> archives.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/list.htm">l (List)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="include.htm">-ai (Include archives)</A>
+ <A href="exclude.htm">-ax (Exclude archives)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/charset.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/charset.htm
new file mode 100644
index 000000000..e30802652
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/charset.htm
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-scs (Set charset for list files) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-scs (Set charset for list files) switch</H1>
+
+<P>Sets charset for list files.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-scs{UTF-8 | WIN | DOS}
+</PRE>
+
+<P>Default charset is UTF-8.</P>
+
+<DL>
+ <DT>UTF-8</DT>
+ <DD>Unicode UTF-8 character set.</DD>
+ <DT>WIN</DT>
+ <DD>Default character set of Windows.</DD>
+ <DT>DOS</DT>
+ <DD>Default DOS (OEM) character set of Windows.</DD>
+</DL>
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z a archive.7z @listfile.txt -scsWIN
+</PRE>
+
+<P>compresses files from <SPAN class="filename">listfile.txt</SPAN> list, that contains
+list of files in default character set of Windows.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/update.htm">u (Update)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/exclude.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/exclude.htm
new file mode 100644
index 000000000..faf8768e2
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/exclude.htm
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-x (Exclude filenames) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-x (Exclude filenames) switch</H1>
+
+<P>Specifies which filenames or wildcarded names must be excluded from the operation.</P>
+<P>Multiple exclude switches are supported.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-x[&lt;recurse_type>]&lt;file_ref>
+
+&lt;recurse_type> ::= r[- | 0]
+&lt;file_ref> ::= @{listfile} | !{wildcard}
+</PRE>
+
+<P>See <A href="include.htm">-i (Include)</A> switch description for information about
+ option parameters.</P>
+
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z a -tzip archive.zip *.txt -x!temp.*
+</PRE>
+
+<P>adds to the archive <SPAN class="filename">archive.zip</SPAN> all
+ <SPAN class="filename">*.txt</SPAN> files,
+ except <SPAN class="filename">temp.*</SPAN> files.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/list.htm">l (List)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="recurse.htm">-r (Recurse)</A>,
+ <A href="include.htm">-i (Include)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/include.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/include.htm
new file mode 100644
index 000000000..009f5efcb
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/include.htm
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-i (Include filenames) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-i (Include filenames) switch</H1>
+
+<P>Specifies additional include filenames and wildcards.</P>
+<P>Multiple include switches are supported.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-i[<A class="parameter" href="#recurse_type">&lt;recurse_type></A>]<A class="parameter" href="#file_ref">&lt;file_ref></A>
+
+<A class="parameter" href="#recurse_type">&lt;recurse_type></A> ::= r[- | 0]
+<A class="parameter" href="#file_ref">&lt;file_ref></A> ::= @{listfile} | !{wildcard}
+</PRE>
+
+<H4>Parameters</H4>
+
+<DL>
+ <DT><A name="recurse_type"></A>&lt;recurse_type></DT>
+ <DD><P>Specifies how wildcards and file names in this switch must
+ be used. If this option is not given, then the global value, assigned
+ by the <A href="recurse.htm">-r (Recurse)</A> switch will be used. For
+ more details see specification of the
+ <A href="recurse.htm">-r (Recurse)</A> switch.</P>
+<PRE class="syntax">
+&lt;recurse_type> ::= r[- | 0]
+</PRE>
+
+ </DD>
+ <DT><A name="file_ref"></A>&lt;file_ref></DT>
+ <DD>
+ <P>Specifies filenames and wildcards, or a list file, for files to be processed.</P>
+<PRE class="syntax">
+&lt;file_ref> ::= @{listfile} | !{wildcard}
+</PRE>
+ <TABLE>
+ <TR> <TH width="120">Option</TH> <TH>Description</TH> </TR>
+ <TR> <TD>{listfile}</TD> <TD>Specifies name of list file. See
+ <A href = ../syntax.htm#ListFile>List file</A> description.</TD> </TR>
+ <TR> <TD>{wildcard}</TD> <TD>Specifies wildcard or filename.</TD> </TR>
+ </TABLE>
+ </DD>
+</DL>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z a -tzip src.zip *.txt -ir!DIR1\*.cpp
+</PRE>
+
+<P>adds to <SPAN class="filename">src.zip</SPAN> archive all
+ <SPAN class="filename">*.txt</SPAN> files from current directory
+ and all <SPAN class="filename">*.cpp</SPAN>
+ files from directory <SPAN class="filename">DIR1</SPAN>
+ and from all it's subdirectories.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/list.htm">l (List)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="recurse.htm">-r (Recurse)</A>,
+ <A href="exclude.htm">-x (Exclude)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/index.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/index.htm
new file mode 100644
index 000000000..65e335d49
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/index.htm
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>Command Line Switches</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>Command Line Switches</H1>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+&ltswitch>::= &lt;switch_symbol>&lt;switch_characters>[&lt;option>]
+&lt;switch_symbol> ::= '/' | '-'
+
+</PRE>
+<P>On the command line, a switch consists of a switch specifier,
+either a dash (-) or a forward slash (/), followed by the name of
+the switch. Switch names cannot be abbreviated.</P>
+
+<P>Some switches take an argument after the switch name.
+No spaces or tabs are allowed within a switch specification.
+Switch names are not case sensitive, but arguments can be case sensitive.
+</P>
+
+<P>Switch can be used in any place in command line.</B>
+
+<P>See also <A href ="../syntax.htm">Command Line Syntax</A> for more details
+ about using the command line.</P>
+
+<H2>Switch quick reference</H2>
+
+<TABLE border="1" cellpadding="3" cellspacing="0">
+<TR><TH>Switch</TH><TH>Description</TH></TR>
+<TR> <TD><A href="stop_switch.htm">--</A></TD> <TD><A href="stop_switch.htm">Stop switches parsing</A></TD></TR>
+<TR> <TD><A href="ar_include.htm">-ai</A></TD> <TD><A href="ar_include.htm">Include archive filenames</A></TD></TR>
+<TR> <TD><A href="ar_no.htm">-an</A></TD> <TD><A href="ar_no.htm">Disable parsing of archive_name</A></TD></TR>
+<TR> <TD><A href="overwrite.htm">-ao</A></TD> <TD><A href="overwrite.htm">Overwrite mode</A></TD></TR>
+<TR> <TD><A href="ar_exclude.htm">-ax</A></TD> <TD><A href="ar_exclude.htm">Exclude archive filenames</A></TD></TR>
+<TR> <TD><A href="include.htm">-i</A></TD> <TD><A href="include.htm">Include filenames</A></TD></TR>
+<TR> <TD><A href="method.htm">-m</A></TD> <TD><A href="method.htm">Set Compression Method</A></TD></TR>
+<TR> <TD><A href="output_dir.htm">-o</A></TD> <TD><A href="output_dir.htm">Set Output directory</A></TD></TR>
+<TR> <TD><A href="password.htm">-p</A></TD> <TD><A href="password.htm">Set Password</A></TD></TR>
+<TR> <TD><A href="recurse.htm">-r</A></TD> <TD><A href="recurse.htm">Recurse subdirectories</A></TD></TR>
+<TR> <TD><A href="charset.htm">-scs</A></TD> <TD><A href="charset.htm">Set charset for list files</A></TD></TR>
+<TR> <TD><A href="large_pages.htm">-slp</A></TD> <TD><A href="large_pages.htm">Set Large Pages mode</A></TD></TR>
+<TR> <TD><A href="list_tech.htm">-slt</A></TD> <TD><A href="list_tech.htm">Show technical information</A></TD></TR>
+<TR> <TD><A href="sfx.htm">-sfx</A></TD> <TD><A href="sfx.htm">Create SFX archive</A></TD></TR>
+<TR> <TD><A href="stdin.htm">-si</A></TD> <TD><A href="stdin.htm">Read data from StdIn</A></TD></TR>
+<TR> <TD><A href="stdout.htm">-so</A></TD> <TD><A href="stdout.htm">Write data to StdOut</A></TD></TR>
+<TR> <TD><A href="ssc.htm">-ssc</A></TD> <TD><A href="ssc.htm">Set Sensitive Case mode</A></TD></TR>
+<TR> <TD><A href="type.htm">-t</A></TD> <TD><A href="type.htm">Type of archive</A></TD></TR>
+<TR> <TD><A href="update.htm">-u</A></TD> <TD><A href="update.htm">Update options</A></TD></TR>
+<TR> <TD><A href="volume.htm">-v</A></TD> <TD><A href="volume.htm">Create Volumes</A></TD></TR>
+<TR> <TD><A href="working_dir.htm">-w</A></TD> <TD><A href="working_dir.htm">Set Working directory</A></TD></TR>
+<TR> <TD><A href="exclude.htm">-x</A></TD> <TD><A href="exclude.htm">Exclude filenames</A></TD></TR>
+<TR> <TD><A href="yes.htm">-y</A></TD> <TD><A href="yes.htm">Assume Yes on all queries</A></TD></TR>
+</TABLE>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/large_pages.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/large_pages.htm
new file mode 100644
index 000000000..82fd5b77d
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/large_pages.htm
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-slp (Set Large Pages mode) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-slp (Set Large Pages mode) switch</H1>
+
+<P>Sets Large Pages mode.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-slp[-]
+</PRE>
+
+
+<TABLE>
+ <TR><TH width="80">Switch</TH> <TH>Description</TH></TR>
+ <TR><TD>-slp</TD> <TD>Enables Large Pages mode.</TD></TR>
+ <TR><TD>-slp-</TD> <TD>Disables Large Pages mode. This option is default for all commands.</TD></TR>
+</TABLE>
+
+<P>Large Pages mode increases the speed of compression.
+However, there is a pause at the start of compression while 7-Zip allocates the large pages in memory.
+If 7-Zip can't allocate large pages, it allocates usual small pages.
+Also, the Windows Task Manager doesn't show the real memory usage of the program, if 7-Zip uses large pages.
+This feature works only on Windows 2003 / XP x64.
+Also, it requires administrator's rights for your system.
+The recommended size of RAM for this feature is 1 GB or more.
+To install this feature, you must run the 7-Zip File Manager at least once,
+close it, and then reboot the system.</P>
+<P>Your system can hang for several seconds at compressing starting, if you use -slp mode.
+So it's not recommended to use -slp mode to compress small data sets (less than 100 MB).</P>
+
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z a archive.7z -slp a.iso
+</PRE>
+
+<P>compresses <SPAN class="filename">a.iso</SPAN> file with Large Pages mode switched on.</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/list_tech.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/list_tech.htm
new file mode 100644
index 000000000..aa8e522da
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/list_tech.htm
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-slt (Show technical information) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-slt (Show technical information) switch</H1>
+
+<P>Sets technical mode for <A href="../commands/list.htm">l (List)</A> command.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-slt
+</PRE>
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z l -slt archive.7z
+</PRE>
+
+<P>shows detailed technical information for the files in <SPAN class="filename">archive.7z</SPAN>.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/list.htm">l (List)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/method.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/method.htm
new file mode 100644
index 000000000..448dbdf59
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/method.htm
@@ -0,0 +1,625 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-m (Set compression Method) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-m (Set compression Method) switch</H1>
+
+<P>Specifies the compression method.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-m&lt;method_parameters>
+
+</PRE>
+
+<P>The format for this switch depends on the archive type.</P>
+
+<UL>
+<LI><TD><A class="parameter" href="#Zip">Zip</A></TD>
+<LI><TD><A class="parameter" href="#GZ">GZip</A></TD>
+<LI><TD><A class="parameter" href="#BZ2">BZip2</A></TD>
+<LI><TD><A class="parameter" href="#7Z">7z</A></TD>
+<LI><TD><A class="parameter" href="#XZ">XZ</A></TD>
+</UL>
+
+<H2><A name="Zip"></A>Zip</H2>
+<TABLE>
+ <TR>
+ <TH width="160">Parameter</TH>
+ <TH align="center">Default</TH>
+ <TH>Description</TH> </TR>
+ <TR>
+ <TD><A class="parameter" href="#ZipX">x=[0 | 1 | 3 | 5 | 7 | 9 ]</A></TD>
+ <TD align="center">5</TD>
+ <TD>Sets level of compression.</TD> </TR>
+ <TR>
+ <TD>m={MethodID}</TD>
+ <TD align="center">Deflate</TD>
+ <TD>Sets a method: Copy, Deflate, Deflate64, BZip2, LZMA, PPMd.</TD> </TR>
+ <TR>
+ <TD><A class="parameter" href="#Deflate_FastBytes">fb={NumFastBytes}</A></TD>
+ <TD align="center">32</TD>
+ <TD>Sets number of Fast Bytes for Deflate encoder.</TD> </TR>
+ <TR>
+ <TD><A class="parameter" href="#Zip_Pass">pass={NumPasses}</A></TD>
+ <TD align="center">1</TD>
+ <TD>Sets number of Passes for Deflate encoder.</TD></TR>
+ <TR>
+ <TD><A class="parameter" href="#ZipDictionarySize">d={Size}[b|k|m]</A></TD>
+ <TD align="center">900000</TD>
+ <TD>Sets Dictionary size for BZip2</TD></TR>
+ <TR>
+ <TD><A class="parameter" href="#ZipMemorySize">mem={Size}[b|k|m]</A></TD>
+ <TD align="center">24</TD> <TD>Sets size of used memory for PPMd.</TD></TR>
+ <TR>
+ <TD><A class="parameter" href="#ZipOrder">o={Size}</A></TD>
+ <TD align="center">8</TD> <TD>Sets model order for PPMd.</TD></TR>
+ <TR>
+ <TD><A class="parameter" href="#ZipMultiThread">mt=[off | on | {N}]</A></TD>
+ <TD align="center">on</TD>
+ <TD>Sets multithreading mode.</TD></TR>
+ <TR>
+ <TD>em={EncryptionMethodID}</TD>
+ <TD align="center">ZipCrypto</TD>
+ <TD>Sets a encryption method: ZipCrypto, AES128, AES192, AES256</TD> </TR>
+ <TR> <TD><A class="parameter">tc=[off | on]</A></TD>
+ <TD align="center">off</TD> <TD>Stores NTFS timestamps for files: Modification time, Creation time, Last access time.</TD> </TR>
+ <TR> <TD><A class="parameter">cl=[off | on]</A></TD>
+ <TD align="center">off</TD> <TD>7-Zip always uses local code page for file names.</TD> </TR>
+ <TR> <TD><A class="parameter">cu=[off | on]</A></TD>
+ <TD align="center">off</TD> <TD>7-Zip uses UTF-8 for file names that contain non-ASCII symbols.</TD> </TR>
+</TABLE>
+
+<P>By default (if <B>cl</B> and <B>cu</B> switches are not specified), 7-Zip uses UTF-8 encoding
+only for file names that contain symbols unsupported by local code page.</P>
+
+<DL>
+ <DT><A name="ZipX"></A>x=[0 | 1 | 3 | 5 | 7 | 9 ]</DT>
+ <DD>
+ <P>Sets level of compression. x=0 means Copy mode (no compression).</P>
+ <P>Deflate / Deflate64 settings:</P>
+ <TABLE>
+ <TR> <TH>Level</TH> <TH>NumFastBytes</TH> <TH>NumPasses</TH> <TH>Description</TH> </TR>
+ <TR> <TD class="cc">1</TD> <TD class="cc" rowspan=3>32</TD> <TD class="cc" rowspan=3>1</TD> <TD>Fastest</TD> </TR>
+ <TR> <TD class="cc">3</TD> <TD>Fast</TR>
+ <TR> <TD class="cc">5</TD> <TD>Normal</TR>
+ <TR> <TD class="cc">7</TD> <TD class="cc">64</TD> <TD class="cc">3</TD> <TD>Maximum</TD> </TR>
+ <TR> <TD class="cc">9</TD> <TD class="cc">128</TD> <TD class="cc">10</TD> <TD>Ultra</TD> </TR>
+ </TABLE>
+
+ <P>x=1 and x=3 with Deflate method set fast mode for compression.</P>
+
+ <P>BZip2 settings:</P>
+ <TABLE>
+ <TR> <TH>Level</TH> <TH>Dictionary</TH> <TH>NumPasses</TH> <TH>Description</TH> </TR>
+ <TR> <TD class="cc">1</TD> <TD class="cc">100000</TD> <TD class="cc" rowspan=3>1</TD> <TD>Fastest</TD> </TR>
+ <TR> <TD class="cc">3</TD> <TD class="cc">500000</TD> <TD>Fast</TD> </TR>
+ <TR> <TD class="cc">5</TD> <TD class="cc" rowspan=3>900000</TD> <TD>Normal</TD> </TR>
+ <TR> <TD class="cc">7</TD> <TD align="center">2</TD> <TD>Maximum</TD> </TR>
+ <TR> <TD class="cc">9</TD> <TD align="center">7</TD> <TD>Ultra</TD> </TR>
+ </TABLE>
+ </DD>
+
+ <DT><A name="Deflate_FastBytes"></A>fb={NumFastBytes}</DT>
+ <DD>
+ <P>Sets the number of fast bytes for the Deflate/Deflate64 encoder.
+ It can be in the range from 3 to 258 (257 for Deflate64).
+ Usually, a big number gives a little bit better
+ compression ratio and a slower compression process.
+ A large fast bytes parameter can significantly increase the compression ratio
+ for files which contain long identical sequences of bytes.</P>
+ </DD>
+ <DT><A name="Zip_Pass"></A>pass={NumPasses}</DT>
+ <DD>
+ <P>Sets number of passes for Deflate encoder. It can be in the range from 1 to 15 for Deflate and
+ from 1 to 10 for BZip2. Usually, a big number gives a little bit better
+ compression ratio and a slower compression process.
+ </P>
+ </DD>
+ <DT><A name="ZipDictionarySize"></A>d={Size}[b|k|m]</DT>
+ <DD>
+ <P> Sets the Dictionary size for BZip2. You must specify the size in bytes, kilobytes, or megabytes.
+ The maximum value for the Dictionary size is 900000b. If you do not specify any symbol
+ from set [b|k|m], dictionary size will be calculated as DictionarySize = 2^Size bytes.</P>
+ </DD>
+
+ <DT><A name="ZipMemorySize"></A>mem={Size}[b|k|m]</DT>
+ <DD>
+ <P> Sets the size of memory used for PPMd. You must specify the size in bytes, kilobytes, or megabytes.
+ The maximum value is 256 MB = 2^28 bytes. The default value
+ is 24 (16MB). If you do not specify any symbol from the set [b|k|m], the
+ memory size will be calculated as (2^Size) bytes. PPMd uses the same
+ amount of memory for compression and decompression.</P>
+ </DD>
+
+ <DT><A name="ZipOrder"></A>o={Size}</DT>
+ <DD>
+ <P>Sets the model order for PPMd. The size must be in the range [2,16]. The default value is 8.</P>
+ </DD>
+
+ <DT><A name="ZipMultiThread"></A>mt=[off | on | {N}]</DT>
+ <DD>
+ <P>Sets multithread mode. If you have a multiprocessor or multicore system,
+ you can get a speed increase with
+ this switch. This option affects only compression (with any method) and
+ decompression of BZip2 streams.
+ Each thread in the multithread mode uses 32 MB of RAM for buffering.
+ If you specify {N}, 7-Zip tries to use N threads.</P>
+ </DD>
+</DL>
+
+<H2><A name="GZ"></A>GZip</H2>
+GZip uses the same parameters as Zip, but GZip compresses only with Deflate method.
+So GZip supports only the following parameters: x, fb, pass.
+
+<H2><A name="BZ2"></A>BZip2</H2>
+<TABLE>
+ <TR>
+ <TH width="160">Parameter</TH>
+ <TH align="center">Default</TH>
+ <TH>Description</TH> </TR>
+ <TR>
+ <TD><A class="parameter" href="#BZip2X">x=[1 | 3 | 5 | 7 | 9 ]</A></TD>
+ <TD align="center">5</TD>
+ <TD>Sets level of compression.</TD> </TR>
+ <TR>
+ <TD><A class="parameter" href="#BZip2Pass">pass={NumPasses}</A></TD>
+ <TD align="center">1</TD>
+ <TD>Sets number of Passes for Bzip2 encoder.</TD></TR>
+ <TR>
+ <TD><A class="parameter" href="#BZip2DictionarySize">d={Size}[b|k|m]</A></TD>
+ <TD align="center">900000</TD>
+ <TD>Sets Dictionary size for BZip2</TD></TR>
+ <TR>
+ <TD><A class="parameter" href="#BZip2MultiThread">mt=[off | on | {N}]</A></TD>
+ <TD align="center">on</TD>
+ <TD>Sets multithreading mode.</TD></TR>
+</TABLE>
+
+<DL>
+ <DT><A name="BZip2"></A>x=[1 | 3 | 5 | 7 | 9 ]</DT>
+ <DD>
+ <P>Sets level of compression</P>
+ <TABLE>
+ <TR> <TH>Level</TH> <TH>Dictionary</TH> <TH>NumPasses</TH> <TH>Description</TH> </TR>
+ <TR> <TD class="cc">1</TD> <TD class="cc">100000</TD> <TD class="cc" rowspan=3>1</TD> <TD>Fastest</TD> </TR>
+ <TR> <TD class="cc">3</TD> <TD class="cc">500000</TD> <TD>Fast</TD> </TR>
+ <TR> <TD class="cc">5</TD> <TD class="cc" rowspan=3>900000</TD> <TD>Normal</TD> </TR>
+ <TR> <TD class="cc">7</TD> <TD align="center">2</TD> <TD>Maximum</TD> </TR>
+ <TR> <TD class="cc">9</TD> <TD align="center">7</TD> <TD>Ultra</TD> </TR>
+ </TABLE>
+ </DD>
+
+ <DT><A name="BZip2DictionarySize"></A>d={Size}[b|k|m]</DT>
+ <DD>
+ <P> Sets the Dictionary size for BZip2. You must specify the size in bytes, kilobytes, or megabytes.
+ The maximum value for the Dictionary size is 900000b. If you do not specify any symbol
+ from set [b|k|m], dictionary size will be calculated as DictionarySize = 2^Size bytes.</P>
+ </DD>
+
+ <DT><A name="#BZip2Pass"></A>pass={NumPasses}</DT>
+ <DD>
+ <P>Sets the number of passes. It can be in the range from 1 to 10.
+ The default value is 1 for normal mode, 2 for maximum mode and 7 for ultra mode.
+ A bigger number can give a little bit better compression ratio and a slower compression process.
+ </P>
+ </DD>
+ <DT><A name="BZip2MultiThread"></A>mt=[off | on | {N}]</DT>
+ <DD>
+ <P>Sets multithread mode. If you have a multiprocessor or multicore system,
+ you can get a speed increase with
+ this switch. If you specify {N}, for example mt=4, 7-Zip tries to use 4 threads.</P>
+ </DD>
+</DL>
+
+<H2><A name="7Z"></A>7z</H2>
+<TABLE>
+ <TR> <TH width="80">Parameter</TH> <TH align="center">Default</TH> <TH>Description</TH> </TR>
+ <TR> <TD><A class="parameter" href="#SevenZipX">x=[0 | 1 | 3 | 5 | 7 | 9 ]</A></TD>
+ <TD align="center">5</TD><TD>Sets level of compression.</TD> </TR>
+ <TR> <TD><A class="parameter" href="#Solid">s=[off | on | [e] [{N}f] [{N}b | {N}k | {N}m | {N}g]</A></TD>
+ <TD align="center">on</TD> <TD>Sets solid mode.</TD> </TR>
+ <TR> <TD><A class="parameter" href="#Filter">f=[off | on]</A></TD>
+ <TD align="center">on</TD> <TD>Enables or disables compression filters for executable files.</TD> </TR>
+ <TR> <TD><A class="parameter" href="#HeaderCompress">hc=[off | on]</A></TD>
+ <TD align="center">on</TD> <TD>Enables or disables archive header compressing.</TD> </TR>
+ <TR> <TD><A class="parameter" href="#HeaderEncrypt">he=[off | on]</A></TD>
+ <TD align="center">off</TD> <TD>Enables or disables archive header encryption.</TD> </TR>
+ <TR> <TD><A class="parameter" href="#Bind">b{C1}[s{S1}]:{C2}[s{S2}]</A></TD>
+ <TD align="center"> </TD> <TD>Sets binding beetwen coders.</TD> </TR>
+ <TR> <TD><A class="parameter" href="#MethodID">{N}={MethodID}[:param1][:param2][..]</A></TD>
+ <TD align="center">LZMA</TD> <TD>Sets a method: LZMA, LZMA2, PPMd, BZip2, Deflate, Delta, BCJ, BCJ2, Copy.</TD> </TR>
+ <TR> <TD><A class="parameter" href="#MultiThread">mt=[off | on | {N}]</A></TD>
+ <TD align="center">on</TD> <TD>Sets multithreading mode.</TD> </TR>
+ <TR> <TD><A class="parameter">tc=[off | on]</A></TD>
+ <TD align="center">off</TD> <TD>Stores file creation timestamps.</TD> </TR>
+</TABLE>
+
+<DL>
+ <DT><A name="SevenZipX"></A>x=[0 | 1 | 3 | 5 | 7 | 9 ]</DT>
+ <DD>
+ <P>Sets level of compression</P>
+ <TABLE>
+ <TR> <TH>Level</TH> <TH>Method</TH> <TH>Dictionary</TH> <TH>FastBytes</TH> <TH>MatchFinder</TH> <TH>Filter</TH> <TH>Description</TH> </TR>
+ <TR> <TD align="center">0</TD> <TD align="center">Copy</TD> <TD align="center"></TD> <TD align="center"></TD> <TD align="center"></TD> <TD align="center"></TD> <TD>No compression.</TD> </TR>
+ <TR> <TD align="center">1</TD> <TD align="center">LZMA</TD> <TD align="center">64 KB</TD> <TD align="center">32</TD> <TD align="center">HC4</TD> <TD align="center">BCJ</TD> <TD>Fastest compressing</TD> </TR>
+ <TR> <TD align="center">3</TD> <TD align="center">LZMA</TD> <TD align="center">1 MB</TD> <TD align="center">32</TD> <TD align="center">HC4</TD> <TD align="center">BCJ</TD> <TD>Fast compressing</TD> </TR>
+ <TR> <TD align="center">5</TD> <TD align="center">LZMA</TD> <TD align="center">16 MB</TD> <TD align="center">32</TD> <TD align="center">BT4</TD> <TD align="center">BCJ</TD> <TD>Normal compressing</TD> </TR>
+ <TR> <TD align="center">7</TD> <TD align="center">LZMA</TD> <TD align="center">32 MB</TD> <TD align="center">64</TD> <TD align="center">BT4</TD> <TD align="center">BCJ</TD> <TD>Maximum compressing</TD> </TR>
+ <TR> <TD align="center">9</TD> <TD align="center">LZMA</TD> <TD align="center">64 MB</TD> <TD align="center">64</TD> <TD align="center">BT4</TD> <TD align="center">BCJ2</TD><TD>Ultra compressing</TD> </TR>
+ </TABLE>
+ <P>Note: "x" works as "x=9".</P>
+ </DD>
+
+ <DT><A name="Solid"></A>s=[off | on | [e] [{N}f] [{N}b | {N}k | {N}m | {N}g)]</DT>
+ <DD>
+ <P> Enables or disables solid mode. The default mode is s=on.
+ In solid mode, files are grouped together. Usually, compressing in
+ solid mode improves the compression ratio.</P>
+
+ <TABLE>
+ <TR> <TD>e</TD> <TD>Use a separate solid block for each new file extension</TD> </TR>
+ <TR> <TD>{N}f</TD> <TD>Set the limit for number of files in one solid block</TD> </TR>
+ <TR> <TD>{N}b | {N}k | {N}m | {N}g</TD> <TD>Set a limit for the total size of a solid block in bytes</TD> </TR>
+ </TABLE>
+
+ <P>These are the default limits for the solid block size:</P>
+
+ <TABLE>
+ <TR> <TH width="150">Compression Level</TH> <TH>Solid block size</TH> </TR>
+ <TR> <TD>Store</TD> <TD>0 B</TD> </TR>
+ <TR> <TD>Fastest</TD> <TD>16 MB</TD> </TR>
+ <TR> <TD>Fast</TD> <TD>128 MB</TD> </TR>
+ <TR> <TD>Normal</TD> <TD>2 GB</TD> </TR>
+ <TR> <TD>Maximum</TD> <TD>4 GB</TD> </TR>
+ <TR> <TD>Ultra</TD> <TD>4 GB</TD> </TR>
+ </TABLE>
+
+
+ <P>Limitation of the solid block size usually decreases compression ratio but gives the following advantages:</P>
+ <UL>
+ <LI>Decreases losses in case of future archive damage.
+ <LI>Decreases extraction time of a group of files (or just one
+ file), so long as the group doesn't contain the entire archive.</LI></LI>
+ </UL>
+ <P>The updating of solid .7z archives can be slow, since it
+ can require some recompression.</P>
+
+ <P>Example:</P>
+ <PRE class="example">
+ s=100f10m
+ </PRE>
+ <P>set solid mode with 100 files & 10 MB limits per one solid block.</P>
+
+ <DT><A name="Filter"></A>f=[off | on]</DT>
+ <DD>
+ <P>Enables or disables compression filters for executable files:
+ dll, exe, ocx, sfx, sys. It uses BCJ2 filter in Ultra mode and BCJ
+ filter in other modes. The default mode is f=on.
+ </P>
+ <DT><A name="HeaderCompress"></A>hc=[off | on]</DT>
+ <DD>
+ <P> Enables or disables archive header compressing. The default mode is hc=on.
+ If archive header compressing is enabled, some parts of archive header will
+ be compressed with LZMA method.
+ </P>
+ <DT><A name="HeaderEncrypt"></A>he=[off | on]</DT>
+ <DD>
+ <P> Enables or disables archive header encryption. The default mode is he=off.
+ </P>
+ <DT>{N}</DT>
+ <DD>
+ <P>Sets order of methods. It is used also to associate parameters with
+ methods. Numbers must begin from 0. Methods that have smaller numbers will be used
+ before others.</P>
+ </DD>
+
+ <DT><A name="Bind"></A>b{C1}[s{S1}]:{C2}[s{S2}]</DT>
+ <DD>
+ <P> Binds output stream S1 in coder C1 with input stream S2 in coder C2.
+ If stream number is not specified, stream with number 0 will be used.
+ </P>
+ <P> Usally coder has one input stream and
+ one output stream. In 7z some coders can have multiple input and output streams.</P>
+
+ <P>For example, <A class="parameter" href="#BCJ2">BCJ2</A> encoder has one
+ input stream and four output streams.</P>
+ </DD>
+
+ <DT><A name="MultiThread"></A>mt=[off | on | {N}]</DT>
+ <DD>
+ <P>Sets multithread mode. If you have a multiprocessor or multicore system,
+ you can get a increase with this switch.
+ 7-Zip supports multithread mode only for LZMA / LZMA2 compression and
+ BZip2 compression / decompression. If you specify {N}, for example mt=4,
+ 7-Zip tries to use 4 threads. LZMA compression uses only 2 threads.
+ </P>
+ </DD>
+
+ <DT><A name="MethodID"></A>{N}={MethodID}[:param1][:param2] ... [:paramN]</DT>
+ <DD>
+ <P>Sets compression method. You can use any number of methods.
+ The default method is LZMA. </P>
+ <P>Parameters must be in one of the following forms:</P>
+ <UL>
+ <LI>{ParamName}={ParamValue}.
+ <LI>{ParamName}{ParamValue}, if {ParamValue}
+ is number and {ParamName} doesn't contain numbers.
+ </UL>
+
+ <P>Supported methods:</P>
+ <TABLE>
+ <TR> <TH width="60">MethodID</TH> <TH>Description</TH> </TR>
+ <TR> <TD><A class="parameter" href="#LZMA">LZMA</A></TD> <TD>LZ-based algorithm</TD> </TR>
+ <TR> <TD><A class="parameter" href="#LZMA2">LZMA2</A></TD> <TD>LZMA-based algorithm</TD> </TR>
+ <TR> <TD><A class="parameter" href="#PPMd">PPMd</A></TD> <TD>Dmitry Shkarin's PPMdH with small changes</TD> </TR>
+ <TR> <TD>BZip2</TD> <TD>BWT algorithm</TD> </TR>
+ <TR> <TD>Deflate</TD> <TD>LZ+Huffman</TD> </TR>
+ <TR> <TD>Copy</TD> <TD>No compression</TD> </TR>
+ </TABLE>
+
+ <P>Supported filters:</P>
+ <TABLE>
+ <TR> <TH width="60">MethodID</TH> <TH>Description</TH> </TR>
+ <TR> <TD><A class="parameter" href="#Delta">Delta</A></TD> <TD>Delta filter</TD> </TR>
+ <TR> <TD>BCJ</TD> <TD>converter for x86 executables</TD> </TR>
+ <TR> <TD><A class="parameter" href="#BCJ2">BCJ2</A></TD> <TD>converter for x86 executables (version 2)</TD> </TR>
+ <TR> <TD>ARM</TD> <TD>converter for ARM (little endian) executables</TD> </TR>
+ <TR> <TD>ARMT</TD> <TD>converter for ARM Thumb (little endian) executables</TD> </TR>
+ <TR> <TD>IA64</TD> <TD>converter for IA-64 executables</TD> </TR>
+ <TR> <TD>PPC</TD> <TD>converter for PowerPC (big endian) executables</TD> </TR>
+ <TR> <TD>SPARC</TD> <TD>converter for SPARC executables</TD> </TR>
+ </TABLE>
+ <P>Filters increase the compression ratio for some types of files. Filters
+ must be used with one of the compression method (for example, BCJ + LZMA).</P>
+ </DD>
+
+ <H4><A name="LZMA"></A>LZMA</H4>
+ <P> LZMA is an algorithm based on Lempel-Ziv algorithm.
+ It provides very fast decompression (about 10-20 times faster than compression).
+ Memory requirements for compression and decompression also are different (see
+ <A class="parameter" href="#DictionarySize">d={Size}[b|k|m]</A> switch for details).</P>
+
+ <TABLE>
+ <TR> <TH width="80">Parameter</TH> <TH align="center">Default</TH> <TH>Description</TH> </TR>
+
+ <TR> <TD><A class="parameter" href="#LZMAMode">a=[0|1]</A></TD>
+ <TD align="center">1</TD> <TD>Sets compressing mode</TD> </TR>
+ <TR> <TD><A class="parameter" href="#DictionarySize">d={Size}[b|k|m]</A></TD>
+ <TD align="center">24</TD> <TD>Sets Dictionary size</TD> </TR>
+ <TR> <TD><A class="parameter" href="#MatchFinder">mf={MF_ID}</A></TD>
+ <TD align="center">bt4</TD> <TD>Sets Match Finder</TD> </TR>
+ <TR> <TD><A class="parameter" href="#FastBytes">fb={N}</A></TD>
+ <TD align="center">32</TD> <TD>Sets number of Fast Bytes</TD></TR>
+ <TR> <TD><A class="parameter" href="#MatchFinderCycles">mc={N}</A></TD>
+ <TD align="center">32</TD><TD>Sets Number of Cycles for Match Finder</TD> </TR>
+ <TR> <TD><A class="parameter" href="#LitContext">lc={N}</A></TD>
+ <TD align="center">3</TD> <TD>Sets number of Literal Context bits - [0, 8]</TD></TR>
+ <TR> <TD><A class="parameter" href="#LitPos">lp={N}</A></TD>
+ <TD align="center">0</TD> <TD>Sets number of Literal Pos bits - [0, 4]</TD></TR>
+ <TR> <TD><A class="parameter" href="#PosBits">pb={N}</A></TD>
+ <TD align="center">2</TD> <TD>Set number of Pos Bits - [0, 4]</TD></TR>
+ </TABLE>
+
+
+ <DL>
+ <DT><A name="#LZMAMode"></A>a=[0|1]</DT>
+ <DD>
+ <P> Sets compression mode: 0 = fast, 1 = normal.
+ Default value is 1.</P>
+ </DD>
+ <DT><A name="DictionarySize"></A>d={Size}[b|k|m]</DT>
+ <DD>
+ <P> Sets Dictionary size for LZMA. You must specify the size in bytes, kilobytes, or megabytes.
+ The maximum value for dictionary size is 1 GB = 2^30 bytes. Default values for LZMA
+ are 24 (16 MB) in normal mode, 25 (32 MB) in maximum mode (-mx=7)
+ and 26 (64 MB) in ultra mode (-mx=9).
+ If you do not specify any symbol from the set [b|k|m], the
+ dictionary size will be calculated as DictionarySize = 2^Size bytes.
+ For decompressing a file compressed by LZMA method with dictionary size N, you need
+ about N bytes of memory (RAM) available.
+ </P>
+ </DD>
+ <DT><A name="MatchFinder"></A>mf={MF_ID}</DT>
+ <DD>
+ <P> Sets Match Finder for LZMA. Default method is bt4.
+ Algorithms from hc* group don't provide a good compression ratio,
+ but they often work pretty fast in combination with fast mode (a=0).
+ Memory requirements depend on dictionary size (parameter "d" in table below).
+ </P>
+ <TABLE>
+ <TR> <TH>MF_ID</TH> <TH class="cc">Dictionary</TH> <TH class="cc" colspan = 2>Memory Usage</TH> <TH class="cc" colspan = 2>Description</TH> </TR>
+ <TR> <TD class="cc">bt2</TD> <TD></TD> <TD align="right"> 9.5 * d</TD> <TD class="cc" rowspan=6> + 4 MB</TD> <TD class="cc" rowspan=4>Binary Tree</TD> <TD>2 bytes hashing</TD> </TR>
+ <TR> <TD class="cc">bt3</TD> <TD></TD> <TD align="right">11.5 * d</TD> <TD>3 bytes hashing</TD> </TR>
+ <TR> <TD class="cc" rowspan=2>bt4</TD> <TD class="cc">64 KB ... 48 MB</TD> <TD align="right">11.5 * d</TD> <TD class="cc" rowspan=6>4 bytes hashing</TD> </TR>
+ <TR> <TD class="cc">64 MB ... 1024 MB</TD> <TD align="right">10.5 * d</TD> </TR>
+ <TR> <TD class="cc" rowspan=2>hc4</TD> <TD class="cc">64 KB ... 48 MB</TD> <TD align="right"> 7.5 * d</TD> <TD class="cc" rowspan=2>Hash Chain </TD></TR>
+ <TR> <TD class="cc">64 MB ... 1024 MB</TD> <TD align="right"> 6.5 * d</TD> </TR>
+ </TABLE>
+ <P>Note: Your operation system also needs some amount of physical memory for internal purposes.
+ So keep at least 32MB of physical memory unused.</P>
+ </DD>
+
+ <DT><A name="FastBytes"></A>fb={N}</DT>
+ <DD>
+ <P>Sets number of fast bytes for LZMA. It can be in the range from 5 to 273.
+ The default value is 32 for normal mode and 64 for maximum and ultra modes.
+ Usually, a big number gives a little bit better
+ compression ratio and slower compression process.
+ </P>
+ </DD>
+ <DT><A name="MatchFinderCycles"></A>mc={N}</DT>
+ <DD>
+ <P>Sets number of cycles (passes) for match finder. It can be in range from 0 to 1000000000.
+ Default value is (16 + number_of_fast_bytes / 2) for BT* match finders and
+ (8 + number_of_fast_bytes / 4) for HC4 match finder.
+ If you specify mc=0, LZMA will use default value.
+ Usually, a big number gives a little bit better compression ratio and slower
+ compression process. For example, mf=HC4 and mc=10000 can provide almost the same
+ compression ratio as mf=BT4.</P>
+ </DD>
+ <DT><A name="LitContext"></A>lc={N}</DT>
+ <DD>
+ <P>Sets the number of literal context bits (high bits of previous literal).
+ It can be in range from 0 to 8.
+ Default value is 3. Sometimes lc=4 gives gain for big files.</P>
+ </DD>
+ <DT><A name="LitPos"></A>lp={N}</DT>
+ <DD>
+ <P>Sets the number of literal pos bits (low bits of current position for literals).
+ It can be in the range from 0 to 4.
+ The default value is 0. The lp switch is intended for periodical data when the
+ period is equal to 2^value (where lp=value). For example, for 32-bit (4 bytes)
+ periodical data you can use lp=2. Often it's better to set lc=0,
+ if you change lp switch.</P>
+ </DD>
+ <DT><A name="PosBits"></A>pb={N}</DT>
+ <DD>
+ <P>Sets the number of pos bits (low bits of current position).
+ It can be in the range from 0 to 4.
+ The default value is 2. The pb switch is intended for periodical data when the
+ period is equal 2^value (where lp=value). </P>
+ </DD>
+
+ </DL>
+
+ <H4><A name="LZMA2"></A>LZMA2</H4>
+ <P>LZMA2 is modified version of LZMA. it provides the following advantages over LZMA:</P>
+ <UL>
+ <LI>Better compression ratio for data than can't be compressed. LZMA2 can store such
+ blocks of data in uncompressed form. Also it decompresses such data faster.
+ <LI>Better multithreading support. If you compress big file, LZMA2 can split
+ that file to chunks and compress these chunks in multiple threads.
+ </UL>
+
+ <TABLE>
+ <TR> <TH width="80">Parameter</TH> <TH align="center">Default</TH> <TH>Description</TH> </TR>
+
+ <TR> <TD><A class="parameter" href="#ChunkSize">c={Size}[b|k|m]</A></TD>
+ <TD align="center">dictSize * 4</TD> <TD>Sets Chunk size</TD> </TR>
+ </TABLE>
+
+ <P>If you don't specify ChunkSize, LZMA2 sets it to DictionarySize * 4.</P>
+
+ <P>LZMA2 also supports all LZMA parameters, but lp+lc cannot be larger than 4.</P>
+
+ <P>LZMA2 uses: 1 thread for each chunk in x1 and x3 modes; and
+ 2 threads for each chunk in x5, x7 and x9 modes.
+ If LZMA2 is set to use only such number of threads required for one chunk,
+ it doesn't split stream to chunks. So you can get different compression
+ ratio for different number of threads. You can get the best compression
+ ratio, when you use 1 or 2 threads.</P>
+
+ <H4><A name="PPMd"></A>PPMd</H4>
+ <P> PPMd is a PPM-based algorithm. This algorithm is mostly based
+ on Dmitry Shkarin's PPMdH source code. PPMd provides very good compression ratio for
+ plain text files. There is no difference between compression speed and
+ decompression speed. Memory requirements for compression and decompression
+ also are the same.</P>
+ <TABLE>
+ <TR> <TH width="80">Parameter</TH> <TH align="center">Default</TH> <TH>Description</TH> </TR>
+ <TR> <TD><A class="parameter" href="#MemorySize">mem={Size}[b|k|m]</A></TD>
+ <TD align="center">24</TD> <TD>Sets size of used memory for PPMd.</TD> </TR>
+ <TR> <TD><A class="parameter" href="#Order">o={Size}</A></TD>
+ <TD align="center">6</TD> <TD>Sets model order for PPMd.</TD> </TR>
+ </TABLE>
+ <DL>
+ <DT><A name="MemorySize"></A>mem={Size}[b|k|m]</DT>
+ <DD>
+ <P> Sets the size of memory used for PPMd. You must specify the size in bytes, kilobytes, or megabytes.
+ The maximum value is 2GB = 2^31 bytes. The default value
+ is 24 (16MB). If you do not specify any symbol from the set [b|k|m], the
+ memory size will be calculated as (2^Size) bytes. PPMd uses the same
+ amount of memory for compression and decompression.</P>
+ </DD>
+
+ <DT><A name="Order"></A>o={Size}</DT>
+ <DD>
+ <P>Sets the model order for PPMd. The size must be in the range [2,32]. The default value is 6.</P>
+ </DD>
+ </DL>
+
+ <H4><A name="BCJ2"></A>BCJ2</H4>
+ <P>BCJ2 is a Branch converter for 32-bit x86 executables (version 2).
+ It converts some branch instructions for increasing further compression.</P>
+ <P>A BCJ2 encoder has one input stream and four output streams:</P>
+ <UL>
+ <LI>s0: main stream. It requires further compression.</LI>
+ <LI>s1: stream for converted CALL values. It requires further compression.</LI>
+ <LI>s2: stream for converted JUMP values. It requires further compression.</LI>
+ <LI>s3: service stream. It is already compressed.</LI>
+ </UL>
+ <P>If LZMA is used, the size of the dictionary for streams
+ s1 and s2 can be much smaller (512 KB is enough for most cases)
+ than the dictionary size for stream s0.</P>
+
+ <H4><A name="Delta"></A>Delta</H4>
+ <P>It's possible to set delta offset in bytes. For example, to compress 16-bit stereo
+ WAV files, you can set "0=Delta:4". Default delta offset is 1.</P>
+</DL>
+
+<H2><A name="XZ"></A>XZ</H2>
+XZ supports only LZMA2 codec now. The switches are similar to switches for 7z format.
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z a -tzip archive.zip *.jpg -mx0
+</PRE>
+
+<P>adds <SPAN class="filename">*.jpg</SPAN> files to
+ <SPAN class="filename">archive.zip</SPAN> archive without compression.</P>
+
+<PRE class="example">
+7z a -t7z archive.7z *.exe *.dll -m0=BCJ -m1=LZMA:d=21 -ms -mmt
+</PRE>
+
+<P>adds <SPAN class="filename">*.exe</SPAN> and <SPAN class="filename">*.dll</SPAN>
+files to solid archive <SPAN class="filename">archive.7z</SPAN> using LZMA method with
+2 MB dictionary and BCJ converter. Compression will use multithreading optimization.</P>
+
+<PRE class="example">
+7z a -t7z archive.7z *.exe *.dll -m0=BCJ2 -m1=LZMA:d23 -m2=LZMA:d19 -m3=LZMA:d19
+ -mb0:1 -mb0s1:2 -mb0s2:3
+</PRE>
+
+<P>adds <SPAN class="filename">*.exe</SPAN> and <SPAN class="filename">*.dll</SPAN>
+ files to archive <SPAN class="filename">archive.7z</SPAN> using BCJ2 converter,
+ LZMA with 8 MB dictionary for main output stream (s0),
+ and LZMA with 512 KB dictionary for s1 and s2 output streams of BCJ2.</P>
+
+
+<PRE class="example">
+7z a -t7z archive.7z *.txt -m0=PPMd
+</PRE>
+
+<P>adds <SPAN class="filename">*.txt</SPAN> files to archive
+<SPAN class="filename">archive.7z</SPAN> using PPMd method.</P>
+
+
+
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="type.htm">-t (set Type of archive)</A>,
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/output_dir.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/output_dir.htm
new file mode 100644
index 000000000..b4523493b
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/output_dir.htm
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-o (set Output directory) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-o (set Output directory) switch</H1>
+
+<P>Specifies a destination directory where files are to be extracted.</P>
+<P>This switch can be used only with extraction commands.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-o{dir_path}
+</PRE>
+
+<DL>
+ <DT>{dir_path}</DT>
+ <DD>This is the destination directory path. It's not required to end with a backslash.
+ If you specify <B>*</B> in {dir_path}, 7-Zip substitutes that * character to archive name.</DD>
+</DL>
+
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z x archive.zip -oc:\Doc
+</PRE>
+
+<P>extracts all files from the <SPAN class="filename">archive.zip</SPAN> archive
+to the <SPAN class="filename">c:\Doc</SPAN> directory.</P>
+
+<PRE class="example">
+7z x *.zip -o*
+</PRE>
+
+<P>extracts all <SPAN class="filename">*.zip</SPAN> archives to subfolders
+with names of these archives.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/overwrite.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/overwrite.htm
new file mode 100644
index 000000000..c71ae40d8
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/overwrite.htm
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-ao (Overwrite mode) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-ao (Overwrite mode) switch</H1>
+
+<P>Specifies the overwrite mode during extraction, to overwrite files already present on disk.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-ao[a | s | t | u ]
+</PRE>
+
+
+<TABLE>
+ <TR> <TH width="80">Switch</TH> <TH>Description</TH> </TR>
+ <TR> <TD>-aoa</TD> <TD>Overwrite All existing files without prompt.</TD> </TR>
+ <TR> <TD>-aos</TD> <TD>Skip extracting of existing files.</TD> </TR>
+ <TR> <TD>-aou</TD> <TD>aUto rename extracting file (for example, name.txt will
+ be renamed to name_1.txt).</TD> </TR>
+ <TR> <TD>-aot</TD> <TD>auto rename existing file (for example, name.txt will
+ be renamed to name_1.txt).</TD> </TR>
+</TABLE>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z x test.zip -aoa
+</PRE>
+
+<P>extracts all files from <SPAN class="filename">test.zip</SPAN> archive and overwrites
+existing files without any prompt.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="yes.htm">-y (assume Yes on all queries)</A>,
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/password.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/password.htm
new file mode 100644
index 000000000..733dfc4a7
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/password.htm
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-p (set Password) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-p (set Password) switch</H1>
+
+<P>Specifies password.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-p{password}
+</PRE>
+
+<DL>
+ <DT>{password}</DT>
+ <DD>Specifies password.</DD>
+</DL>
+
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z a archive.7z -psecret -mhe *.txt
+</PRE>
+<P>compresses *.txt files to <SPAN class="filename">archive.7z</SPAN> using password
+"secret". Also it encrypts archive headers (-mhe switch), so filenames will be encrypted.
+</P>
+
+<PRE class="example">
+7z x archive.zip -psecret
+</PRE>
+<P>extracts all files from <SPAN class="filename">archive.zip</SPAN> using password
+"secret".</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/recurse.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/recurse.htm
new file mode 100644
index 000000000..08dba2a4a
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/recurse.htm
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-r (Recurse subdirectories) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-r (Recurse subdirectories) switch</H1>
+
+<P>Specifies the method of treating wildcards and filenames on the command line.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-r[- | 0]
+</PRE>
+
+
+<TABLE>
+ <TR><TH width="80">Switch</TH> <TH>Description</TH></TR>
+ <TR><TD>-r</TD> <TD>Enable recurse subdirectories.</TD></TR>
+ <TR><TD>-r-</TD> <TD>Disable recurse subdirectories. This option is default for all commands.</TD></TR>
+ <TR><TD>-r0</TD> <TD>Enable recurse subdirectories only for wildcard names.</TD></TR>
+</TABLE>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z l archive.zip *.doc -r-
+</PRE>
+
+<P>lists all <SPAN class="filename">*.doc</SPAN> files
+ that belong to the archived root directory
+ in the <SPAN class="filename">archive.zip</SPAN> archive.
+ </P>
+
+<PRE class="example">
+7z a -tzip archive.zip -r src\*.cpp src\*.h
+</PRE>
+
+<P>adds all <SPAN class="filename">*.cpp</SPAN> and <SPAN class="filename">*.h</SPAN>
+ files from directory <SPAN class="filename">src</SPAN> and all it's subdirectories
+ to the <SPAN class="filename">archive.zip</SPAN> archive.</P>
+
+<PRE class="example">
+7z a archive.7z folder1\
+</PRE>
+
+<P>adds all files from directory <SPAN class="filename">folder1</SPAN> and all it's subdirectories
+ to the <SPAN class="filename">archive.7z</SPAN> archive.</P>
+
+<PRE class="example">
+7z a archive.7z -r folder2\
+</PRE>
+
+<P>searches all <SPAN class="filename">folder2</SPAN> directories in all subdirectories,
+ and adds them (including all subdirectories) to the <SPAN class="filename">archive.7z</SPAN> archive.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/list.htm">l (List)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="include.htm">-i (Include)</A>,
+ <A href="exclude.htm">-x (Exclude)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/sfx.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/sfx.htm
new file mode 100644
index 000000000..126028963
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/sfx.htm
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-sfx (Create SFX archive) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-sfx (Create SFX archive) switch</H1>
+
+<P>Creates self extracting archive.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-sfx[<A class="parameter" href="#SFX_Module">{SFX_Module}</A>]
+</PRE>
+
+<DL>
+ <DT><A name="SFX_Module"></A>{SFX_Module}</DT>
+ <DD>
+ <P>Specifies the SFX module that will be combined with the archive.
+ This module must be placed in the same directory as the 7z.exe.
+ If {SFX_Module} is not assigned, 7-Zip will use standard console
+ SFX module 7zCon.sfx.</P>
+ <TABLE>
+ <TR> <TH width="60">SFX_Module</TH> <TH>Description</TH> </TR>
+ <TR> <TD>7z.sfx</TD> <TD>Windows version.</TD> </TR>
+ <TR> <TD>7zCon.sfx</TD> <TD>Console version.</TD> </TR>
+ <TR> <TD>7zS.sfx</TD> <TD>Windows version for installers.</TD> </TR>
+ <TR> <TD>7zSD.sfx</TD> <TD>Windows version for installers (uses MSVCRT.dll).</TD> </TR>
+ </TABLE>
+ </DD>
+</DL>
+
+<P>
+All SFX modules are uncompressed. You can use UPX program
+(http://upx.sourceforge.net)
+to compresss such modules. After compressing by the UPX program, the size of the
+sfx module will be reduced to 40-50% of its original size.
+</P>
+
+<H4>SFX modules for installers</H4>
+<P>SFX modules for installers are included in an external package (7z_extra). You can download
+these modules from www.7-zip.org. SFX modules for installers (7zS.sfx and 7zSD.sfx)
+allow you to create your own installation program.
+Such a module extracts the archive to the user's temp folder, and runs a specified program,
+and removes the temp files after the program finishes.
+A self-extracting archive for installers must be created as joining 3 files:
+SFX_Module, Installer_Config, 7z_Archive.
+In addition, an optional file, Installer_Config, is allowed. You can use the following command to
+create an installer self-extracting archive:</P>
+<PRE class="example">
+copy /b 7zS.sfx + config.txt + archive.7z archive.exe
+</PRE>
+
+<P>An optimally small installation package size can be achieved,
+if the installation files are uncompressed before including them in the 7z archive.</P>
+
+<P><SPAN class="filename">-y</SPAN> switch for installer module specifies quiet mode extraction.</P>
+
+<H4>Installer Config file format</H4>
+<P>
+This config file contains commands for the Installer. The file begins with the string
+<B>;!@Install@!UTF-8!</B> and ends with <B>;!@InstallEnd@!</B>.
+The file must be written in UTF-8 encoding.
+The file contains any or all these string pairs:
+<P>ID_String="Value"</P>
+<P>
+ <TABLE>
+ <TR> <TH width="60">ID_String</TH> <TH>Description</TH> </TR>
+ <TR> <TD>Title</TD> <TD>Title for messages</TD> </TR>
+ <TR> <TD>BeginPrompt</TD> <TD>Begin Prompt message</TD> </TR>
+ <TR> <TD>Progress</TD> <TD>Value can be "yes" or "no". Default value is "yes".</TD> </TR>
+ <TR> <TD>RunProgram</TD> <TD>Command for executing. Default value is "setup.exe". Substring <B>%%T</B>
+ will be replaced with path to temporary folder, where files were extracted</TD> </TR>
+ <TR> <TD>Directory</TD> <TD>Directory prefix for "RunProgram". Default value is ".\\"</TD> </TR>
+ <TR> <TD>ExecuteFile</TD> <TD>Name of file for executing</TD> </TR>
+ <TR> <TD>ExecuteParameters</TD> <TD>Parameters for "ExecuteFile"</TD> </TR>
+ </TABLE>
+</P>
+<P>You may omit any pair.</P>
+
+<P>There are two ways to run a installation program: <B>RunProgram</B> and <B>ExecuteFile</B>.
+Use <B>RunProgram</B>, if you want to run a program from the .7z archive.
+Use <B>ExecuteFile</B>, if you want to open a document from the .7z archive, or
+if you want to execute a command from Windows.</P>
+
+<P>If you use <B>RunProgram</B>, and if you specify empty directory prefix: <B>Directory</B>="",
+the system searches for the executable file in the following sequence:</P>
+<OL>
+<LI>The directory from which the application (installer) loaded.
+<LI>The temporary folder, where files were extracted.
+<LI>The Windows system directory.
+</OL>
+
+<H4>Config file Examples</H4>
+
+<PRE class="example">
+;!@Install@!UTF-8!
+Title="7-Zip 4.00"
+BeginPrompt="Do you want to install the 7-Zip 4.00?"
+RunProgram="setup.exe"
+;!@InstallEnd@!
+</PRE>
+
+<BR>
+
+
+<PRE class="example">
+;!@Install@!UTF-8!
+Title="7-Zip 4.00"
+BeginPrompt="Do you want to install the 7-Zip 4.00?"
+ExecuteFile="7zip.msi"
+;!@InstallEnd@!
+</PRE>
+
+<BR>
+
+<PRE class="example">
+;!@Install@!UTF-8!
+Title="7-Zip 4.01 Update"
+BeginPrompt="Do you want to install the 7-Zip 4.01 Update?"
+ExecuteFile="msiexec.exe"
+ExecuteParameters="/i 7zip.msi REINSTALL=ALL REINSTALLMODE=vomus"
+;!@InstallEnd@!
+</PRE>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z a -sfx a.exe *.txt
+</PRE>
+
+<P>adds <SPAN class="filename">*.txt</SPAN> files to self extracting
+ archive <SPAN class="filename">a.exe</SPAN> using the default console SFX module.</P>
+
+<PRE class="example">
+7z a -sfx7z.sfx a.exe *
+</PRE>
+
+<P>adds all files to self extracting archive <SPAN class="filename">a.exe</SPAN>
+with module <SPAN class="filename">7z.sfx</SPAN> using windows version of SFX mudule.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/ssc.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/ssc.htm
new file mode 100644
index 000000000..023dbf88b
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/ssc.htm
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-ssc (Set Sensitive Case mode) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-ssc (Set Sensitive Case mode) switch</H1>
+
+<P>Sets sensitive case mode for file names.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-scs[-]
+</PRE>
+
+<TABLE>
+ <TR><TH width="80">Switch</TH> <TH>Description</TH></TR>
+ <TR><TD>-ssc</TD> <TD>Set case-sensitive mode. It's default for Posix/Linux systems.</TD></TR>
+ <TR><TD>-ssc-</TD> <TD>Set case-insensitive mode. It's default for Windows systems.</TD></TR>
+</TABLE>
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z a archive.7z A*.txt -ssc -r
+</PRE>
+
+<P>compresses all <SPAN class="filename">A*.txt</SPAN> files
+ from current directory and all it's subdirectories. That command doesn't compress
+ <SPAN class="filename">a*.txt</SPAN> files.
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/list.htm">l (List)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/stdin.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/stdin.htm
new file mode 100644
index 000000000..f16b4ebe2
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/stdin.htm
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-si (read data from stdin) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-si (read data from stdin) switch</H1>
+
+<P>Causes 7-Zip to read data from stdin (standard input) instead of from disc files.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-si{file_name}
+</PRE>
+
+<DL>
+ <DT>{file_name}</DT>
+ <DD>Specifies a name that will be stored in the archive for the compressed data.
+ If file_name is not specified, data will be stored without a name.</DD>
+</DL>
+
+<P>Note: The current version of 7-Zip support reading of archives from stdin only for xz, lzma, tar, gzip and bzip2 archives.</P>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z a archive.gz -tgzip -siDoc2.txt < Doc.txt
+</PRE>
+
+<P>compresses input stream from file Doc.txt to
+<SPAN class="filename">archive.gz</SPAN> archive
+using <SPAN class="filename">Doc2.txt</SPAN> file name.</P>
+
+<PRE class="example">
+7z x 7z905.tar.gz -so | 7z x -si -ttar
+</PRE>
+
+<P>decompresses <SPAN class="filename">tar.gz</SPAN> archive.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/stdout.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/stdout.htm
new file mode 100644
index 000000000..62e5a662a
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/stdout.htm
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-so (write data to stdout) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-so (write data to stdout) switch</H1>
+
+<P>Causes 7-Zip to write output data to stdout (standard output stream).</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-so
+</PRE>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z x archive.gz -so > Doc.txt
+</PRE>
+
+<P>decompresses <SPAN class="filename">archive.gz</SPAN>
+archive to output stream and then redirects that stream to
+<SPAN class="filename">Doc.txt</SPAN> file.</P>
+
+
+<PRE class="example">
+7z a dummy -tgzip -so Doc.txt > archive.gz
+</PRE>
+
+<P>compresses the <SPAN class="filename">Doc.txt</SPAN> file to the 7-Zip standard
+output stream and writes that stream to
+<SPAN class="filename">archive.gz</SPAN> file.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/stop_switch.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/stop_switch.htm
new file mode 100644
index 000000000..12383e507
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/stop_switch.htm
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-- (Stop switches parsing) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-- (Stop switches parsing) switch</H1>
+
+<P>Disables switch parsing after "--" on the command line.
+This is to allow 7-Zip to use file names that start with "-".
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+--
+</PRE>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z t -- -ArchiveName.7z
+</PRE>
+
+<P>tests <SPAN class="filename">-ArchiveName.7z</SPAN> archive.</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/style.css b/src/libs/7zip/unix/DOCS/MANUAL/switches/style.css
new file mode 100644
index 000000000..13ebb79ce
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/style.css
@@ -0,0 +1,232 @@
+body
+ {
+ padding: 0px 0px 0px 26px;
+ background: #ffffff;
+ color: #000000;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 80%;
+ }
+
+div
+ {
+ width: 90%;
+ border: 2px solid #999999;
+ padding: 4px 8px;
+ background: #cccccc;
+ }
+
+h1, h2, h3, h4
+ {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ margin-left: -26px;
+ }
+
+h1
+ {
+ font-size: 145%;
+ margin-top: .5em;
+ margin-bottom: 1em;
+ }
+
+h2
+ {
+ font-size: 130%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+h3
+ {
+ font-size: 115%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+h4
+ {
+ font-size: 100%;
+ margin-top: 1.5em;
+ margin-bottom: .6em;
+ }
+
+ul p, ol p, dl p
+ {
+ margin-left: 0em;
+ }
+
+p
+ {
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+
+dl
+ {
+ /*margin-top: 0em; */
+ }
+
+dt
+ {
+ margin-top: .76em;
+ margin-bottom: .5em;
+ font-weight: bold;
+ }
+
+dd
+ {
+ margin-top: .5em;
+ margin-bottom: .5em;
+ margin-left: 1.9em;
+ }
+
+
+ul, ol
+ {
+ margin-top: .6em;
+ margin-bottom: 0em;
+ }
+
+ol
+ {
+ margin-left: 3.6em;
+ }
+
+ul
+ {
+ list-style-type: disc;
+ margin-left: 1.9em;
+ }
+
+li
+ {
+ margin-bottom: .6em;
+ }
+
+ul ol, ol ol
+ {
+ list-style-type: lower-alpha;
+ {
+
+ /*
+pre
+ {
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+ */
+
+pre,code
+ {
+ font: 100% Courier New, Courier, mono;
+ color: #000000;
+ cursor: text;
+ }
+
+pre.syntax
+ {
+ background: #dddddd;
+ padding: 2pt,4pt
+ }
+
+pre.syntax
+ {
+ color: #000000;
+ }
+
+pre.example
+ {
+ margin-left: 2.0em;
+ /*margin-top: 12.0em;*/
+ /*margin-bottom: 1.0em;*/
+ color: #C00000;
+ /*padding: 10pt,20pt*/
+ }
+
+table
+ {
+ /* width: 90%; */
+ background: #999999;
+ margin-top: .6em;
+ margin-bottom: .3em;
+ }
+
+th
+ {
+ padding: 4px 8px;
+ background: #cccccc;
+ text-align: left;
+ font-size: 80%;
+ vertical-align: bottom;
+ }
+
+th.cc
+ {
+ text-align: center;
+ vertical-align: middle;
+ }
+
+td
+ {
+ padding: 4px 8px;
+ background: #ffffff;
+ vertical-align: top;
+ font-size: 80%;
+ }
+
+td.cc
+ {
+ text-align: center;
+ vertical-align: middle;
+ }
+
+
+blockquote
+ {
+ margin-left: 3.8em;
+ margin-right: 3.8em;
+ margin-top: .6em;
+ margin-bottom: .6em;
+ }
+
+a:link
+ {
+ color: #0066ff;
+ }
+
+a:visited
+ {
+ color: #996600;
+ }
+
+a:hover
+ {
+ color: #cc9900;
+ }
+
+a.parameter:link
+ {
+ color: #0066ff;
+ text-decoration:none;
+ }
+
+a.parameter:visited
+ {
+ text-decoration:none;
+ }
+
+div.footer
+ {
+ width: 100%;
+ border: none;
+ background: #ffffff;
+ margin-top: 18pt;
+ padding-bottom: 12pt;
+ color: #228B22;
+ text-align: center;
+ font-size: 70%;
+ }
+
+span.filename
+{
+ color: #F00000;
+}
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/type.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/type.htm
new file mode 100644
index 000000000..73af4e1a9
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/type.htm
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-o (set Output directory) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-t (set Type of archive) switch</H1>
+
+<P>Specifies the type of archive.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-t{archive_type}
+</PRE>
+
+<DL>
+ <DT>{archive_type}</DT>
+ <DD>Specifies the type of archive. It can be: *, 7z, split, zip, gzip, bzip2, tar, ... , or
+ combination of them, like: mbr.vhd
+</DD>
+</DL>
+
+<P>If -t{archive_type} switch is not specified, 7-Zip uses extension of archive filename to
+ detect the type of archive. If you create new archive, -t{archive_type} switch is not
+ specified and there is no extension of archive, 7-Zip will create .7z archive.</P>
+
+<P>When you extract archive of some types that contains another
+archive without compression (for example, MBR in VHD), 7-Zip can open both
+levels in one step. If you want to open/extract just top
+level archive, use <SPAN class="filename">-t*</SPAN> switch.</P>
+
+<P>Note: gzip or bzip2 formats support only one file per archive.
+If you want to compress more than one file to these formats,
+create a tar archive first, and then compress it with your selected format.</P>
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z a -tzip archive.zip *.txt
+</PRE>
+
+<P>adds all <SPAN class="filename">*.txt</SPAN> files from current directory
+to zip archive <SPAN class="filename">archive.zip</SPAN>.</P>
+
+<PRE class="example">
+7z t -t7z.split archive.7z.001
+</PRE>
+
+<P>tests all files in <SPAN class="filename">archive.7z.001</SPAN>. It also checks
+that archive is multivolume .7z archive.</P>
+
+<PRE class="example">
+7z x -tiso archive.iso
+</PRE>
+
+<P>extracts files from <SPAN class="filename">archive.iso</SPAN> open as ISO archive.
+
+<PRE class="example">
+7z x -tudf archive.iso
+</PRE>
+
+<P>extracts files from <SPAN class="filename">archive.iso</SPAN> open as UDF archive.
+
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/list.htm">l (List)</A>,
+ <A href="../commands/test.htm">t (Test)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/update.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/update.htm
new file mode 100644
index 000000000..3c707a784
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/update.htm
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-u (Update options) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-u (Update options) switch</H1>
+
+<P>Specifies how to update files in an archive and (or) how to create new archives.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-u<A class="parameter" href="#disable_base_archive">[-]</A>&lt;action_set><A class="parameter" href="#new_archive_name">[!{new_archive_name}]</A>
+
+ &lt;action_set> ::= &lt;state_action>...
+
+ &lt;state_action> ::= <A class="parameter" href="#state">&lt;state></A><A class="parameter" href="#state">&lt;action></A>
+
+ <A class="parameter" href="#action">&lt;state></A> ::= p | q | r | x | y | z | w
+
+ <A class="parameter" href="#action">&lt;action></A> ::= 0 | 1 | 2 | 3
+</PRE>
+
+
+<H4>Parameters</H4>
+
+<DL>
+ <DT><A name="disable_base_archive"></A>dash (-)</DT>
+ <DD><P>Disables any updates in the base archive.</P>
+
+ <P>The term <B>base archive</B> means the archive assigned by "base_archive_name"
+ on the command line. See <A href="../syntax.htm">Command line syntax</A>
+ for more details.</P>
+ </DD>
+ <DT><A name="new_archive_name"></A>{new_archive_name}</DT>
+ <DD><P>Specifies the path name of the new archive to be created.
+ All options in this switch will refer to this new archive.</P>
+ <P>If not assigned, then all options in this switch will
+ refer to the base archive of the command.</P>
+ </DD>
+ <DT><A name="state"></A>&lt;state></DT>
+ <DD><P>Specifies the state of a particular file to be processed.</P>
+ <PRE class="syntax">&lt;state> ::= p | q | r | x | y | z | w</PRE>
+ <P>For each unique filename there are 6 variants of state:</P>
+ <TABLE>
+ <TR> <TH>&lt;state></TH> <TH>State condition</TH>
+ <TH width="20%">File on Disk</TH> <TH width="20%">File in Archive</TH> </TR>
+
+ <TR> <TD align="center">p</TD> <TD>File exists in archive, but is not matched with wildcard.</TD>
+ <TD>&nbsp;</TD> <TD>Exists, but is not matched</TD> </TR>
+
+ <TR> <TD align="center">q</TD> <TD>File exists in archive, but doesn't exist on disk.</TD>
+ <TD>Doesn't exist</TD> <TD>Exists</TD> </TR>
+
+ <TR> <TD align="center">r</TD> <TD>File doesn't exist in archive, but exists on disk.</TD>
+ <TD>Exists</TD> <TD>Doesn't exist</TD> </TR>
+
+ <TR> <TD align="center">x</TD> <TD>File in archive is newer than the file on disk.</TD>
+ <TD>Older</TD> <TD>Newer</TD> </TR>
+
+ <TR> <TD align="center">y</TD> <TD>File in archive is older than the file on disk.</TD>
+ <TD>Newer</TD> <TD>Older</TD> </TR>
+
+ <TR> <TD align="center">z</TD> <TD>File in archive is same as the file on disk</TD>
+ <TD>Same</TD> <TD>Same</TD> </TR>
+
+ <TR> <TD align="center">w</TD> <TD>Can not be detected what file is newer
+ (times are the same, sizes are different)</TD>
+ <TD>?</TD> <TD>?</TD> </TR>
+ </TABLE>
+ </DD>
+
+ <DT><A name="action"></A>&lt;action></DT>
+ <DD><P>Specifies the action for a given <A class="parameter" href="#state">&lt;state></A>.</P>
+ <PRE class="syntax">&lt;action> ::= 0 | 1 | 2 | 3</PRE>
+ <P>For each state you can specify one of the three variants of actions:</P>
+ <TABLE>
+ <TR> <TH>&lt;action></TH> <TH>Description</TH></TR>
+ <TR> <TD align="center">0</TD> <TD>Ignore file (don't create item in new archive for this file)</TD></TR>
+ <TR> <TD align="center">1</TD> <TD>Copy file (copy from old archive to new)</TD></TR>
+ <TR> <TD align="center">2</TD> <TD>Compress (compress file from disk to new archive)</TD></TR>
+ <TR> <TD align="center">3</TD> <TD>Create Anti-item (item that will delete file or directory during extracting). This feature is supported only in 7z format.</TD></TR>
+ </TABLE>
+ </DD>
+</DL>
+
+
+<H4>Remarks</H4>
+
+<P>Any update command (such as <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/update.htm">u (Update)</A>) can be assigned in these terms.</P>
+<P>The following table shows action sets for update commands.</P>
+
+<TABLE>
+ <TR> <TH>command \ <A class="parameter" href="#state">&lt;state></A></TH>
+ <TH>p</TH> <TH>q</TH> <TH>r</TH> <TH>x</TH> <TH>y</TH> <TH>z</TH> <TH>w</TH></TR>
+ <TR> <TH><A href="../commands/delete.htm">d (Delete)</A></TH> <TD>1</TD> <TD>0</TD> <TD>0</TD> <TD>0</TD> <TD>0</TD> <TD>0</TD> <TD>0</TD></TR>
+ <TR> <TH><A href="../commands/add.htm">a (Add)</A></TH> <TD>1</TD> <TD>1</TD> <TD>2</TD> <TD>2</TD> <TD>2</TD> <TD>2</TD> <TD>2</TD></TR>
+ <TR> <TH><A href="../commands/update.htm">u (Update)</A></TH> <TD>1</TD> <TD>1</TD> <TD>2</TD> <TD>1</TD> <TD>2</TD> <TD>1</TD> <TD>2</TD></TR>
+ <TR> <TH>Freshen</TH> <TD>1</TD> <TD>1</TD> <TD>0</TD> <TD>1</TD> <TD>2</TD> <TD>1</TD> <TD>2</TD></TR>
+ <TR> <TH>Synchronize</TH> <TD>1</TD> <TD>0</TD> <TD>2</TD> <TD>1</TD> <TD>2</TD> <TD>1</TD> <TD>2</TD></TR>
+</TABLE>
+
+
+<P>If you don't specify a
+<A class="parameter" href="#new_archive_name"><I>!{new_archive_name}</I></A> option, then
+all options will refer to the main archive (the archive assigned on the command line after the 7z command).
+If you specify <A class="parameter" href="#new_archive_name"><I>!{new_archive_name}</I></A>
+option, then 7-Zip also will create a new archive with the specified name and all options
+will refer to that new archive.</P>
+
+<P>Multiple update switches are supported.
+7-Zip can create any number of new archives during one operation.</P>
+
+<P>By default, the action set for each new archive is assigned
+as the action set of the main command. There are 3 different
+action sets for commands: <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/update.htm">u (Update)</A>.
+You can overload any &lt;state_action> pair.</P>
+
+<H4>Time zone notes</H4>
+<P>If you change time zone (when you move your computer to another time zone
+or if there are clock changes for daylight saving in your zone), you can have some problems
+with update commands that depend from file's modification time. It's strongly recommended to use only
+file system that uses Coordinated Universal Time (UTC) and archive format that also uses UTC.
+In that case you will have no problems with time zone changes.
+Also it's recommended to use only UTC formats in other cases, for example, if you send files to
+someone in another time zone.</P>
+
+<P>Also in some cases there are no problems, if both file system and archive format use local time, for example, FAT file system and ZIP format.</P>
+<UL>
+<LI>UTC file systems: NTFS
+<LI>UTC archive formats: .zip with -mtc switch, 7z, tar, gzip2, iso, wim
+<LI>Local time file systems : FAT, FAT32
+<LI>Local time archive formats : rar, zip, cab
+</UL>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z u c:\1\exist.7z -u- -up0q3x2z0!c:\1\update.7z *
+</PRE>
+
+<P>creates a new archive <SPAN class="filename">update.7z</SPAN> and
+writes to this archive all files from current directory which differ from
+files in <SPAN class="filename">exist.7z</SPAN> archive.
+<SPAN class="filename">exist.7z</SPAN> archive will not be changed.</P>
+
+<PRE class="example">
+7z u c:\1\exist.7z -up0q3x2z0!c:\1\update.7z * -ms=off
+</PRE>
+
+<P>creates a new archive <SPAN class="filename">update.7z</SPAN> and
+writes to this archive all files from the current directory which differ from
+files in <SPAN class="filename">exist.7z</SPAN> archive.
+
+<P>Note: the updating of solid .7z archives can be slow, since it
+can require some recompression.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/volume.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/volume.htm
new file mode 100644
index 000000000..91ddc2924
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/volume.htm
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-v (Create Volumes) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-v (Create Volumes) switch</H1>
+
+<P>Specifies volume sizes.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-v{Size}[b | k | m | g]
+
+</PRE>
+<DL>
+ <DT>{Size}[b | k | m | g]</DT>
+ <DD>Specifies volume size in Bytes, Kilobytes (1 Kilobyte = 1024 bytes),
+ Megabytes (1 Megabyte = 1024 Kilobytes) or Gigabytes (1 Gigabyte = 1024 Megabytes).
+ if you specify only {Size}, 7-zip will treat it as bytes.</DD>
+</DL>
+
+<P>It's possible to specify several -v switches.</P>
+
+<P><B>NOTE:</B> Please don't use volumes (and don't copy volumes) before finishing archiving.
+7-Zip can change any volume (including first volume) at the end of archiving operation.</P>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z a a.7z *.txt -v10k -v15k -v2m
+</PRE>
+
+<P>creates multivolume <SPAN class="filename">a.7z</SPAN> archive.
+First volume will be 10 KB, second will be 15 KB, and all others will be 2 MB.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/working_dir.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/working_dir.htm
new file mode 100644
index 000000000..415c3971b
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/working_dir.htm
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-w (set Working directory) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-w (set Working directory) switch</H1>
+
+<P>Sets the working directory for the temporary base archive. By
+default, 7-Zip builds a new base archive file in the same directory as the
+old base archive file. By specifying this switch, you can set the
+working directory where the temporary base archive file will be built.
+After the temporary base archive file is built, it is copied over the
+original archive; then, the temporary file is deleted.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">
+-w[<A class="parameter" href="#dir_path">{dir_path}</A>]
+</PRE>
+
+<DL>
+ <DT><A name="dir_path"></A>{dir_path}</DT>
+ <DD>
+ <P>Specifies the destination directory path. It's not required that
+ a path end with a backslash.</P>
+ <P>If &lt;dir_path> is not assigned, then 7-Zip will use the Windows temporary directory.</P>
+ </DD>
+</DL>
+
+
+<H4>Example</H4>
+
+<PRE class="example">
+7z a -tzip archive.zip *.cpp -wc:\temp
+</PRE>
+
+<P>adds <SPAN class="filename">*.cpp</SPAN> files to the
+<SPAN class="filename">archive.zip</SPAN> archive, creating a temporary archive
+in <SPAN class="filename">c:\temp</SPAN> folder.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/add.htm">a (Add)</A>,
+ <A href="../commands/delete.htm">d (Delete)</A>,
+ <A href="../commands/update.htm">u (Update)</A>,
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/switches/yes.htm b/src/libs/7zip/unix/DOCS/MANUAL/switches/yes.htm
new file mode 100644
index 000000000..142ffd20c
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/switches/yes.htm
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>-y (assume Yes on all queries) switch</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>-y (assume Yes on all queries) switch</H1>
+
+<P>Disables most of the normal user queries during 7-Zip
+execution. You can use this switch to suppress overwrite queries in the
+<A href="../commands/extract.htm">e (Extract)</A> and
+<A href="../commands/extract_full.htm">x (Extract with full paths)</A> commands.</P>
+
+<H4>Syntax</H4>
+
+<PRE class="syntax">-y</PRE>
+
+<H4>Examples</H4>
+
+<PRE class="example">
+7z x src.zip -y
+</PRE>
+
+<P>extracts all files from
+ <SPAN class="filename">src.zip</SPAN> archive. All overwrite queries will be
+suppressed and files on disk with same filenames as in archive will be
+overwritten.</P>
+
+<H4>Commands that can be used with this switch</H4>
+
+<P>
+ <A href="../commands/extract.htm">e (Extract)</A>,
+ <A href="../commands/extract_full.htm">x (Extract with full paths)</A>
+</P>
+
+<H4>See also</H4>
+
+<P>
+ <B>Switches:</B>
+ <A href="overwrite.htm">-ao (Overwrite mode)</A>,
+</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/MANUAL/syntax.htm b/src/libs/7zip/unix/DOCS/MANUAL/syntax.htm
new file mode 100644
index 000000000..63822e03b
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/MANUAL/syntax.htm
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+ <META http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+ <TITLE>Command Line Syntax</TITLE>
+ <LINK href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<H1>Command Line Syntax</H1>
+
+<PRE class = "syntax">
+7z <A href = "commands/index.htm">&lt;command></A> [<A href = "switches/index.htm">&lt;switch></A>...] &lt;base_archive_name> [&lt;arguments>...]
+</PRE>
+<PRE class = "syntax">
+&lt;arguments> ::= <A href = "switches/index.htm">&lt;switch></A> | &lt;wildcard> | &lt;filename> | &lt;list_file>
+<A href = "switches/index.htm">&lt;switch></A>::= &lt;switch_symbol>&lt;switch_characters>[&lt;option>]
+&lt;switch_symbol> ::= '/' | '-'
+&lt;list_file> ::= @{filename}
+</PRE>
+
+
+<P>Expressions in square brackets (between '[' and ']') are optional.</P>
+
+<P>Expressions in curly braces ('{' and '}') mean that instead of that
+Expression (including braces), the user must substitute some string.</P>
+
+<P>Expression</P>
+
+<PRE class = "syntax">
+expression1 | expression2 | ... | expressionN</DT>
+</PRE>
+
+<P>
+means that any (but only one) from these expressions must be specified.
+
+<P><A href = "commands/index.htm">Commands</A> and
+<A href = "switches/index.htm">switches</A> can be entered in upper or lower case.</P>
+
+<P>Command is the first non-switch argument.</P>
+
+<P>The "base_archive_name" must be the first filename on the command line
+after the command.</P>
+
+<P>The switches and other filenames can be in any order.</P>
+
+<P>Wildcards or filenames with spaces must be quoted:</P>
+
+<PRE>
+ "Dir\Program files\*"
+ Dir\"Program files"\*
+</PRE>
+
+<P>Switch options can be combined to save command line length. However, some
+switch options take optional string arguments and therefore, must be the
+last option in a combined argument token string because 7-Zip accepts the
+rest of the argument token as the optional argument.</P>
+
+<P>7-Zip uses wild name matching similar to Windows 95:</P>
+<UL>
+ <LI><B>'*'</B> means a sequence of arbitrary characters.</LI>
+ <LI><B>'?'</B> means any character.</LI>
+</UL>
+
+<P><B>
+7-Zip doesn't uses the system wildcard parser. 7-Zip doesn't
+follow the archaic rule by which *.* means any file. 7-Zip treats
+*.* as matching the name of any file that has an extension. To process all files, you must
+use a * wildcard.</B></P>
+
+<P>Examples:</P>
+<TABLE border = "0">
+ <TR><TD>*.txt</TD><TD>means all files with an extension of ".txt"</TD></TR>
+ <TR><TD>?a*</TD><TD>means all files with a second character of "a"</TD></TR>
+ <TR><TD>*1*</TD><TD>means all names that contains character "1"</TD></TR>
+ <TR><TD>*.*.*</TD><TD>means all names that contain two at least "." characters</TD></TR>
+</TABLE>
+
+
+<P>The default wildcard "*" will be used if there is no filename/wildcard in the
+command line.</P>
+
+<P>Slash ('\') at the end of a path means a directory. Without a Slash ('\') at
+the end of the path, the path can refer either to a file or a directory.
+
+
+<H2><A name = "ListFile"></A>List file</H2>
+
+<P>You can supply one or more filenames or wildcards for special list files
+(files containing lists of files). The filenames in such list file must be
+separated by new line symbol(s).</P>
+
+<P>For list files, 7-Zip uses UTF-8 encoding by default. You can change encoding
+using <A href = "switches/charset.htm">-scs</A> switch.</P>
+
+<P>Multiple list files are supported.</P>
+
+<P>For example, if the file "listfile.txt" contains the following:</P>
+
+<PRE>
+ My programs\*.cpp
+ Src\*.cpp
+</PRE>
+<P>then the command</P>
+
+<PRE>
+ 7z a -tzip archive.zip @listfile.txt
+</PRE>
+
+<P>adds to the archive "archive.zip" all "*.cpp" files from directories "My
+programs" and "Src".</P>
+
+<H2><A name = "ListFile"></A>Short and Long File Names</H2>
+
+<P>7-Zip supports short file names (like FILENA~1.TXT) in some cases.
+However, it's strongly recommended to use only the real (long) file names.</P>
+
+</BODY>
+</HTML>
diff --git a/src/libs/7zip/unix/DOCS/Methods.txt b/src/libs/7zip/unix/DOCS/Methods.txt
new file mode 100644
index 000000000..f52e7c315
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/Methods.txt
@@ -0,0 +1,152 @@
+7-Zip method IDs (9.18)
+-----------------------
+
+Each compression or crypto method in 7z has unique binary value (ID).
+The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes).
+
+If you want to add some new ID, you have two ways:
+1) Write request for allocating IDs to 7-zip developers.
+2) Generate 8-bytes ID:
+
+ 3F ZZ ZZ ZZ ZZ ZZ MM MM
+
+ 3F - Prefix for random IDs (1 byte)
+ ZZ ZZ ZZ ZZ ZZ - Developer ID (5 bytes). Use real random bytes.
+
+ MM MM - Method ID (2 bytes)
+
+ You can notify 7-Zip developers about your Developer ID / Method ID.
+
+ Note: Use new ID only if old codec can not decode data encoded with new version.
+
+
+List of defined IDs
+-------------------
+
+00 - Copy
+
+03 - Delta
+04 - x86 (BCJ)
+05 - PPC (Big Endian)
+06 - IA64
+07 - ARM (little endian)
+08 - ARM Thumb (little endian)
+09 - SPARC
+21 - LZMA2
+
+02.. - Common
+ 03 Swap
+ - 2 Swap2
+ - 4 Swap4
+
+03.. - 7z
+ 01 - LZMA
+ 01 - Version
+
+ 03 - Branch
+ 01 - x86
+ 03 - BCJ
+ 1B - BCJ2
+ 02 - PPC
+ 05 - PPC (Big Endian)
+ 03 - Alpha
+ 01 - Alpha
+ 04 - IA64
+ 01 - IA64
+ 05 - ARM
+ 01 - ARM
+ 06 - M68
+ 05 - M68 (Big Endian)
+ 07 - ARM Thumb
+ 01 - ARMT
+ 08 - SPARC
+ 05 - SPARC
+
+ 04 - PPMD
+ 01 - Version
+
+ 7F -
+ 01 - experimental methods.
+
+
+04.. - Misc
+ 00 - Reserved
+ 01 - Zip
+ 00 - Copy (not used). Use {00} instead
+ 01 - Shrink
+ 06 - Implode
+ 08 - Deflate
+ 09 - Deflate64
+ 10 - Imploding
+ 12 - BZip2 (not used). Use {04 02 02} instead
+ 14 - LZMA
+ 60 - Jpeg
+ 61 - WavPack
+ 62 - PPMd
+ 63 - wzAES
+ 02 - BZip
+ 02 - BZip2
+ 03 - Rar
+ 01 - Rar15
+ 02 - Rar20
+ 03 - Rar29
+ 04 - Arj
+ 01 - Arj (1,2,3)
+ 02 - Arj 4
+ 05 - Z
+ 06 - Lzh
+ 07 - Reserved for 7z
+ 08 - Cab
+ 09 - NSIS
+ 01 - DeflateNSIS
+ 02 - BZip2NSIS
+
+
+06.. - Crypto
+ 00 -
+ 01 - AES
+ 0x - AES-128
+ 4x - AES-192
+ 8x - AES-256
+ Cx - AES
+
+ x0 - ECB
+ x1 - CBC
+ x2 - CFB
+ x3 - OFB
+
+ 07 - Reserved
+ 0F - Reserved
+
+ F0 - Misc Ciphers (Real Ciphers without hashing algo)
+
+ F1 - Misc Ciphers (Combine)
+ 01 - Zip
+ 01 - Main Zip crypto algo
+ 03 - RAR
+ 02 -
+ 03 - Rar29 AES-128 + (modified SHA-1)
+ 07 - 7z
+ 01 - AES-256 + SHA-256
+
+07.. - Hash (subject to change)
+ 00 -
+ 01 - CRC
+ 02 - SHA-1
+ 03 - SHA-256
+ 04 - SHA-384
+ 05 - SHA-512
+
+ F0 - Misc Hash
+
+ F1 - Misc
+ 03 - RAR
+ 03 - Rar29 Password Hashing (modified SHA1)
+ 07 - 7z
+ 01 - SHA-256 Password Hashing
+
+
+
+
+---
+End of document
diff --git a/src/libs/7zip/unix/DOCS/copying.txt b/src/libs/7zip/unix/DOCS/copying.txt
new file mode 100644
index 000000000..4c3890127
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/copying.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/libs/7zip/unix/DOCS/history.txt b/src/libs/7zip/unix/DOCS/history.txt
new file mode 100644
index 000000000..05a9a2165
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/history.txt
@@ -0,0 +1,456 @@
+Sources history of the 7-Zip
+----------------------------
+
+9.18 2010-11-02
+-------------------------
+- New small SFX module for installers (C/Util/SfxSetup).
+
+
+9.17 2010-10-04
+-------------------------
+- IStream.h::IOutStream::
+ STDMETHOD(SetSize)(Int64 newSize) PURE;
+ was changed to
+ STDMETHOD(SetSize)(UInt64 newSize) PURE;
+
+
+9.09 2009-12-12
+-------------------------
+- The bug was fixed:
+ Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c
+ incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
+
+
+9.05 2009-07-05
+-------------------------
+- FileMapping.h::CFileMapping now returns WRes
+
+
+9.04 2009-05-30
+-------------------------
+- ICoder.h: NCoderPropID::EEnum values were changed
+
+
+9.02 2009-04-23
+-------------------------
+- Bug was fixed: if swap2 filter was requests at compression,
+ 7-zip used swap4 filter instead (but id was swap2), so archives were incorrect.
+
+4.61 2008-11-23
+-------------------------
+- Bug in ver. 4.58+ was fixed:
+ 7-Zip didn't use any -m* switch after -mtc, -mcl or -mcu for .zip archives.
+- Bug in .CAB code was fixed. 7-Zip didn't show some empty files,
+ if .CAB archive contains more than one empty file.
+
+
+4.59 2008-07-27
+-------------------------
+- Bug was fixed:
+ LZMA Encoder in fast compression mode could access memory outside of
+ allocated range in some rare cases.
+
+
+4.59 alpha 2008-05-30
+-------------------------
+- BUGS was fixed:
+ 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases.
+ 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties.
+
+4.58 alpha 9 2008-04-29
+-------------------------
+- BUG was fixed: 7-Zip showed incorrect timestamps in ISO files.
+
+
+4.58 alpha 8 2008-04-15
+-------------------------
+- BUG in 4.58 alpha 5/6/7 was fixed:
+ LZMA encoder worked incorrectly, if lp != 0.
+- Unicode (UTF-8) support for filenames in .ZIP archives. Now there are 3 modes:
+ 1) Default mode: 7-Zip uses UTF-8, if the local code page doesn't contain required symbols.
+ 2) -mcu switch: 7-Zip uses UTF-8, if there are non-ASCII symbols.
+ 3) -mcl switch: 7-Zip uses local code page.
+- Now it's possible to use -mSW- and -mSW+ switches instead of -mSW=off and -mSW=on
+
+
+4.58 alpha 7 2008-04-08
+-------------------------
+- BUG was fixed: BZip2Encoder and BZip2Decoder used CEvent objects without
+ creating, when BZip2 code was called with one thread (with -mmt1 switch or with
+ default switches on single thread CPU).
+- .lzma support.
+- RPM and NSIS support was improved.
+- LZMA now stores only (2 << n) or (3 << n) dictionary size value to LZMA properties.
+
+
+4.58 alpha 6 2008-03-27
+-------------------------
+- NTFS time extra in ZIP.
+- New item property - kpidTimeType - VT_UI4 (0 - NTFS, 1 - Unix, 2 - DOS).
+- Static CRC table is not required now for Lzma Encoder (in Lz MatchFinder).
+
+
+4.58 alpha 5 2008-03-19
+-------------------------
+- Creation time (-mtc switch) for .7z archives
+- LZMA encoder was converted to ANSI-C
+
+
+4.58 alpha 3 2008-02-25
+-------------------------
+- Speed optimizations for LZMA decoding. Now it uses C code instead of C++.
+- 7-Zip now has 128 MB dictionary limit for 32-bit version:
+ It's for speed optimization: kNumLogBits = 9 + sizeof(size_t) / 2;
+- TAR: 'D' link flag support.
+- 7-Zip now can unpack multivolume RAR archives created with
+ "old style volume names" scheme (-vn switch) and names *.001, *.002, ...
+- Fixed bugs:
+ - 7-Zip FM could not copy / move files to root network folders like \\COMPNAME\FOLDERNAME\
+ In case of move it removed original files.
+ - SFX-WIN: if there are errors, it still could return 0.
+ - ZIP (.XPS file) isZip64 && thisDiskNumber16 == 0xFFFF.
+ - ZIP name updating:
+ If zip file contains extra field and you try to change properties of files,
+ 7-zip tries to delete all extra fileds (except for WzAES).
+ And that code could hang.
+ - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run.
+ - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp
+ as modification time stamp.
+
+4.58 alpha 2 2007-12-31
+-------------------------
+- Small changes in Deflate and LZMA compression.
+- Some speed optimizations.
+
+
+4.57
+----
+- Bug was fixed:
+ Anti item is created for wrong file:
+ http://sourceforge.net/forum/forum.php?thread_id=1880366&forum_id=45798
+
+
+4.52 beta 2007-07-32
+-------------------------
+- 7-Zip could not decompress some cab files
+- "." dir creating at FAT was fixed / long names
+
+
+4.50 beta 2007-07-24
+-------------------------
+- 7-Zip now replaces unsupported filenames (like "nul", "com1") during extracting.
+- New switch for command line version:
+ -ssc[-] enables/disables case-sensitive mode.
+- 7z.exe l shows archive comment for zip archives
+- Some bugs were fixed: long paths names shorter than 4.
+- Speed optimizations for AES encryption.
+
+
+
+4.56 beta 2007-09-13
+-------------------------
+- some fixes in LZ encoder (LZMA and Deflate) code.
+ size_t was replaces to ptrdiff_t.
+ size_t version worked incorrectly with some compilers.
+
+
+4.46 beta 2007-05-25
+-------------------------
+- CPP Synchronization objects now return HRes (error code) instead of bool.
+
+
+4.45 beta 2007-04-16
+-------------------------
+- 7-Zip now uses C version of CRC, so you must call CrcGenerateTable at
+ stratup code, or you must add CPP/Common/CRC.cpp to your project.
+- Method ID in .7z now is 63-bit integer (UInt64).
+- Open error messages
+- unRar 1.5 fixed
+- unShrink fixed
+- BUG of 4.43 beta and 4.44 beta was fixed.
+ 7-Zip compressing to .zip in multi-threading mode didn't work in some cases.
+
+
+4.44 beta 2007-01-20
+-------------------------
+
+- Bug was fixed: LZMAEncoder.cpp::CEncoder::GetOptimumFast
+ it was:
+ data++
+ fixed version:
+ data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
+ It could lead to very small cpmpression ratio decreasing when block needs move.
+
+
+4.30 beta 2005-11-18
+-------------------------
+- Security.h::AddLockMemoryPrivilege - installs "Large pages" feature
+- MemoryLock.h::EnableLockMemoryPrivilege - enables "Large pages" feature
+- Alloc.h::SetLargePageSize - sets optimal LargePageSize size
+
+
+4.27 2005-09-21
+-------------------------
+- Some GUIDs/interfaces were changed.
+ IStream.h:
+ ISequentialInStream::Read now works as old ReadPart
+ ISequentialOutStream::Write now works as old WritePart
+
+
+4.26 beta 2005-08-05
+-------------------------
+- MyAlloc(0)/BigAlloc(0) now return 0
+
+
+4.25 beta 2005-07-31
+-------------------------
+- More 64-bit compatibilty
+
+
+4.24 beta 2005-07-06
+-------------------------
+- Common\NewHandler.h: using throw() for code size optimization.
+
+
+4.23 2005-06-29
+-------------------------
+- Bug was fixed: memory leak in Cab decoder.
+
+
+4.19 beta 2005-05-21
+-------------------------
+- BZip2 code was rewritten. Now 7-Zip doesn't use original BZip2 code.
+ Old (original) version was moved to folder 7zip/Compress/BZip2Original/
+
+
+4.14 beta 2005-01-11
+-------------------------
+- STL using was reduced
+- 7za now supports Split(001) archves
+
+
+4.10 beta 2004-10-21
+-------------------------
+- Codecs now use new interface: ICompressSetDecoderProperties2
+
+
+4.07 beta 2004-10-03
+-------------------------
+- some interfaces were changed slightly to support
+ -stdin -stdout mode.
+- FilterCoder for simple filters
+- Wildcard censor class was changed.
+- Bug was fixed: when encrypted stream was multiple 16,
+ it used additional 16 empty bytes.
+
+
+3.11 2003-10-06
+-------------------------
+ File functions support unicode strings even
+ on Windows 95/98/ME.
+
+
+3.08.02 2003-09-20
+-------------------------
+ More compatible with GCC.
+
+
+3.08.02 beta 2003-08-20
+-------------------------
+ Extracting bug in 7zExtract.cpp was fixed.
+
+
+3.08 beta 2003-08-19
+-------------------------
+ Big source code reconstruction.
+
+
+2.30 Beta 32 2003-05-15
+-------------------------
+ Small changes in Deflate decoder.
+
+
+2.30 Beta 31 2003-04-29
+-------------------------
+ Common/NewHandler.cpp
+ HeapAlloc in (included to beta 30) was changed to malloc.
+ HeapAlloc worked slower in Win95/98/Me.
+
+
+2.30 Beta 30 2003-04-21
+-------------------------
+ new file: Common/String.cpp
+ Common/NewHandler.* were changed
+
+
+2.30 Beta 29 2003-04-07
+-------------------------
+ Small changes in LZMA code.
+
+
+2.30 Beta 28 2003-02-16
+-------------------------
+ Processing anti-files was corrected.
+
+
+2.30 Beta 27 2003-01-24
+-------------------------
+ Project/Archiver/Format/Common/ArchiveInterface.h:
+ new IArchiveOpenVolumeCallback interface.
+
+
+2.30 Beta 26 2003-01-12
+-------------------------
+ SDK/Interface/PropID.h:
+ kpidComment now is kpidCommented
+
+
+2.30 Beta 25 2003-01-02
+-------------------------
+ Main archive interfaces were changed.
+
+
+2.30 Beta 24 2002-11-01
+-------------------------
+ SDK/Windows/Synchronization.h
+ SDK/Windows/Synchronization.cpp
+ - some changes.
+
+
+2.30 Beta 23 2002-09-07
+-------------------------
+ Project/FileManager folder was added.
+ Notation of some source files was changed.
+
+
+2.30 Beta 22 2002-08-28
+-------------------------
+ Project/FileManager folder was added.
+ Notation of some source files was changed.
+
+
+
+2.30 Beta 21 2002-07-08
+-------------------------
+ Project/Compress/LZ/MatchFinder/BinTree/BinTree.h
+ Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h
+ Project/Compress/LZ/MatchFinder/BinTree/HC.h
+ Project/Compress/LZ/MatchFinder/BinTree/HCMain.h
+ - RAM requirements for LZMA (7z) compression were reduced.
+
+
+2.30 Beta 20 2002-07-01
+-------------------------
+- SDK/Stream/WindowOut.h
+ now it uses only required memory (dictionary size).
+- Project/Archiver/Resource
+ contains common resurces
+
+
+2.30 Beta 19 2002-04-11
+-------------------------
+- SDK/Archive/Rar/Handler.cpp
+ supporting RAR29
+
+2.30 Beta 18 2002-03-25
+-------------------------
+- SDK/Archive/Cab/MSZipDecoder.cpp
+ SDK/Archive/Cab/LZXDecoder.cpp:
+ bug with corrupted archives was fixed
+- Project/Compress/LZ/MatchFinder/BinTree/BinTree.h
+- Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h
+ some speed optimization (using prefetching)
+
+
+2.30 Beta 17 2002-03-03
+-------------------------
+- ARJ suppport.
+
+
+2.30 Beta 16 2002-02-24
+-------------------------
+- Project/Compress/LZ/LZMA/Decoder.cpp:
+ Bug was fixed: LZMA could not extract more than 4 GB.
+- RPM and CPIO formats.
+- Project/Compress/LZ/LZMA/Encoder.*
+ Project/Archiver/Format/7z/OutHandler.cpp
+ New fast compression mode for LZMA: -m0a=0.
+- New match finders for LZMA: bt4b, hc3, hc4.
+
+
+2.30 Beta 15 2002-02-17
+-------------------------
+- Compression ratio in LZMA was slightly improved:
+ Project/Compress/LZ/LZMA/Encoder.*
+ Project/Archiver/Format/7z/OutHandler.cpp
+
+
+2.30 Beta 14 2002-02-10
+-------------------------
+- Supporting multithreading for LZMA:
+ Project/Compress/LZ/MatchFinder/MT
+- Common/String.h:
+ CStringBase::Replace function was fixed.
+
+
+2.30 Beta 13 2002-01-27
+-------------------------
+- Compress/LZ/MatchFinder/BinTree3.h:
+ method
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ - one VirtualAlloc array was splitted to
+ the for 3 arrays.
+ - Hash-functions were changed.
+
+
+
+2.30 Beta 12 2002-01-16
+-------------------------
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ Compress/LZ/MatchFinder/Patricia.h:
+ Compress/PPM/PPMd/SubAlloc.h:
+ Beta 11 bugs were fixed:
+ - VirtualFree was used incorrectly
+ - checking WIN32 instead _WINDOWS.
+ Compress/LZ/MatchFinder/Patricia.h:
+ Beta 11 bug with deleting m_Hash2Descendants was fixed.
+
+
+2.30 Beta 11 2002-01-15
+-------------------------
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ Compress/LZ/MatchFinder/Patricia.h:
+ Compress/PPM/PPMd/SubAlloc.h:
+ using VirtualAlloc for memory allocating
+- Exlorer/ContextMenu.cpp:
+ Testing supporting.
+ CreateProcess instead WinExec
+- Format/Common/IArchiveHandler.h:
+ Exlorer/ProxyHandler.cpp:
+ FAR/Plugin.cpp:
+ New properties names: Method, HostOS.
+- Exlorer/OverwriteDialog.cpp:
+ FAR/OverwriteDialog.cpp:
+ Windows/PropVariantConversions.h
+ Using National time format was eliminated.
+
+
+
+2.30 Beta 10 2002-01-11
+-------------------------
+- Exlorer/ContextMenu.cpp: bug with context menu on
+ Windows NT4 in Unicode version was fixed.
+- Format/7z/UpdateArchiveEngine.cpp: bug was fixed -
+ Updating in Beta 8 and 9 didn't work.
+- Exlorer/CCompressDialog.cpp: history growing bug was fixed.
+
+
+2.30 Beta 9 2002-01-08
+-------------------------
+- SDK/Common/Vector.h: sopporting sorted object vectors .
+- Lang features.
+- Two new match finders: pat3h and pat4h.
+- SDK/Archive/Zip/InEngine.cpp: bug was fixed.
+- SDK/Windows/FileDir.cpp: function CreateComplexDirectory
+ was changed.
+
diff --git a/src/libs/7zip/unix/DOCS/lzma.txt b/src/libs/7zip/unix/DOCS/lzma.txt
new file mode 100644
index 000000000..659323237
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/lzma.txt
@@ -0,0 +1,598 @@
+LZMA SDK 9.20
+-------------
+
+LZMA SDK provides the documentation, samples, header files, libraries,
+and tools you need to develop applications that use LZMA compression.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+LZMA is an improved version of famous LZ77 compression algorithm.
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for
+decompressing.
+
+
+
+LICENSE
+-------
+
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+Some code in LZMA SDK is based on public domain code from another developers:
+ 1) PPMd var.H (2001): Dmitry Shkarin
+ 2) SHA-256: Wei Dai (Crypto++ library)
+
+
+LZMA SDK Contents
+-----------------
+
+LZMA SDK includes:
+
+ - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing
+ - Compiled file->file LZMA compressing/decompressing program for Windows system
+
+
+UNIX/Linux version
+------------------
+To compile C++ version of file->file LZMA encoding, go to directory
+CPP/7zip/Bundles/LzmaCon
+and call make to recompile it:
+ make -f makefile.gcc clean all
+
+In some UNIX/Linux versions you must compile LZMA with static libraries.
+To compile with static libraries, you can use
+LIB = -lm -static
+
+
+Files
+---------------------
+lzma.txt - LZMA SDK description (this file)
+7zFormat.txt - 7z Format description
+7zC.txt - 7z ANSI-C Decoder description
+methods.txt - Compression method IDs for .7z
+lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
+7zr.exe - 7-Zip with 7z/lzma/xz support.
+history.txt - history of the LZMA SDK
+
+
+Source code structure
+---------------------
+
+C/ - C files
+ 7zCrc*.* - CRC code
+ Alloc.* - Memory allocation functions
+ Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+ LzFind.* - Match finder for LZ (LZMA) encoders
+ LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding
+ LzHash.h - Additional file for LZ match finder
+ LzmaDec.* - LZMA decoding
+ LzmaEnc.* - LZMA encoding
+ LzmaLib.* - LZMA Library for DLL calling
+ Types.h - Basic types for another .c files
+ Threads.* - The code for multithreading.
+
+ LzmaLib - LZMA Library (.DLL for Windows)
+
+ LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder).
+
+ Archive - files related to archiving
+ 7z - 7z ANSI-C Decoder
+
+CPP/ -- CPP files
+
+ Common - common files for C++ projects
+ Windows - common files for Windows related code
+
+ 7zip - files related to 7-Zip Project
+
+ Common - common files for 7-Zip
+
+ Compress - files related to compression/decompression
+
+ Archive - files related to archiving
+
+ Common - common files for archive handling
+ 7z - 7z C++ Encoder/Decoder
+
+ Bundles - Modules that are bundles of other modules
+
+ Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2
+ LzmaCon - lzma.exe: LZMA compression/decompression
+ Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2
+ Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2.
+
+ UI - User Interface files
+
+ Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
+ Common - Common UI files
+ Console - Code for console archiver
+
+
+
+CS/ - C# files
+ 7zip
+ Common - some common files for 7-Zip
+ Compress - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ LzmaAlone - file->file LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+Java/ - Java files
+ SevenZip
+ Compression - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+
+C/C++ source code of LZMA SDK is part of 7-Zip project.
+7-Zip source code can be downloaded from 7-Zip's SourceForge page:
+
+ http://sourceforge.net/projects/sevenzip/
+
+
+
+LZMA features
+-------------
+ - Variable dictionary size (up to 1 GB)
+ - Estimated compressing speed: about 2 MB/s on 2 GHz CPU
+ - Estimated decompressing speed:
+ - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64
+ - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC
+ - Small memory requirements for decompressing (16 KB + DictionarySize)
+ - Small code size for decompressing: 5-8 KB
+
+LZMA decoder uses only integer operations and can be
+implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
+
+Some critical operations that affect the speed of LZMA decompression:
+ 1) 32*16 bit integer multiply
+ 2) Misspredicted branches (penalty mostly depends from pipeline length)
+ 3) 32-bit shift and arithmetic operations
+
+The speed of LZMA decompressing mostly depends from CPU speed.
+Memory speed has no big meaning. But if your CPU has small data cache,
+overall weight of memory speed will slightly increase.
+
+
+How To Use
+----------
+
+Using LZMA encoder/decoder executable
+--------------------------------------
+
+Usage: LZMA <e|d> inputFile outputFile [<switches>...]
+
+ e: encode file
+
+ d: decode file
+
+ b: Benchmark. There are two tests: compressing and decompressing
+ with LZMA method. Benchmark shows rating in MIPS (million
+ instructions per second). Rating value is calculated from
+ measured speed and it is normalized with Intel's Core 2 results.
+ Also Benchmark checks possible hardware errors (RAM
+ errors in most cases). Benchmark uses these settings:
+ (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter.
+ Also you can change the number of iterations. Example for 30 iterations:
+ LZMA b 30
+ Default number of iterations is 10.
+
+<Switches>
+
+
+ -a{N}: set compression mode 0 = fast, 1 = normal
+ default: 1 (normal)
+
+ d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB)
+ The maximum value for dictionary size is 1 GB = 2^30 bytes.
+ Dictionary size is calculated as DictionarySize = 2^N bytes.
+ For decompressing file compressed by LZMA method with dictionary
+ size D = 2^N you need about D bytes of memory (RAM).
+
+ -fb{N}: set number of fast bytes - [5, 273], default: 128
+ Usually big number gives a little bit better compression ratio
+ and slower compression process.
+
+ -lc{N}: set number of literal context bits - [0, 8], default: 3
+ Sometimes lc=4 gives gain for big files.
+
+ -lp{N}: set number of literal pos bits - [0, 4], default: 0
+ lp switch is intended for periodical data when period is
+ equal 2^N. For example, for 32-bit (4 bytes)
+ periodical data you can use lp=2. Often it's better to set lc0,
+ if you change lp switch.
+
+ -pb{N}: set number of pos bits - [0, 4], default: 2
+ pb switch is intended for periodical data
+ when period is equal 2^N.
+
+ -mf{MF_ID}: set Match Finder. Default: bt4.
+ Algorithms from hc* group doesn't provide good compression
+ ratio, but they often works pretty fast in combination with
+ fast mode (-a0).
+
+ Memory requirements depend from dictionary size
+ (parameter "d" in table below).
+
+ MF_ID Memory Description
+
+ bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing.
+ bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing.
+ bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing.
+ hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
+
+ -eos: write End Of Stream marker. By default LZMA doesn't write
+ eos marker, since LZMA decoder knows uncompressed size
+ stored in .lzma file header.
+
+ -si: Read data from stdin (it will write End Of Stream marker).
+ -so: Write data to stdout
+
+
+Examples:
+
+1) LZMA e file.bin file.lzma -d16 -lc0
+
+compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
+and 0 literal context bits. -lc0 allows to reduce memory requirements
+for decompression.
+
+
+2) LZMA e file.bin file.lzma -lc0 -lp2
+
+compresses file.bin to file.lzma with settings suitable
+for 32-bit periodical data (for example, ARM or MIPS code).
+
+3) LZMA d file.lzma file.bin
+
+decompresses file.lzma to file.bin.
+
+
+Compression ratio hints
+-----------------------
+
+Recommendations
+---------------
+
+To increase the compression ratio for LZMA compressing it's desirable
+to have aligned data (if it's possible) and also it's desirable to locate
+data in such order, where code is grouped in one place and data is
+grouped in other place (it's better than such mixing: code, data, code,
+data, ...).
+
+
+Filters
+-------
+You can increase the compression ratio for some data types, using
+special filters before compressing. For example, it's possible to
+increase the compression ratio on 5-10% for code for those CPU ISAs:
+x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
+
+You can find C source code of such filters in C/Bra*.* files
+
+You can check the compression ratio gain of these filters with such
+7-Zip commands (example for ARM code):
+No filter:
+ 7z a a1.7z a.bin -m0=lzma
+
+With filter for little-endian ARM code:
+ 7z a a2.7z a.bin -m0=arm -m1=lzma
+
+It works in such manner:
+Compressing = Filter_encoding + LZMA_encoding
+Decompressing = LZMA_decoding + Filter_decoding
+
+Compressing and decompressing speed of such filters is very high,
+so it will not increase decompressing time too much.
+Moreover, it reduces decompression time for LZMA_decoding,
+since compression ratio with filtering is higher.
+
+These filters convert CALL (calling procedure) instructions
+from relative offsets to absolute addresses, so such data becomes more
+compressible.
+
+For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+ 0 1 Special LZMA properties (lc,lp, pb in encoded form)
+ 1 4 Dictionary size (little endian)
+ 5 8 Uncompressed size (little endian). -1 means unknown size
+ 13 Compressed data
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
+If you want to use old interfaces you can download previous version of LZMA SDK
+from sourceforge.net site.
+
+To use ANSI-C LZMA Decoder you need the following files:
+1) LzmaDec.h + LzmaDec.c + Types.h
+LzmaUtil/LzmaUtil.c is example application that uses these files.
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+Stack usage of LZMA decoding function for local variables is not
+larger than 200-400 bytes.
+
+LZMA Decoder uses dictionary buffer and internal state structure.
+Internal state structure consumes
+ state_size = (4 + (1.5 << (lc + lp))) KB
+by default (lc=3, lp=0), state_size = 16 KB.
+
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 2 interfaces:
+1) Single-call Decompressing
+2) Multi-call State Decompressing (zlib-like interface)
+
+You must use external allocator:
+Example:
+void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
+void SzFree(void *p, void *address) { p = p; free(address); }
+ISzAlloc alloc = { SzAlloc, SzFree };
+
+You can use p = p; operator to disable compiler warnings.
+
+
+Single-call Decompressing
+-------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+Compile defines: no defines
+Memory Requirements:
+ - Input buffer: compressed size
+ - Output buffer: uncompressed size
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+
+Interface:
+ int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ propData - LZMA properties (5 bytes)
+ propSize - size of propData buffer (5 bytes)
+ finishMode - It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+ You can use LZMA_FINISH_END, when you know that
+ current output buffer covers last bytes of stream.
+ alloc - Memory allocator.
+
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+
+ Output:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+
+ If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
+ and output value of destLen will be less than output buffer size limit.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+
+Multi-call State Decompressing (zlib-like interface)
+----------------------------------------------------
+
+When to use: file->file decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in LZMA properties header)
+
+1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
+ unsigned char header[LZMA_PROPS_SIZE + 8];
+ ReadFile(inFile, header, sizeof(header)
+
+2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
+
+ CLzmaDec state;
+ LzmaDec_Constr(&state);
+ res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
+ if (res != SZ_OK)
+ return res;
+
+3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
+
+ LzmaDec_Init(&state);
+ for (;;)
+ {
+ ...
+ int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
+ ...
+ }
+
+
+4) Free all allocated structures
+ LzmaDec_Free(&state, &g_Alloc);
+
+For full code example, look at C/LzmaUtil/LzmaUtil.c code.
+
+
+How To compress data
+--------------------
+
+Compile files: LzmaEnc.h + LzmaEnc.c + Types.h +
+LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h
+
+Memory Requirements:
+ - (dictSize * 11.5 + 6 MB) + state_size
+
+Lzma Encoder can use two memory allocators:
+1) alloc - for small arrays.
+2) allocBig - for big arrays.
+
+For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
+better compression speed. Note that Windows has bad implementation for
+Large RAM Pages.
+It's OK to use same allocator for alloc and allocBig.
+
+
+Single-call Compression with callbacks
+--------------------------------------
+
+Check C/LzmaUtil/LzmaUtil.c as example,
+
+When to use: file->file decompressing
+
+1) you must implement callback structures for interfaces:
+ISeqInStream
+ISeqOutStream
+ICompressProgress
+ISzAlloc
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+ CFileSeqInStream inStream;
+ CFileSeqOutStream outStream;
+
+ inStream.funcTable.Read = MyRead;
+ inStream.file = inFile;
+ outStream.funcTable.Write = MyWrite;
+ outStream.file = outFile;
+
+
+2) Create CLzmaEncHandle object;
+
+ CLzmaEncHandle enc;
+
+ enc = LzmaEnc_Create(&g_Alloc);
+ if (enc == 0)
+ return SZ_ERROR_MEM;
+
+
+3) initialize CLzmaEncProps properties;
+
+ LzmaEncProps_Init(&props);
+
+ Then you can change some properties in that structure.
+
+4) Send LZMA properties to LZMA Encoder
+
+ res = LzmaEnc_SetProps(enc, &props);
+
+5) Write encoded properties to header
+
+ Byte header[LZMA_PROPS_SIZE + 8];
+ size_t headerSize = LZMA_PROPS_SIZE;
+ UInt64 fileSize;
+ int i;
+
+ res = LzmaEnc_WriteProperties(enc, header, &headerSize);
+ fileSize = MyGetFileLength(inFile);
+ for (i = 0; i < 8; i++)
+ header[headerSize++] = (Byte)(fileSize >> (8 * i));
+ MyWriteFileAndCheck(outFile, header, headerSize)
+
+6) Call encoding function:
+ res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
+ NULL, &g_Alloc, &g_Alloc);
+
+7) Destroy LZMA Encoder Object
+ LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
+
+
+If callback function return some error code, LzmaEnc_Encode also returns that code
+or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS.
+
+
+Single-call RAM->RAM Compression
+--------------------------------
+
+Single-call RAM->RAM Compression is similar to Compression with callbacks,
+but you provide pointers to buffers instead of pointers to stream callbacks:
+
+HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+
+
+
+Defines
+-------
+
+_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
+
+_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
+ some structures will be doubled in that case.
+
+_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit.
+
+_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type.
+
+
+_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder.
+
+
+C++ LZMA Encoder/Decoder
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it,
+you can study basics of COM/OLE.
+C++ LZMA code is just wrapper over ANSI-C code.
+
+
+C++ Notes
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
+you must check that you correctly work with "new" operator.
+7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
+So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
+operator new(size_t size)
+{
+ void *p = ::malloc(size);
+ if (p == 0)
+ throw CNewException();
+ return p;
+}
+If you use MSCV that throws exception for "new" operator, you can compile without
+"NewHandler.cpp". So standard exception will be used. Actually some code of
+7-Zip catches any exception in internal code and converts it to HRESULT code.
+So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/src/libs/7zip/unix/DOCS/readme.txt b/src/libs/7zip/unix/DOCS/readme.txt
new file mode 100644
index 000000000..aad462642
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/readme.txt
@@ -0,0 +1,181 @@
+7-Zip 9.20 Sources
+------------------
+
+7-Zip is a file archiver for Windows.
+
+7-Zip Copyright (C) 1999-2010 Igor Pavlov.
+
+
+License Info
+------------
+
+7-Zip is free software distributed under the GNU LGPL
+(except for unRar code).
+read License.txt for more infomation about license.
+
+Notes about unRAR license:
+
+Please check main restriction from unRar license:
+
+ 2. The unRAR sources may be used in any software to handle RAR
+ archives without limitations free of charge, but cannot be used
+ to re-create the RAR compression algorithm, which is proprietary.
+ Distribution of modified unRAR sources in separate form or as a
+ part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+In brief it means:
+1) You can compile and use compiled files under GNU LGPL rules, since
+ unRAR license almost has no restrictions for compiled files.
+ You can link these compiled files to LGPL programs.
+2) You can fix bugs in source code and use compiled fixed version.
+3) You can not use unRAR sources to re-create the RAR compression algorithm.
+
+
+LZMA SDK
+--------
+
+Also this package contains files from LZMA SDK
+you can download LZMA SDK from this page:
+http://www.7-zip.org/sdk.html
+read about addtional licenses for LZMA SDK in file
+DOC/lzma.txt
+
+
+How to compile
+--------------
+To compile sources you need Visual C++ 6.0.
+For compiling some files you also need
+new Platform SDK from Microsoft' Site:
+http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm
+or
+http://www.microsoft.com/msdownload/platformsdk/sdkupdate/XPSP2FULLInstall.htm
+or
+http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
+
+If you use MSVC6, specify SDK directories at top of directories lists:
+Tools / Options / Directories
+ - Include files
+ - Library files
+
+
+To compile 7-Zip for AMD64 and IA64 you need:
+ Windows Server 2003 SP1 Platform SDK from microsoft.com
+
+Also you need Microsoft Macro Assembler:
+ - ml.exe for x86
+ - ml64.exe for AMD64
+You can use ml.exe from Windows SDK for Windows Vista or some other version.
+
+
+Compiling under Unix/Linux
+--------------------------
+Check this site for Posix/Linux version:
+http://sourceforge.net/projects/p7zip/
+
+
+Notes:
+------
+7-Zip consists of COM modules (DLL files).
+But 7-Zip doesn't use standard COM interfaces for creating objects.
+Look at
+7zip\UI\Client7z folder for example of using DLL files of 7-Zip.
+Some DLL files can use other DLL files from 7-Zip.
+If you don't like it, you must use standalone version of DLL.
+To compile standalone version of DLL you must include all used parts
+to project and define some defs.
+For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll
+that works with 7z format. So you can use such DLL in your project
+without additional DLL files.
+
+
+Description of 7-Zip sources package
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+DOC Documentation
+---
+ 7zFormat.txt - 7z format description
+ copying.txt - GNU LGPL license
+ unRarLicense.txt - License for unRAR part of source code
+ history.txt - Sources history
+ Methods.txt - Compression method IDs
+ readme.txt - Readme file
+ lzma.txt - LZMA SDK description
+ 7zip.nsi - installer script for NSIS
+
+
+C - Source code in C
+CPP - Source code in CPP
+
+Common Common modules
+Windows Win32 wrappers
+
+7zip
+-------
+ Common Common modules for 7-zip
+
+ Archive 7-Zip Archive Format Plugins
+ --------
+ Common
+ 7z
+ Arj
+ BZip2
+ Cab
+ Cpio
+ GZip
+ Rar
+ Rpm
+ Split
+ Tar
+ Zip
+
+ Bundle Modules that are bundles of other modules
+ ------
+ Alone 7za.exe: Standalone version of 7z
+ Alone7z 7zr.exe: Standalone version of 7z that supports only 7z/LZMA/BCJ/BCJ2
+ SFXCon 7zCon.sfx: Console 7z SFX module
+ SFXWin 7z.sfx: Windows 7z SFX module
+ SFXSetup 7zS.sfx: Windows 7z SFX module for Installers
+ Format7z 7za.dll: .7z support
+ Format7zExtract 7zxa.dll: .7z support, extracting only
+ Format7zR 7zr.dll: .7z support, LZMA/BCJ* only
+ Format7zExtractR 7zxr.dll: .7z support, LZMA/BCJ* only, extracting only
+ Format7zF 7z.dll: all formats
+
+ UI
+ --
+ Agent Intermediary modules for FAR plugin and Explorer plugin
+ Console 7z.exe Console version
+ Explorer Explorer plugin
+ Resource Resources
+ Far FAR plugin
+ Client7z Test application for 7za.dll
+
+ Compress
+ --------
+ BZip2 BZip2 compressor
+ Branch Branch converter
+ ByteSwap Byte Swap converter
+ Copy Copy coder
+ Deflate
+ Implode
+ Arj
+ LZMA
+ PPMd Dmitry Shkarin's PPMdH with small changes.
+ LZ Lempel - Ziv
+
+ Crypto Crypto modules
+ ------
+ 7zAES Cipher for 7z
+ AES AES Cipher
+ Rar20 Cipher for Rar 2.0
+ RarAES Cipher for Rar 3.0
+ Zip Cipher for Zip
+
+ FileManager File Manager
+
+
+---
+Igor Pavlov
+http://www.7-zip.org
diff --git a/src/libs/7zip/unix/DOCS/unRarLicense.txt b/src/libs/7zip/unix/DOCS/unRarLicense.txt
new file mode 100644
index 000000000..5f78b728d
--- /dev/null
+++ b/src/libs/7zip/unix/DOCS/unRarLicense.txt
@@ -0,0 +1,41 @@
+ ****** ***** ****** unRAR - free utility for RAR archives
+ ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ****** ******* ****** License for use and distribution of
+ ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ** ** ** ** ** ** FREE portable version
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ The source code of unRAR utility is freeware. This means:
+
+ 1. All copyrights to RAR and the utility unRAR are exclusively
+ owned by the author - Alexander Roshal.
+
+ 2. The unRAR sources may be used in any software to handle RAR
+ archives without limitations free of charge, but cannot be used
+ to re-create the RAR compression algorithm, which is proprietary.
+ Distribution of modified unRAR sources in separate form or as a
+ part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+ 3. The unRAR utility may be freely distributed. No person or company
+ may charge a fee for the distribution of unRAR without written
+ permission from the copyright holder.
+
+ 4. THE RAR ARCHIVER AND THE UNRAR UTILITY ARE DISTRIBUTED "AS IS".
+ NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
+ YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
+ DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
+ OR MISUSING THIS SOFTWARE.
+
+ 5. Installing and using the unRAR utility signifies acceptance of
+ these terms and conditions of the license.
+
+ 6. If you don't agree with terms of the license you must remove
+ unRAR files from your storage devices and cease to use the
+ utility.
+
+ Thank you for your interest in RAR and unRAR.
+
+
+ Alexander L. Roshal \ No newline at end of file
diff --git a/src/libs/7zip/unix/README b/src/libs/7zip/unix/README
new file mode 100644
index 000000000..f5cb312f4
--- /dev/null
+++ b/src/libs/7zip/unix/README
@@ -0,0 +1,358 @@
+ p7zip 9.20
+ ==========
+
+Homepage : http://p7zip.sourceforge.net/
+
+p7zip is a port of the Windows programs 7z.exe and 7za.exe provided by 7-zip.
+
+7-zip is a file archiver with the highest compression ratio.
+Homepage : www.7-zip.org
+
+ 7z uses plugins (7z.so and Codecs/Rar29.so) to handle archives.
+ 7za is a stand-alone executable.
+ 7za handles less archive formats than 7z.exe.
+ 7zr is a light stand-alone executable that supports only 7z/LZMA/BCJ/BCJ2.
+
+NEW:
+ 7zG : see GUI/readme.txt
+
+CAUTION :
+---------
+
+- FIRST : DO NOT USE the 7-zip format for backup purpose on Linux/Unix because :
+ - 7-zip does not store the owner/group of the file
+
+ On Linux/Unix, in order to backup directories you must use tar !
+ to backup a directory : tar cf - directory | 7za a -si directory.tar.7z
+ to restore your backup : 7za x -so directory.tar.7z | tar xf -
+
+- if you want to send files and directories (not the owner of file)
+ to others Unix/MacOS/Windows users, you can use the 7-zip format.
+
+ example : 7za a directory.7z directory
+
+ do not use "-r" because this flag does not do what you think
+ do not use directory/* because of ".*" files
+ (example : "directory/*" does not match "directory/.profile")
+
+
+BUILD :
+-------
+
+ If you have downloaded the "bin" package,
+ use directly the program bin/7za.
+ (tested on Redhat 9.0, Fedora 2, Mandrake 10.0, Debian 3.0)
+ As the program is statically linked, its should run on many x86 or amd64 linux.
+
+ If you have downloaded the "source" package,
+
+ According to your OS, copy makefile.linux,
+ makefile.freebsd, makefile.cygwin, ...
+ over makefile.machine
+
+ Example : building 7za, 7z (with its plugins), 7zr and Client7z and passing the internal tests
+ cp makefile.linux_x86_asm_gcc_4 makefile.linux
+ make all_test
+
+
+ If you want to make a parallel build on a 4 cpu machine : make -j 4 TARGET
+
+ If you have trouble, try : make -f makefile.oldmake TARGET
+
+ make depend : to rebuild the makefile.depend
+ make clean : to clean all directories
+ make : to build bin/7za
+ make sfx : to build bin/7zCon.sfx (7za can now create SFX archive)
+ make 7z : to build bin/7z and its plugins :
+ - "bin/7z.so" (GNU LGPL + AES code license)
+ - "bin/Codecs/Rar29.so" (GNU LGPL + unRAR restriction)
+ make 7zr : to build bin/7zr
+ make all : to build bin/7za and bin/7zCon.sfx
+ make all2 : to build bin/7za, bin/7z (with its plugins) and bin/7zCon.sfx
+ make all3 : to build bin/7za, bin/7z (with its plugins), bin/7zr and bin/7zCon.sfx
+ make test : to test bin/7za (extracting, archiving, password ...)
+ make test_7z : to test bin/7z (extracting, archiving, password ...)
+ make test_7zr : to test bin/7zr (extracting, archiving, ...)
+
+ make 7zG : to build bin/7zG and its plugins :
+ - "bin/7z.so" (GNU LGPL + AES code license)
+ - "bin/Codecs/Rar29.so" (GNU LGPL + unRAR restriction)
+ make test_7zG : to test bin/7zG (extracting, archiving, ...)
+
+
+ this procedure has been tested on :
+ - x86 CPU :
+ Linux - Debian 3.0 Stable
+ Linux - Ubuntu 10.10
+ MacOS 10.6.6
+
+ - AMD64 CPU :
+ Linux - Ubuntu 10.10
+ MacOS 10.6.6
+
+ - sparc CPU :
+ Solaris 8 (sparc) with gcc 2.95.2
+
+ - powerpc CPU :
+ MacOS X 10.4 (ppc)
+
+ Some older versions of p7zip were tested :
+ - x86 CPU :
+ DOS - (built with DJGPP, see http://blairdude.googlepages.com/p7zip )
+ Linux - Redhat 9.0 Standart
+ Linux - Fedora 2 (Redhat) (gcc 3.3.3 and gcc-3.4.1 with
+ stack-smashing protector from www.trl.ibm.com/projects/security/ssp/)
+ Linux - Mandrake 10.0 Official
+ Linux - Ubuntu 8.04
+ FreeBSD 5.2.1 (gcc 3.3.3)
+ MacOS 10.4.8
+ NetBSD
+ CYGWIN_NT-5.1 1.5.9(0.112/4/2) 2004-03-18 23:05 i686 Cygwin
+ Solaris 9 (x86) with gcc 3.3.2
+ Solaris 10 (x86)
+
+ - alpha CPU :
+ Linux - Debian 3.0 (alpha) with gcc 2.95.4
+
+ - AMD64 CPU :
+ Linux - SuSE 8 ES (AMD64 Opteron) with gcc 3.2.2
+ Linux - Fedora 4 (AMD64 Turion) with gcc 4.0.1
+ Linux - Ubuntu 8.10
+
+ - Itanium CPU :
+ HP-UX B.11.31 U ia64 with aCC (HP C/aC++ B3910B A.06.14 [Feb 22 2007])
+
+ - s390x CPU :
+ Linux - SUSE Enterprise Linux 10 - with gcc 4.1.2
+ ( only the 32bits built works, the 64bits built does not pass the tests )
+
+ - sparc CPU :
+ Solaris 9 (sparc) with gcc 3.3.2
+
+ - powerpc CPU :
+ MacOS X 10.1/darwin 5.5 with gcc 932.1 (gcc 2.95.2)
+ MacOS X 10.3 with XCode 1.5
+
+ - openpower CPU :
+ Linux openpower-linux1 2.6.5-7.97-pseries64 (ppc64) with gcc 3.3.3
+
+ - IBM :
+ AIX 5.3 with gcc 4.1.0
+
+ - Tru64 :
+ OSF 5.1 with gcc 3.4.2
+
+ - PA-RISC :
+ HP-UX 11.11 with aCC (HP ANSI C++ B3910B A.03.73)
+ HP-UX 11.11 with gcc 3.4.2 (7za and 7zr : OK, 7z : failed because of a buggy gcc for HP-UX,
+ plugins don't work because C++ constructors are not called !)
+
+
+BUILD with cmake
+----------------
+ You can only build 7za.
+
+ cd CPP/7zip/CMAKE
+
+ edit generate.sh to choose your target
+
+ ./generate.sh
+
+ the cmake project for the target is in "CPP/7zip/CMAKE/Alone".
+
+ For the target "Unix Makefiles", use "make" to compile
+
+ For others target, use the IDE (CodeBlocks, KDevelop3, Eclipse CDT4)
+
+INSTALL :
+---------
+
+ method 1
+ --------
+ - edit install.sh to change DEST_HOME
+ - ./install.sh : to install
+ Remark : you must be "root" to install 7za in the directory "/usr/local"
+
+ method 2
+ --------
+ - 7za is a stand-alone program, you can put this program where you want.
+ example : cp bin/7za /usr/local/bin/7za
+
+ - 7z needs its plugins. You must copy the file 7z, 7z.so
+ and the directory Codecs in the same destination directory.
+
+ - if you want to be able to create SFX archive, copy bin/7zCon.sfx
+ to the directory where 7za or 7z can be found.
+
+
+USAGE:
+------
+ Remark : you can replace 7za with 7z.
+
+ 7za t archive.7z : tests files in the archive archive.7z
+ 7za l archive.7z : lists all files from archive archive.7z
+ 7za x archive.7z : extracts all files from archive archive.7z
+ to the current directory
+
+ 7za a archive.7z file1 fileN : add files to the archive archive.7z
+
+ 7za a archive.7z dir1 : add all files and subdirectories from directory "dir1" to archive archive.7z
+
+ CAUTION : do not use the flag "-r" unless you know what you are doing ...
+
+ 7za a -sfx archive.exe dir1 : add all files from directory "dir1" to SFX archive archive.exe
+ (Remark : SFX archive MUST end with ".exe")
+
+ You can also add or extract files to/from .zip or .tar archives.
+ You can also compress/uncompress .gz or .bz2 files.
+
+ 7za a -tzip archive.zip file file2 file3
+ 7za a -ttar archive.tar file
+ 7za a -tgzip file.gz file
+ 7za a -tbzip2 archive.bz2 file
+
+ You can use password for archives:
+ 7za a -pmy_password archive.7z dir1
+
+ For .7z archive only, you can enable archive header encryption with "-mhe"
+ 7za a -mhe=on -pmy_password archive.7z dir1
+
+ For more, see the documentation of 7za.exe in DOCS/MANUAL directory
+ 7za a -t7z -m0=lzma -mx=9 -mfb=64 -md=32m -ms=on archive.7z dir1
+ adds all files from directory "dir1" to archive archive.7z
+ using "ultra settings".
+ -t7z : 7z archive
+ -m0=lzma : lzma method
+ -mx=9 : level of compression = 9 (Ultra)
+ -mfb=64 : number of fast bytes for LZMA = 64
+ -md=32m : dictionary size = 32 megabytes
+ -ms=on : solid archive = on
+
+ To use the new codec "lzma2"
+ 7za a -m0=lzma2 archive.7z directory
+
+
+BENCHMARKS :
+------------
+ 7za b : bench LZMA codec
+ 7z b -mm=crc : make internal crc check.
+
+
+hugetlbfs (large pages)
+------------
+
+ Using huges pages in Linux requires some preparations.
+ First, make sure your running kernel has support for hugetlbfs compiled in:
+
+ ~$ grep hugetlbfs /proc/filesystems
+ nodev hugetlbfs
+
+ You can view your current huge page configuration like this:
+
+ ~$ grep Huge /proc/meminfo
+ HugePages_Total: 0
+ HugePages_Free: 0
+ HugePages_Rsvd: 0
+ HugePages_Surp: 0
+ Hugepagesize: 2048 kB
+
+ In this case the size of a huge page is 2 MiB.
+ So, if you have 2 GiB of RAM and want to reserve 512 MiB for huge pages,
+ you would need 256 pages.
+
+ Do the following as root:
+
+ ~# echo 296 >/proc/sys/vm/nr_hugepages
+ ~# grep Huge /proc/meminfo
+ HugePages_Total: 296
+ HugePages_Free: 296
+ HugePages_Rsvd: 0
+ HugePages_Surp: 0
+ Hugepagesize: 2048 kB
+
+ Finally, make access from user space possible:
+
+ ~# mkdir /hugepages
+ ~# mount -t hugetlbfs -o rw,nosuid,nodev,noexec,noatime none /hugepages
+ ~# chmod 1777 /hugepages
+
+ Option 1 : Now huge pages are configured.
+ In your shell, set the environment variable HUGETLB_PATH to the mount point:
+ ~$ export HUGETLB_PATH=/hugepages
+ or
+
+ Option 2 : Let p7zip find out the first directory with the type "hugetlbfs"
+
+
+ To enable huge page use in p7zip, pass the '-slp' switch to it.
+ Ex: 7za -slp a t.7z dir
+
+
+
+ If you want this to be a permanent setup :
+ - mkdir /hugepages
+
+ - add an entry to your /etc/fstab so that when you reboot your computer,
+ your hugetlbfs will mount automatically :
+ hugetlbfs /hugepages hugetlbfs rw,nosuid,nodev,noexec,noatime 0 0
+
+ - add this in your /etc/rc.local :
+ chmod 1777 /hugepages
+ echo 296 > /proc/sys/vm/nr_hugepages
+
+ optional : export HUGETLB_PATH=/hugepages
+
+ To enable huge page use in p7zip, pass the '-slp' switch to it : 7za -slp b
+
+
+ Remark : with current CPU : "7za -slp b" is not faster than "7za b".
+ If you want to see some speedup, compress at least 300MB
+ Ex : 7za -slp -mx=9 -a big_file.tar.7z big_file.tar
+
+
+LICENSE :
+---------
+ please read DOCS/License.txt.
+
+LIMITATIONS from 7-zip :
+------------------------
+
+ - does not support uid/gid for the .tar format (so, use tar on Unix)
+
+LIMITATIONS for Unix version only :
+-----------------------------------
+
+ - can handle properly UNICODE filenames only if the environment is UTF-8.
+ Example : export LANG=en_US.UTF-8 ; unset LC_CTYPE
+ Remark : see the possible values for LANG in the directory
+ - /usr/lib/locale : Fedora 2 / Solaris 8
+ - /usr/share/locale : OpenBSD / Debian / FreeBSD / MacOS X / Mandrake 10.1 / NetBSD
+
+ On Linux, to display the available locales : locale -a
+
+ p7zip relies on LC_CTYPE and then on LANG to convert name to/from UNICODE.
+ the command "locale" should display these environment variables.
+ you can also do "echo $LC_CTYPE" and "echo $LANG".
+
+ If you do not plan to export your archive, you can use the flag "-no-utf16".
+ Usage :
+ 7za a -no-utf16 archive.7z dirOrFile1 ... dirOrFileN
+ 7za t -no-utf16 archive.7z
+ 7za l -no-utf16 archive.7z
+ 7za x -no-utf16 archive.7z
+
+ - ignores Windows file access permissions (files are created with default permissions)
+
+ see also TODO file.
+
+DEVELOPPER CORNER:
+------------------
+
+ - WaitForMultipleObject has no equivalence on Unix.
+ - Events don't exist.
+ - sizeof(wchar_t) = 4 with GCC (2 with MS VC++)
+ - "FIXME" in source code indicates that you should add codes to better handle all cases.
+
+ - "FIXED" in source code indicates that the original code has been changed to work in Unix environment.
+
+ see also TODO file.
diff --git a/src/libs/7zip/unix/TODO b/src/libs/7zip/unix/TODO
new file mode 100644
index 000000000..82f87d68b
--- /dev/null
+++ b/src/libs/7zip/unix/TODO
@@ -0,0 +1,39 @@
+
+7za/7z
+======
+- auto-generate config.h (use a configure script ...)
+
+- suppress all exit(EXIT_FAILURE), FIXME, ...
+
+- no chmod for TAR (should restore the rights set)
+
+- no chown(uid,gid) for TAR
+
+- Use a more portable "String.h"
+
+- UTF16 : try to test with Complex Unicode filenames
+
+- KNOWN BUGS
+
+ - date (format arj/rar/chm) ?
+
+ - absolute path ?
+
+- zip format : better support of symbolic links
+
+7zG / 7zFM
+==========================
+
+- better help displaying
+
+- better support for space in filenames
+
+
+7zG :
+ - sfx: wants 7z.sfx instead of 7zCon.sfx ?
+ - the dialogs are not on top of other windows => not visible ...
+
+
+7zFM :
+ - the path "/" does not work (on OSX ?)
+ - strange behaviour : selected/unselected items
diff --git a/src/libs/7zip/unix/installer_framework_changes.txt b/src/libs/7zip/unix/installer_framework_changes.txt
new file mode 100644
index 000000000..b9e1616f2
--- /dev/null
+++ b/src/libs/7zip/unix/installer_framework_changes.txt
@@ -0,0 +1,511 @@
+There are deleted files and very small changes to get the integration process of new versions very simple.
+--diff-filter=M means "modified" and
+--diff-filter=D means "deleted" files
+
+=== output of: git diff --diff-filter=M ===
+
+diff --git a/C/AesOpt.c b/C/AesOpt.c
+index 60cfd86..c0bd8bc 100644
+--- a/C/AesOpt.c
++++ b/C/AesOpt.c
+@@ -5,7 +5,7 @@
+
+ #ifdef MY_CPU_X86_OR_AMD64
+ #if _MSC_VER >= 1500
+-#define USE_INTEL_AES
++//#define USE_INTEL_AES
+ #endif
+ #endif
+
+diff --git a/CPP/7zip/Common/RegisterArc.h b/CPP/7zip/Common/RegisterArc.h
+index bc2a034..9b8cbd3 100644
+--- a/CPP/7zip/Common/RegisterArc.h
++++ b/CPP/7zip/Common/RegisterArc.h
+@@ -27,6 +27,6 @@ void RegisterArc(const CArcInfo *arcInfo);
+
+ #define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \
+ REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \
+- static REGISTER_ARC_NAME(x) g_RegisterArc;
+-
++ static REGISTER_ARC_NAME(x) g_RegisterArc; \
++ void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; }
+ #endif
+diff --git a/CPP/7zip/Common/RegisterCodec.h b/CPP/7zip/Common/RegisterCodec.h
+index 786b4a4..d53c434 100644
+--- a/CPP/7zip/Common/RegisterCodec.h
++++ b/CPP/7zip/Common/RegisterCodec.h
+@@ -22,12 +22,13 @@ void RegisterCodec(const CCodecInfo *codecInfo);
+
+ #define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \
+ REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \
+- static REGISTER_CODEC_NAME(x) g_RegisterCodec;
++ static REGISTER_CODEC_NAME(x) g_RegisterCodec; \
++ void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; }
+
+ #define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x
+ #define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \
+ REGISTER_CODECS_NAME(x)() { for (int i = 0; i < sizeof(g_CodecsInfo) / sizeof(g_CodecsInfo[0]); i++) \
+ RegisterCodec(&g_CodecsInfo[i]); }}; \
+- static REGISTER_CODECS_NAME(x) g_RegisterCodecs;
+-
++ static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \
++ void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; }
+ #endif
+diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h
+index eb3c52d..f483e39 100644
+--- a/CPP/Common/MyString.h
++++ b/CPP/Common/MyString.h
+@@ -7,6 +7,8 @@
+
+ #include "MyVector.h"
+
++#include <windows.h>
++
+ template <class T>
+ inline int MyStringLen(const T *s)
+ {
+
+=== output of: git diff --diff-filter=D --name-only ===
+Asm/x64/7zCrcT8U.asm
+Asm/x86/7zCrcT8U.asm
+CPP/7zip/Bundles/Alone/makefile
+CPP/7zip/Bundles/Alone/makefile.depend
+CPP/7zip/Bundles/Alone/makefile.list
+CPP/7zip/Bundles/Alone7z/makefile
+CPP/7zip/Bundles/Alone7z/makefile.depend
+CPP/7zip/Bundles/Alone7z/makefile.list
+CPP/7zip/Bundles/AloneGCOV/makefile
+CPP/7zip/Bundles/Format7zFree/makefile
+CPP/7zip/Bundles/Format7zFree/makefile.depend
+CPP/7zip/Bundles/Format7zFree/makefile.list
+CPP/7zip/Bundles/SFXCon/Main.cpp
+CPP/7zip/Bundles/SFXCon/makefile
+CPP/7zip/Bundles/SFXCon/makefile.depend
+CPP/7zip/Bundles/SFXCon/makefile.list
+CPP/7zip/CMAKE/CMakeLists_7zFM.txt
+CPP/7zip/CMAKE/CMakeLists_7zG.txt
+CPP/7zip/CMAKE/CMakeLists_7za.txt
+CPP/7zip/CMAKE/CMakeLists_ALL.txt
+CPP/7zip/CMAKE/CMakeLists_Format7zFree.txt
+CPP/7zip/CMAKE/generate.sh
+CPP/7zip/CMAKE/generate_xcode.sh
+CPP/7zip/Compress/LZMA_Alone/makefile
+CPP/7zip/Compress/Rar/makefile
+CPP/7zip/Compress/Rar/makefile.depend
+CPP/7zip/Compress/Rar/makefile.list
+CPP/7zip/PREMAKE/generate.sh
+CPP/7zip/PREMAKE/premake4.lua
+CPP/7zip/QMAKE/7ZA/7ZA.pro
+CPP/7zip/QMAKE/7ZA/7ZA_osx.pro
+CPP/7zip/QMAKE/test_emul/test_emul.pro
+CPP/7zip/TEST/TestUI/makefile
+CPP/7zip/TEST/TestUI/makefile.depend
+CPP/7zip/TEST/TestUI/makefile.list
+CPP/7zip/UI/Client7z/makefile
+CPP/7zip/UI/Client7z/makefile.depend
+CPP/7zip/UI/Client7z/makefile.list
+CPP/7zip/UI/ClientCodec/makefile
+CPP/7zip/UI/ClientCodec/makefile.depend
+CPP/7zip/UI/ClientCodec/makefile.list
+CPP/7zip/UI/Console/makefile
+CPP/7zip/UI/Console/makefile.depend
+CPP/7zip/UI/Console/makefile.list
+CPP/7zip/UI/Explorer/ContextMenu.h
+CPP/7zip/UI/Explorer/MyMessages.cpp
+CPP/7zip/UI/Explorer/MyMessages.h
+CPP/7zip/UI/FileManager/App.cpp
+CPP/7zip/UI/FileManager/App.h
+CPP/7zip/UI/FileManager/AppState.h
+CPP/7zip/UI/FileManager/BrowseDialog.h
+CPP/7zip/UI/FileManager/ClassDefs.cpp
+CPP/7zip/UI/FileManager/ComboDialog.cpp
+CPP/7zip/UI/FileManager/ComboDialog.h
+CPP/7zip/UI/FileManager/ComboDialogRes.h
+CPP/7zip/UI/FileManager/ComboDialog_rc.cpp
+CPP/7zip/UI/FileManager/CopyDialog.cpp
+CPP/7zip/UI/FileManager/CopyDialog.h
+CPP/7zip/UI/FileManager/CopyDialogRes.h
+CPP/7zip/UI/FileManager/CopyDialog_rc.cpp
+CPP/7zip/UI/FileManager/DialogSize.h
+CPP/7zip/UI/FileManager/ExtractCallback.cpp
+CPP/7zip/UI/FileManager/ExtractCallback.h
+CPP/7zip/UI/FileManager/FM.cpp
+CPP/7zip/UI/FileManager/FM_rc.cpp
+CPP/7zip/UI/FileManager/FSDrives.cpp
+CPP/7zip/UI/FileManager/FSDrives.h
+CPP/7zip/UI/FileManager/FSFolder.cpp
+CPP/7zip/UI/FileManager/FSFolder.h
+CPP/7zip/UI/FileManager/FSFolderCopy.cpp
+CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp
+CPP/7zip/UI/FileManager/FileFolderPluginOpen.h
+CPP/7zip/UI/FileManager/FormatUtils.cpp
+CPP/7zip/UI/FileManager/FormatUtils.h
+CPP/7zip/UI/FileManager/HelpUtils.h
+CPP/7zip/UI/FileManager/IFolder.h
+CPP/7zip/UI/FileManager/LangUtils.cpp
+CPP/7zip/UI/FileManager/LangUtils.h
+CPP/7zip/UI/FileManager/ListViewDialog.cpp
+CPP/7zip/UI/FileManager/ListViewDialog.h
+CPP/7zip/UI/FileManager/ListViewDialogRes.h
+CPP/7zip/UI/FileManager/ListViewDialog_rc.cpp
+CPP/7zip/UI/FileManager/MessagesDialog.cpp
+CPP/7zip/UI/FileManager/MessagesDialog.h
+CPP/7zip/UI/FileManager/MessagesDialogRes.h
+CPP/7zip/UI/FileManager/MessagesDialog_rc.cpp
+CPP/7zip/UI/FileManager/MyLoadMenu.cpp
+CPP/7zip/UI/FileManager/MyLoadMenu.h
+CPP/7zip/UI/FileManager/NetFolder.h.OUT
+CPP/7zip/UI/FileManager/OpenCallback.cpp
+CPP/7zip/UI/FileManager/OpenCallback.h
+CPP/7zip/UI/FileManager/OverwriteDialog.cpp
+CPP/7zip/UI/FileManager/OverwriteDialog.h
+CPP/7zip/UI/FileManager/OverwriteDialogRes.h
+CPP/7zip/UI/FileManager/OverwriteDialog_rc.cpp
+CPP/7zip/UI/FileManager/Panel.cpp
+CPP/7zip/UI/FileManager/Panel.h
+CPP/7zip/UI/FileManager/PanelCopy.cpp
+CPP/7zip/UI/FileManager/PanelCrc.cpp
+CPP/7zip/UI/FileManager/PanelCrc.cpp.back
+CPP/7zip/UI/FileManager/PanelFolderChange.cpp
+CPP/7zip/UI/FileManager/PanelItemOpen.cpp
+CPP/7zip/UI/FileManager/PanelItems.cpp
+CPP/7zip/UI/FileManager/PanelListNotify.cpp
+CPP/7zip/UI/FileManager/PanelMenu.cpp
+CPP/7zip/UI/FileManager/PanelOperations.cpp
+CPP/7zip/UI/FileManager/PanelSelect.cpp
+CPP/7zip/UI/FileManager/PanelSort.cpp
+CPP/7zip/UI/FileManager/PanelSplitFile.cpp
+CPP/7zip/UI/FileManager/PasswordDialog.cpp
+CPP/7zip/UI/FileManager/PasswordDialog.h
+CPP/7zip/UI/FileManager/PasswordDialogRes.h
+CPP/7zip/UI/FileManager/PasswordDialog_rc.cpp
+CPP/7zip/UI/FileManager/PluginInterface.h
+CPP/7zip/UI/FileManager/PluginLoader.h
+CPP/7zip/UI/FileManager/ProgramLocation.cpp
+CPP/7zip/UI/FileManager/ProgramLocation.h
+CPP/7zip/UI/FileManager/ProgressDialog2.cpp
+CPP/7zip/UI/FileManager/ProgressDialog2.h
+CPP/7zip/UI/FileManager/ProgressDialog2Res.h
+CPP/7zip/UI/FileManager/ProgressDialog2_rc.cpp
+CPP/7zip/UI/FileManager/ProgressDialogRes.h
+CPP/7zip/UI/FileManager/PropertyName.cpp
+CPP/7zip/UI/FileManager/PropertyName.h
+CPP/7zip/UI/FileManager/PropertyNameRes.h
+CPP/7zip/UI/FileManager/RegistryAssociations.cpp
+CPP/7zip/UI/FileManager/RegistryAssociations.h
+CPP/7zip/UI/FileManager/RegistryPlugins.h
+CPP/7zip/UI/FileManager/RegistryUtils.cpp
+CPP/7zip/UI/FileManager/RegistryUtils.h
+CPP/7zip/UI/FileManager/RootFolder.cpp
+CPP/7zip/UI/FileManager/RootFolder.h
+CPP/7zip/UI/FileManager/SplitDialog.cpp
+CPP/7zip/UI/FileManager/SplitDialog.h
+CPP/7zip/UI/FileManager/SplitDialogRes.h
+CPP/7zip/UI/FileManager/SplitDialog_rc.cpp
+CPP/7zip/UI/FileManager/SplitUtils.cpp
+CPP/7zip/UI/FileManager/SplitUtils.h
+CPP/7zip/UI/FileManager/StringUtils.cpp
+CPP/7zip/UI/FileManager/StringUtils.h
+CPP/7zip/UI/FileManager/SysIconUtils.cpp
+CPP/7zip/UI/FileManager/SysIconUtils.h
+CPP/7zip/UI/FileManager/TextPairs.cpp
+CPP/7zip/UI/FileManager/TextPairs.h
+CPP/7zip/UI/FileManager/UpdateCallback100.cpp
+CPP/7zip/UI/FileManager/UpdateCallback100.h
+CPP/7zip/UI/FileManager/ViewSettings.cpp
+CPP/7zip/UI/FileManager/ViewSettings.h
+CPP/7zip/UI/FileManager/err
+CPP/7zip/UI/FileManager/makefile
+CPP/7zip/UI/FileManager/makefile.depend
+CPP/7zip/UI/FileManager/makefile.list
+CPP/7zip/UI/FileManager/res/Add2PNG.h
+CPP/7zip/UI/FileManager/res/AddPNG.h
+CPP/7zip/UI/FileManager/res/Copy2PNG.h
+CPP/7zip/UI/FileManager/res/CopyPNG.h
+CPP/7zip/UI/FileManager/res/Delete2PNG.h
+CPP/7zip/UI/FileManager/res/DeletePNG.h
+CPP/7zip/UI/FileManager/res/Extract2PNG.h
+CPP/7zip/UI/FileManager/res/ExtractPNG.h
+CPP/7zip/UI/FileManager/res/Info2PNG.h
+CPP/7zip/UI/FileManager/res/InfoPNG.h
+CPP/7zip/UI/FileManager/res/Move2PNG.h
+CPP/7zip/UI/FileManager/res/MovePNG.h
+CPP/7zip/UI/FileManager/res/ParentFolder.h
+CPP/7zip/UI/FileManager/res/Test2PNG.h
+CPP/7zip/UI/FileManager/res/TestPNG.h
+CPP/7zip/UI/FileManager/resource.h
+CPP/7zip/UI/FileManager/resourceGui.h
+CPP/7zip/UI/FileManager/wxFM.cpp
+CPP/7zip/UI/GUI/makefile
+CPP/7zip/UI/GUI/makefile.depend
+CPP/7zip/UI/GUI/makefile.list
+CPP/7zip/UI/P7ZIP/FileDir.o
+CPP/7zip/UI/P7ZIP/FileFind.o
+CPP/7zip/UI/P7ZIP/IntToString.o
+CPP/7zip/UI/P7ZIP/MyString.o
+CPP/7zip/UI/P7ZIP/MyVector.o
+CPP/7zip/UI/P7ZIP/StringConvert.o
+CPP/7zip/UI/P7ZIP/Threads.o
+CPP/7zip/UI/P7ZIP/makefile
+CPP/7zip/UI/P7ZIP/makefile.depend
+CPP/7zip/UI/P7ZIP/makefile.list
+CPP/7zip/UI/P7ZIP/wine_date_and_time.o
+CPP/7zip/UI/P7ZIP/wxP7ZIP.o
+CPP/myWindows/makefile
+CPP/myWindows/makefile.depend
+CPP/myWindows/makefile.list
+GUI/Contents/Info.plist
+GUI/Contents/PkgInfo
+GUI/Contents/Resources/p7zip.icns
+GUI/Lang/af.txt
+GUI/Lang/ar.txt
+GUI/Lang/ast.txt
+GUI/Lang/az.txt
+GUI/Lang/ba.txt
+GUI/Lang/be.txt
+GUI/Lang/bg.txt
+GUI/Lang/bn.txt
+GUI/Lang/br.txt
+GUI/Lang/ca.txt
+GUI/Lang/cs.txt
+GUI/Lang/cy.txt
+GUI/Lang/da.txt
+GUI/Lang/de.txt
+GUI/Lang/el.txt
+GUI/Lang/en.ttt
+GUI/Lang/eo.txt
+GUI/Lang/es.txt
+GUI/Lang/et.txt
+GUI/Lang/eu.txt
+GUI/Lang/ext.txt
+GUI/Lang/fa.txt
+GUI/Lang/fi.txt
+GUI/Lang/fr.txt
+GUI/Lang/fur.txt
+GUI/Lang/fy.txt
+GUI/Lang/gl.txt
+GUI/Lang/gu.txt
+GUI/Lang/he.txt
+GUI/Lang/hi.txt
+GUI/Lang/hr.txt
+GUI/Lang/hu.txt
+GUI/Lang/hy.txt
+GUI/Lang/id.txt
+GUI/Lang/io.txt
+GUI/Lang/is.txt
+GUI/Lang/it.txt
+GUI/Lang/ja.txt
+GUI/Lang/ka.txt
+GUI/Lang/kk.txt
+GUI/Lang/ko.txt
+GUI/Lang/ku-ckb.txt
+GUI/Lang/ku.txt
+GUI/Lang/lt.txt
+GUI/Lang/lv.txt
+GUI/Lang/mk.txt
+GUI/Lang/mn.txt
+GUI/Lang/mr.txt
+GUI/Lang/ms.txt
+GUI/Lang/nb.txt
+GUI/Lang/ne.txt
+GUI/Lang/nl.txt
+GUI/Lang/nn.txt
+GUI/Lang/pa-in.txt
+GUI/Lang/pl.txt
+GUI/Lang/ps.txt
+GUI/Lang/pt-br.txt
+GUI/Lang/pt.txt
+GUI/Lang/ro.txt
+GUI/Lang/ru.txt
+GUI/Lang/sa.txt
+GUI/Lang/si.txt
+GUI/Lang/sk.txt
+GUI/Lang/sl.txt
+GUI/Lang/sq.txt
+GUI/Lang/sr-spc.txt
+GUI/Lang/sr-spl.txt
+GUI/Lang/sv.txt
+GUI/Lang/ta.txt
+GUI/Lang/th.txt
+GUI/Lang/tr.txt
+GUI/Lang/tt.txt
+GUI/Lang/ug.txt
+GUI/Lang/uk.txt
+GUI/Lang/uz.txt
+GUI/Lang/va.txt
+GUI/Lang/vi.txt
+GUI/Lang/zh-cn.txt
+GUI/Lang/zh-tw.txt
+GUI/help/7zip.hhc
+GUI/help/7zip.hhk
+GUI/help/cmdline/commands/add.htm
+GUI/help/cmdline/commands/bench.htm
+GUI/help/cmdline/commands/delete.htm
+GUI/help/cmdline/commands/extract.htm
+GUI/help/cmdline/commands/extract_full.htm
+GUI/help/cmdline/commands/index.htm
+GUI/help/cmdline/commands/list.htm
+GUI/help/cmdline/commands/style.css
+GUI/help/cmdline/commands/test.htm
+GUI/help/cmdline/commands/update.htm
+GUI/help/cmdline/exit_codes.htm
+GUI/help/cmdline/index.htm
+GUI/help/cmdline/style.css
+GUI/help/cmdline/switches/ar_exclude.htm
+GUI/help/cmdline/switches/ar_include.htm
+GUI/help/cmdline/switches/ar_no.htm
+GUI/help/cmdline/switches/charset.htm
+GUI/help/cmdline/switches/exclude.htm
+GUI/help/cmdline/switches/include.htm
+GUI/help/cmdline/switches/index.htm
+GUI/help/cmdline/switches/large_pages.htm
+GUI/help/cmdline/switches/list_tech.htm
+GUI/help/cmdline/switches/method.htm
+GUI/help/cmdline/switches/output_dir.htm
+GUI/help/cmdline/switches/overwrite.htm
+GUI/help/cmdline/switches/password.htm
+GUI/help/cmdline/switches/recurse.htm
+GUI/help/cmdline/switches/sfx.htm
+GUI/help/cmdline/switches/ssc.htm
+GUI/help/cmdline/switches/stdin.htm
+GUI/help/cmdline/switches/stdout.htm
+GUI/help/cmdline/switches/stop_switch.htm
+GUI/help/cmdline/switches/style.css
+GUI/help/cmdline/switches/type.htm
+GUI/help/cmdline/switches/update.htm
+GUI/help/cmdline/switches/volume.htm
+GUI/help/cmdline/switches/working_dir.htm
+GUI/help/cmdline/switches/yes.htm
+GUI/help/cmdline/syntax.htm
+GUI/help/fm/about.htm
+GUI/help/fm/benchmark.htm
+GUI/help/fm/index.htm
+GUI/help/fm/menu.htm
+GUI/help/fm/options.htm
+GUI/help/fm/plugins/7-zip/add.htm
+GUI/help/fm/plugins/7-zip/extract.htm
+GUI/help/fm/plugins/7-zip/index.htm
+GUI/help/fm/plugins/7-zip/style.css
+GUI/help/fm/plugins/index.htm
+GUI/help/fm/plugins/style.css
+GUI/help/fm/style.css
+GUI/help/general/7z.htm
+GUI/help/general/faq.htm
+GUI/help/general/formats.htm
+GUI/help/general/index.htm
+GUI/help/general/license.htm
+GUI/help/general/performance.htm
+GUI/help/general/style.css
+GUI/help/general/thanks.htm
+GUI/help/start.htm
+GUI/help/style.css
+GUI/kde3/p7zip_compress.desktop
+GUI/kde3/p7zip_compress2.desktop
+GUI/kde3/p7zip_extract.desktop
+GUI/kde3/p7zip_extract_subdir.desktop
+GUI/kde3/p7zip_extract_to.desktop
+GUI/kde3/p7zip_test.desktop
+GUI/kde3/readme.txt
+GUI/kde4/p7zip_compress.desktop
+GUI/kde4/p7zip_compress2.desktop
+GUI/kde4/p7zip_extract.desktop
+GUI/kde4/p7zip_extract_subdir.desktop
+GUI/kde4/p7zip_extract_to.desktop
+GUI/kde4/p7zip_test.desktop
+GUI/kde4/readme.txt
+GUI/p7zipForFilemanager
+GUI/p7zip_16.icns
+GUI/p7zip_16.png
+GUI/p7zip_16_ok.png
+GUI/p7zip_32.png
+GUI/p7zip_32.xpm
+check/check.sh
+check/check_7zr.sh
+check/check_Client7z.sh
+check/check_install.sh
+check/clean_all.sh
+check/my_86_filter/makefile
+check/my_86_filter/makefile.depend
+check/my_86_filter/makefile.list
+check/my_86_filter/my_86_filter.cpp
+check/test/7za.exe.lzma
+check/test/7za.exe.lzma86
+check/test/7za.exe.lzma_eos
+check/test/7za.exe.xz
+check/test/7za433_7zip_bzip2.7z
+check/test/7za433_7zip_lzma.7z
+check/test/7za433_7zip_lzma2.7z
+check/test/7za433_7zip_lzma2_bcj2.7z
+check/test/7za433_7zip_lzma2_crypto.7z
+check/test/7za433_7zip_lzma_bcj2.7z
+check/test/7za433_7zip_lzma_crypto.7z
+check/test/7za433_7zip_ppmd.7z
+check/test/7za433_7zip_ppmd_bcj2.7z
+check/test/7za433_tar.tar
+contrib/VirtualFileSystemForMidnightCommander/ChangeLog
+contrib/VirtualFileSystemForMidnightCommander/readme
+contrib/VirtualFileSystemForMidnightCommander/readme.u7z
+contrib/VirtualFileSystemForMidnightCommander/u7z
+contrib/gzip-like_CLI_wrapper_for_7z/README
+contrib/gzip-like_CLI_wrapper_for_7z/check/check.sh
+contrib/gzip-like_CLI_wrapper_for_7z/check/files.tar
+contrib/gzip-like_CLI_wrapper_for_7z/man1/p7zip.1
+contrib/gzip-like_CLI_wrapper_for_7z/p7zip
+contrib/qnx630sp3/qnx630sp3-shared
+contrib/qnx630sp3/qnx630sp3-static
+install.sh
+install_local_context_menu.sh
+integration_context_menu.txt
+makefile
+makefile.aix_gcc
+makefile.beos
+makefile.crc32
+makefile.cygwin
+makefile.cygwin_asm
+makefile.djgpp_old
+makefile.djgpp_watt
+makefile.freebsd5
+makefile.freebsd6
+makefile.glb
+makefile.gprof
+makefile.hpux-acc
+makefile.hpux-acc_64
+makefile.hpux-gcc
+makefile.linux_amd64
+makefile.linux_amd64_asm
+makefile.linux_amd64_asm_icc
+makefile.linux_any_cpu
+makefile.linux_any_cpu_gcc_4.X
+makefile.linux_clang_amd64
+makefile.linux_cross_arm
+makefile.linux_gcc_2.95_no_need_for_libstdc
+makefile.linux_other
+makefile.linux_s390x
+makefile.linux_x86_asm_gcc_4.X
+makefile.linux_x86_asm_gcc_4.X_fltk
+makefile.linux_x86_asm_gcc_mudflap_4.X
+makefile.linux_x86_asm_icc
+makefile.linux_x86_icc
+makefile.machine
+makefile.macosx_32bits
+makefile.macosx_32bits_asm
+makefile.macosx_32bits_ppc
+makefile.macosx_64bits
+makefile.macosx_llvm_64bits
+makefile.netbsd
+makefile.netware_asm_gcc_3.X
+makefile.oldmake
+makefile.openbsd
+makefile.openbsd_no_port
+makefile.qnx_shared.bin
+makefile.qnx_shared.so
+makefile.qnx_static
+makefile.rules
+makefile.solaris_sparc_CC_32
+makefile.solaris_sparc_CC_64
+makefile.solaris_sparc_gcc
+makefile.solaris_x86
+makefile.tru64
+man1/7z.1
+man1/7za.1
+man1/7zr.1
diff --git a/src/libs/7zip/unix/unix.pri b/src/libs/7zip/unix/unix.pri
new file mode 100644
index 000000000..696e229ff
--- /dev/null
+++ b/src/libs/7zip/unix/unix.pri
@@ -0,0 +1,228 @@
+isEmpty(7ZIP_BASE): 7ZIP_BASE = $$(7ZIP_BASE)
+isEmpty(7ZIP_BASE): error(Please call qmake with 7ZIP_BASE=<path to nokia-sdk source directory> or add this line before you include that file in your pro file)
+
+7ZIP_BASE=$$7ZIP_BASE/unix
+
+DEFINES += _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE NDEBUG _REENTRANT ENV_UNIX BREAK_HANDLER UNICODE _UNICODE
+
+macx:DEFINES += ENV_MACOSX
+
+CXXFLAGS += -fvisibility
+
+INCLUDEPATH += $$7ZIP_BASE/CPP \
+ $$7ZIP_BASE/CPP/myWindows \
+ $$7ZIP_BASE/CPP/include_windows
+
+SOURCES += $$7ZIP_BASE/CPP/myWindows/myGetTickCount.cpp \
+ $$7ZIP_BASE/CPP/myWindows/wine_date_and_time.cpp \
+ $$7ZIP_BASE/CPP/myWindows/myAddExeFlag.cpp \
+ $$7ZIP_BASE/CPP/myWindows/mySplitCommandLine.cpp \
+
+SOURCES += \
+$$7ZIP_BASE/CPP/7zip/UI/Console/ConsoleClose.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Console/List.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Console/OpenCallbackConsole.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Console/PercentPrinter.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Console/UserInputUtils.cpp \
+$$7ZIP_BASE/CPP/Common/CommandLineParser.cpp \
+$$7ZIP_BASE/CPP/Common/CRC.cpp \
+$$7ZIP_BASE/CPP/Common/IntToString.cpp \
+$$7ZIP_BASE/CPP/Common/ListFileUtils.cpp \
+$$7ZIP_BASE/CPP/Common/StdInStream.cpp \
+$$7ZIP_BASE/CPP/Common/StdOutStream.cpp \
+$$7ZIP_BASE/CPP/Common/MyString.cpp \
+$$7ZIP_BASE/CPP/Common/StringToInt.cpp \
+$$7ZIP_BASE/CPP/Common/UTFConvert.cpp \
+$$7ZIP_BASE/CPP/Common/StringConvert.cpp \
+$$7ZIP_BASE/CPP/Common/MyWindows.cpp \
+$$7ZIP_BASE/CPP/Common/MyVector.cpp \
+$$7ZIP_BASE/CPP/Common/Wildcard.cpp \
+$$7ZIP_BASE/CPP/Windows/Error.cpp \
+$$7ZIP_BASE/CPP/Windows/FileDir.cpp \
+$$7ZIP_BASE/CPP/Windows/FileFind.cpp \
+$$7ZIP_BASE/CPP/Windows/FileIO.cpp \
+$$7ZIP_BASE/CPP/Windows/FileName.cpp \
+$$7ZIP_BASE/CPP/Windows/PropVariant.cpp \
+$$7ZIP_BASE/CPP/Windows/PropVariantConversions.cpp \
+$$7ZIP_BASE/CPP/Windows/Synchronization.cpp \
+$$7ZIP_BASE/CPP/Windows/System.cpp \
+$$7ZIP_BASE/CPP/Windows/Time.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/CreateCoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/CWrappers.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/FilePathAutoRename.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/FileStreams.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/FilterCoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/InBuffer.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/InOutTempBuffer.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/LimitedStreams.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/LockedStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/MemBlocks.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/MethodId.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/MethodProps.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/OffsetStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/OutBuffer.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/OutMemStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/ProgressMt.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/ProgressUtils.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/StreamBinder.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/StreamObjects.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/StreamUtils.cpp \
+$$7ZIP_BASE/CPP/7zip/Common/VirtThread.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveCommandLine.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/DefaultName.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/EnumDirItems.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/Extract.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/ExtractingFilePath.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/LoadCodecs.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/OpenArchive.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/PropIDUtils.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/SetProperties.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/SortUtils.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/TempFiles.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/Update.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/UpdateAction.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/UpdateCallback.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/UpdatePair.cpp \
+$$7ZIP_BASE/CPP/7zip/UI/Common/UpdateProduce.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/DeflateProps.cpp \ #new
+$$7ZIP_BASE/CPP/7zip/Archive/Bz2Handler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/GzHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/LzmaHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/SplitHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/XzHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/ZHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2MT.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/CrossThreadProgress.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/DummyOutStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/FindSignature.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/HandlerOut.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/InStreamWithCRC.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/ItemNameUtils.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/MultiStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Common/ParseProperties.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zCompressionMode.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zDecode.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zEncode.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zExtract.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderInStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderOutStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandlerOut.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zHeader.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zIn.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zOut.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zProperties.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zSpecStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zUpdate.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Cab/CabBlockInStream.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Cab/CabHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Cab/CabHeader.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Cab/CabIn.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Tar/TarHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Tar/TarHandlerOut.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Tar/TarHeader.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Tar/TarIn.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Tar/TarOut.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Tar/TarUpdate.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipAddCommon.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipHandler.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipHeader.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipIn.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipItem.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipOut.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipUpdate.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BcjCoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/Bcj2Coder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BitlDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BranchCoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BranchMisc.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/ByteSwap.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BZip2Crc.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BZip2Decoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BZip2Encoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/CopyCoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/DeflateDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/DeflateEncoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/DeltaFilter.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/ImplodeDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/Lzma2Decoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/Lzma2Encoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/LzmaDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/LzmaEncoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/LzOutWindow.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/Lzx86Converter.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/LzxDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/PpmdDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/PpmdEncoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/PpmdZip.cpp \ #new
+$$7ZIP_BASE/CPP/7zip/Compress/QuantumDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/ShrinkDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/ZDecoder.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/7zAes.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/HmacSha1.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/MyAes.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/RandGen.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/Sha1.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/WzAes.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/ZipCrypto.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/ZipStrong.cpp \
+$$7ZIP_BASE/C/7zStream.c \
+$$7ZIP_BASE/C/Aes.c \
+$$7ZIP_BASE/C/Bra.c \
+$$7ZIP_BASE/C/Bra86.c \
+$$7ZIP_BASE/C/BraIA64.c \
+$$7ZIP_BASE/C/BwtSort.c \
+$$7ZIP_BASE/C/Delta.c \
+$$7ZIP_BASE/C/HuffEnc.c \
+$$7ZIP_BASE/C/LzFind.c \
+$$7ZIP_BASE/C/LzFindMt.c \
+$$7ZIP_BASE/C/Lzma2Dec.c \
+$$7ZIP_BASE/C/Lzma2Enc.c \
+$$7ZIP_BASE/C/LzmaDec.c \
+$$7ZIP_BASE/C/LzmaEnc.c \
+$$7ZIP_BASE/C/MtCoder.c \
+$$7ZIP_BASE/C/Sha256.c \
+$$7ZIP_BASE/C/Sort.c \
+$$7ZIP_BASE/C/Threads.c \
+$$7ZIP_BASE/C/Xz.c \
+$$7ZIP_BASE/C/XzCrc64.c \
+$$7ZIP_BASE/C/XzDec.c \
+$$7ZIP_BASE/C/XzEnc.c \
+$$7ZIP_BASE/C/XzIn.c \
+$$7ZIP_BASE/C/7zCrc.c \
+$$7ZIP_BASE/C/Ppmd7Enc.c \ #new
+$$7ZIP_BASE/C/Ppmd7Dec.c \ #new
+$$7ZIP_BASE/C/Ppmd7.c \ #new
+$$7ZIP_BASE/C/Ppmd8.c \ #new
+$$7ZIP_BASE/C/Ppmd8Enc.c \ #new
+$$7ZIP_BASE/C/Ppmd8Dec.c \ #new
+$$7ZIP_BASE/C/Alloc.c \ #new
+$$7ZIP_BASE/C/7zCrcOpt.c \ #new
+$$7ZIP_BASE/CPP/7zip/Archive/7z/7zRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Cab/CabRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Tar/TarRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/Bcj2Register.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BcjRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BranchRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/BZip2Register.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/CopyRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/Deflate64Register.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/DeflateRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/Lzma2Register.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/LzmaRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Compress/PpmdRegister.cpp \
+$$7ZIP_BASE/CPP/7zip/Crypto/7zAesRegister.cpp
+
+
diff --git a/src/libs/7zip/win/C/7z.h b/src/libs/7zip/win/C/7z.h
new file mode 100644
index 000000000..01c4cac6a
--- /dev/null
+++ b/src/libs/7zip/win/C/7z.h
@@ -0,0 +1,203 @@
+/* 7z.h -- 7z interface
+2010-03-11 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_H
+#define __7Z_H
+
+#include "7zBuf.h"
+
+EXTERN_C_BEGIN
+
+#define k7zStartHeaderSize 0x20
+#define k7zSignatureSize 6
+extern Byte k7zSignature[k7zSignatureSize];
+#define k7zMajorVersion 0
+
+enum EIdEnum
+{
+ k7zIdEnd,
+ k7zIdHeader,
+ k7zIdArchiveProperties,
+ k7zIdAdditionalStreamsInfo,
+ k7zIdMainStreamsInfo,
+ k7zIdFilesInfo,
+ k7zIdPackInfo,
+ k7zIdUnpackInfo,
+ k7zIdSubStreamsInfo,
+ k7zIdSize,
+ k7zIdCRC,
+ k7zIdFolder,
+ k7zIdCodersUnpackSize,
+ k7zIdNumUnpackStream,
+ k7zIdEmptyStream,
+ k7zIdEmptyFile,
+ k7zIdAnti,
+ k7zIdName,
+ k7zIdCTime,
+ k7zIdATime,
+ k7zIdMTime,
+ k7zIdWinAttributes,
+ k7zIdComment,
+ k7zIdEncodedHeader,
+ k7zIdStartPos,
+ k7zIdDummy
+};
+
+typedef struct
+{
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+ UInt64 MethodID;
+ CBuf Props;
+} CSzCoderInfo;
+
+void SzCoderInfo_Init(CSzCoderInfo *p);
+void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc);
+
+typedef struct
+{
+ UInt32 InIndex;
+ UInt32 OutIndex;
+} CSzBindPair;
+
+typedef struct
+{
+ CSzCoderInfo *Coders;
+ CSzBindPair *BindPairs;
+ UInt32 *PackStreams;
+ UInt64 *UnpackSizes;
+ UInt32 NumCoders;
+ UInt32 NumBindPairs;
+ UInt32 NumPackStreams;
+ int UnpackCRCDefined;
+ UInt32 UnpackCRC;
+
+ UInt32 NumUnpackStreams;
+} CSzFolder;
+
+void SzFolder_Init(CSzFolder *p);
+UInt64 SzFolder_GetUnpackSize(CSzFolder *p);
+int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex);
+UInt32 SzFolder_GetNumOutStreams(CSzFolder *p);
+UInt64 SzFolder_GetUnpackSize(CSzFolder *p);
+
+SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
+ ILookInStream *stream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize, ISzAlloc *allocMain);
+
+typedef struct
+{
+ UInt32 Low;
+ UInt32 High;
+} CNtfsFileTime;
+
+typedef struct
+{
+ CNtfsFileTime MTime;
+ UInt64 Size;
+ UInt32 Crc;
+ UInt32 Attrib;
+ Byte HasStream;
+ Byte IsDir;
+ Byte IsAnti;
+ Byte CrcDefined;
+ Byte MTimeDefined;
+ Byte AttribDefined;
+} CSzFileItem;
+
+void SzFile_Init(CSzFileItem *p);
+
+typedef struct
+{
+ UInt64 *PackSizes;
+ Byte *PackCRCsDefined;
+ UInt32 *PackCRCs;
+ CSzFolder *Folders;
+ CSzFileItem *Files;
+ UInt32 NumPackStreams;
+ UInt32 NumFolders;
+ UInt32 NumFiles;
+} CSzAr;
+
+void SzAr_Init(CSzAr *p);
+void SzAr_Free(CSzAr *p, ISzAlloc *alloc);
+
+
+/*
+ SzExtract extracts file from archive
+
+ *outBuffer must be 0 before first call for each new archive.
+
+ Extracting cache:
+ If you need to decompress more than one file, you can send
+ these values from previous call:
+ *blockIndex,
+ *outBuffer,
+ *outBufferSize
+ You can consider "*outBuffer" as cache of solid block. If your archive is solid,
+ it will increase decompression speed.
+
+ If you use external function, you can declare these 3 cache variables
+ (blockIndex, outBuffer, outBufferSize) as static in that external function.
+
+ Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
+*/
+
+typedef struct
+{
+ CSzAr db;
+
+ UInt64 startPosAfterHeader;
+ UInt64 dataPos;
+
+ UInt32 *FolderStartPackStreamIndex;
+ UInt64 *PackStreamStartPositions;
+ UInt32 *FolderStartFileIndex;
+ UInt32 *FileIndexToFolderIndexMap;
+
+ size_t *FileNameOffsets; /* in 2-byte steps */
+ CBuf FileNames; /* UTF-16-LE */
+} CSzArEx;
+
+void SzArEx_Init(CSzArEx *p);
+void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc);
+UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
+int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
+
+/*
+if dest == NULL, the return value specifies the required size of the buffer,
+ in 16-bit characters, including the null-terminating character.
+if dest != NULL, the return value specifies the number of 16-bit characters that
+ are written to the dest, including the null-terminating character. */
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+
+SRes SzArEx_Extract(
+ const CSzArEx *db,
+ ILookInStream *inStream,
+ UInt32 fileIndex, /* index of file */
+ UInt32 *blockIndex, /* index of solid block */
+ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
+ size_t *outBufferSize, /* buffer size for output buffer */
+ size_t *offset, /* offset of stream for required file in *outBuffer */
+ size_t *outSizeProcessed, /* size of file in *outBuffer */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp);
+
+
+/*
+SzArEx_Open Errors:
+SZ_ERROR_NO_ARCHIVE
+SZ_ERROR_ARCHIVE
+SZ_ERROR_UNSUPPORTED
+SZ_ERROR_MEM
+SZ_ERROR_CRC
+SZ_ERROR_INPUT_EOF
+SZ_ERROR_FAIL
+*/
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/7zAlloc.c b/src/libs/7zip/win/C/7zAlloc.c
new file mode 100644
index 000000000..964b28db3
--- /dev/null
+++ b/src/libs/7zip/win/C/7zAlloc.c
@@ -0,0 +1,76 @@
+/* 7zAlloc.c -- Allocation functions
+2010-10-29 : Igor Pavlov : Public domain */
+
+#include "7zAlloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+
+#ifdef _SZ_ALLOC_DEBUG
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountTemp = 0;
+
+#endif
+
+void *SzAlloc(void *p, size_t size)
+{
+ p = p;
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
+ g_allocCount++;
+ #endif
+ return malloc(size);
+}
+
+void SzFree(void *p, void *address)
+{
+ p = p;
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ {
+ g_allocCount--;
+ fprintf(stderr, "\nFree; count = %10d", g_allocCount);
+ }
+ #endif
+ free(address);
+}
+
+void *SzAllocTemp(void *p, size_t size)
+{
+ p = p;
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp);
+ g_allocCountTemp++;
+ #ifdef _WIN32
+ return HeapAlloc(GetProcessHeap(), 0, size);
+ #endif
+ #endif
+ return malloc(size);
+}
+
+void SzFreeTemp(void *p, void *address)
+{
+ p = p;
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ {
+ g_allocCountTemp--;
+ fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
+ }
+ #ifdef _WIN32
+ HeapFree(GetProcessHeap(), 0, address);
+ return;
+ #endif
+ #endif
+ free(address);
+}
diff --git a/src/libs/7zip/win/C/7zAlloc.h b/src/libs/7zip/win/C/7zAlloc.h
new file mode 100644
index 000000000..3344e9373
--- /dev/null
+++ b/src/libs/7zip/win/C/7zAlloc.h
@@ -0,0 +1,15 @@
+/* 7zAlloc.h -- Allocation functions
+2010-10-29 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_ALLOC_H
+#define __7Z_ALLOC_H
+
+#include <stdlib.h>
+
+void *SzAlloc(void *p, size_t size);
+void SzFree(void *p, void *address);
+
+void *SzAllocTemp(void *p, size_t size);
+void SzFreeTemp(void *p, void *address);
+
+#endif
diff --git a/src/libs/7zip/win/C/7zBuf.c b/src/libs/7zip/win/C/7zBuf.c
new file mode 100644
index 000000000..14e7f4e2b
--- /dev/null
+++ b/src/libs/7zip/win/C/7zBuf.c
@@ -0,0 +1,36 @@
+/* 7zBuf.c -- Byte Buffer
+2008-03-28
+Igor Pavlov
+Public domain */
+
+#include "7zBuf.h"
+
+void Buf_Init(CBuf *p)
+{
+ p->data = 0;
+ p->size = 0;
+}
+
+int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc)
+{
+ p->size = 0;
+ if (size == 0)
+ {
+ p->data = 0;
+ return 1;
+ }
+ p->data = (Byte *)alloc->Alloc(alloc, size);
+ if (p->data != 0)
+ {
+ p->size = size;
+ return 1;
+ }
+ return 0;
+}
+
+void Buf_Free(CBuf *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->data);
+ p->data = 0;
+ p->size = 0;
+}
diff --git a/src/libs/7zip/win/C/7zBuf.h b/src/libs/7zip/win/C/7zBuf.h
new file mode 100644
index 000000000..e9f2f316d
--- /dev/null
+++ b/src/libs/7zip/win/C/7zBuf.h
@@ -0,0 +1,39 @@
+/* 7zBuf.h -- Byte Buffer
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_BUF_H
+#define __7Z_BUF_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+ Byte *data;
+ size_t size;
+} CBuf;
+
+void Buf_Init(CBuf *p);
+int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc);
+void Buf_Free(CBuf *p, ISzAlloc *alloc);
+
+typedef struct
+{
+ Byte *data;
+ size_t size;
+ size_t pos;
+} CDynBuf;
+
+void DynBuf_Construct(CDynBuf *p);
+void DynBuf_SeekToBeg(CDynBuf *p);
+int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc);
+void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/7zBuf2.c b/src/libs/7zip/win/C/7zBuf2.c
new file mode 100644
index 000000000..8d17e0dcf
--- /dev/null
+++ b/src/libs/7zip/win/C/7zBuf2.c
@@ -0,0 +1,45 @@
+/* 7zBuf2.c -- Byte Buffer
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include <string.h>
+#include "7zBuf.h"
+
+void DynBuf_Construct(CDynBuf *p)
+{
+ p->data = 0;
+ p->size = 0;
+ p->pos = 0;
+}
+
+void DynBuf_SeekToBeg(CDynBuf *p)
+{
+ p->pos = 0;
+}
+
+int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc)
+{
+ if (size > p->size - p->pos)
+ {
+ size_t newSize = p->pos + size;
+ Byte *data;
+ newSize += newSize / 4;
+ data = (Byte *)alloc->Alloc(alloc, newSize);
+ if (data == 0)
+ return 0;
+ p->size = newSize;
+ memcpy(data, p->data, p->pos);
+ alloc->Free(alloc, p->data);
+ p->data = data;
+ }
+ memcpy(p->data + p->pos, buf, size);
+ p->pos += size;
+ return 1;
+}
+
+void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->data);
+ p->data = 0;
+ p->size = 0;
+ p->pos = 0;
+}
diff --git a/src/libs/7zip/win/C/7zCrc.c b/src/libs/7zip/win/C/7zCrc.c
new file mode 100644
index 000000000..a92084961
--- /dev/null
+++ b/src/libs/7zip/win/C/7zCrc.c
@@ -0,0 +1,74 @@
+/* 7zCrc.c -- CRC32 calculation
+2009-11-23 : Igor Pavlov : Public domain */
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define kCrcPoly 0xEDB88320
+
+#ifdef MY_CPU_LE
+#define CRC_NUM_TABLES 8
+#else
+#define CRC_NUM_TABLES 1
+#endif
+
+typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+static CRC_FUNC g_CrcUpdate;
+UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
+
+#if CRC_NUM_TABLES == 1
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+static UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+#else
+
+UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+#endif
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+ return g_CrcUpdate(v, data, size, g_CrcTable);
+}
+
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
+{
+ return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
+}
+
+void MY_FAST_CALL CrcGenerateTable()
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ g_CrcTable[i] = r;
+ }
+ #if CRC_NUM_TABLES == 1
+ g_CrcUpdate = CrcUpdateT1;
+ #else
+ for (; i < 256 * CRC_NUM_TABLES; i++)
+ {
+ UInt32 r = g_CrcTable[i - 256];
+ g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+ }
+ g_CrcUpdate = CrcUpdateT4;
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (!CPU_Is_InOrder())
+ g_CrcUpdate = CrcUpdateT8;
+ #endif
+ #endif
+}
diff --git a/src/libs/7zip/win/C/7zCrc.h b/src/libs/7zip/win/C/7zCrc.h
new file mode 100644
index 000000000..38e3e5fbc
--- /dev/null
+++ b/src/libs/7zip/win/C/7zCrc.h
@@ -0,0 +1,25 @@
+/* 7zCrc.h -- CRC32 calculation
+2009-11-21 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_CRC_H
+#define __7Z_CRC_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+extern UInt32 g_CrcTable[];
+
+/* Call CrcGenerateTable one time before other CRC functions */
+void MY_FAST_CALL CrcGenerateTable(void);
+
+#define CRC_INIT_VAL 0xFFFFFFFF
+#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
+#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/7zCrcOpt.c b/src/libs/7zip/win/C/7zCrcOpt.c
new file mode 100644
index 000000000..6c766a209
--- /dev/null
+++ b/src/libs/7zip/win/C/7zCrcOpt.c
@@ -0,0 +1,34 @@
+/* 7zCrcOpt.c -- CRC32 calculation : optimized version
+2009-11-23 : Igor Pavlov : Public domain */
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_LE
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ for (; size >= 4; size -= 4, p += 4)
+ {
+ v ^= *(const UInt32 *)p;
+ v =
+ table[0x300 + (v & 0xFF)] ^
+ table[0x200 + ((v >> 8) & 0xFF)] ^
+ table[0x100 + ((v >> 16) & 0xFF)] ^
+ table[0x000 + ((v >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ return CrcUpdateT4(v, data, size, table);
+}
+
+#endif
diff --git a/src/libs/7zip/win/C/7zDec.c b/src/libs/7zip/win/C/7zDec.c
new file mode 100644
index 000000000..b6d809956
--- /dev/null
+++ b/src/libs/7zip/win/C/7zDec.c
@@ -0,0 +1,470 @@
+/* 7zDec.c -- Decoding from 7z folder
+2010-11-02 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+/* #define _7ZIP_PPMD_SUPPPORT */
+
+#include "7z.h"
+
+#include "Bcj2.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "LzmaDec.h"
+#include "Lzma2Dec.h"
+#ifdef _7ZIP_PPMD_SUPPPORT
+#include "Ppmd7.h"
+#endif
+
+#define k_Copy 0
+#define k_LZMA2 0x21
+#define k_LZMA 0x30101
+#define k_BCJ 0x03030103
+#define k_PPC 0x03030205
+#define k_ARM 0x03030501
+#define k_ARMT 0x03030701
+#define k_SPARC 0x03030805
+#define k_BCJ2 0x0303011B
+
+#ifdef _7ZIP_PPMD_SUPPPORT
+
+#define k_PPMD 0x30401
+
+typedef struct
+{
+ IByteIn p;
+ const Byte *cur;
+ const Byte *end;
+ const Byte *begin;
+ UInt64 processed;
+ Bool extra;
+ SRes res;
+ ILookInStream *inStream;
+} CByteInToLook;
+
+static Byte ReadByte(void *pp)
+{
+ CByteInToLook *p = (CByteInToLook *)pp;
+ if (p->cur != p->end)
+ return *p->cur++;
+ if (p->res == SZ_OK)
+ {
+ size_t size = p->cur - p->begin;
+ p->processed += size;
+ p->res = p->inStream->Skip(p->inStream, size);
+ size = (1 << 25);
+ p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
+ p->cur = p->begin;
+ p->end = p->begin + size;
+ if (size != 0)
+ return *p->cur++;;
+ }
+ p->extra = True;
+ return 0;
+}
+
+static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
+{
+ CPpmd7 ppmd;
+ CByteInToLook s;
+ SRes res = SZ_OK;
+
+ s.p.Read = ReadByte;
+ s.inStream = inStream;
+ s.begin = s.end = s.cur = NULL;
+ s.extra = False;
+ s.res = SZ_OK;
+ s.processed = 0;
+
+ if (coder->Props.size != 5)
+ return SZ_ERROR_UNSUPPORTED;
+
+ {
+ unsigned order = coder->Props.data[0];
+ UInt32 memSize = GetUi32(coder->Props.data + 1);
+ if (order < PPMD7_MIN_ORDER ||
+ order > PPMD7_MAX_ORDER ||
+ memSize < PPMD7_MIN_MEM_SIZE ||
+ memSize > PPMD7_MAX_MEM_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ Ppmd7_Construct(&ppmd);
+ if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
+ return SZ_ERROR_MEM;
+ Ppmd7_Init(&ppmd, order);
+ }
+ {
+ CPpmd7z_RangeDec rc;
+ Ppmd7z_RangeDec_CreateVTable(&rc);
+ rc.Stream = &s.p;
+ if (!Ppmd7z_RangeDec_Init(&rc))
+ res = SZ_ERROR_DATA;
+ else if (s.extra)
+ res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
+ else
+ {
+ SizeT i;
+ for (i = 0; i < outSize; i++)
+ {
+ int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
+ if (s.extra || sym < 0)
+ break;
+ outBuffer[i] = (Byte)sym;
+ }
+ if (i != outSize)
+ res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
+ else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
+ res = SZ_ERROR_DATA;
+ }
+ }
+ Ppmd7_Free(&ppmd, allocMain);
+ return res;
+}
+
+#endif
+
+
+static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
+{
+ CLzmaDec state;
+ SRes res = SZ_OK;
+
+ LzmaDec_Construct(&state);
+ RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
+ state.dic = outBuffer;
+ state.dicBufSize = outSize;
+ LzmaDec_Init(&state);
+
+ for (;;)
+ {
+ Byte *inBuf = NULL;
+ size_t lookahead = (1 << 18);
+ if (lookahead > inSize)
+ lookahead = (size_t)inSize;
+ res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
+ if (res != SZ_OK)
+ break;
+
+ {
+ SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
+ ELzmaStatus status;
+ res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
+ lookahead -= inProcessed;
+ inSize -= inProcessed;
+ if (res != SZ_OK)
+ break;
+ if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
+ {
+ if (state.dicBufSize != outSize || lookahead != 0 ||
+ (status != LZMA_STATUS_FINISHED_WITH_MARK &&
+ status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
+ res = SZ_ERROR_DATA;
+ break;
+ }
+ res = inStream->Skip((void *)inStream, inProcessed);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ LzmaDec_FreeProbs(&state, allocMain);
+ return res;
+}
+
+static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
+{
+ CLzma2Dec state;
+ SRes res = SZ_OK;
+
+ Lzma2Dec_Construct(&state);
+ if (coder->Props.size != 1)
+ return SZ_ERROR_DATA;
+ RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain));
+ state.decoder.dic = outBuffer;
+ state.decoder.dicBufSize = outSize;
+ Lzma2Dec_Init(&state);
+
+ for (;;)
+ {
+ Byte *inBuf = NULL;
+ size_t lookahead = (1 << 18);
+ if (lookahead > inSize)
+ lookahead = (size_t)inSize;
+ res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
+ if (res != SZ_OK)
+ break;
+
+ {
+ SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
+ ELzmaStatus status;
+ res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
+ lookahead -= inProcessed;
+ inSize -= inProcessed;
+ if (res != SZ_OK)
+ break;
+ if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
+ {
+ if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
+ (status != LZMA_STATUS_FINISHED_WITH_MARK))
+ res = SZ_ERROR_DATA;
+ break;
+ }
+ res = inStream->Skip((void *)inStream, inProcessed);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ Lzma2Dec_FreeProbs(&state, allocMain);
+ return res;
+}
+
+static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
+{
+ while (inSize > 0)
+ {
+ void *inBuf;
+ size_t curSize = (1 << 18);
+ if (curSize > inSize)
+ curSize = (size_t)inSize;
+ RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
+ if (curSize == 0)
+ return SZ_ERROR_INPUT_EOF;
+ memcpy(outBuffer, inBuf, curSize);
+ outBuffer += curSize;
+ inSize -= curSize;
+ RINOK(inStream->Skip((void *)inStream, curSize));
+ }
+ return SZ_OK;
+}
+
+static Bool IS_MAIN_METHOD(UInt32 m)
+{
+ switch(m)
+ {
+ case k_Copy:
+ case k_LZMA:
+ case k_LZMA2:
+ #ifdef _7ZIP_PPMD_SUPPPORT
+ case k_PPMD:
+ #endif
+ return True;
+ }
+ return False;
+}
+
+static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
+{
+ return
+ c->NumInStreams == 1 &&
+ c->NumOutStreams == 1 &&
+ c->MethodID <= (UInt32)0xFFFFFFFF &&
+ IS_MAIN_METHOD((UInt32)c->MethodID);
+}
+
+#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
+
+static SRes CheckSupportedFolder(const CSzFolder *f)
+{
+ if (f->NumCoders < 1 || f->NumCoders > 4)
+ return SZ_ERROR_UNSUPPORTED;
+ if (!IS_SUPPORTED_CODER(&f->Coders[0]))
+ return SZ_ERROR_UNSUPPORTED;
+ if (f->NumCoders == 1)
+ {
+ if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ return SZ_OK;
+ }
+ if (f->NumCoders == 2)
+ {
+ CSzCoderInfo *c = &f->Coders[1];
+ if (c->MethodID > (UInt32)0xFFFFFFFF ||
+ c->NumInStreams != 1 ||
+ c->NumOutStreams != 1 ||
+ f->NumPackStreams != 1 ||
+ f->PackStreams[0] != 0 ||
+ f->NumBindPairs != 1 ||
+ f->BindPairs[0].InIndex != 1 ||
+ f->BindPairs[0].OutIndex != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ switch ((UInt32)c->MethodID)
+ {
+ case k_BCJ:
+ case k_ARM:
+ break;
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ return SZ_OK;
+ }
+ if (f->NumCoders == 4)
+ {
+ if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
+ !IS_SUPPORTED_CODER(&f->Coders[2]) ||
+ !IS_BCJ2(&f->Coders[3]))
+ return SZ_ERROR_UNSUPPORTED;
+ if (f->NumPackStreams != 4 ||
+ f->PackStreams[0] != 2 ||
+ f->PackStreams[1] != 6 ||
+ f->PackStreams[2] != 1 ||
+ f->PackStreams[3] != 0 ||
+ f->NumBindPairs != 3 ||
+ f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
+ f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
+ f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
+ return SZ_ERROR_UNSUPPORTED;
+ return SZ_OK;
+ }
+ return SZ_ERROR_UNSUPPORTED;
+}
+
+static UInt64 GetSum(const UInt64 *values, UInt32 index)
+{
+ UInt64 sum = 0;
+ UInt32 i;
+ for (i = 0; i < index; i++)
+ sum += values[i];
+ return sum;
+}
+
+#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
+
+static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
+ ILookInStream *inStream, UInt64 startPos,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
+ Byte *tempBuf[])
+{
+ UInt32 ci;
+ SizeT tempSizes[3] = { 0, 0, 0};
+ SizeT tempSize3 = 0;
+ Byte *tempBuf3 = 0;
+
+ RINOK(CheckSupportedFolder(folder));
+
+ for (ci = 0; ci < folder->NumCoders; ci++)
+ {
+ CSzCoderInfo *coder = &folder->Coders[ci];
+
+ if (IS_MAIN_METHOD((UInt32)coder->MethodID))
+ {
+ UInt32 si = 0;
+ UInt64 offset;
+ UInt64 inSize;
+ Byte *outBufCur = outBuffer;
+ SizeT outSizeCur = outSize;
+ if (folder->NumCoders == 4)
+ {
+ UInt32 indices[] = { 3, 2, 0 };
+ UInt64 unpackSize = folder->UnpackSizes[ci];
+ si = indices[ci];
+ if (ci < 2)
+ {
+ Byte *temp;
+ outSizeCur = (SizeT)unpackSize;
+ if (outSizeCur != unpackSize)
+ return SZ_ERROR_MEM;
+ temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
+ if (temp == 0 && outSizeCur != 0)
+ return SZ_ERROR_MEM;
+ outBufCur = tempBuf[1 - ci] = temp;
+ tempSizes[1 - ci] = outSizeCur;
+ }
+ else if (ci == 2)
+ {
+ if (unpackSize > outSize) /* check it */
+ return SZ_ERROR_PARAM;
+ tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
+ tempSize3 = outSizeCur = (SizeT)unpackSize;
+ }
+ else
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ offset = GetSum(packSizes, si);
+ inSize = packSizes[si];
+ RINOK(LookInStream_SeekTo(inStream, startPos + offset));
+
+ if (coder->MethodID == k_Copy)
+ {
+ if (inSize != outSizeCur) /* check it */
+ return SZ_ERROR_DATA;
+ RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
+ }
+ else if (coder->MethodID == k_LZMA)
+ {
+ RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ }
+ else if (coder->MethodID == k_LZMA2)
+ {
+ RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ }
+ else
+ {
+ #ifdef _7ZIP_PPMD_SUPPPORT
+ RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ #else
+ return SZ_ERROR_UNSUPPORTED;
+ #endif
+ }
+ }
+ else if (coder->MethodID == k_BCJ2)
+ {
+ UInt64 offset = GetSum(packSizes, 1);
+ UInt64 s3Size = packSizes[1];
+ SRes res;
+ if (ci != 3)
+ return SZ_ERROR_UNSUPPORTED;
+ RINOK(LookInStream_SeekTo(inStream, startPos + offset));
+ tempSizes[2] = (SizeT)s3Size;
+ if (tempSizes[2] != s3Size)
+ return SZ_ERROR_MEM;
+ tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
+ if (tempBuf[2] == 0 && tempSizes[2] != 0)
+ return SZ_ERROR_MEM;
+ res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
+ RINOK(res)
+
+ res = Bcj2_Decode(
+ tempBuf3, tempSize3,
+ tempBuf[0], tempSizes[0],
+ tempBuf[1], tempSizes[1],
+ tempBuf[2], tempSizes[2],
+ outBuffer, outSize);
+ RINOK(res)
+ }
+ else
+ {
+ if (ci != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ switch(coder->MethodID)
+ {
+ case k_BCJ:
+ {
+ UInt32 state;
+ x86_Convert_Init(state);
+ x86_Convert(outBuffer, outSize, 0, &state, 0);
+ break;
+ }
+ CASE_BRA_CONV(ARM)
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+ return SZ_OK;
+}
+
+SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
+ ILookInStream *inStream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
+{
+ Byte *tempBuf[3] = { 0, 0, 0};
+ int i;
+ SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
+ outBuffer, (SizeT)outSize, allocMain, tempBuf);
+ for (i = 0; i < 3; i++)
+ IAlloc_Free(allocMain, tempBuf[i]);
+ return res;
+}
diff --git a/src/libs/7zip/win/C/7zFile.c b/src/libs/7zip/win/C/7zFile.c
new file mode 100644
index 000000000..a66c9e9d0
--- /dev/null
+++ b/src/libs/7zip/win/C/7zFile.c
@@ -0,0 +1,284 @@
+/* 7zFile.c -- File IO
+2009-11-24 : Igor Pavlov : Public domain */
+
+#include "7zFile.h"
+
+#ifndef USE_WINDOWS_FILE
+
+#ifndef UNDER_CE
+#include <errno.h>
+#endif
+
+#else
+
+/*
+ ReadFile and WriteFile functions in Windows have BUG:
+ If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
+ from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
+ (Insufficient system resources exist to complete the requested service).
+ Probably in some version of Windows there are problems with other sizes:
+ for 32 MB (maybe also for 16 MB).
+ And message can be "Network connection was lost"
+*/
+
+#define kChunkSizeMax (1 << 22)
+
+#endif
+
+void File_Construct(CSzFile *p)
+{
+ #ifdef USE_WINDOWS_FILE
+ p->handle = INVALID_HANDLE_VALUE;
+ #else
+ p->file = NULL;
+ #endif
+}
+
+#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
+static WRes File_Open(CSzFile *p, const char *name, int writeMode)
+{
+ #ifdef USE_WINDOWS_FILE
+ p->handle = CreateFileA(name,
+ writeMode ? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ, NULL,
+ writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
+ #else
+ p->file = fopen(name, writeMode ? "wb+" : "rb");
+ return (p->file != 0) ? 0 :
+ #ifdef UNDER_CE
+ 2; /* ENOENT */
+ #else
+ errno;
+ #endif
+ #endif
+}
+
+WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
+WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }
+#endif
+
+#ifdef USE_WINDOWS_FILE
+static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
+{
+ p->handle = CreateFileW(name,
+ writeMode ? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ, NULL,
+ writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
+}
+WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
+WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
+#endif
+
+WRes File_Close(CSzFile *p)
+{
+ #ifdef USE_WINDOWS_FILE
+ if (p->handle != INVALID_HANDLE_VALUE)
+ {
+ if (!CloseHandle(p->handle))
+ return GetLastError();
+ p->handle = INVALID_HANDLE_VALUE;
+ }
+ #else
+ if (p->file != NULL)
+ {
+ int res = fclose(p->file);
+ if (res != 0)
+ return res;
+ p->file = NULL;
+ }
+ #endif
+ return 0;
+}
+
+WRes File_Read(CSzFile *p, void *data, size_t *size)
+{
+ size_t originalSize = *size;
+ if (originalSize == 0)
+ return 0;
+
+ #ifdef USE_WINDOWS_FILE
+
+ *size = 0;
+ do
+ {
+ DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
+ DWORD processed = 0;
+ BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
+ data = (void *)((Byte *)data + processed);
+ originalSize -= processed;
+ *size += processed;
+ if (!res)
+ return GetLastError();
+ if (processed == 0)
+ break;
+ }
+ while (originalSize > 0);
+ return 0;
+
+ #else
+
+ *size = fread(data, 1, originalSize, p->file);
+ if (*size == originalSize)
+ return 0;
+ return ferror(p->file);
+
+ #endif
+}
+
+WRes File_Write(CSzFile *p, const void *data, size_t *size)
+{
+ size_t originalSize = *size;
+ if (originalSize == 0)
+ return 0;
+
+ #ifdef USE_WINDOWS_FILE
+
+ *size = 0;
+ do
+ {
+ DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
+ DWORD processed = 0;
+ BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
+ data = (void *)((Byte *)data + processed);
+ originalSize -= processed;
+ *size += processed;
+ if (!res)
+ return GetLastError();
+ if (processed == 0)
+ break;
+ }
+ while (originalSize > 0);
+ return 0;
+
+ #else
+
+ *size = fwrite(data, 1, originalSize, p->file);
+ if (*size == originalSize)
+ return 0;
+ return ferror(p->file);
+
+ #endif
+}
+
+WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ LARGE_INTEGER value;
+ DWORD moveMethod;
+ value.LowPart = (DWORD)*pos;
+ value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
+ switch (origin)
+ {
+ case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
+ case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
+ case SZ_SEEK_END: moveMethod = FILE_END; break;
+ default: return ERROR_INVALID_PARAMETER;
+ }
+ value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
+ if (value.LowPart == 0xFFFFFFFF)
+ {
+ WRes res = GetLastError();
+ if (res != NO_ERROR)
+ return res;
+ }
+ *pos = ((Int64)value.HighPart << 32) | value.LowPart;
+ return 0;
+
+ #else
+
+ int moveMethod;
+ int res;
+ switch (origin)
+ {
+ case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
+ case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
+ case SZ_SEEK_END: moveMethod = SEEK_END; break;
+ default: return 1;
+ }
+ res = fseek(p->file, (long)*pos, moveMethod);
+ *pos = ftell(p->file);
+ return res;
+
+ #endif
+}
+
+WRes File_GetLength(CSzFile *p, UInt64 *length)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ DWORD sizeHigh;
+ DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
+ if (sizeLow == 0xFFFFFFFF)
+ {
+ DWORD res = GetLastError();
+ if (res != NO_ERROR)
+ return res;
+ }
+ *length = (((UInt64)sizeHigh) << 32) + sizeLow;
+ return 0;
+
+ #else
+
+ long pos = ftell(p->file);
+ int res = fseek(p->file, 0, SEEK_END);
+ *length = ftell(p->file);
+ fseek(p->file, pos, SEEK_SET);
+ return res;
+
+ #endif
+}
+
+
+/* ---------- FileSeqInStream ---------- */
+
+static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size)
+{
+ CFileSeqInStream *p = (CFileSeqInStream *)pp;
+ return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
+}
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
+{
+ p->s.Read = FileSeqInStream_Read;
+}
+
+
+/* ---------- FileInStream ---------- */
+
+static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
+{
+ CFileInStream *p = (CFileInStream *)pp;
+ return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ CFileInStream *p = (CFileInStream *)pp;
+ return File_Seek(&p->file, pos, origin);
+}
+
+void FileInStream_CreateVTable(CFileInStream *p)
+{
+ p->s.Read = FileInStream_Read;
+ p->s.Seek = FileInStream_Seek;
+}
+
+
+/* ---------- FileOutStream ---------- */
+
+static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
+{
+ CFileOutStream *p = (CFileOutStream *)pp;
+ File_Write(&p->file, data, &size);
+ return size;
+}
+
+void FileOutStream_CreateVTable(CFileOutStream *p)
+{
+ p->s.Write = FileOutStream_Write;
+}
diff --git a/src/libs/7zip/win/C/7zFile.h b/src/libs/7zip/win/C/7zFile.h
new file mode 100644
index 000000000..84538c03f
--- /dev/null
+++ b/src/libs/7zip/win/C/7zFile.h
@@ -0,0 +1,83 @@
+/* 7zFile.h -- File IO
+2009-11-24 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_FILE_H
+#define __7Z_FILE_H
+
+#ifdef _WIN32
+#define USE_WINDOWS_FILE
+#endif
+
+#ifdef USE_WINDOWS_FILE
+#include <windows.h>
+#else
+#include <stdio.h>
+#endif
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+/* ---------- File ---------- */
+
+typedef struct
+{
+ #ifdef USE_WINDOWS_FILE
+ HANDLE handle;
+ #else
+ FILE *file;
+ #endif
+} CSzFile;
+
+void File_Construct(CSzFile *p);
+#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
+WRes InFile_Open(CSzFile *p, const char *name);
+WRes OutFile_Open(CSzFile *p, const char *name);
+#endif
+#ifdef USE_WINDOWS_FILE
+WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
+WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
+#endif
+WRes File_Close(CSzFile *p);
+
+/* reads max(*size, remain file's size) bytes */
+WRes File_Read(CSzFile *p, void *data, size_t *size);
+
+/* writes *size bytes */
+WRes File_Write(CSzFile *p, const void *data, size_t *size);
+
+WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
+WRes File_GetLength(CSzFile *p, UInt64 *length);
+
+
+/* ---------- FileInStream ---------- */
+
+typedef struct
+{
+ ISeqInStream s;
+ CSzFile file;
+} CFileSeqInStream;
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
+
+
+typedef struct
+{
+ ISeekInStream s;
+ CSzFile file;
+} CFileInStream;
+
+void FileInStream_CreateVTable(CFileInStream *p);
+
+
+typedef struct
+{
+ ISeqOutStream s;
+ CSzFile file;
+} CFileOutStream;
+
+void FileOutStream_CreateVTable(CFileOutStream *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/7zIn.c b/src/libs/7zip/win/C/7zIn.c
new file mode 100644
index 000000000..ec93a43ff
--- /dev/null
+++ b/src/libs/7zip/win/C/7zIn.c
@@ -0,0 +1,1402 @@
+/* 7zIn.c -- 7z Input functions
+2010-10-29 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "7z.h"
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+#define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; }
+
+#define NUM_FOLDER_CODERS_MAX 32
+#define NUM_CODER_STREAMS_MAX 32
+
+void SzCoderInfo_Init(CSzCoderInfo *p)
+{
+ Buf_Init(&p->Props);
+}
+
+void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc)
+{
+ Buf_Free(&p->Props, alloc);
+ SzCoderInfo_Init(p);
+}
+
+void SzFolder_Init(CSzFolder *p)
+{
+ p->Coders = 0;
+ p->BindPairs = 0;
+ p->PackStreams = 0;
+ p->UnpackSizes = 0;
+ p->NumCoders = 0;
+ p->NumBindPairs = 0;
+ p->NumPackStreams = 0;
+ p->UnpackCRCDefined = 0;
+ p->UnpackCRC = 0;
+ p->NumUnpackStreams = 0;
+}
+
+void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc)
+{
+ UInt32 i;
+ if (p->Coders)
+ for (i = 0; i < p->NumCoders; i++)
+ SzCoderInfo_Free(&p->Coders[i], alloc);
+ IAlloc_Free(alloc, p->Coders);
+ IAlloc_Free(alloc, p->BindPairs);
+ IAlloc_Free(alloc, p->PackStreams);
+ IAlloc_Free(alloc, p->UnpackSizes);
+ SzFolder_Init(p);
+}
+
+UInt32 SzFolder_GetNumOutStreams(CSzFolder *p)
+{
+ UInt32 result = 0;
+ UInt32 i;
+ for (i = 0; i < p->NumCoders; i++)
+ result += p->Coders[i].NumOutStreams;
+ return result;
+}
+
+int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex)
+{
+ UInt32 i;
+ for (i = 0; i < p->NumBindPairs; i++)
+ if (p->BindPairs[i].InIndex == inStreamIndex)
+ return i;
+ return -1;
+}
+
+
+int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex)
+{
+ UInt32 i;
+ for (i = 0; i < p->NumBindPairs; i++)
+ if (p->BindPairs[i].OutIndex == outStreamIndex)
+ return i;
+ return -1;
+}
+
+UInt64 SzFolder_GetUnpackSize(CSzFolder *p)
+{
+ int i = (int)SzFolder_GetNumOutStreams(p);
+ if (i == 0)
+ return 0;
+ for (i--; i >= 0; i--)
+ if (SzFolder_FindBindPairForOutStream(p, i) < 0)
+ return p->UnpackSizes[i];
+ /* throw 1; */
+ return 0;
+}
+
+void SzFile_Init(CSzFileItem *p)
+{
+ p->HasStream = 1;
+ p->IsDir = 0;
+ p->IsAnti = 0;
+ p->CrcDefined = 0;
+ p->MTimeDefined = 0;
+}
+
+void SzAr_Init(CSzAr *p)
+{
+ p->PackSizes = 0;
+ p->PackCRCsDefined = 0;
+ p->PackCRCs = 0;
+ p->Folders = 0;
+ p->Files = 0;
+ p->NumPackStreams = 0;
+ p->NumFolders = 0;
+ p->NumFiles = 0;
+}
+
+void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
+{
+ UInt32 i;
+ if (p->Folders)
+ for (i = 0; i < p->NumFolders; i++)
+ SzFolder_Free(&p->Folders[i], alloc);
+
+ IAlloc_Free(alloc, p->PackSizes);
+ IAlloc_Free(alloc, p->PackCRCsDefined);
+ IAlloc_Free(alloc, p->PackCRCs);
+ IAlloc_Free(alloc, p->Folders);
+ IAlloc_Free(alloc, p->Files);
+ SzAr_Init(p);
+}
+
+
+void SzArEx_Init(CSzArEx *p)
+{
+ SzAr_Init(&p->db);
+ p->FolderStartPackStreamIndex = 0;
+ p->PackStreamStartPositions = 0;
+ p->FolderStartFileIndex = 0;
+ p->FileIndexToFolderIndexMap = 0;
+ p->FileNameOffsets = 0;
+ Buf_Init(&p->FileNames);
+}
+
+void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->FolderStartPackStreamIndex);
+ IAlloc_Free(alloc, p->PackStreamStartPositions);
+ IAlloc_Free(alloc, p->FolderStartFileIndex);
+ IAlloc_Free(alloc, p->FileIndexToFolderIndexMap);
+
+ IAlloc_Free(alloc, p->FileNameOffsets);
+ Buf_Free(&p->FileNames, alloc);
+
+ SzAr_Free(&p->db, alloc);
+ SzArEx_Init(p);
+}
+
+/*
+UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
+{
+ return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+}
+
+UInt64 GetFilePackSize(int fileIndex) const
+{
+ int folderIndex = FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex >= 0)
+ {
+ const CSzFolder &folderInfo = Folders[folderIndex];
+ if (FolderStartFileIndex[folderIndex] == fileIndex)
+ return GetFolderFullPackSize(folderIndex);
+ }
+ return 0;
+}
+*/
+
+#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \
+ if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; }
+
+static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc)
+{
+ UInt32 startPos = 0;
+ UInt64 startPosSize = 0;
+ UInt32 i;
+ UInt32 folderIndex = 0;
+ UInt32 indexInFolder = 0;
+ MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc);
+ for (i = 0; i < p->db.NumFolders; i++)
+ {
+ p->FolderStartPackStreamIndex[i] = startPos;
+ startPos += p->db.Folders[i].NumPackStreams;
+ }
+
+ MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc);
+
+ for (i = 0; i < p->db.NumPackStreams; i++)
+ {
+ p->PackStreamStartPositions[i] = startPosSize;
+ startPosSize += p->db.PackSizes[i];
+ }
+
+ MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc);
+ MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc);
+
+ for (i = 0; i < p->db.NumFiles; i++)
+ {
+ CSzFileItem *file = p->db.Files + i;
+ int emptyStream = !file->HasStream;
+ if (emptyStream && indexInFolder == 0)
+ {
+ p->FileIndexToFolderIndexMap[i] = (UInt32)-1;
+ continue;
+ }
+ if (indexInFolder == 0)
+ {
+ /*
+ v3.13 incorrectly worked with empty folders
+ v4.07: Loop for skipping empty folders
+ */
+ for (;;)
+ {
+ if (folderIndex >= p->db.NumFolders)
+ return SZ_ERROR_ARCHIVE;
+ p->FolderStartFileIndex[folderIndex] = i;
+ if (p->db.Folders[folderIndex].NumUnpackStreams != 0)
+ break;
+ folderIndex++;
+ }
+ }
+ p->FileIndexToFolderIndexMap[i] = folderIndex;
+ if (emptyStream)
+ continue;
+ indexInFolder++;
+ if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams)
+ {
+ folderIndex++;
+ indexInFolder = 0;
+ }
+ }
+ return SZ_OK;
+}
+
+
+UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder)
+{
+ return p->dataPos +
+ p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+}
+
+int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize)
+{
+ UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex];
+ CSzFolder *folder = p->db.Folders + folderIndex;
+ UInt64 size = 0;
+ UInt32 i;
+ for (i = 0; i < folder->NumPackStreams; i++)
+ {
+ UInt64 t = size + p->db.PackSizes[packStreamIndex + i];
+ if (t < size) /* check it */
+ return SZ_ERROR_FAIL;
+ size = t;
+ }
+ *resSize = size;
+ return SZ_OK;
+}
+
+
+/*
+SRes SzReadTime(const CObjectVector<CBuf> &dataVector,
+ CObjectVector<CSzFileItem> &files, UInt64 type)
+{
+ CBoolVector boolVector;
+ RINOK(ReadBoolVector2(files.Size(), boolVector))
+
+ CStreamSwitch streamSwitch;
+ RINOK(streamSwitch.Set(this, &dataVector));
+
+ for (int i = 0; i < files.Size(); i++)
+ {
+ CSzFileItem &file = files[i];
+ CArchiveFileTime fileTime;
+ bool defined = boolVector[i];
+ if (defined)
+ {
+ UInt32 low, high;
+ RINOK(SzReadUInt32(low));
+ RINOK(SzReadUInt32(high));
+ fileTime.dwLowDateTime = low;
+ fileTime.dwHighDateTime = high;
+ }
+ switch(type)
+ {
+ case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break;
+ case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break;
+ case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break;
+ }
+ }
+ return SZ_OK;
+}
+*/
+
+static int TestSignatureCandidate(Byte *testBytes)
+{
+ size_t i;
+ for (i = 0; i < k7zSignatureSize; i++)
+ if (testBytes[i] != k7zSignature[i])
+ return 0;
+ return 1;
+}
+
+typedef struct _CSzState
+{
+ Byte *Data;
+ size_t Size;
+}CSzData;
+
+static SRes SzReadByte(CSzData *sd, Byte *b)
+{
+ if (sd->Size == 0)
+ return SZ_ERROR_ARCHIVE;
+ sd->Size--;
+ *b = *sd->Data++;
+ return SZ_OK;
+}
+
+static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size)
+{
+ size_t i;
+ for (i = 0; i < size; i++)
+ {
+ RINOK(SzReadByte(sd, data + i));
+ }
+ return SZ_OK;
+}
+
+static SRes SzReadUInt32(CSzData *sd, UInt32 *value)
+{
+ int i;
+ *value = 0;
+ for (i = 0; i < 4; i++)
+ {
+ Byte b;
+ RINOK(SzReadByte(sd, &b));
+ *value |= ((UInt32)(b) << (8 * i));
+ }
+ return SZ_OK;
+}
+
+static SRes SzReadNumber(CSzData *sd, UInt64 *value)
+{
+ Byte firstByte;
+ Byte mask = 0x80;
+ int i;
+ RINOK(SzReadByte(sd, &firstByte));
+ *value = 0;
+ for (i = 0; i < 8; i++)
+ {
+ Byte b;
+ if ((firstByte & mask) == 0)
+ {
+ UInt64 highPart = firstByte & (mask - 1);
+ *value += (highPart << (8 * i));
+ return SZ_OK;
+ }
+ RINOK(SzReadByte(sd, &b));
+ *value |= ((UInt64)b << (8 * i));
+ mask >>= 1;
+ }
+ return SZ_OK;
+}
+
+static SRes SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+ UInt64 value64;
+ RINOK(SzReadNumber(sd, &value64));
+ if (value64 >= 0x80000000)
+ return SZ_ERROR_UNSUPPORTED;
+ if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
+ return SZ_ERROR_UNSUPPORTED;
+ *value = (UInt32)value64;
+ return SZ_OK;
+}
+
+static SRes SzReadID(CSzData *sd, UInt64 *value)
+{
+ return SzReadNumber(sd, value);
+}
+
+static SRes SzSkeepDataSize(CSzData *sd, UInt64 size)
+{
+ if (size > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ sd->Size -= (size_t)size;
+ sd->Data += (size_t)size;
+ return SZ_OK;
+}
+
+static SRes SzSkeepData(CSzData *sd)
+{
+ UInt64 size;
+ RINOK(SzReadNumber(sd, &size));
+ return SzSkeepDataSize(sd, size);
+}
+
+static SRes SzReadArchiveProperties(CSzData *sd)
+{
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ SzSkeepData(sd);
+ }
+ return SZ_OK;
+}
+
+static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute)
+{
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if (type == attribute)
+ return SZ_OK;
+ if (type == k7zIdEnd)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(SzSkeepData(sd));
+ }
+}
+
+static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
+{
+ Byte b = 0;
+ Byte mask = 0;
+ size_t i;
+ MY_ALLOC(Byte, *v, numItems, alloc);
+ for (i = 0; i < numItems; i++)
+ {
+ if (mask == 0)
+ {
+ RINOK(SzReadByte(sd, &b));
+ mask = 0x80;
+ }
+ (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
+ mask >>= 1;
+ }
+ return SZ_OK;
+}
+
+static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
+{
+ Byte allAreDefined;
+ size_t i;
+ RINOK(SzReadByte(sd, &allAreDefined));
+ if (allAreDefined == 0)
+ return SzReadBoolVector(sd, numItems, v, alloc);
+ MY_ALLOC(Byte, *v, numItems, alloc);
+ for (i = 0; i < numItems; i++)
+ (*v)[i] = 1;
+ return SZ_OK;
+}
+
+static SRes SzReadHashDigests(
+ CSzData *sd,
+ size_t numItems,
+ Byte **digestsDefined,
+ UInt32 **digests,
+ ISzAlloc *alloc)
+{
+ size_t i;
+ RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc));
+ MY_ALLOC(UInt32, *digests, numItems, alloc);
+ for (i = 0; i < numItems; i++)
+ if ((*digestsDefined)[i])
+ {
+ RINOK(SzReadUInt32(sd, (*digests) + i));
+ }
+ return SZ_OK;
+}
+
+static SRes SzReadPackInfo(
+ CSzData *sd,
+ UInt64 *dataOffset,
+ UInt32 *numPackStreams,
+ UInt64 **packSizes,
+ Byte **packCRCsDefined,
+ UInt32 **packCRCs,
+ ISzAlloc *alloc)
+{
+ UInt32 i;
+ RINOK(SzReadNumber(sd, dataOffset));
+ RINOK(SzReadNumber32(sd, numPackStreams));
+
+ RINOK(SzWaitAttribute(sd, k7zIdSize));
+
+ MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc);
+
+ for (i = 0; i < *numPackStreams; i++)
+ {
+ RINOK(SzReadNumber(sd, (*packSizes) + i));
+ }
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ if (type == k7zIdCRC)
+ {
+ RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc));
+ continue;
+ }
+ RINOK(SzSkeepData(sd));
+ }
+ if (*packCRCsDefined == 0)
+ {
+ MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc);
+ MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc);
+ for (i = 0; i < *numPackStreams; i++)
+ {
+ (*packCRCsDefined)[i] = 0;
+ (*packCRCs)[i] = 0;
+ }
+ }
+ return SZ_OK;
+}
+
+static SRes SzReadSwitch(CSzData *sd)
+{
+ Byte external;
+ RINOK(SzReadByte(sd, &external));
+ return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
+}
+
+static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc)
+{
+ UInt32 numCoders, numBindPairs, numPackStreams, i;
+ UInt32 numInStreams = 0, numOutStreams = 0;
+
+ RINOK(SzReadNumber32(sd, &numCoders));
+ if (numCoders > NUM_FOLDER_CODERS_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ folder->NumCoders = numCoders;
+
+ MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc);
+
+ for (i = 0; i < numCoders; i++)
+ SzCoderInfo_Init(folder->Coders + i);
+
+ for (i = 0; i < numCoders; i++)
+ {
+ Byte mainByte;
+ CSzCoderInfo *coder = folder->Coders + i;
+ {
+ unsigned idSize, j;
+ Byte longID[15];
+ RINOK(SzReadByte(sd, &mainByte));
+ idSize = (unsigned)(mainByte & 0xF);
+ RINOK(SzReadBytes(sd, longID, idSize));
+ if (idSize > sizeof(coder->MethodID))
+ return SZ_ERROR_UNSUPPORTED;
+ coder->MethodID = 0;
+ for (j = 0; j < idSize; j++)
+ coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j);
+
+ if ((mainByte & 0x10) != 0)
+ {
+ RINOK(SzReadNumber32(sd, &coder->NumInStreams));
+ RINOK(SzReadNumber32(sd, &coder->NumOutStreams));
+ if (coder->NumInStreams > NUM_CODER_STREAMS_MAX ||
+ coder->NumOutStreams > NUM_CODER_STREAMS_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ else
+ {
+ coder->NumInStreams = 1;
+ coder->NumOutStreams = 1;
+ }
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt64 propertiesSize = 0;
+ RINOK(SzReadNumber(sd, &propertiesSize));
+ if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc))
+ return SZ_ERROR_MEM;
+ RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize));
+ }
+ }
+ while ((mainByte & 0x80) != 0)
+ {
+ RINOK(SzReadByte(sd, &mainByte));
+ RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 n;
+ RINOK(SzReadNumber32(sd, &n));
+ RINOK(SzReadNumber32(sd, &n));
+ }
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt64 propertiesSize = 0;
+ RINOK(SzReadNumber(sd, &propertiesSize));
+ RINOK(SzSkeepDataSize(sd, propertiesSize));
+ }
+ }
+ numInStreams += coder->NumInStreams;
+ numOutStreams += coder->NumOutStreams;
+ }
+
+ if (numOutStreams == 0)
+ return SZ_ERROR_UNSUPPORTED;
+
+ folder->NumBindPairs = numBindPairs = numOutStreams - 1;
+ MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc);
+
+ for (i = 0; i < numBindPairs; i++)
+ {
+ CSzBindPair *bp = folder->BindPairs + i;
+ RINOK(SzReadNumber32(sd, &bp->InIndex));
+ RINOK(SzReadNumber32(sd, &bp->OutIndex));
+ }
+
+ if (numInStreams < numBindPairs)
+ return SZ_ERROR_UNSUPPORTED;
+
+ folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs;
+ MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc);
+
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams ; i++)
+ if (SzFolder_FindBindPairForInStream(folder, i) < 0)
+ break;
+ if (i == numInStreams)
+ return SZ_ERROR_UNSUPPORTED;
+ folder->PackStreams[0] = i;
+ }
+ else
+ for (i = 0; i < numPackStreams; i++)
+ {
+ RINOK(SzReadNumber32(sd, folder->PackStreams + i));
+ }
+ return SZ_OK;
+}
+
+static SRes SzReadUnpackInfo(
+ CSzData *sd,
+ UInt32 *numFolders,
+ CSzFolder **folders, /* for alloc */
+ ISzAlloc *alloc,
+ ISzAlloc *allocTemp)
+{
+ UInt32 i;
+ RINOK(SzWaitAttribute(sd, k7zIdFolder));
+ RINOK(SzReadNumber32(sd, numFolders));
+ {
+ RINOK(SzReadSwitch(sd));
+
+ MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc);
+
+ for (i = 0; i < *numFolders; i++)
+ SzFolder_Init((*folders) + i);
+
+ for (i = 0; i < *numFolders; i++)
+ {
+ RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc));
+ }
+ }
+
+ RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize));
+
+ for (i = 0; i < *numFolders; i++)
+ {
+ UInt32 j;
+ CSzFolder *folder = (*folders) + i;
+ UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder);
+
+ MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc);
+
+ for (j = 0; j < numOutStreams; j++)
+ {
+ RINOK(SzReadNumber(sd, folder->UnpackSizes + j));
+ }
+ }
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type == k7zIdCRC)
+ {
+ SRes res;
+ Byte *crcsDefined = 0;
+ UInt32 *crcs = 0;
+ res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp);
+ if (res == SZ_OK)
+ {
+ for (i = 0; i < *numFolders; i++)
+ {
+ CSzFolder *folder = (*folders) + i;
+ folder->UnpackCRCDefined = crcsDefined[i];
+ folder->UnpackCRC = crcs[i];
+ }
+ }
+ IAlloc_Free(allocTemp, crcs);
+ IAlloc_Free(allocTemp, crcsDefined);
+ RINOK(res);
+ continue;
+ }
+ RINOK(SzSkeepData(sd));
+ }
+}
+
+static SRes SzReadSubStreamsInfo(
+ CSzData *sd,
+ UInt32 numFolders,
+ CSzFolder *folders,
+ UInt32 *numUnpackStreams,
+ UInt64 **unpackSizes,
+ Byte **digestsDefined,
+ UInt32 **digests,
+ ISzAlloc *allocTemp)
+{
+ UInt64 type = 0;
+ UInt32 i;
+ UInt32 si = 0;
+ UInt32 numDigests = 0;
+
+ for (i = 0; i < numFolders; i++)
+ folders[i].NumUnpackStreams = 1;
+ *numUnpackStreams = numFolders;
+
+ for (;;)
+ {
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdNumUnpackStream)
+ {
+ *numUnpackStreams = 0;
+ for (i = 0; i < numFolders; i++)
+ {
+ UInt32 numStreams;
+ RINOK(SzReadNumber32(sd, &numStreams));
+ folders[i].NumUnpackStreams = numStreams;
+ *numUnpackStreams += numStreams;
+ }
+ continue;
+ }
+ if (type == k7zIdCRC || type == k7zIdSize)
+ break;
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SzSkeepData(sd));
+ }
+
+ if (*numUnpackStreams == 0)
+ {
+ *unpackSizes = 0;
+ *digestsDefined = 0;
+ *digests = 0;
+ }
+ else
+ {
+ *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64));
+ RINOM(*unpackSizes);
+ *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte));
+ RINOM(*digestsDefined);
+ *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32));
+ RINOM(*digests);
+ }
+
+ for (i = 0; i < numFolders; i++)
+ {
+ /*
+ v3.13 incorrectly worked with empty folders
+ v4.07: we check that folder is empty
+ */
+ UInt64 sum = 0;
+ UInt32 j;
+ UInt32 numSubstreams = folders[i].NumUnpackStreams;
+ if (numSubstreams == 0)
+ continue;
+ if (type == k7zIdSize)
+ for (j = 1; j < numSubstreams; j++)
+ {
+ UInt64 size;
+ RINOK(SzReadNumber(sd, &size));
+ (*unpackSizes)[si++] = size;
+ sum += size;
+ }
+ (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum;
+ }
+ if (type == k7zIdSize)
+ {
+ RINOK(SzReadID(sd, &type));
+ }
+
+ for (i = 0; i < *numUnpackStreams; i++)
+ {
+ (*digestsDefined)[i] = 0;
+ (*digests)[i] = 0;
+ }
+
+
+ for (i = 0; i < numFolders; i++)
+ {
+ UInt32 numSubstreams = folders[i].NumUnpackStreams;
+ if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
+ numDigests += numSubstreams;
+ }
+
+
+ si = 0;
+ for (;;)
+ {
+ if (type == k7zIdCRC)
+ {
+ int digestIndex = 0;
+ Byte *digestsDefined2 = 0;
+ UInt32 *digests2 = 0;
+ SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp);
+ if (res == SZ_OK)
+ {
+ for (i = 0; i < numFolders; i++)
+ {
+ CSzFolder *folder = folders + i;
+ UInt32 numSubstreams = folder->NumUnpackStreams;
+ if (numSubstreams == 1 && folder->UnpackCRCDefined)
+ {
+ (*digestsDefined)[si] = 1;
+ (*digests)[si] = folder->UnpackCRC;
+ si++;
+ }
+ else
+ {
+ UInt32 j;
+ for (j = 0; j < numSubstreams; j++, digestIndex++)
+ {
+ (*digestsDefined)[si] = digestsDefined2[digestIndex];
+ (*digests)[si] = digests2[digestIndex];
+ si++;
+ }
+ }
+ }
+ }
+ IAlloc_Free(allocTemp, digestsDefined2);
+ IAlloc_Free(allocTemp, digests2);
+ RINOK(res);
+ }
+ else if (type == k7zIdEnd)
+ return SZ_OK;
+ else
+ {
+ RINOK(SzSkeepData(sd));
+ }
+ RINOK(SzReadID(sd, &type));
+ }
+}
+
+
+static SRes SzReadStreamsInfo(
+ CSzData *sd,
+ UInt64 *dataOffset,
+ CSzAr *p,
+ UInt32 *numUnpackStreams,
+ UInt64 **unpackSizes, /* allocTemp */
+ Byte **digestsDefined, /* allocTemp */
+ UInt32 **digests, /* allocTemp */
+ ISzAlloc *alloc,
+ ISzAlloc *allocTemp)
+{
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if ((UInt64)(int)type != type)
+ return SZ_ERROR_UNSUPPORTED;
+ switch((int)type)
+ {
+ case k7zIdEnd:
+ return SZ_OK;
+ case k7zIdPackInfo:
+ {
+ RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams,
+ &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc));
+ break;
+ }
+ case k7zIdUnpackInfo:
+ {
+ RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp));
+ break;
+ }
+ case k7zIdSubStreamsInfo:
+ {
+ RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders,
+ numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp));
+ break;
+ }
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ }
+}
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+ size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+ if (dest != 0)
+ {
+ size_t i;
+ const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2);
+ for (i = 0; i < len; i++)
+ dest[i] = GetUi16(src + i * 2);
+ }
+ return len;
+}
+
+static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes)
+{
+ UInt32 i;
+ size_t pos = 0;
+ for (i = 0; i < numFiles; i++)
+ {
+ sizes[i] = pos;
+ for (;;)
+ {
+ if (pos >= size)
+ return SZ_ERROR_ARCHIVE;
+ if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0)
+ break;
+ pos++;
+ }
+ pos++;
+ }
+ sizes[i] = pos;
+ return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+}
+
+static SRes SzReadHeader2(
+ CSzArEx *p, /* allocMain */
+ CSzData *sd,
+ UInt64 **unpackSizes, /* allocTemp */
+ Byte **digestsDefined, /* allocTemp */
+ UInt32 **digests, /* allocTemp */
+ Byte **emptyStreamVector, /* allocTemp */
+ Byte **emptyFileVector, /* allocTemp */
+ Byte **lwtVector, /* allocTemp */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt64 type;
+ UInt32 numUnpackStreams = 0;
+ UInt32 numFiles = 0;
+ CSzFileItem *files = 0;
+ UInt32 numEmptyStreams = 0;
+ UInt32 i;
+
+ RINOK(SzReadID(sd, &type));
+
+ if (type == k7zIdArchiveProperties)
+ {
+ RINOK(SzReadArchiveProperties(sd));
+ RINOK(SzReadID(sd, &type));
+ }
+
+
+ if (type == k7zIdMainStreamsInfo)
+ {
+ RINOK(SzReadStreamsInfo(sd,
+ &p->dataPos,
+ &p->db,
+ &numUnpackStreams,
+ unpackSizes,
+ digestsDefined,
+ digests, allocMain, allocTemp));
+ p->dataPos += p->startPosAfterHeader;
+ RINOK(SzReadID(sd, &type));
+ }
+
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type != k7zIdFilesInfo)
+ return SZ_ERROR_ARCHIVE;
+
+ RINOK(SzReadNumber32(sd, &numFiles));
+ p->db.NumFiles = numFiles;
+
+ MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain);
+
+ p->db.Files = files;
+ for (i = 0; i < numFiles; i++)
+ SzFile_Init(files + i);
+
+ for (;;)
+ {
+ UInt64 type;
+ UInt64 size;
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SzReadNumber(sd, &size));
+ if (size > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ if ((UInt64)(int)type != type)
+ {
+ RINOK(SzSkeepDataSize(sd, size));
+ }
+ else
+ switch((int)type)
+ {
+ case k7zIdName:
+ {
+ size_t namesSize;
+ RINOK(SzReadSwitch(sd));
+ namesSize = (size_t)size - 1;
+ if ((namesSize & 1) != 0)
+ return SZ_ERROR_ARCHIVE;
+ if (!Buf_Create(&p->FileNames, namesSize, allocMain))
+ return SZ_ERROR_MEM;
+ MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
+ memcpy(p->FileNames.data, sd->Data, namesSize);
+ RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets))
+ RINOK(SzSkeepDataSize(sd, namesSize));
+ break;
+ }
+ case k7zIdEmptyStream:
+ {
+ RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp));
+ numEmptyStreams = 0;
+ for (i = 0; i < numFiles; i++)
+ if ((*emptyStreamVector)[i])
+ numEmptyStreams++;
+ break;
+ }
+ case k7zIdEmptyFile:
+ {
+ RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp));
+ break;
+ }
+ case k7zIdWinAttributes:
+ {
+ RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
+ RINOK(SzReadSwitch(sd));
+ for (i = 0; i < numFiles; i++)
+ {
+ CSzFileItem *f = &files[i];
+ Byte defined = (*lwtVector)[i];
+ f->AttribDefined = defined;
+ f->Attrib = 0;
+ if (defined)
+ {
+ RINOK(SzReadUInt32(sd, &f->Attrib));
+ }
+ }
+ IAlloc_Free(allocTemp, *lwtVector);
+ *lwtVector = NULL;
+ break;
+ }
+ case k7zIdMTime:
+ {
+ RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
+ RINOK(SzReadSwitch(sd));
+ for (i = 0; i < numFiles; i++)
+ {
+ CSzFileItem *f = &files[i];
+ Byte defined = (*lwtVector)[i];
+ f->MTimeDefined = defined;
+ f->MTime.Low = f->MTime.High = 0;
+ if (defined)
+ {
+ RINOK(SzReadUInt32(sd, &f->MTime.Low));
+ RINOK(SzReadUInt32(sd, &f->MTime.High));
+ }
+ }
+ IAlloc_Free(allocTemp, *lwtVector);
+ *lwtVector = NULL;
+ break;
+ }
+ default:
+ {
+ RINOK(SzSkeepDataSize(sd, size));
+ }
+ }
+ }
+
+ {
+ UInt32 emptyFileIndex = 0;
+ UInt32 sizeIndex = 0;
+ for (i = 0; i < numFiles; i++)
+ {
+ CSzFileItem *file = files + i;
+ file->IsAnti = 0;
+ if (*emptyStreamVector == 0)
+ file->HasStream = 1;
+ else
+ file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1);
+ if (file->HasStream)
+ {
+ file->IsDir = 0;
+ file->Size = (*unpackSizes)[sizeIndex];
+ file->Crc = (*digests)[sizeIndex];
+ file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex];
+ sizeIndex++;
+ }
+ else
+ {
+ if (*emptyFileVector == 0)
+ file->IsDir = 1;
+ else
+ file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1);
+ emptyFileIndex++;
+ file->Size = 0;
+ file->Crc = 0;
+ file->CrcDefined = 0;
+ }
+ }
+ }
+ return SzArEx_Fill(p, allocMain);
+}
+
+static SRes SzReadHeader(
+ CSzArEx *p,
+ CSzData *sd,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt64 *unpackSizes = 0;
+ Byte *digestsDefined = 0;
+ UInt32 *digests = 0;
+ Byte *emptyStreamVector = 0;
+ Byte *emptyFileVector = 0;
+ Byte *lwtVector = 0;
+ SRes res = SzReadHeader2(p, sd,
+ &unpackSizes, &digestsDefined, &digests,
+ &emptyStreamVector, &emptyFileVector, &lwtVector,
+ allocMain, allocTemp);
+ IAlloc_Free(allocTemp, unpackSizes);
+ IAlloc_Free(allocTemp, digestsDefined);
+ IAlloc_Free(allocTemp, digests);
+ IAlloc_Free(allocTemp, emptyStreamVector);
+ IAlloc_Free(allocTemp, emptyFileVector);
+ IAlloc_Free(allocTemp, lwtVector);
+ return res;
+}
+
+static SRes SzReadAndDecodePackedStreams2(
+ ILookInStream *inStream,
+ CSzData *sd,
+ CBuf *outBuffer,
+ UInt64 baseOffset,
+ CSzAr *p,
+ UInt64 **unpackSizes,
+ Byte **digestsDefined,
+ UInt32 **digests,
+ ISzAlloc *allocTemp)
+{
+
+ UInt32 numUnpackStreams = 0;
+ UInt64 dataStartPos;
+ CSzFolder *folder;
+ UInt64 unpackSize;
+ SRes res;
+
+ RINOK(SzReadStreamsInfo(sd, &dataStartPos, p,
+ &numUnpackStreams, unpackSizes, digestsDefined, digests,
+ allocTemp, allocTemp));
+
+ dataStartPos += baseOffset;
+ if (p->NumFolders != 1)
+ return SZ_ERROR_ARCHIVE;
+
+ folder = p->Folders;
+ unpackSize = SzFolder_GetUnpackSize(folder);
+
+ RINOK(LookInStream_SeekTo(inStream, dataStartPos));
+
+ if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp))
+ return SZ_ERROR_MEM;
+
+ res = SzFolder_Decode(folder, p->PackSizes,
+ inStream, dataStartPos,
+ outBuffer->data, (size_t)unpackSize, allocTemp);
+ RINOK(res);
+ if (folder->UnpackCRCDefined)
+ if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC)
+ return SZ_ERROR_CRC;
+ return SZ_OK;
+}
+
+static SRes SzReadAndDecodePackedStreams(
+ ILookInStream *inStream,
+ CSzData *sd,
+ CBuf *outBuffer,
+ UInt64 baseOffset,
+ ISzAlloc *allocTemp)
+{
+ CSzAr p;
+ UInt64 *unpackSizes = 0;
+ Byte *digestsDefined = 0;
+ UInt32 *digests = 0;
+ SRes res;
+ SzAr_Init(&p);
+ res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset,
+ &p, &unpackSizes, &digestsDefined, &digests,
+ allocTemp);
+ SzAr_Free(&p, allocTemp);
+ IAlloc_Free(allocTemp, unpackSizes);
+ IAlloc_Free(allocTemp, digestsDefined);
+ IAlloc_Free(allocTemp, digests);
+ return res;
+}
+
+static SRes SzArEx_Open2(
+ CSzArEx *p,
+ ILookInStream *inStream,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ Byte header[k7zStartHeaderSize];
+ Int64 startArcPos;
+ UInt64 nextHeaderOffset, nextHeaderSize;
+ size_t nextHeaderSizeT;
+ UInt32 nextHeaderCRC;
+ CBuf buffer;
+ SRes res;
+
+ startArcPos = 0;
+ RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
+
+ RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
+
+ if (!TestSignatureCandidate(header))
+ return SZ_ERROR_NO_ARCHIVE;
+ if (header[6] != k7zMajorVersion)
+ return SZ_ERROR_UNSUPPORTED;
+
+ nextHeaderOffset = GetUi64(header + 12);
+ nextHeaderSize = GetUi64(header + 20);
+ nextHeaderCRC = GetUi32(header + 28);
+
+ p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
+
+ if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
+ return SZ_ERROR_CRC;
+
+ nextHeaderSizeT = (size_t)nextHeaderSize;
+ if (nextHeaderSizeT != nextHeaderSize)
+ return SZ_ERROR_MEM;
+ if (nextHeaderSizeT == 0)
+ return SZ_OK;
+ if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
+ nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
+ return SZ_ERROR_NO_ARCHIVE;
+
+ {
+ Int64 pos = 0;
+ RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
+ if ((UInt64)pos < startArcPos + nextHeaderOffset ||
+ (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
+ (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
+ return SZ_ERROR_INPUT_EOF;
+ }
+
+ RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
+
+ if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp))
+ return SZ_ERROR_MEM;
+
+ res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT);
+ if (res == SZ_OK)
+ {
+ res = SZ_ERROR_ARCHIVE;
+ if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC)
+ {
+ CSzData sd;
+ UInt64 type;
+ sd.Data = buffer.data;
+ sd.Size = buffer.size;
+ res = SzReadID(&sd, &type);
+ if (res == SZ_OK)
+ {
+ if (type == k7zIdEncodedHeader)
+ {
+ CBuf outBuffer;
+ Buf_Init(&outBuffer);
+ res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp);
+ if (res != SZ_OK)
+ Buf_Free(&outBuffer, allocTemp);
+ else
+ {
+ Buf_Free(&buffer, allocTemp);
+ buffer.data = outBuffer.data;
+ buffer.size = outBuffer.size;
+ sd.Data = buffer.data;
+ sd.Size = buffer.size;
+ res = SzReadID(&sd, &type);
+ }
+ }
+ }
+ if (res == SZ_OK)
+ {
+ if (type == k7zIdHeader)
+ res = SzReadHeader(p, &sd, allocMain, allocTemp);
+ else
+ res = SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+ Buf_Free(&buffer, allocTemp);
+ return res;
+}
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp)
+{
+ SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
+ if (res != SZ_OK)
+ SzArEx_Free(p, allocMain);
+ return res;
+}
+
+SRes SzArEx_Extract(
+ const CSzArEx *p,
+ ILookInStream *inStream,
+ UInt32 fileIndex,
+ UInt32 *blockIndex,
+ Byte **outBuffer,
+ size_t *outBufferSize,
+ size_t *offset,
+ size_t *outSizeProcessed,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex];
+ SRes res = SZ_OK;
+ *offset = 0;
+ *outSizeProcessed = 0;
+ if (folderIndex == (UInt32)-1)
+ {
+ IAlloc_Free(allocMain, *outBuffer);
+ *blockIndex = folderIndex;
+ *outBuffer = 0;
+ *outBufferSize = 0;
+ return SZ_OK;
+ }
+
+ if (*outBuffer == 0 || *blockIndex != folderIndex)
+ {
+ CSzFolder *folder = p->db.Folders + folderIndex;
+ UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder);
+ size_t unpackSize = (size_t)unpackSizeSpec;
+ UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0);
+
+ if (unpackSize != unpackSizeSpec)
+ return SZ_ERROR_MEM;
+ *blockIndex = folderIndex;
+ IAlloc_Free(allocMain, *outBuffer);
+ *outBuffer = 0;
+
+ RINOK(LookInStream_SeekTo(inStream, startOffset));
+
+ if (res == SZ_OK)
+ {
+ *outBufferSize = unpackSize;
+ if (unpackSize != 0)
+ {
+ *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
+ if (*outBuffer == 0)
+ res = SZ_ERROR_MEM;
+ }
+ if (res == SZ_OK)
+ {
+ res = SzFolder_Decode(folder,
+ p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex],
+ inStream, startOffset,
+ *outBuffer, unpackSize, allocTemp);
+ if (res == SZ_OK)
+ {
+ if (folder->UnpackCRCDefined)
+ {
+ if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC)
+ res = SZ_ERROR_CRC;
+ }
+ }
+ }
+ }
+ }
+ if (res == SZ_OK)
+ {
+ UInt32 i;
+ CSzFileItem *fileItem = p->db.Files + fileIndex;
+ *offset = 0;
+ for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
+ *offset += (UInt32)p->db.Files[i].Size;
+ *outSizeProcessed = (size_t)fileItem->Size;
+ if (*offset + *outSizeProcessed > *outBufferSize)
+ return SZ_ERROR_FAIL;
+ if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc)
+ res = SZ_ERROR_CRC;
+ }
+ return res;
+}
diff --git a/src/libs/7zip/win/C/7zStream.c b/src/libs/7zip/win/C/7zStream.c
new file mode 100644
index 000000000..0ebb7b5f9
--- /dev/null
+++ b/src/libs/7zip/win/C/7zStream.c
@@ -0,0 +1,169 @@
+/* 7zStream.c -- 7z Stream functions
+2010-03-11 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "Types.h"
+
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(stream->Read(stream, buf, &processed));
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size)
+{
+ return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf)
+{
+ size_t processed = 1;
+ RINOK(stream->Read(stream, buf, &processed));
+ return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
+}
+
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset)
+{
+ Int64 t = offset;
+ return stream->Seek(stream, &t, SZ_SEEK_SET);
+}
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size)
+{
+ const void *lookBuf;
+ if (*size == 0)
+ return SZ_OK;
+ RINOK(stream->Look(stream, &lookBuf, size));
+ memcpy(buf, lookBuf, *size);
+ return stream->Skip(stream, *size);
+}
+
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(stream->Read(stream, buf, &processed));
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size)
+{
+ return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size > 0)
+ {
+ p->pos = 0;
+ size2 = LookToRead_BUF_SIZE;
+ res = p->realStream->Read(p->realStream, p->buf, &size2);
+ p->size = size2;
+ }
+ if (size2 < *size)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size > 0)
+ {
+ p->pos = 0;
+ if (*size > LookToRead_BUF_SIZE)
+ *size = LookToRead_BUF_SIZE;
+ res = p->realStream->Read(p->realStream, p->buf, size);
+ size2 = p->size = *size;
+ }
+ if (size2 < *size)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead_Skip(void *pp, size_t offset)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ p->pos += offset;
+ return SZ_OK;
+}
+
+static SRes LookToRead_Read(void *pp, void *buf, size_t *size)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t rem = p->size - p->pos;
+ if (rem == 0)
+ return p->realStream->Read(p->realStream, buf, size);
+ if (rem > *size)
+ rem = *size;
+ memcpy(buf, p->buf + p->pos, rem);
+ p->pos += rem;
+ *size = rem;
+ return SZ_OK;
+}
+
+static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ p->pos = p->size = 0;
+ return p->realStream->Seek(p->realStream, pos, origin);
+}
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead)
+{
+ p->s.Look = lookahead ?
+ LookToRead_Look_Lookahead :
+ LookToRead_Look_Exact;
+ p->s.Skip = LookToRead_Skip;
+ p->s.Read = LookToRead_Read;
+ p->s.Seek = LookToRead_Seek;
+}
+
+void LookToRead_Init(CLookToRead *p)
+{
+ p->pos = p->size = 0;
+}
+
+static SRes SecToLook_Read(void *pp, void *buf, size_t *size)
+{
+ CSecToLook *p = (CSecToLook *)pp;
+ return LookInStream_LookRead(p->realStream, buf, size);
+}
+
+void SecToLook_CreateVTable(CSecToLook *p)
+{
+ p->s.Read = SecToLook_Read;
+}
+
+static SRes SecToRead_Read(void *pp, void *buf, size_t *size)
+{
+ CSecToRead *p = (CSecToRead *)pp;
+ return p->realStream->Read(p->realStream, buf, size);
+}
+
+void SecToRead_CreateVTable(CSecToRead *p)
+{
+ p->s.Read = SecToRead_Read;
+}
diff --git a/src/libs/7zip/win/C/7zVersion.h b/src/libs/7zip/win/C/7zVersion.h
new file mode 100644
index 000000000..9d99c5dff
--- /dev/null
+++ b/src/libs/7zip/win/C/7zVersion.h
@@ -0,0 +1,7 @@
+#define MY_VER_MAJOR 9
+#define MY_VER_MINOR 20
+#define MY_VER_BUILD 0
+#define MY_VERSION "9.20"
+#define MY_DATE "2010-11-18"
+#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
diff --git a/src/libs/7zip/win/C/Aes.c b/src/libs/7zip/win/C/Aes.c
new file mode 100644
index 000000000..e7221cd2b
--- /dev/null
+++ b/src/libs/7zip/win/C/Aes.c
@@ -0,0 +1,282 @@
+/* Aes.c -- AES encryption / decryption
+2009-11-23 : Igor Pavlov : Public domain */
+
+#include "Aes.h"
+#include "CpuArch.h"
+
+static UInt32 T[256 * 4];
+static Byte Sbox[256] = {
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
+
+void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);
+
+void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
+
+AES_CODE_FUNC g_AesCbc_Encode;
+AES_CODE_FUNC g_AesCbc_Decode;
+AES_CODE_FUNC g_AesCtr_Code;
+
+static UInt32 D[256 * 4];
+static Byte InvS[256];
+
+static Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
+
+#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF)
+
+#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24))
+
+#define gb0(x) ( (x) & 0xFF)
+#define gb1(x) (((x) >> ( 8)) & 0xFF)
+#define gb2(x) (((x) >> (16)) & 0xFF)
+#define gb3(x) (((x) >> (24)) & 0xFF)
+
+void AesGenTables(void)
+{
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ InvS[Sbox[i]] = (Byte)i;
+ for (i = 0; i < 256; i++)
+ {
+ {
+ UInt32 a1 = Sbox[i];
+ UInt32 a2 = xtime(a1);
+ UInt32 a3 = a2 ^ a1;
+ T[ i] = Ui32(a2, a1, a1, a3);
+ T[0x100 + i] = Ui32(a3, a2, a1, a1);
+ T[0x200 + i] = Ui32(a1, a3, a2, a1);
+ T[0x300 + i] = Ui32(a1, a1, a3, a2);
+ }
+ {
+ UInt32 a1 = InvS[i];
+ UInt32 a2 = xtime(a1);
+ UInt32 a4 = xtime(a2);
+ UInt32 a8 = xtime(a4);
+ UInt32 a9 = a8 ^ a1;
+ UInt32 aB = a8 ^ a2 ^ a1;
+ UInt32 aD = a8 ^ a4 ^ a1;
+ UInt32 aE = a8 ^ a4 ^ a2;
+ D[ i] = Ui32(aE, a9, aD, aB);
+ D[0x100 + i] = Ui32(aB, aE, a9, aD);
+ D[0x200 + i] = Ui32(aD, aB, aE, a9);
+ D[0x300 + i] = Ui32(a9, aD, aB, aE);
+ }
+ }
+ g_AesCbc_Encode = AesCbc_Encode;
+ g_AesCbc_Decode = AesCbc_Decode;
+ g_AesCtr_Code = AesCtr_Code;
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (CPU_Is_Aes_Supported())
+ {
+ g_AesCbc_Encode = AesCbc_Encode_Intel;
+ g_AesCbc_Decode = AesCbc_Decode_Intel;
+ g_AesCtr_Code = AesCtr_Code_Intel;
+ }
+ #endif
+}
+
+#define HT(i, x, s) (T + (x << 8))[gb ## x(s[(i + x) & 3])]
+#define HT4(m, i, s, p) m[i] = \
+ HT(i, 0, s) ^ \
+ HT(i, 1, s) ^ \
+ HT(i, 2, s) ^ \
+ HT(i, 3, s) ^ w[p + i]
+/* such order (2031) in HT16 is for VC6/K8 speed optimization) */
+#define HT16(m, s, p) \
+ HT4(m, 2, s, p); \
+ HT4(m, 0, s, p); \
+ HT4(m, 3, s, p); \
+ HT4(m, 1, s, p); \
+
+#define FT(i, x) Sbox[gb ## x(m[(i + x) & 3])]
+#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i];
+
+#define HD(i, x, s) (D + (x << 8))[gb ## x(s[(i - x) & 3])]
+#define HD4(m, i, s, p) m[i] = \
+ HD(i, 0, s) ^ \
+ HD(i, 1, s) ^ \
+ HD(i, 2, s) ^ \
+ HD(i, 3, s) ^ w[p + i];
+/* such order (0231) in HD16 is for VC6/K8 speed optimization) */
+#define HD16(m, s, p) \
+ HD4(m, 0, s, p); \
+ HD4(m, 2, s, p); \
+ HD4(m, 3, s, p); \
+ HD4(m, 1, s, p); \
+
+#define FD(i, x) InvS[gb ## x(m[(i - x) & 3])]
+#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i];
+
+void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize)
+{
+ unsigned i, wSize;
+ wSize = keySize + 28;
+ keySize /= 4;
+ w[0] = ((UInt32)keySize / 2) + 3;
+ w += 4;
+
+ for (i = 0; i < keySize; i++, key += 4)
+ w[i] = GetUi32(key);
+
+ for (; i < wSize; i++)
+ {
+ UInt32 t = w[i - 1];
+ unsigned rem = i % keySize;
+ if (rem == 0)
+ t = Ui32(Sbox[gb1(t)] ^ Rcon[i / keySize], Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]);
+ else if (keySize > 6 && rem == 4)
+ t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]);
+ w[i] = w[i - keySize] ^ t;
+ }
+}
+
+void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize)
+{
+ unsigned i, num;
+ Aes_SetKey_Enc(w, key, keySize);
+ num = keySize + 20;
+ w += 8;
+ for (i = 0; i < num; i++)
+ {
+ UInt32 r = w[i];
+ w[i] =
+ D[ Sbox[gb0(r)]] ^
+ D[0x100 + Sbox[gb1(r)]] ^
+ D[0x200 + Sbox[gb2(r)]] ^
+ D[0x300 + Sbox[gb3(r)]];
+ }
+}
+
+/* Aes_Encode and Aes_Decode functions work with little-endian words.
+ src and dest are pointers to 4 UInt32 words.
+ arc and dest can point to same block */
+
+static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
+{
+ UInt32 s[4];
+ UInt32 m[4];
+ UInt32 numRounds2 = w[0];
+ w += 4;
+ s[0] = src[0] ^ w[0];
+ s[1] = src[1] ^ w[1];
+ s[2] = src[2] ^ w[2];
+ s[3] = src[3] ^ w[3];
+ w += 4;
+ for (;;)
+ {
+ HT16(m, s, 0);
+ if (--numRounds2 == 0)
+ break;
+ HT16(s, m, 4);
+ w += 8;
+ }
+ w += 4;
+ FT4(0); FT4(1); FT4(2); FT4(3);
+}
+
+static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
+{
+ UInt32 s[4];
+ UInt32 m[4];
+ UInt32 numRounds2 = w[0];
+ w += 4 + numRounds2 * 8;
+ s[0] = src[0] ^ w[0];
+ s[1] = src[1] ^ w[1];
+ s[2] = src[2] ^ w[2];
+ s[3] = src[3] ^ w[3];
+ for (;;)
+ {
+ w -= 8;
+ HD16(m, s, 4);
+ if (--numRounds2 == 0)
+ break;
+ HD16(s, m, 0);
+ }
+ FD4(0); FD4(1); FD4(2); FD4(3);
+}
+
+void AesCbc_Init(UInt32 *p, const Byte *iv)
+{
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ p[i] = GetUi32(iv + i * 4);
+}
+
+void MY_FAST_CALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
+ {
+ p[0] ^= GetUi32(data);
+ p[1] ^= GetUi32(data + 4);
+ p[2] ^= GetUi32(data + 8);
+ p[3] ^= GetUi32(data + 12);
+
+ Aes_Encode(p + 4, p, p);
+
+ SetUi32(data, p[0]);
+ SetUi32(data + 4, p[1]);
+ SetUi32(data + 8, p[2]);
+ SetUi32(data + 12, p[3]);
+ }
+}
+
+void MY_FAST_CALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ UInt32 in[4], out[4];
+ for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
+ {
+ in[0] = GetUi32(data);
+ in[1] = GetUi32(data + 4);
+ in[2] = GetUi32(data + 8);
+ in[3] = GetUi32(data + 12);
+
+ Aes_Decode(p + 4, out, in);
+
+ SetUi32(data, p[0] ^ out[0]);
+ SetUi32(data + 4, p[1] ^ out[1]);
+ SetUi32(data + 8, p[2] ^ out[2]);
+ SetUi32(data + 12, p[3] ^ out[3]);
+
+ p[0] = in[0];
+ p[1] = in[1];
+ p[2] = in[2];
+ p[3] = in[3];
+ }
+}
+
+void MY_FAST_CALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ for (; numBlocks != 0; numBlocks--)
+ {
+ UInt32 temp[4];
+ Byte buf[16];
+ int i;
+ if (++p[0] == 0)
+ p[1]++;
+ Aes_Encode(p + 4, temp, p);
+ SetUi32(buf, temp[0]);
+ SetUi32(buf + 4, temp[1]);
+ SetUi32(buf + 8, temp[2]);
+ SetUi32(buf + 12, temp[3]);
+ for (i = 0; i < 16; i++)
+ *data++ ^= buf[i];
+ }
+}
diff --git a/src/libs/7zip/win/C/Aes.h b/src/libs/7zip/win/C/Aes.h
new file mode 100644
index 000000000..c9b0677c8
--- /dev/null
+++ b/src/libs/7zip/win/C/Aes.h
@@ -0,0 +1,38 @@
+/* Aes.h -- AES encryption / decryption
+2009-11-23 : Igor Pavlov : Public domain */
+
+#ifndef __AES_H
+#define __AES_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+#define AES_BLOCK_SIZE 16
+
+/* Call AesGenTables one time before other AES functions */
+void AesGenTables(void);
+
+/* UInt32 pointers must be 16-byte aligned */
+
+/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */
+#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4)
+
+/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */
+/* keySize = 16 or 24 or 32 (bytes) */
+typedef void (MY_FAST_CALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize);
+void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize);
+void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize);
+
+/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */
+void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */
+/* data - 16-byte aligned pointer to data */
+/* numBlocks - the number of 16-byte blocks in data array */
+typedef void (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks);
+extern AES_CODE_FUNC g_AesCbc_Encode;
+extern AES_CODE_FUNC g_AesCbc_Decode;
+extern AES_CODE_FUNC g_AesCtr_Code;
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/AesOpt.c b/src/libs/7zip/win/C/AesOpt.c
new file mode 100644
index 000000000..c0bd8bc15
--- /dev/null
+++ b/src/libs/7zip/win/C/AesOpt.c
@@ -0,0 +1,182 @@
+/* AesOpt.c -- Intel's AES
+2009-11-23 : Igor Pavlov : Public domain */
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+#if _MSC_VER >= 1500
+//#define USE_INTEL_AES
+#endif
+#endif
+
+#ifdef USE_INTEL_AES
+
+#include <wmmintrin.h>
+
+void MY_FAST_CALL AesCbc_Encode_Intel(__m128i *p, __m128i *data, size_t numBlocks)
+{
+ __m128i m = *p;
+ for (; numBlocks != 0; numBlocks--, data++)
+ {
+ UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;
+ const __m128i *w = p + 3;
+ m = _mm_xor_si128(m, *data);
+ m = _mm_xor_si128(m, p[2]);
+ do
+ {
+ m = _mm_aesenc_si128(m, w[0]);
+ m = _mm_aesenc_si128(m, w[1]);
+ w += 2;
+ }
+ while (--numRounds2 != 0);
+ m = _mm_aesenc_si128(m, w[0]);
+ m = _mm_aesenclast_si128(m, w[1]);
+ *data = m;
+ }
+ *p = m;
+}
+
+#define NUM_WAYS 3
+
+#define AES_OP_W(op, n) { \
+ const __m128i t = w[n]; \
+ m0 = op(m0, t); \
+ m1 = op(m1, t); \
+ m2 = op(m2, t); \
+ }
+
+#define AES_DEC(n) AES_OP_W(_mm_aesdec_si128, n)
+#define AES_DEC_LAST(n) AES_OP_W(_mm_aesdeclast_si128, n)
+#define AES_ENC(n) AES_OP_W(_mm_aesenc_si128, n)
+#define AES_ENC_LAST(n) AES_OP_W(_mm_aesenclast_si128, n)
+
+void MY_FAST_CALL AesCbc_Decode_Intel(__m128i *p, __m128i *data, size_t numBlocks)
+{
+ __m128i iv = *p;
+ for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS)
+ {
+ UInt32 numRounds2 = *(const UInt32 *)(p + 1);
+ const __m128i *w = p + numRounds2 * 2;
+ __m128i m0, m1, m2;
+ {
+ const __m128i t = w[2];
+ m0 = _mm_xor_si128(t, data[0]);
+ m1 = _mm_xor_si128(t, data[1]);
+ m2 = _mm_xor_si128(t, data[2]);
+ }
+ numRounds2--;
+ do
+ {
+ AES_DEC(1)
+ AES_DEC(0)
+ w -= 2;
+ }
+ while (--numRounds2 != 0);
+ AES_DEC(1)
+ AES_DEC_LAST(0)
+
+ {
+ __m128i t;
+ t = _mm_xor_si128(m0, iv); iv = data[0]; data[0] = t;
+ t = _mm_xor_si128(m1, iv); iv = data[1]; data[1] = t;
+ t = _mm_xor_si128(m2, iv); iv = data[2]; data[2] = t;
+ }
+ }
+ for (; numBlocks != 0; numBlocks--, data++)
+ {
+ UInt32 numRounds2 = *(const UInt32 *)(p + 1);
+ const __m128i *w = p + numRounds2 * 2;
+ __m128i m = _mm_xor_si128(w[2], *data);
+ numRounds2--;
+ do
+ {
+ m = _mm_aesdec_si128(m, w[1]);
+ m = _mm_aesdec_si128(m, w[0]);
+ w -= 2;
+ }
+ while (--numRounds2 != 0);
+ m = _mm_aesdec_si128(m, w[1]);
+ m = _mm_aesdeclast_si128(m, w[0]);
+
+ m = _mm_xor_si128(m, iv);
+ iv = *data;
+ *data = m;
+ }
+ *p = iv;
+}
+
+void MY_FAST_CALL AesCtr_Code_Intel(__m128i *p, __m128i *data, size_t numBlocks)
+{
+ __m128i ctr = *p;
+ __m128i one;
+ one.m128i_u64[0] = 1;
+ one.m128i_u64[1] = 0;
+ for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS)
+ {
+ UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;
+ const __m128i *w = p;
+ __m128i m0, m1, m2;
+ {
+ const __m128i t = w[2];
+ ctr = _mm_add_epi64(ctr, one); m0 = _mm_xor_si128(ctr, t);
+ ctr = _mm_add_epi64(ctr, one); m1 = _mm_xor_si128(ctr, t);
+ ctr = _mm_add_epi64(ctr, one); m2 = _mm_xor_si128(ctr, t);
+ }
+ w += 3;
+ do
+ {
+ AES_ENC(0)
+ AES_ENC(1)
+ w += 2;
+ }
+ while (--numRounds2 != 0);
+ AES_ENC(0)
+ AES_ENC_LAST(1)
+ data[0] = _mm_xor_si128(data[0], m0);
+ data[1] = _mm_xor_si128(data[1], m1);
+ data[2] = _mm_xor_si128(data[2], m2);
+ }
+ for (; numBlocks != 0; numBlocks--, data++)
+ {
+ UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;
+ const __m128i *w = p;
+ __m128i m;
+ ctr = _mm_add_epi64(ctr, one);
+ m = _mm_xor_si128(ctr, p[2]);
+ w += 3;
+ do
+ {
+ m = _mm_aesenc_si128(m, w[0]);
+ m = _mm_aesenc_si128(m, w[1]);
+ w += 2;
+ }
+ while (--numRounds2 != 0);
+ m = _mm_aesenc_si128(m, w[0]);
+ m = _mm_aesenclast_si128(m, w[1]);
+ *data = _mm_xor_si128(*data, m);
+ }
+ *p = ctr;
+}
+
+#else
+
+void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);
+void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);
+
+void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ AesCbc_Encode(p, data, numBlocks);
+}
+
+void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ AesCbc_Decode(p, data, numBlocks);
+}
+
+void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ AesCtr_Code(p, data, numBlocks);
+}
+
+#endif
diff --git a/src/libs/7zip/win/C/Alloc.c b/src/libs/7zip/win/C/Alloc.c
new file mode 100644
index 000000000..358a7b526
--- /dev/null
+++ b/src/libs/7zip/win/C/Alloc.c
@@ -0,0 +1,127 @@
+/* Alloc.c -- Memory allocation functions
+2008-09-24
+Igor Pavlov
+Public domain */
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <stdlib.h>
+
+#include "Alloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef _SZ_ALLOC_DEBUG
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountMid = 0;
+int g_allocCountBig = 0;
+#endif
+
+void *MyAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ {
+ void *p = malloc(size);
+ fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p);
+ return p;
+ }
+ #else
+ return malloc(size);
+ #endif
+}
+
+void MyFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address);
+ #endif
+ free(address);
+}
+
+#ifdef _WIN32
+
+void *MidAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++);
+ #endif
+ return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void MidFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
+ #endif
+ if (address == 0)
+ return;
+ VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#ifndef MEM_LARGE_PAGES
+#undef _7ZIP_LARGE_PAGES
+#endif
+
+#ifdef _7ZIP_LARGE_PAGES
+SIZE_T g_LargePageSize = 0;
+typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
+#endif
+
+void SetLargePageSize()
+{
+ #ifdef _7ZIP_LARGE_PAGES
+ SIZE_T size = 0;
+ GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
+ GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
+ if (largePageMinimum == 0)
+ return;
+ size = largePageMinimum();
+ if (size == 0 || (size & (size - 1)) != 0)
+ return;
+ g_LargePageSize = size;
+ #endif
+}
+
+
+void *BigAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++);
+ #endif
+
+ #ifdef _7ZIP_LARGE_PAGES
+ if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18))
+ {
+ void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)),
+ MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+ if (res != 0)
+ return res;
+ }
+ #endif
+ return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void BigFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
+ #endif
+
+ if (address == 0)
+ return;
+ VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#endif
diff --git a/src/libs/7zip/win/C/Alloc.h b/src/libs/7zip/win/C/Alloc.h
new file mode 100644
index 000000000..b8e414367
--- /dev/null
+++ b/src/libs/7zip/win/C/Alloc.h
@@ -0,0 +1,38 @@
+/* Alloc.h -- Memory allocation functions
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __COMMON_ALLOC_H
+#define __COMMON_ALLOC_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *MyAlloc(size_t size);
+void MyFree(void *address);
+
+#ifdef _WIN32
+
+void SetLargePageSize();
+
+void *MidAlloc(size_t size);
+void MidFree(void *address);
+void *BigAlloc(size_t size);
+void BigFree(void *address);
+
+#else
+
+#define MidAlloc(size) MyAlloc(size)
+#define MidFree(address) MyFree(address)
+#define BigAlloc(size) MyAlloc(size)
+#define BigFree(address) MyFree(address)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/Bcj2.c b/src/libs/7zip/win/C/Bcj2.c
new file mode 100644
index 000000000..20199ce56
--- /dev/null
+++ b/src/libs/7zip/win/C/Bcj2.c
@@ -0,0 +1,132 @@
+/* Bcj2.c -- Converter for x86 code (BCJ2)
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Bcj2.h"
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
+#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*buffer++)
+#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
+#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \
+ { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }}
+
+#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; }
+
+#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;
+
+int Bcj2_Decode(
+ const Byte *buf0, SizeT size0,
+ const Byte *buf1, SizeT size1,
+ const Byte *buf2, SizeT size2,
+ const Byte *buf3, SizeT size3,
+ Byte *outBuf, SizeT outSize)
+{
+ CProb p[256 + 2];
+ SizeT inPos = 0, outPos = 0;
+
+ const Byte *buffer, *bufferLim;
+ UInt32 range, code;
+ Byte prevByte = 0;
+
+ unsigned int i;
+ for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
+ p[i] = kBitModelTotal >> 1;
+
+ buffer = buf3;
+ bufferLim = buffer + size3;
+ RC_INIT2
+
+ if (outSize == 0)
+ return SZ_OK;
+
+ for (;;)
+ {
+ Byte b;
+ CProb *prob;
+ UInt32 bound;
+ UInt32 ttt;
+
+ SizeT limit = size0 - inPos;
+ if (outSize - outPos < limit)
+ limit = outSize - outPos;
+ while (limit != 0)
+ {
+ Byte b = buf0[inPos];
+ outBuf[outPos++] = b;
+ if (IsJ(prevByte, b))
+ break;
+ inPos++;
+ prevByte = b;
+ limit--;
+ }
+
+ if (limit == 0 || outPos == outSize)
+ break;
+
+ b = buf0[inPos++];
+
+ if (b == 0xE8)
+ prob = p + prevByte;
+ else if (b == 0xE9)
+ prob = p + 256;
+ else
+ prob = p + 257;
+
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob)
+ prevByte = b;
+ }
+ else
+ {
+ UInt32 dest;
+ const Byte *v;
+ UPDATE_1(prob)
+ if (b == 0xE8)
+ {
+ v = buf1;
+ if (size1 < 4)
+ return SZ_ERROR_DATA;
+ buf1 += 4;
+ size1 -= 4;
+ }
+ else
+ {
+ v = buf2;
+ if (size2 < 4)
+ return SZ_ERROR_DATA;
+ buf2 += 4;
+ size2 -= 4;
+ }
+ dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) |
+ ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4);
+ outBuf[outPos++] = (Byte)dest;
+ if (outPos == outSize)
+ break;
+ outBuf[outPos++] = (Byte)(dest >> 8);
+ if (outPos == outSize)
+ break;
+ outBuf[outPos++] = (Byte)(dest >> 16);
+ if (outPos == outSize)
+ break;
+ outBuf[outPos++] = prevByte = (Byte)(dest >> 24);
+ }
+ }
+ return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA;
+}
diff --git a/src/libs/7zip/win/C/Bcj2.h b/src/libs/7zip/win/C/Bcj2.h
new file mode 100644
index 000000000..dbc054148
--- /dev/null
+++ b/src/libs/7zip/win/C/Bcj2.h
@@ -0,0 +1,38 @@
+/* Bcj2.h -- Converter for x86 code (BCJ2)
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __BCJ2_H
+#define __BCJ2_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Conditions:
+ outSize <= FullOutputSize,
+ where FullOutputSize is full size of output stream of x86_2 filter.
+
+If buf0 overlaps outBuf, there are two required conditions:
+ 1) (buf0 >= outBuf)
+ 2) (buf0 + size0 >= outBuf + FullOutputSize).
+
+Returns:
+ SZ_OK
+ SZ_ERROR_DATA - Data error
+*/
+
+int Bcj2_Decode(
+ const Byte *buf0, SizeT size0,
+ const Byte *buf1, SizeT size1,
+ const Byte *buf2, SizeT size2,
+ const Byte *buf3, SizeT size3,
+ Byte *outBuf, SizeT outSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/Bra.c b/src/libs/7zip/win/C/Bra.c
new file mode 100644
index 000000000..2e47b1413
--- /dev/null
+++ b/src/libs/7zip/win/C/Bra.c
@@ -0,0 +1,133 @@
+/* Bra.c -- Converters for RISC code
+2010-04-16 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ ip += 8;
+ for (i = 0; i <= size; i += 4)
+ {
+ if (data[i + 3] == 0xEB)
+ {
+ UInt32 dest;
+ UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]);
+ src <<= 2;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ dest >>= 2;
+ data[i + 2] = (Byte)(dest >> 16);
+ data[i + 1] = (Byte)(dest >> 8);
+ data[i + 0] = (Byte)dest;
+ }
+ }
+ return i;
+}
+
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ ip += 4;
+ for (i = 0; i <= size; i += 2)
+ {
+ if ((data[i + 1] & 0xF8) == 0xF0 &&
+ (data[i + 3] & 0xF8) == 0xF8)
+ {
+ UInt32 dest;
+ UInt32 src =
+ (((UInt32)data[i + 1] & 0x7) << 19) |
+ ((UInt32)data[i + 0] << 11) |
+ (((UInt32)data[i + 3] & 0x7) << 8) |
+ (data[i + 2]);
+
+ src <<= 1;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ dest >>= 1;
+
+ data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7));
+ data[i + 0] = (Byte)(dest >> 11);
+ data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7));
+ data[i + 2] = (Byte)dest;
+ i += 2;
+ }
+ }
+ return i;
+}
+
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ for (i = 0; i <= size; i += 4)
+ {
+ if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1)
+ {
+ UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3] & (~3));
+
+ UInt32 dest;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3));
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] &= 0x3;
+ data[i + 3] |= dest;
+ }
+ }
+ return i;
+}
+
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ UInt32 i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ for (i = 0; i <= size; i += 4)
+ {
+ if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) ||
+ (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0))
+ {
+ UInt32 src =
+ ((UInt32)data[i + 0] << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3]);
+ UInt32 dest;
+
+ src <<= 2;
+ if (encoding)
+ dest = ip + i + src;
+ else
+ dest = src - (ip + i);
+ dest >>= 2;
+
+ dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
+
+ data[i + 0] = (Byte)(dest >> 24);
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] = (Byte)dest;
+ }
+ }
+ return i;
+}
diff --git a/src/libs/7zip/win/C/Bra.h b/src/libs/7zip/win/C/Bra.h
new file mode 100644
index 000000000..5748c1c05
--- /dev/null
+++ b/src/libs/7zip/win/C/Bra.h
@@ -0,0 +1,68 @@
+/* Bra.h -- Branch converters for executables
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __BRA_H
+#define __BRA_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+These functions convert relative addresses to absolute addresses
+in CALL instructions to increase the compression ratio.
+
+ In:
+ data - data buffer
+ size - size of data
+ ip - current virtual Instruction Pinter (IP) value
+ state - state variable for x86 converter
+ encoding - 0 (for decoding), 1 (for encoding)
+
+ Out:
+ state - state variable for x86 converter
+
+ Returns:
+ The number of processed bytes. If you call these functions with multiple calls,
+ you must start next call with first byte after block of processed bytes.
+
+ Type Endian Alignment LookAhead
+
+ x86 little 1 4
+ ARMT little 2 2
+ ARM little 4 0
+ PPC big 4 0
+ SPARC big 4 0
+ IA64 little 16 0
+
+ size must be >= Alignment + LookAhead, if it's not last block.
+ If (size < Alignment + LookAhead), converter returns 0.
+
+ Example:
+
+ UInt32 ip = 0;
+ for ()
+ {
+ ; size must be >= Alignment + LookAhead, if it's not last block
+ SizeT processed = Convert(data, size, ip, 1);
+ data += processed;
+ size -= processed;
+ ip += processed;
+ }
+*/
+
+#define x86_Convert_Init(state) { state = 0; }
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/Bra86.c b/src/libs/7zip/win/C/Bra86.c
new file mode 100644
index 000000000..1ee0e709b
--- /dev/null
+++ b/src/libs/7zip/win/C/Bra86.c
@@ -0,0 +1,85 @@
+/* Bra86.c -- Converter for x86 code (BCJ)
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
+const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
+{
+ SizeT bufferPos = 0, prevPosT;
+ UInt32 prevMask = *state & 0x7;
+ if (size < 5)
+ return 0;
+ ip += 5;
+ prevPosT = (SizeT)0 - 1;
+
+ for (;;)
+ {
+ Byte *p = data + bufferPos;
+ Byte *limit = data + size - 4;
+ for (; p < limit; p++)
+ if ((*p & 0xFE) == 0xE8)
+ break;
+ bufferPos = (SizeT)(p - data);
+ if (p >= limit)
+ break;
+ prevPosT = bufferPos - prevPosT;
+ if (prevPosT > 3)
+ prevMask = 0;
+ else
+ {
+ prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
+ if (prevMask != 0)
+ {
+ Byte b = p[4 - kMaskToBitNumber[prevMask]];
+ if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
+ {
+ prevPosT = bufferPos;
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ continue;
+ }
+ }
+ }
+ prevPosT = bufferPos;
+
+ if (Test86MSByte(p[4]))
+ {
+ UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+ UInt32 dest;
+ for (;;)
+ {
+ Byte b;
+ int index;
+ if (encoding)
+ dest = (ip + (UInt32)bufferPos) + src;
+ else
+ dest = src - (ip + (UInt32)bufferPos);
+ if (prevMask == 0)
+ break;
+ index = kMaskToBitNumber[prevMask] * 8;
+ b = (Byte)(dest >> (24 - index));
+ if (!Test86MSByte(b))
+ break;
+ src = dest ^ ((1 << (32 - index)) - 1);
+ }
+ p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
+ p[3] = (Byte)(dest >> 16);
+ p[2] = (Byte)(dest >> 8);
+ p[1] = (Byte)dest;
+ bufferPos += 5;
+ }
+ else
+ {
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ }
+ }
+ prevPosT = bufferPos - prevPosT;
+ *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
+ return bufferPos;
+}
diff --git a/src/libs/7zip/win/C/BraIA64.c b/src/libs/7zip/win/C/BraIA64.c
new file mode 100644
index 000000000..0b4ee85bc
--- /dev/null
+++ b/src/libs/7zip/win/C/BraIA64.c
@@ -0,0 +1,67 @@
+/* BraIA64.c -- Converter for IA-64 code
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+static const Byte kBranchTable[32] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+};
+
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 16)
+ return 0;
+ size -= 16;
+ for (i = 0; i <= size; i += 16)
+ {
+ UInt32 instrTemplate = data[i] & 0x1F;
+ UInt32 mask = kBranchTable[instrTemplate];
+ UInt32 bitPos = 5;
+ int slot;
+ for (slot = 0; slot < 3; slot++, bitPos += 41)
+ {
+ UInt32 bytePos, bitRes;
+ UInt64 instruction, instNorm;
+ int j;
+ if (((mask >> slot) & 1) == 0)
+ continue;
+ bytePos = (bitPos >> 3);
+ bitRes = bitPos & 0x7;
+ instruction = 0;
+ for (j = 0; j < 6; j++)
+ instruction += (UInt64)data[i + j + bytePos] << (8 * j);
+
+ instNorm = instruction >> bitRes;
+ if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0)
+ {
+ UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
+ UInt32 dest;
+ src |= ((UInt32)(instNorm >> 36) & 1) << 20;
+
+ src <<= 4;
+
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+
+ dest >>= 4;
+
+ instNorm &= ~((UInt64)(0x8FFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
+
+ instruction &= (1 << bitRes) - 1;
+ instruction |= (instNorm << bitRes);
+ for (j = 0; j < 6; j++)
+ data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
+ }
+ }
+ }
+ return i;
+}
diff --git a/src/libs/7zip/win/C/BwtSort.c b/src/libs/7zip/win/C/BwtSort.c
new file mode 100644
index 000000000..207305072
--- /dev/null
+++ b/src/libs/7zip/win/C/BwtSort.c
@@ -0,0 +1,516 @@
+/* BwtSort.c -- BWT block sorting
+2008-08-17
+Igor Pavlov
+Public domain */
+
+#include "BwtSort.h"
+#include "Sort.h"
+
+/* #define BLOCK_SORT_USE_HEAP_SORT */
+
+#define NO_INLINE MY_FAST_CALL
+
+/* Don't change it !!! */
+#define kNumHashBytes 2
+#define kNumHashValues (1 << (kNumHashBytes * 8))
+
+/* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */
+#define kNumRefBitsMax 12
+
+#define BS_TEMP_SIZE kNumHashValues
+
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
+
+/* 32 Flags in UInt32 word */
+#define kNumFlagsBits 5
+#define kNumFlagsInWord (1 << kNumFlagsBits)
+#define kFlagsMask (kNumFlagsInWord - 1)
+#define kAllFlags 0xFFFFFFFF
+
+#else
+
+#define kNumBitsMax 20
+#define kIndexMask ((1 << kNumBitsMax) - 1)
+#define kNumExtraBits (32 - kNumBitsMax)
+#define kNumExtra0Bits (kNumExtraBits - 2)
+#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1)
+
+#define SetFinishedGroupSize(p, size) \
+ { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \
+ if ((size) > (1 << kNumExtra0Bits)) { \
+ *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \
+
+static void SetGroupSize(UInt32 *p, UInt32 size)
+{
+ if (--size == 0)
+ return;
+ *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax);
+ if (size >= (1 << kNumExtra0Bits))
+ {
+ *p |= 0x40000000;
+ p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax);
+ }
+}
+
+#endif
+
+/*
+SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks
+ "range" is not real range. It's only for optimization.
+returns: 1 - if there are groups, 0 - no more groups
+*/
+
+UInt32 NO_INLINE SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ , UInt32 left, UInt32 range
+ #endif
+ )
+{
+ UInt32 *ind2 = Indices + groupOffset;
+ UInt32 *Groups;
+ if (groupSize <= 1)
+ {
+ /*
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetFinishedGroupSize(ind2, 1);
+ #endif
+ */
+ return 0;
+ }
+ Groups = Indices + BlockSize + BS_TEMP_SIZE;
+ if (groupSize <= ((UInt32)1 << NumRefBits)
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ && groupSize <= range
+ #endif
+ )
+ {
+ UInt32 *temp = Indices + BlockSize;
+ UInt32 j;
+ UInt32 mask, thereAreGroups, group, cg;
+ {
+ UInt32 gPrev;
+ UInt32 gRes = 0;
+ {
+ UInt32 sp = ind2[0] + NumSortedBytes;
+ if (sp >= BlockSize) sp -= BlockSize;
+ gPrev = Groups[sp];
+ temp[0] = (gPrev << NumRefBits);
+ }
+
+ for (j = 1; j < groupSize; j++)
+ {
+ UInt32 sp = ind2[j] + NumSortedBytes;
+ UInt32 g;
+ if (sp >= BlockSize) sp -= BlockSize;
+ g = Groups[sp];
+ temp[j] = (g << NumRefBits) | j;
+ gRes |= (gPrev ^ g);
+ }
+ if (gRes == 0)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ }
+
+ HeapSort(temp, groupSize);
+ mask = ((1 << NumRefBits) - 1);
+ thereAreGroups = 0;
+
+ group = groupOffset;
+ cg = (temp[0] >> NumRefBits);
+ temp[0] = ind2[temp[0] & mask];
+
+ {
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags = Groups + BlockSize;
+ #else
+ UInt32 prevGroupStart = 0;
+ #endif
+
+ for (j = 1; j < groupSize; j++)
+ {
+ UInt32 val = temp[j];
+ UInt32 cgCur = (val >> NumRefBits);
+
+ if (cgCur != cg)
+ {
+ cg = cgCur;
+ group = groupOffset + j;
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = group - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #else
+ SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
+ prevGroupStart = j;
+ #endif
+ }
+ else
+ thereAreGroups = 1;
+ {
+ UInt32 ind = ind2[val & mask];
+ temp[j] = ind;
+ Groups[ind] = group;
+ }
+ }
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
+ #endif
+ }
+
+ for (j = 0; j < groupSize; j++)
+ ind2[j] = temp[j];
+ return thereAreGroups;
+ }
+
+ /* Check that all strings are in one group (cannot sort) */
+ {
+ UInt32 group, j;
+ UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ group = Groups[sp];
+ for (j = 1; j < groupSize; j++)
+ {
+ sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] != group)
+ break;
+ }
+ if (j == groupSize)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ }
+
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ {
+ /* ---------- Range Sort ---------- */
+ UInt32 i;
+ UInt32 mid;
+ for (;;)
+ {
+ UInt32 j;
+ if (range <= 1)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ mid = left + ((range + 1) >> 1);
+ j = groupSize;
+ i = 0;
+ do
+ {
+ UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] >= mid)
+ {
+ for (j--; j > i; j--)
+ {
+ sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] < mid)
+ {
+ UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp;
+ break;
+ }
+ }
+ if (i >= j)
+ break;
+ }
+ }
+ while (++i < j);
+ if (i == 0)
+ {
+ range = range - (mid - left);
+ left = mid;
+ }
+ else if (i == groupSize)
+ range = (mid - left);
+ else
+ break;
+ }
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = (groupOffset + i - 1);
+ UInt32 *Flags = Groups + BlockSize;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #endif
+
+ {
+ UInt32 j;
+ for (j = i; j < groupSize; j++)
+ Groups[ind2[j]] = groupOffset + i;
+ }
+
+ {
+ UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left);
+ return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left));
+ }
+
+ }
+
+ #else
+
+ /* ---------- Heap Sort ---------- */
+
+ {
+ UInt32 j;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ ind2[j] = sp;
+ }
+
+ HeapSortRef(ind2, Groups, groupSize);
+
+ /* Write Flags */
+ {
+ UInt32 sp = ind2[0];
+ UInt32 group = Groups[sp];
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags = Groups + BlockSize;
+ #else
+ UInt32 prevGroupStart = 0;
+ #endif
+
+ for (j = 1; j < groupSize; j++)
+ {
+ sp = ind2[j];
+ if (Groups[sp] != group)
+ {
+ group = Groups[sp];
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = groupOffset + j - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #else
+ SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
+ prevGroupStart = j;
+ #endif
+ }
+ }
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
+ #endif
+ }
+ {
+ /* Write new Groups values and Check that there are groups */
+ UInt32 thereAreGroups = 0;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 group = groupOffset + j;
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax);
+ if ((ind2[j] & 0x40000000) != 0)
+ subGroupSize += ((ind2[j + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ subGroupSize++;
+ for (;;)
+ {
+ UInt32 original = ind2[j];
+ UInt32 sp = original & kIndexMask;
+ if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
+ ind2[j] = sp | (original & ~kIndexMask);
+ Groups[sp] = group;
+ if (--subGroupSize == 0)
+ break;
+ j++;
+ thereAreGroups = 1;
+ }
+ #else
+ UInt32 *Flags = Groups + BlockSize;
+ for (;;)
+ {
+ UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
+ ind2[j] = sp;
+ Groups[sp] = group;
+ if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0)
+ break;
+ j++;
+ thereAreGroups = 1;
+ }
+ #endif
+ }
+ return thereAreGroups;
+ }
+ }
+ #endif
+}
+
+/* conditions: blockSize > 0 */
+UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize)
+{
+ UInt32 *counters = Indices + blockSize;
+ UInt32 i;
+ UInt32 *Groups;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags;
+ #endif
+
+ /* Radix-Sort for 2 bytes */
+ for (i = 0; i < kNumHashValues; i++)
+ counters[i] = 0;
+ for (i = 0; i < blockSize - 1; i++)
+ counters[((UInt32)data[i] << 8) | data[i + 1]]++;
+ counters[((UInt32)data[i] << 8) | data[0]]++;
+
+ Groups = counters + BS_TEMP_SIZE;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ Flags = Groups + blockSize;
+ {
+ UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits;
+ for (i = 0; i < numWords; i++)
+ Flags[i] = kAllFlags;
+ }
+ #endif
+
+ {
+ UInt32 sum = 0;
+ for (i = 0; i < kNumHashValues; i++)
+ {
+ UInt32 groupSize = counters[i];
+ if (groupSize > 0)
+ {
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 t = sum + groupSize - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ #endif
+ sum += groupSize;
+ }
+ counters[i] = sum - groupSize;
+ }
+
+ for (i = 0; i < blockSize - 1; i++)
+ Groups[i] = counters[((UInt32)data[i] << 8) | data[i + 1]];
+ Groups[i] = counters[((UInt32)data[i] << 8) | data[0]];
+
+ for (i = 0; i < blockSize - 1; i++)
+ Indices[counters[((UInt32)data[i] << 8) | data[i + 1]]++] = i;
+ Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i;
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 prev = 0;
+ for (i = 0; i < kNumHashValues; i++)
+ {
+ UInt32 prevGroupSize = counters[i] - prev;
+ if (prevGroupSize == 0)
+ continue;
+ SetGroupSize(Indices + prev, prevGroupSize);
+ prev = counters[i];
+ }
+ }
+ #endif
+ }
+
+ {
+ int NumRefBits;
+ UInt32 NumSortedBytes;
+ for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++);
+ NumRefBits = 32 - NumRefBits;
+ if (NumRefBits > kNumRefBitsMax)
+ NumRefBits = kNumRefBitsMax;
+
+ for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 finishedGroupSize = 0;
+ #endif
+ UInt32 newLimit = 0;
+ for (i = 0; i < blockSize;)
+ {
+ UInt32 groupSize;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+
+ if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0)
+ {
+ i++;
+ continue;
+ }
+ for (groupSize = 1;
+ (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0;
+ groupSize++);
+
+ groupSize++;
+
+ #else
+
+ groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
+ {
+ Bool finishedGroup = ((Indices[i] & 0x80000000) == 0);
+ if ((Indices[i] & 0x40000000) != 0)
+ {
+ groupSize += ((Indices[i + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ Indices[i + 1] &= kIndexMask;
+ }
+ Indices[i] &= kIndexMask;
+ groupSize++;
+ if (finishedGroup || groupSize == 1)
+ {
+ Indices[i - finishedGroupSize] &= kIndexMask;
+ if (finishedGroupSize > 1)
+ Indices[i - finishedGroupSize + 1] &= kIndexMask;
+ {
+ UInt32 newGroupSize = groupSize + finishedGroupSize;
+ SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize);
+ finishedGroupSize = newGroupSize;
+ }
+ i += groupSize;
+ continue;
+ }
+ finishedGroupSize = 0;
+ }
+
+ #endif
+
+ if (NumSortedBytes >= blockSize)
+ {
+ UInt32 j;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 t = (i + j);
+ /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */
+ Groups[Indices[t]] = t;
+ }
+ }
+ else
+ if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ , 0, blockSize
+ #endif
+ ) != 0)
+ newLimit = i + groupSize;
+ i += groupSize;
+ }
+ if (newLimit == 0)
+ break;
+ }
+ }
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ for (i = 0; i < blockSize;)
+ {
+ UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
+ if ((Indices[i] & 0x40000000) != 0)
+ {
+ groupSize += ((Indices[i + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ Indices[i + 1] &= kIndexMask;
+ }
+ Indices[i] &= kIndexMask;
+ groupSize++;
+ i += groupSize;
+ }
+ #endif
+ return Groups[0];
+}
+
diff --git a/src/libs/7zip/win/C/BwtSort.h b/src/libs/7zip/win/C/BwtSort.h
new file mode 100644
index 000000000..ce5598f0f
--- /dev/null
+++ b/src/libs/7zip/win/C/BwtSort.h
@@ -0,0 +1,30 @@
+/* BwtSort.h -- BWT block sorting
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __BWT_SORT_H
+#define __BWT_SORT_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */
+/* #define BLOCK_SORT_EXTERNAL_FLAGS */
+
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5))
+#else
+#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0
+#endif
+
+#define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16))
+
+UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/CpuArch.c b/src/libs/7zip/win/C/CpuArch.c
new file mode 100644
index 000000000..260cc1f45
--- /dev/null
+++ b/src/libs/7zip/win/C/CpuArch.c
@@ -0,0 +1,168 @@
+/* CpuArch.c -- CPU specific code
+2010-10-26: Igor Pavlov : Public domain */
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
+#define USE_ASM
+#endif
+
+#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
+static UInt32 CheckFlag(UInt32 flag)
+{
+ #ifdef _MSC_VER
+ __asm pushfd;
+ __asm pop EAX;
+ __asm mov EDX, EAX;
+ __asm xor EAX, flag;
+ __asm push EAX;
+ __asm popfd;
+ __asm pushfd;
+ __asm pop EAX;
+ __asm xor EAX, EDX;
+ __asm push EDX;
+ __asm popfd;
+ __asm and flag, EAX;
+ #else
+ __asm__ __volatile__ (
+ "pushf\n\t"
+ "pop %%EAX\n\t"
+ "movl %%EAX,%%EDX\n\t"
+ "xorl %0,%%EAX\n\t"
+ "push %%EAX\n\t"
+ "popf\n\t"
+ "pushf\n\t"
+ "pop %%EAX\n\t"
+ "xorl %%EDX,%%EAX\n\t"
+ "push %%EDX\n\t"
+ "popf\n\t"
+ "andl %%EAX, %0\n\t":
+ "=c" (flag) : "c" (flag));
+ #endif
+ return flag;
+}
+#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
+#else
+#define CHECK_CPUID_IS_SUPPORTED
+#endif
+
+static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
+{
+ #ifdef USE_ASM
+
+ #ifdef _MSC_VER
+
+ UInt32 a2, b2, c2, d2;
+ __asm xor EBX, EBX;
+ __asm xor ECX, ECX;
+ __asm xor EDX, EDX;
+ __asm mov EAX, function;
+ __asm cpuid;
+ __asm mov a2, EAX;
+ __asm mov b2, EBX;
+ __asm mov c2, ECX;
+ __asm mov d2, EDX;
+
+ *a = a2;
+ *b = b2;
+ *c = c2;
+ *d = d2;
+
+ #else
+
+ __asm__ __volatile__ (
+ "cpuid"
+ : "=a" (*a) ,
+ "=b" (*b) ,
+ "=c" (*c) ,
+ "=d" (*d)
+ : "0" (function)) ;
+
+ #endif
+
+ #else
+
+ int CPUInfo[4];
+ __cpuid(CPUInfo, function);
+ *a = CPUInfo[0];
+ *b = CPUInfo[1];
+ *c = CPUInfo[2];
+ *d = CPUInfo[3];
+
+ #endif
+}
+
+Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
+{
+ CHECK_CPUID_IS_SUPPORTED
+ MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
+ MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
+ return True;
+}
+
+static UInt32 kVendors[][3] =
+{
+ { 0x756E6547, 0x49656E69, 0x6C65746E},
+ { 0x68747541, 0x69746E65, 0x444D4163},
+ { 0x746E6543, 0x48727561, 0x736C7561}
+};
+
+int x86cpuid_GetFirm(const Cx86cpuid *p)
+{
+ unsigned i;
+ for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
+ {
+ const UInt32 *v = kVendors[i];
+ if (v[0] == p->vendor[0] &&
+ v[1] == p->vendor[1] &&
+ v[2] == p->vendor[2])
+ return (int)i;
+ }
+ return -1;
+}
+
+Bool CPU_Is_InOrder()
+{
+ Cx86cpuid p;
+ int firm;
+ UInt32 family, model;
+ if (!x86cpuid_CheckAndRead(&p))
+ return True;
+ family = x86cpuid_GetFamily(&p);
+ model = x86cpuid_GetModel(&p);
+ firm = x86cpuid_GetFirm(&p);
+ switch (firm)
+ {
+ case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C));
+ case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
+ case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
+ }
+ return True;
+}
+
+#if !defined(MY_CPU_AMD64) && defined(_WIN32)
+static Bool CPU_Sys_Is_SSE_Supported()
+{
+ OSVERSIONINFO vi;
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ if (!GetVersionEx(&vi))
+ return False;
+ return (vi.dwMajorVersion >= 5);
+}
+#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
+#else
+#define CHECK_SYS_SSE_SUPPORT
+#endif
+
+Bool CPU_Is_Aes_Supported()
+{
+ Cx86cpuid p;
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_CheckAndRead(&p))
+ return False;
+ return (p.c >> 25) & 1;
+}
+
+#endif
diff --git a/src/libs/7zip/win/C/CpuArch.h b/src/libs/7zip/win/C/CpuArch.h
new file mode 100644
index 000000000..01930c7e6
--- /dev/null
+++ b/src/libs/7zip/win/C/CpuArch.h
@@ -0,0 +1,155 @@
+/* CpuArch.h -- CPU specific code
+2010-10-26: Igor Pavlov : Public domain */
+
+#ifndef __CPU_ARCH_H
+#define __CPU_ARCH_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+/*
+MY_CPU_LE means that CPU is LITTLE ENDIAN.
+If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
+
+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
+If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
+*/
+
+#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
+#define MY_CPU_AMD64
+#endif
+
+#if defined(MY_CPU_AMD64) || defined(_M_IA64)
+#define MY_CPU_64BIT
+#endif
+
+#if defined(_M_IX86) || defined(__i386__)
+#define MY_CPU_X86
+#endif
+
+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
+#define MY_CPU_X86_OR_AMD64
+#endif
+
+#if defined(MY_CPU_X86) || defined(_M_ARM)
+#define MY_CPU_32BIT
+#endif
+
+#if defined(_WIN32) && defined(_M_ARM)
+#define MY_CPU_ARM_LE
+#endif
+
+#if defined(_WIN32) && defined(_M_IA64)
+#define MY_CPU_IA64_LE
+#endif
+
+#if defined(MY_CPU_X86_OR_AMD64)
+#define MY_CPU_LE_UNALIGN
+#endif
+
+#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
+#define MY_CPU_LE
+#endif
+
+#if defined(__BIG_ENDIAN__)
+#define MY_CPU_BE
+#endif
+
+#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
+Stop_Compiling_Bad_Endian
+#endif
+
+#ifdef MY_CPU_LE_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(p))
+#define GetUi32(p) (*(const UInt32 *)(p))
+#define GetUi64(p) (*(const UInt64 *)(p))
+#define SetUi16(p, d) *(UInt16 *)(p) = (d);
+#define SetUi32(p, d) *(UInt32 *)(p) = (d);
+#define SetUi64(p, d) *(UInt64 *)(p) = (d);
+
+#else
+
+#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
+
+#define GetUi32(p) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((UInt32)((const Byte *)(p))[2] << 16) | \
+ ((UInt32)((const Byte *)(p))[3] << 24))
+
+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
+
+#define SetUi16(p, d) { UInt32 _x_ = (d); \
+ ((Byte *)(p))[0] = (Byte)_x_; \
+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
+
+#define SetUi32(p, d) { UInt32 _x_ = (d); \
+ ((Byte *)(p))[0] = (Byte)_x_; \
+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
+ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
+ ((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
+
+#define SetUi64(p, d) { UInt64 _x64_ = (d); \
+ SetUi32(p, (UInt32)_x64_); \
+ SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
+
+#endif
+
+#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
+
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+
+#else
+
+#define GetBe32(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 24) | \
+ ((UInt32)((const Byte *)(p))[1] << 16) | \
+ ((UInt32)((const Byte *)(p))[2] << 8) | \
+ ((const Byte *)(p))[3] )
+
+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+
+#endif
+
+#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+typedef struct
+{
+ UInt32 maxFunc;
+ UInt32 vendor[3];
+ UInt32 ver;
+ UInt32 b;
+ UInt32 c;
+ UInt32 d;
+} Cx86cpuid;
+
+enum
+{
+ CPU_FIRM_INTEL,
+ CPU_FIRM_AMD,
+ CPU_FIRM_VIA
+};
+
+Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
+int x86cpuid_GetFirm(const Cx86cpuid *p);
+
+#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
+#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
+#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
+
+Bool CPU_Is_InOrder();
+Bool CPU_Is_Aes_Supported();
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/Delta.c b/src/libs/7zip/win/C/Delta.c
new file mode 100644
index 000000000..2b327f15f
--- /dev/null
+++ b/src/libs/7zip/win/C/Delta.c
@@ -0,0 +1,62 @@
+/* Delta.c -- Delta converter
+2009-05-26 : Igor Pavlov : Public domain */
+
+#include "Delta.h"
+
+void Delta_Init(Byte *state)
+{
+ unsigned i;
+ for (i = 0; i < DELTA_STATE_SIZE; i++)
+ state[i] = 0;
+}
+
+static void MyMemCpy(Byte *dest, const Byte *src, unsigned size)
+{
+ unsigned i;
+ for (i = 0; i < size; i++)
+ dest[i] = src[i];
+}
+
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte buf[DELTA_STATE_SIZE];
+ unsigned j = 0;
+ MyMemCpy(buf, state, delta);
+ {
+ SizeT i;
+ for (i = 0; i < size;)
+ {
+ for (j = 0; j < delta && i < size; i++, j++)
+ {
+ Byte b = data[i];
+ data[i] = (Byte)(b - buf[j]);
+ buf[j] = b;
+ }
+ }
+ }
+ if (j == delta)
+ j = 0;
+ MyMemCpy(state, buf + j, delta - j);
+ MyMemCpy(state + delta - j, buf, j);
+}
+
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte buf[DELTA_STATE_SIZE];
+ unsigned j = 0;
+ MyMemCpy(buf, state, delta);
+ {
+ SizeT i;
+ for (i = 0; i < size;)
+ {
+ for (j = 0; j < delta && i < size; i++, j++)
+ {
+ buf[j] = data[i] = (Byte)(buf[j] + data[i]);
+ }
+ }
+ }
+ if (j == delta)
+ j = 0;
+ MyMemCpy(state, buf + j, delta - j);
+ MyMemCpy(state + delta - j, buf, j);
+}
diff --git a/src/libs/7zip/win/C/Delta.h b/src/libs/7zip/win/C/Delta.h
new file mode 100644
index 000000000..0d4cd6274
--- /dev/null
+++ b/src/libs/7zip/win/C/Delta.h
@@ -0,0 +1,23 @@
+/* Delta.h -- Delta converter
+2009-04-15 : Igor Pavlov : Public domain */
+
+#ifndef __DELTA_H
+#define __DELTA_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DELTA_STATE_SIZE 256
+
+void Delta_Init(Byte *state);
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/HuffEnc.c b/src/libs/7zip/win/C/HuffEnc.c
new file mode 100644
index 000000000..561c7e5da
--- /dev/null
+++ b/src/libs/7zip/win/C/HuffEnc.c
@@ -0,0 +1,146 @@
+/* HuffEnc.c -- functions for Huffman encoding
+2009-09-02 : Igor Pavlov : Public domain */
+
+#include "HuffEnc.h"
+#include "Sort.h"
+
+#define kMaxLen 16
+#define NUM_BITS 10
+#define MASK ((1 << NUM_BITS) - 1)
+
+#define NUM_COUNTERS 64
+
+#define HUFFMAN_SPEED_OPT
+
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
+{
+ UInt32 num = 0;
+ /* if (maxLen > 10) maxLen = 10; */
+ {
+ UInt32 i;
+
+ #ifdef HUFFMAN_SPEED_OPT
+
+ UInt32 counters[NUM_COUNTERS];
+ for (i = 0; i < NUM_COUNTERS; i++)
+ counters[i] = 0;
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
+ }
+
+ for (i = 1; i < NUM_COUNTERS; i++)
+ {
+ UInt32 temp = counters[i];
+ counters[i] = num;
+ num += temp;
+ }
+
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ if (freq == 0)
+ lens[i] = 0;
+ else
+ p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS);
+ }
+ counters[0] = 0;
+ HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
+
+ #else
+
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ if (freq == 0)
+ lens[i] = 0;
+ else
+ p[num++] = i | (freq << NUM_BITS);
+ }
+ HeapSort(p, num);
+
+ #endif
+ }
+
+ if (num < 2)
+ {
+ unsigned minCode = 0;
+ unsigned maxCode = 1;
+ if (num == 1)
+ {
+ maxCode = (unsigned)p[0] & MASK;
+ if (maxCode == 0)
+ maxCode++;
+ }
+ p[minCode] = 0;
+ p[maxCode] = 1;
+ lens[minCode] = lens[maxCode] = 1;
+ return;
+ }
+
+ {
+ UInt32 b, e, i;
+
+ i = b = e = 0;
+ do
+ {
+ UInt32 n, m, freq;
+ n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+ freq = (p[n] & ~MASK);
+ p[n] = (p[n] & MASK) | (e << NUM_BITS);
+ m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+ freq += (p[m] & ~MASK);
+ p[m] = (p[m] & MASK) | (e << NUM_BITS);
+ p[e] = (p[e] & MASK) | freq;
+ e++;
+ }
+ while (num - e > 1);
+
+ {
+ UInt32 lenCounters[kMaxLen + 1];
+ for (i = 0; i <= kMaxLen; i++)
+ lenCounters[i] = 0;
+
+ p[--e] &= MASK;
+ lenCounters[1] = 2;
+ while (e > 0)
+ {
+ UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
+ p[e] = (p[e] & MASK) | (len << NUM_BITS);
+ if (len >= maxLen)
+ for (len = maxLen - 1; lenCounters[len] == 0; len--);
+ lenCounters[len]--;
+ lenCounters[len + 1] += 2;
+ }
+
+ {
+ UInt32 len;
+ i = 0;
+ for (len = maxLen; len != 0; len--)
+ {
+ UInt32 num;
+ for (num = lenCounters[len]; num != 0; num--)
+ lens[p[i++] & MASK] = (Byte)len;
+ }
+ }
+
+ {
+ UInt32 nextCodes[kMaxLen + 1];
+ {
+ UInt32 code = 0;
+ UInt32 len;
+ for (len = 1; len <= kMaxLen; len++)
+ nextCodes[len] = code = (code + lenCounters[len - 1]) << 1;
+ }
+ /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
+
+ {
+ UInt32 i;
+ for (i = 0; i < numSymbols; i++)
+ p[i] = nextCodes[lens[i]]++;
+ }
+ }
+ }
+ }
+}
diff --git a/src/libs/7zip/win/C/HuffEnc.h b/src/libs/7zip/win/C/HuffEnc.h
new file mode 100644
index 000000000..9cf4bfde8
--- /dev/null
+++ b/src/libs/7zip/win/C/HuffEnc.h
@@ -0,0 +1,27 @@
+/* HuffEnc.h -- Huffman encoding
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __HUFF_ENC_H
+#define __HUFF_ENC_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Conditions:
+ num <= 1024 = 2 ^ NUM_BITS
+ Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS)
+ maxLen <= 16 = kMaxLen
+ Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
+*/
+
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/LzFind.c b/src/libs/7zip/win/C/LzFind.c
new file mode 100644
index 000000000..e3ecb0542
--- /dev/null
+++ b/src/libs/7zip/win/C/LzFind.c
@@ -0,0 +1,761 @@
+/* LzFind.c -- Match finder for LZ algorithms
+2009-04-22 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "LzFind.h"
+#include "LzHash.h"
+
+#define kEmptyHashValue 0
+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
+#define kNormalizeMask (~(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)3 << 30)
+
+#define kStartMaxLen 3
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ if (!p->directInput)
+ {
+ alloc->Free(alloc, p->bufferBase);
+ p->bufferBase = 0;
+ }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+{
+ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+ if (p->directInput)
+ {
+ p->blockSize = blockSize;
+ return 1;
+ }
+ if (p->bufferBase == 0 || p->blockSize != blockSize)
+ {
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
+ }
+ return (p->bufferBase != 0);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+
+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+{
+ p->posLimit -= subValue;
+ p->pos -= subValue;
+ p->streamPos -= subValue;
+}
+
+static void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return;
+ if (p->directInput)
+ {
+ UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+ if (curSize > p->directInputRem)
+ curSize = (UInt32)p->directInputRem;
+ p->directInputRem -= curSize;
+ p->streamPos += curSize;
+ if (p->directInputRem == 0)
+ p->streamEndWasReached = 1;
+ return;
+ }
+ for (;;)
+ {
+ Byte *dest = p->buffer + (p->streamPos - p->pos);
+ size_t size = (p->bufferBase + p->blockSize - dest);
+ if (size == 0)
+ return;
+ p->result = p->stream->Read(p->stream, dest, &size);
+ if (p->result != SZ_OK)
+ return;
+ if (size == 0)
+ {
+ p->streamEndWasReached = 1;
+ return;
+ }
+ p->streamPos += (UInt32)size;
+ if (p->streamPos - p->pos > p->keepSizeAfter)
+ return;
+ }
+}
+
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+ memmove(p->bufferBase,
+ p->buffer - p->keepSizeBefore,
+ (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
+ p->buffer = p->bufferBase + p->keepSizeBefore;
+}
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+ if (p->directInput)
+ return 0;
+ /* if (p->streamEndWasReached) return 0; */
+ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+ if (p->streamEndWasReached)
+ return;
+ if (p->keepSizeAfter >= p->streamPos - p->pos)
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+{
+ if (MatchFinder_NeedMove(p))
+ MatchFinder_MoveBlock(p);
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+ p->cutValue = 32;
+ p->btMode = 1;
+ p->numHashBytes = 4;
+ p->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+ UInt32 i;
+ p->bufferBase = 0;
+ p->directInput = 0;
+ p->hash = 0;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ p->crc[i] = r;
+ }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hash);
+ p->hash = 0;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+{
+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return 0;
+ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc)
+{
+ UInt32 sizeReserv;
+ if (historySize > kMaxHistorySize)
+ {
+ MatchFinder_Free(p, alloc);
+ return 0;
+ }
+ sizeReserv = historySize >> 1;
+ if (historySize > ((UInt32)2 << 30))
+ sizeReserv = historySize >> 2;
+ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
+
+ p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
+ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+ if (LzInWindow_Create(p, sizeReserv, alloc))
+ {
+ UInt32 newCyclicBufferSize = historySize + 1;
+ UInt32 hs;
+ p->matchMaxLen = matchMaxLen;
+ {
+ p->fixedHashSize = 0;
+ if (p->numHashBytes == 2)
+ hs = (1 << 16) - 1;
+ else
+ {
+ hs = historySize - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ hs |= 0xFFFF; /* don't change it! It's required for Deflate */
+ if (hs > (1 << 24))
+ {
+ if (p->numHashBytes == 3)
+ hs = (1 << 24) - 1;
+ else
+ hs >>= 1;
+ }
+ }
+ p->hashMask = hs;
+ hs++;
+ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
+ hs += p->fixedHashSize;
+ }
+
+ {
+ UInt32 prevSize = p->hashSizeSum + p->numSons;
+ UInt32 newSize;
+ p->historySize = historySize;
+ p->hashSizeSum = hs;
+ p->cyclicBufferSize = newCyclicBufferSize;
+ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
+ newSize = p->hashSizeSum + p->numSons;
+ if (p->hash != 0 && prevSize == newSize)
+ return 1;
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->hash = AllocRefs(newSize, alloc);
+ if (p->hash != 0)
+ {
+ p->son = p->hash + p->hashSizeSum;
+ return 1;
+ }
+ }
+ }
+ MatchFinder_Free(p, alloc);
+ return 0;
+}
+
+static void MatchFinder_SetLimits(CMatchFinder *p)
+{
+ UInt32 limit = kMaxValForNormalize - p->pos;
+ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+ if (limit2 < limit)
+ limit = limit2;
+ limit2 = p->streamPos - p->pos;
+ if (limit2 <= p->keepSizeAfter)
+ {
+ if (limit2 > 0)
+ limit2 = 1;
+ }
+ else
+ limit2 -= p->keepSizeAfter;
+ if (limit2 < limit)
+ limit = limit2;
+ {
+ UInt32 lenLimit = p->streamPos - p->pos;
+ if (lenLimit > p->matchMaxLen)
+ lenLimit = p->matchMaxLen;
+ p->lenLimit = lenLimit;
+ }
+ p->posLimit = p->pos + limit;
+}
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+ UInt32 i;
+ for (i = 0; i < p->hashSizeSum; i++)
+ p->hash[i] = kEmptyHashValue;
+ p->cyclicBufferPos = 0;
+ p->buffer = p->bufferBase;
+ p->pos = p->streamPos = p->cyclicBufferSize;
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+ MatchFinder_ReadBlock(p);
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
+{
+ return (p->pos - p->historySize - 1) & kNormalizeMask;
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+{
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 value = items[i];
+ if (value <= subValue)
+ value = kEmptyHashValue;
+ else
+ value -= subValue;
+ items[i] = value;
+ }
+}
+
+static void MatchFinder_Normalize(CMatchFinder *p)
+{
+ UInt32 subValue = MatchFinder_GetSubValue(p);
+ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
+ MatchFinder_ReduceOffsets(p, subValue);
+}
+
+static void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+ if (p->pos == kMaxValForNormalize)
+ MatchFinder_Normalize(p);
+ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
+ MatchFinder_CheckAndMoveAndRead(p);
+ if (p->cyclicBufferPos == p->cyclicBufferSize)
+ p->cyclicBufferPos = 0;
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ son[_cyclicBufferPos] = curMatch;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ return distances;
+ {
+ const Byte *pb = cur - delta;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+ {
+ UInt32 len = 0;
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ return distances;
+ }
+ }
+ }
+ }
+}
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return distances;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return distances;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ {
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+#define MOVE_POS \
+ ++p->cyclicBufferPos; \
+ p->buffer++; \
+ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+
+#define MOVE_POS_RET MOVE_POS return offset;
+
+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+ cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
+#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define GET_MATCHES_FOOTER(offset, maxLen) \
+ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
+ distances + offset, maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 2)
+}
+
+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, delta2, maxLen, offset;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC;
+
+ delta2 = p->pos - p->hash[hash2Value];
+ curMatch = p->hash[kFix3HashSize + hashValue];
+
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+
+
+ maxLen = 2;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[0] = maxLen;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances + offset, maxLen) - (distances));
+ MOVE_POS_RET
+}
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances, 2) - (distances));
+ MOVE_POS_RET
+}
+
+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value;
+ SKIP_HEADER(3)
+ HASH3_CALC;
+ curMatch = p->hash[kFix3HashSize + hashValue];
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] = p->pos;
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 2)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 3)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+}
diff --git a/src/libs/7zip/win/C/LzFind.h b/src/libs/7zip/win/C/LzFind.h
new file mode 100644
index 000000000..010c4b92b
--- /dev/null
+++ b/src/libs/7zip/win/C/LzFind.h
@@ -0,0 +1,115 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2009-04-22 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_H
+#define __LZ_FIND_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+ Byte *buffer;
+ UInt32 pos;
+ UInt32 posLimit;
+ UInt32 streamPos;
+ UInt32 lenLimit;
+
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufferBase;
+ ISeqInStream *stream;
+ int streamEndWasReached;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ int directInput;
+ size_t directInputRem;
+ int btMode;
+ int bigHash;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ UInt32 hashSizeSum;
+ UInt32 numSons;
+ SRes result;
+ UInt32 crc[256];
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+ historySize <= 3 GB
+ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *distances, UInt32 maxLen);
+
+/*
+Conditions:
+ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+ Mf_Init_Func Init;
+ Mf_GetIndexByte_Func GetIndexByte;
+ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+ Mf_GetMatches_Func GetMatches;
+ Mf_Skip_Func Skip;
+} IMatchFinder;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+
+void MatchFinder_Init(CMatchFinder *p);
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/LzFindMt.c b/src/libs/7zip/win/C/LzFindMt.c
new file mode 100644
index 000000000..aa41ed98a
--- /dev/null
+++ b/src/libs/7zip/win/C/LzFindMt.c
@@ -0,0 +1,793 @@
+/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
+2009-09-20 : Igor Pavlov : Public domain */
+
+#include "LzHash.h"
+
+#include "LzFindMt.h"
+
+void MtSync_Construct(CMtSync *p)
+{
+ p->wasCreated = False;
+ p->csWasInitialized = False;
+ p->csWasEntered = False;
+ Thread_Construct(&p->thread);
+ Event_Construct(&p->canStart);
+ Event_Construct(&p->wasStarted);
+ Event_Construct(&p->wasStopped);
+ Semaphore_Construct(&p->freeSemaphore);
+ Semaphore_Construct(&p->filledSemaphore);
+}
+
+void MtSync_GetNextBlock(CMtSync *p)
+{
+ if (p->needStart)
+ {
+ p->numProcessedBlocks = 1;
+ p->needStart = False;
+ p->stopWriting = False;
+ p->exit = False;
+ Event_Reset(&p->wasStarted);
+ Event_Reset(&p->wasStopped);
+
+ Event_Set(&p->canStart);
+ Event_Wait(&p->wasStarted);
+ }
+ else
+ {
+ CriticalSection_Leave(&p->cs);
+ p->csWasEntered = False;
+ p->numProcessedBlocks++;
+ Semaphore_Release1(&p->freeSemaphore);
+ }
+ Semaphore_Wait(&p->filledSemaphore);
+ CriticalSection_Enter(&p->cs);
+ p->csWasEntered = True;
+}
+
+/* MtSync_StopWriting must be called if Writing was started */
+
+void MtSync_StopWriting(CMtSync *p)
+{
+ UInt32 myNumBlocks = p->numProcessedBlocks;
+ if (!Thread_WasCreated(&p->thread) || p->needStart)
+ return;
+ p->stopWriting = True;
+ if (p->csWasEntered)
+ {
+ CriticalSection_Leave(&p->cs);
+ p->csWasEntered = False;
+ }
+ Semaphore_Release1(&p->freeSemaphore);
+
+ Event_Wait(&p->wasStopped);
+
+ while (myNumBlocks++ != p->numProcessedBlocks)
+ {
+ Semaphore_Wait(&p->filledSemaphore);
+ Semaphore_Release1(&p->freeSemaphore);
+ }
+ p->needStart = True;
+}
+
+void MtSync_Destruct(CMtSync *p)
+{
+ if (Thread_WasCreated(&p->thread))
+ {
+ MtSync_StopWriting(p);
+ p->exit = True;
+ if (p->needStart)
+ Event_Set(&p->canStart);
+ Thread_Wait(&p->thread);
+ Thread_Close(&p->thread);
+ }
+ if (p->csWasInitialized)
+ {
+ CriticalSection_Delete(&p->cs);
+ p->csWasInitialized = False;
+ }
+
+ Event_Close(&p->canStart);
+ Event_Close(&p->wasStarted);
+ Event_Close(&p->wasStopped);
+ Semaphore_Close(&p->freeSemaphore);
+ Semaphore_Close(&p->filledSemaphore);
+
+ p->wasCreated = False;
+}
+
+#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
+
+static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+ if (p->wasCreated)
+ return SZ_OK;
+
+ RINOK_THREAD(CriticalSection_Init(&p->cs));
+ p->csWasInitialized = True;
+
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
+
+ RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
+ RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
+
+ p->needStart = True;
+
+ RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj));
+ p->wasCreated = True;
+ return SZ_OK;
+}
+
+static SRes MtSync_Create(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks)
+{
+ SRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
+ if (res != SZ_OK)
+ MtSync_Destruct(p);
+ return res;
+}
+
+void MtSync_Init(CMtSync *p) { p->needStart = True; }
+
+#define kMtMaxValForNormalize 0xFFFFFFFF
+
+#define DEF_GetHeads2(name, v, action) \
+static void GetHeads ## name(const Byte *p, UInt32 pos, \
+UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
+{ action; for (; numHeads != 0; numHeads--) { \
+const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
+
+#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
+
+DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; )
+DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
+DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask)
+DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
+/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */
+
+void HashThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->hashSync;
+ for (;;)
+ {
+ UInt32 numProcessedBlocks = 0;
+ Event_Wait(&p->canStart);
+ Event_Set(&p->wasStarted);
+ for (;;)
+ {
+ if (p->exit)
+ return;
+ if (p->stopWriting)
+ {
+ p->numProcessedBlocks = numProcessedBlocks;
+ Event_Set(&p->wasStopped);
+ break;
+ }
+
+ {
+ CMatchFinder *mf = mt->MatchFinder;
+ if (MatchFinder_NeedMove(mf))
+ {
+ CriticalSection_Enter(&mt->btSync.cs);
+ CriticalSection_Enter(&mt->hashSync.cs);
+ {
+ const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf);
+ const Byte *afterPtr;
+ MatchFinder_MoveBlock(mf);
+ afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
+ mt->pointerToCurPos -= beforePtr - afterPtr;
+ mt->buffer -= beforePtr - afterPtr;
+ }
+ CriticalSection_Leave(&mt->btSync.cs);
+ CriticalSection_Leave(&mt->hashSync.cs);
+ continue;
+ }
+
+ Semaphore_Wait(&p->freeSemaphore);
+
+ MatchFinder_ReadIfRequired(mf);
+ if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
+ {
+ UInt32 subValue = (mf->pos - mf->historySize - 1);
+ MatchFinder_ReduceOffsets(mf, subValue);
+ MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1);
+ }
+ {
+ UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+ UInt32 num = mf->streamPos - mf->pos;
+ heads[0] = 2;
+ heads[1] = num;
+ if (num >= mf->numHashBytes)
+ {
+ num = num - mf->numHashBytes + 1;
+ if (num > kMtHashBlockSize - 2)
+ num = kMtHashBlockSize - 2;
+ mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc);
+ heads[0] += num;
+ }
+ mf->pos += num;
+ mf->buffer += num;
+ }
+ }
+
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+ }
+}
+
+void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
+{
+ MtSync_GetNextBlock(&p->hashSync);
+ p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
+ p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
+ p->hashNumAvail = p->hashBuf[p->hashBufPos++];
+}
+
+#define kEmptyHashValue 0
+
+/* #define MFMT_GM_INLINE */
+
+#ifdef MFMT_GM_INLINE
+
+#define NO_INLINE MY_FAST_CALL
+
+Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
+{
+ do
+ {
+ UInt32 *distances = _distances + 1;
+ UInt32 curMatch = pos - *hash++;
+
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ UInt32 cutValue = _cutValue;
+ UInt32 maxLen = _maxLen;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ break;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ break;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+ pos++;
+ _cyclicBufferPos++;
+ cur++;
+ {
+ UInt32 num = (UInt32)(distances - _distances);
+ *_distances = num - 1;
+ _distances += num;
+ limit -= num;
+ }
+ }
+ while (limit > 0 && --size != 0);
+ *posRes = pos;
+ return limit;
+}
+
+#endif
+
+void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ UInt32 numProcessed = 0;
+ UInt32 curPos = 2;
+ UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
+ distances[1] = p->hashNumAvail;
+ while (curPos < limit)
+ {
+ if (p->hashBufPos == p->hashBufPosLimit)
+ {
+ MatchFinderMt_GetNextBlock_Hash(p);
+ distances[1] = numProcessed + p->hashNumAvail;
+ if (p->hashNumAvail >= p->numHashBytes)
+ continue;
+ for (; p->hashNumAvail != 0; p->hashNumAvail--)
+ distances[curPos++] = 0;
+ break;
+ }
+ {
+ UInt32 size = p->hashBufPosLimit - p->hashBufPos;
+ UInt32 lenLimit = p->matchMaxLen;
+ UInt32 pos = p->pos;
+ UInt32 cyclicBufferPos = p->cyclicBufferPos;
+ if (lenLimit >= p->hashNumAvail)
+ lenLimit = p->hashNumAvail;
+ {
+ UInt32 size2 = p->hashNumAvail - lenLimit + 1;
+ if (size2 < size)
+ size = size2;
+ size2 = p->cyclicBufferSize - cyclicBufferPos;
+ if (size2 < size)
+ size = size2;
+ }
+ #ifndef MFMT_GM_INLINE
+ while (curPos < limit && size-- != 0)
+ {
+ UInt32 *startDistances = distances + curPos;
+ UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
+ pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ startDistances + 1, p->numHashBytes - 1) - startDistances);
+ *startDistances = num - 1;
+ curPos += num;
+ cyclicBufferPos++;
+ pos++;
+ p->buffer++;
+ }
+ #else
+ {
+ UInt32 posRes;
+ curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
+ p->hashBufPos += posRes - pos;
+ cyclicBufferPos += posRes - pos;
+ p->buffer += posRes - pos;
+ pos = posRes;
+ }
+ #endif
+
+ numProcessed += pos - p->pos;
+ p->hashNumAvail -= pos - p->pos;
+ p->pos = pos;
+ if (cyclicBufferPos == p->cyclicBufferSize)
+ cyclicBufferPos = 0;
+ p->cyclicBufferPos = cyclicBufferPos;
+ }
+ }
+ distances[0] = curPos;
+}
+
+void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
+{
+ CMtSync *sync = &p->hashSync;
+ if (!sync->needStart)
+ {
+ CriticalSection_Enter(&sync->cs);
+ sync->csWasEntered = True;
+ }
+
+ BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
+
+ if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
+ {
+ UInt32 subValue = p->pos - p->cyclicBufferSize;
+ MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2);
+ p->pos -= subValue;
+ }
+
+ if (!sync->needStart)
+ {
+ CriticalSection_Leave(&sync->cs);
+ sync->csWasEntered = False;
+ }
+}
+
+void BtThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->btSync;
+ for (;;)
+ {
+ UInt32 blockIndex = 0;
+ Event_Wait(&p->canStart);
+ Event_Set(&p->wasStarted);
+ for (;;)
+ {
+ if (p->exit)
+ return;
+ if (p->stopWriting)
+ {
+ p->numProcessedBlocks = blockIndex;
+ MtSync_StopWriting(&mt->hashSync);
+ Event_Set(&p->wasStopped);
+ break;
+ }
+ Semaphore_Wait(&p->freeSemaphore);
+ BtFillBlock(mt, blockIndex++);
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+ }
+}
+
+void MatchFinderMt_Construct(CMatchFinderMt *p)
+{
+ p->hashBuf = 0;
+ MtSync_Construct(&p->hashSync);
+ MtSync_Construct(&p->btSync);
+}
+
+void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hashBuf);
+ p->hashBuf = 0;
+}
+
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
+{
+ MtSync_Destruct(&p->hashSync);
+ MtSync_Destruct(&p->btSync);
+ MatchFinderMt_FreeMem(p, alloc);
+}
+
+#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
+#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
+
+static unsigned MY_STD_CALL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
+static unsigned MY_STD_CALL BtThreadFunc2(void *p)
+{
+ Byte allocaDummy[0x180];
+ int i = 0;
+ for (i = 0; i < 16; i++)
+ allocaDummy[i] = (Byte)i;
+ BtThreadFunc((CMatchFinderMt *)p);
+ return 0;
+}
+
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
+{
+ CMatchFinder *mf = p->MatchFinder;
+ p->historySize = historySize;
+ if (kMtBtBlockSize <= matchMaxLen * 4)
+ return SZ_ERROR_PARAM;
+ if (p->hashBuf == 0)
+ {
+ p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
+ if (p->hashBuf == 0)
+ return SZ_ERROR_MEM;
+ p->btBuf = p->hashBuf + kHashBufferSize;
+ }
+ keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
+ keepAddBufferAfter += kMtHashBlockSize;
+ if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
+ return SZ_ERROR_MEM;
+
+ RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
+ RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
+ return SZ_OK;
+}
+
+/* Call it after ReleaseStream / SetStream */
+void MatchFinderMt_Init(CMatchFinderMt *p)
+{
+ CMatchFinder *mf = p->MatchFinder;
+ p->btBufPos = p->btBufPosLimit = 0;
+ p->hashBufPos = p->hashBufPosLimit = 0;
+ MatchFinder_Init(mf);
+ p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf);
+ p->btNumAvailBytes = 0;
+ p->lzPos = p->historySize + 1;
+
+ p->hash = mf->hash;
+ p->fixedHashSize = mf->fixedHashSize;
+ p->crc = mf->crc;
+
+ p->son = mf->son;
+ p->matchMaxLen = mf->matchMaxLen;
+ p->numHashBytes = mf->numHashBytes;
+ p->pos = mf->pos;
+ p->buffer = mf->buffer;
+ p->cyclicBufferPos = mf->cyclicBufferPos;
+ p->cyclicBufferSize = mf->cyclicBufferSize;
+ p->cutValue = mf->cutValue;
+}
+
+/* ReleaseStream is required to finish multithreading */
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
+{
+ MtSync_StopWriting(&p->btSync);
+ /* p->MatchFinder->ReleaseStream(); */
+}
+
+void MatchFinderMt_Normalize(CMatchFinderMt *p)
+{
+ MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
+ p->lzPos = p->historySize + 1;
+}
+
+void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
+{
+ UInt32 blockIndex;
+ MtSync_GetNextBlock(&p->btSync);
+ blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
+ p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
+ p->btBufPosLimit += p->btBuf[p->btBufPos++];
+ p->btNumAvailBytes = p->btBuf[p->btBufPos++];
+ if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize)
+ MatchFinderMt_Normalize(p);
+}
+
+const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+{
+ return p->pointerToCurPos;
+}
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+{
+ GET_NEXT_BLOCK_IF_REQUIRED;
+ return p->btNumAvailBytes;
+}
+
+Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
+{
+ return p->pointerToCurPos[index];
+}
+
+UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, curMatch2;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH2_CALC
+
+ curMatch2 = hash[hash2Value];
+ hash[hash2Value] = lzPos;
+
+ if (curMatch2 >= matchMinPos)
+ if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ *distances++ = 2;
+ *distances++ = lzPos - curMatch2 - 1;
+ }
+ return distances;
+}
+
+UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH3_CALC
+
+ curMatch2 = hash[ hash2Value];
+ curMatch3 = hash[kFix3HashSize + hash3Value];
+
+ hash[ hash2Value] =
+ hash[kFix3HashSize + hash3Value] =
+ lzPos;
+
+ if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch2 - 1;
+ if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+ {
+ distances[0] = 3;
+ return distances + 2;
+ }
+ distances[0] = 2;
+ distances += 2;
+ }
+ if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+ {
+ *distances++ = 3;
+ *distances++ = lzPos - curMatch3 - 1;
+ }
+ return distances;
+}
+
+/*
+UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 lzPos = p->lzPos;
+ MT_HASH4_CALC
+
+ curMatch2 = hash[ hash2Value];
+ curMatch3 = hash[kFix3HashSize + hash3Value];
+ curMatch4 = hash[kFix4HashSize + hash4Value];
+
+ hash[ hash2Value] =
+ hash[kFix3HashSize + hash3Value] =
+ hash[kFix4HashSize + hash4Value] =
+ lzPos;
+
+ if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch2 - 1;
+ if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
+ {
+ distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
+ return distances + 2;
+ }
+ distances[0] = 2;
+ distances += 2;
+ }
+ if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
+ {
+ distances[1] = lzPos - curMatch3 - 1;
+ if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
+ {
+ distances[0] = 4;
+ return distances + 2;
+ }
+ distances[0] = 3;
+ distances += 2;
+ }
+
+ if (curMatch4 >= matchMinPos)
+ if (
+ cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
+ cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
+ )
+ {
+ *distances++ = 4;
+ *distances++ = lzPos - curMatch4 - 1;
+ }
+ return distances;
+}
+*/
+
+#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
+
+UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ const UInt32 *btBuf = p->btBuf + p->btBufPos;
+ UInt32 len = *btBuf++;
+ p->btBufPos += 1 + len;
+ p->btNumAvailBytes--;
+ {
+ UInt32 i;
+ for (i = 0; i < len; i += 2)
+ {
+ *distances++ = *btBuf++;
+ *distances++ = *btBuf++;
+ }
+ }
+ INCREASE_LZ_POS
+ return len;
+}
+
+UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
+{
+ const UInt32 *btBuf = p->btBuf + p->btBufPos;
+ UInt32 len = *btBuf++;
+ p->btBufPos += 1 + len;
+
+ if (len == 0)
+ {
+ if (p->btNumAvailBytes-- >= 4)
+ len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
+ }
+ else
+ {
+ /* Condition: there are matches in btBuf with length < p->numHashBytes */
+ UInt32 *distances2;
+ p->btNumAvailBytes--;
+ distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
+ do
+ {
+ *distances2++ = *btBuf++;
+ *distances2++ = *btBuf++;
+ }
+ while ((len -= 2) != 0);
+ len = (UInt32)(distances2 - (distances));
+ }
+ INCREASE_LZ_POS
+ return len;
+}
+
+#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
+#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
+#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0);
+
+void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER2_MT { p->btNumAvailBytes--;
+ SKIP_FOOTER_MT
+}
+
+void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(2)
+ UInt32 hash2Value;
+ MT_HASH2_CALC
+ hash[hash2Value] = p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(3)
+ UInt32 hash2Value, hash3Value;
+ MT_HASH3_CALC
+ hash[kFix3HashSize + hash3Value] =
+ hash[ hash2Value] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+/*
+void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(4)
+ UInt32 hash2Value, hash3Value, hash4Value;
+ MT_HASH4_CALC
+ hash[kFix4HashSize + hash4Value] =
+ hash[kFix3HashSize + hash3Value] =
+ hash[ hash2Value] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+*/
+
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
+ switch(p->MatchFinder->numHashBytes)
+ {
+ case 2:
+ p->GetHeadsFunc = GetHeads2;
+ p->MixMatchesFunc = (Mf_Mix_Matches)0;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
+ break;
+ case 3:
+ p->GetHeadsFunc = GetHeads3;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
+ break;
+ default:
+ /* case 4: */
+ p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
+ /* p->GetHeadsFunc = GetHeads4; */
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
+ break;
+ /*
+ default:
+ p->GetHeadsFunc = GetHeads5;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;
+ break;
+ */
+ }
+}
diff --git a/src/libs/7zip/win/C/LzFindMt.h b/src/libs/7zip/win/C/LzFindMt.h
new file mode 100644
index 000000000..b985af5fe
--- /dev/null
+++ b/src/libs/7zip/win/C/LzFindMt.h
@@ -0,0 +1,105 @@
+/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_MT_H
+#define __LZ_FIND_MT_H
+
+#include "LzFind.h"
+#include "Threads.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define kMtHashBlockSize (1 << 13)
+#define kMtHashNumBlocks (1 << 3)
+#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1)
+
+#define kMtBtBlockSize (1 << 14)
+#define kMtBtNumBlocks (1 << 6)
+#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1)
+
+typedef struct _CMtSync
+{
+ Bool wasCreated;
+ Bool needStart;
+ Bool exit;
+ Bool stopWriting;
+
+ CThread thread;
+ CAutoResetEvent canStart;
+ CAutoResetEvent wasStarted;
+ CAutoResetEvent wasStopped;
+ CSemaphore freeSemaphore;
+ CSemaphore filledSemaphore;
+ Bool csWasInitialized;
+ Bool csWasEntered;
+ CCriticalSection cs;
+ UInt32 numProcessedBlocks;
+} CMtSync;
+
+typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
+
+/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
+#define kMtCacheLineDummy 128
+
+typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
+ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc);
+
+typedef struct _CMatchFinderMt
+{
+ /* LZ */
+ const Byte *pointerToCurPos;
+ UInt32 *btBuf;
+ UInt32 btBufPos;
+ UInt32 btBufPosLimit;
+ UInt32 lzPos;
+ UInt32 btNumAvailBytes;
+
+ UInt32 *hash;
+ UInt32 fixedHashSize;
+ UInt32 historySize;
+ const UInt32 *crc;
+
+ Mf_Mix_Matches MixMatchesFunc;
+
+ /* LZ + BT */
+ CMtSync btSync;
+ Byte btDummy[kMtCacheLineDummy];
+
+ /* BT */
+ UInt32 *hashBuf;
+ UInt32 hashBufPos;
+ UInt32 hashBufPosLimit;
+ UInt32 hashNumAvail;
+
+ CLzRef *son;
+ UInt32 matchMaxLen;
+ UInt32 numHashBytes;
+ UInt32 pos;
+ Byte *buffer;
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be historySize + 1 */
+ UInt32 cutValue;
+
+ /* BT + Hash */
+ CMtSync hashSync;
+ /* Byte hashDummy[kMtCacheLineDummy]; */
+
+ /* Hash */
+ Mf_GetHeads GetHeadsFunc;
+ CMatchFinder *MatchFinder;
+} CMatchFinderMt;
+
+void MatchFinderMt_Construct(CMatchFinderMt *p);
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc);
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc);
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable);
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/LzHash.h b/src/libs/7zip/win/C/LzHash.h
new file mode 100644
index 000000000..f3e89966c
--- /dev/null
+++ b/src/libs/7zip/win/C/LzHash.h
@@ -0,0 +1,54 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_HASH_H
+#define __LZ_HASH_H
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+#define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
+ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
+ hash4Value &= (kHash4Size - 1); }
+
+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/src/libs/7zip/win/C/Lzma2Dec.c b/src/libs/7zip/win/C/Lzma2Dec.c
new file mode 100644
index 000000000..7ea1cc953
--- /dev/null
+++ b/src/libs/7zip/win/C/Lzma2Dec.c
@@ -0,0 +1,356 @@
+/* Lzma2Dec.c -- LZMA2 Decoder
+2009-05-03 : Igor Pavlov : Public domain */
+
+/* #define SHOW_DEBUG_INFO */
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include <string.h>
+
+#include "Lzma2Dec.h"
+
+/*
+00000000 - EOS
+00000001 U U - Uncompressed Reset Dic
+00000010 U U - Uncompressed No Reset
+100uuuuu U U P P - LZMA no reset
+101uuuuu U U P P - LZMA reset state
+110uuuuu U U P P S - LZMA reset state + new prop
+111uuuuu U U P P S - LZMA reset state + new prop + reset dic
+
+ u, U - Unpack Size
+ P - Pack Size
+ S - Props
+*/
+
+#define LZMA2_CONTROL_LZMA (1 << 7)
+#define LZMA2_CONTROL_COPY_NO_RESET 2
+#define LZMA2_CONTROL_COPY_RESET_DIC 1
+#define LZMA2_CONTROL_EOF 0
+
+#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0)
+
+#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3)
+#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2)
+
+#define LZMA2_LCLP_MAX 4
+#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+typedef enum
+{
+ LZMA2_STATE_CONTROL,
+ LZMA2_STATE_UNPACK0,
+ LZMA2_STATE_UNPACK1,
+ LZMA2_STATE_PACK0,
+ LZMA2_STATE_PACK1,
+ LZMA2_STATE_PROP,
+ LZMA2_STATE_DATA,
+ LZMA2_STATE_DATA_CONT,
+ LZMA2_STATE_FINISHED,
+ LZMA2_STATE_ERROR
+} ELzma2State;
+
+static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
+{
+ UInt32 dicSize;
+ if (prop > 40)
+ return SZ_ERROR_UNSUPPORTED;
+ dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
+ props[0] = (Byte)LZMA2_LCLP_MAX;
+ props[1] = (Byte)(dicSize);
+ props[2] = (Byte)(dicSize >> 8);
+ props[3] = (Byte)(dicSize >> 16);
+ props[4] = (Byte)(dicSize >> 24);
+ return SZ_OK;
+}
+
+SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ RINOK(Lzma2Dec_GetOldProps(prop, props));
+ return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
+}
+
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ RINOK(Lzma2Dec_GetOldProps(prop, props));
+ return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
+}
+
+void Lzma2Dec_Init(CLzma2Dec *p)
+{
+ p->state = LZMA2_STATE_CONTROL;
+ p->needInitDic = True;
+ p->needInitState = True;
+ p->needInitProp = True;
+ LzmaDec_Init(&p->decoder);
+}
+
+static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
+{
+ switch(p->state)
+ {
+ case LZMA2_STATE_CONTROL:
+ p->control = b;
+ PRF(printf("\n %4X ", p->decoder.dicPos));
+ PRF(printf(" %2X", b));
+ if (p->control == 0)
+ return LZMA2_STATE_FINISHED;
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if ((p->control & 0x7F) > 2)
+ return LZMA2_STATE_ERROR;
+ p->unpackSize = 0;
+ }
+ else
+ p->unpackSize = (UInt32)(p->control & 0x1F) << 16;
+ return LZMA2_STATE_UNPACK0;
+
+ case LZMA2_STATE_UNPACK0:
+ p->unpackSize |= (UInt32)b << 8;
+ return LZMA2_STATE_UNPACK1;
+
+ case LZMA2_STATE_UNPACK1:
+ p->unpackSize |= (UInt32)b;
+ p->unpackSize++;
+ PRF(printf(" %8d", p->unpackSize));
+ return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
+
+ case LZMA2_STATE_PACK0:
+ p->packSize = (UInt32)b << 8;
+ return LZMA2_STATE_PACK1;
+
+ case LZMA2_STATE_PACK1:
+ p->packSize |= (UInt32)b;
+ p->packSize++;
+ PRF(printf(" %8d", p->packSize));
+ return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP:
+ (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA);
+
+ case LZMA2_STATE_PROP:
+ {
+ int lc, lp;
+ if (b >= (9 * 5 * 5))
+ return LZMA2_STATE_ERROR;
+ lc = b % 9;
+ b /= 9;
+ p->decoder.prop.pb = b / 5;
+ lp = b % 5;
+ if (lc + lp > LZMA2_LCLP_MAX)
+ return LZMA2_STATE_ERROR;
+ p->decoder.prop.lc = lc;
+ p->decoder.prop.lp = lp;
+ p->needInitProp = False;
+ return LZMA2_STATE_DATA;
+ }
+ }
+ return LZMA2_STATE_ERROR;
+}
+
+static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
+{
+ memcpy(p->dic + p->dicPos, src, size);
+ p->dicPos += size;
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
+ p->checkDicSize = p->prop.dicSize;
+ p->processedPos += (UInt32)size;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState);
+
+SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->state != LZMA2_STATE_FINISHED)
+ {
+ SizeT dicPos = p->decoder.dicPos;
+ if (p->state == LZMA2_STATE_ERROR)
+ return SZ_ERROR_DATA;
+ if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
+ {
+ if (*srcLen == inSize)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ (*srcLen)++;
+ p->state = Lzma2Dec_UpdateState(p, *src++);
+ continue;
+ }
+ {
+ SizeT destSizeCur = dicLimit - dicPos;
+ SizeT srcSizeCur = inSize - *srcLen;
+ ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
+
+ if (p->unpackSize <= destSizeCur)
+ {
+ destSizeCur = (SizeT)p->unpackSize;
+ curFinishMode = LZMA_FINISH_END;
+ }
+
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if (*srcLen == inSize)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
+ if (initDic)
+ p->needInitProp = p->needInitState = True;
+ else if (p->needInitDic)
+ return SZ_ERROR_DATA;
+ p->needInitDic = False;
+ LzmaDec_InitDicAndState(&p->decoder, initDic, False);
+ }
+
+ if (srcSizeCur > destSizeCur)
+ srcSizeCur = destSizeCur;
+
+ if (srcSizeCur == 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);
+
+ src += srcSizeCur;
+ *srcLen += srcSizeCur;
+ p->unpackSize -= (UInt32)srcSizeCur;
+ p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
+ }
+ else
+ {
+ SizeT outSizeProcessed;
+ SRes res;
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ int mode = LZMA2_GET_LZMA_MODE(p);
+ Bool initDic = (mode == 3);
+ Bool initState = (mode > 0);
+ if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
+ p->needInitDic = False;
+ p->needInitState = False;
+ p->state = LZMA2_STATE_DATA_CONT;
+ }
+ if (srcSizeCur > p->packSize)
+ srcSizeCur = (SizeT)p->packSize;
+
+ res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status);
+
+ src += srcSizeCur;
+ *srcLen += srcSizeCur;
+ p->packSize -= (UInt32)srcSizeCur;
+
+ outSizeProcessed = p->decoder.dicPos - dicPos;
+ p->unpackSize -= (UInt32)outSizeProcessed;
+
+ RINOK(res);
+ if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ return res;
+
+ if (srcSizeCur == 0 && outSizeProcessed == 0)
+ {
+ if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ||
+ p->unpackSize != 0 || p->packSize != 0)
+ return SZ_ERROR_DATA;
+ p->state = LZMA2_STATE_CONTROL;
+ }
+ if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ *status = LZMA_STATUS_NOT_FINISHED;
+ }
+ }
+ }
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+}
+
+SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT srcSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->decoder.dicPos == p->decoder.dicBufSize)
+ p->decoder.dicPos = 0;
+ dicPos = p->decoder.dicPos;
+ if (outSize > p->decoder.dicBufSize - dicPos)
+ {
+ outSizeCur = p->decoder.dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status);
+ src += srcSizeCur;
+ inSize -= srcSizeCur;
+ *srcLen += srcSizeCur;
+ outSizeCur = p->decoder.dicPos - dicPos;
+ memcpy(dest, p->decoder.dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzma2Dec decoder;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ Byte props[LZMA_PROPS_SIZE];
+
+ Lzma2Dec_Construct(&decoder);
+
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ decoder.decoder.dic = dest;
+ decoder.decoder.dicBufSize = outSize;
+
+ RINOK(Lzma2Dec_GetOldProps(prop, props));
+ RINOK(LzmaDec_AllocateProbs(&decoder.decoder, props, LZMA_PROPS_SIZE, alloc));
+
+ *srcLen = inSize;
+ res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status);
+ *destLen = decoder.decoder.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+
+ LzmaDec_FreeProbs(&decoder.decoder, alloc);
+ return res;
+}
diff --git a/src/libs/7zip/win/C/Lzma2Dec.h b/src/libs/7zip/win/C/Lzma2Dec.h
new file mode 100644
index 000000000..6bc07bbc1
--- /dev/null
+++ b/src/libs/7zip/win/C/Lzma2Dec.h
@@ -0,0 +1,84 @@
+/* Lzma2Dec.h -- LZMA2 Decoder
+2009-05-03 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA2_DEC_H
+#define __LZMA2_DEC_H
+
+#include "LzmaDec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ---------- State Interface ---------- */
+
+typedef struct
+{
+ CLzmaDec decoder;
+ UInt32 packSize;
+ UInt32 unpackSize;
+ int state;
+ Byte control;
+ Bool needInitDic;
+ Bool needInitState;
+ Bool needInitProp;
+} CLzma2Dec;
+
+#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder)
+#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc);
+#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc);
+
+SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
+void Lzma2Dec_Init(CLzma2Dec *p);
+
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/Lzma2Enc.c b/src/libs/7zip/win/C/Lzma2Enc.c
new file mode 100644
index 000000000..e97597f63
--- /dev/null
+++ b/src/libs/7zip/win/C/Lzma2Enc.c
@@ -0,0 +1,477 @@
+/* Lzma2Enc.c -- LZMA2 Encoder
+2010-09-24 : Igor Pavlov : Public domain */
+
+/* #include <stdio.h> */
+#include <string.h>
+
+/* #define _7ZIP_ST */
+
+#include "Lzma2Enc.h"
+
+#ifndef _7ZIP_ST
+#include "MtCoder.h"
+#else
+#define NUM_MT_CODER_THREADS_MAX 1
+#endif
+
+#define LZMA2_CONTROL_LZMA (1 << 7)
+#define LZMA2_CONTROL_COPY_NO_RESET 2
+#define LZMA2_CONTROL_COPY_RESET_DIC 1
+#define LZMA2_CONTROL_EOF 0
+
+#define LZMA2_LCLP_MAX 4
+
+#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
+
+#define LZMA2_PACK_SIZE_MAX (1 << 16)
+#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX
+#define LZMA2_UNPACK_SIZE_MAX (1 << 21)
+#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX
+
+#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16)
+
+
+#define PRF(x) /* x */
+
+/* ---------- CLzma2EncInt ---------- */
+
+typedef struct
+{
+ CLzmaEncHandle enc;
+ UInt64 srcPos;
+ Byte props;
+ Bool needInitState;
+ Bool needInitProp;
+} CLzma2EncInt;
+
+static SRes Lzma2EncInt_Init(CLzma2EncInt *p, const CLzma2EncProps *props)
+{
+ Byte propsEncoded[LZMA_PROPS_SIZE];
+ SizeT propsSize = LZMA_PROPS_SIZE;
+ RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps));
+ RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize));
+ p->srcPos = 0;
+ p->props = propsEncoded[0];
+ p->needInitState = True;
+ p->needInitProp = True;
+ return SZ_OK;
+}
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize,
+ ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp);
+void LzmaEnc_Finish(CLzmaEncHandle pp);
+void LzmaEnc_SaveState(CLzmaEncHandle pp);
+void LzmaEnc_RestoreState(CLzmaEncHandle pp);
+
+
+static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
+ size_t *packSizeRes, ISeqOutStream *outStream)
+{
+ size_t packSizeLimit = *packSizeRes;
+ size_t packSize = packSizeLimit;
+ UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX;
+ unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0);
+ Bool useCopyBlock;
+ SRes res;
+
+ *packSizeRes = 0;
+ if (packSize < lzHeaderSize)
+ return SZ_ERROR_OUTPUT_EOF;
+ packSize -= lzHeaderSize;
+
+ LzmaEnc_SaveState(p->enc);
+ res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState,
+ outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize);
+
+ PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize));
+
+ if (unpackSize == 0)
+ return res;
+
+ if (res == SZ_OK)
+ useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16));
+ else
+ {
+ if (res != SZ_ERROR_OUTPUT_EOF)
+ return res;
+ res = SZ_OK;
+ useCopyBlock = True;
+ }
+
+ if (useCopyBlock)
+ {
+ size_t destPos = 0;
+ PRF(printf("################# COPY "));
+ while (unpackSize > 0)
+ {
+ UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE;
+ if (packSizeLimit - destPos < u + 3)
+ return SZ_ERROR_OUTPUT_EOF;
+ outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET);
+ outBuf[destPos++] = (Byte)((u - 1) >> 8);
+ outBuf[destPos++] = (Byte)(u - 1);
+ memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u);
+ unpackSize -= u;
+ destPos += u;
+ p->srcPos += u;
+ if (outStream)
+ {
+ *packSizeRes += destPos;
+ if (outStream->Write(outStream, outBuf, destPos) != destPos)
+ return SZ_ERROR_WRITE;
+ destPos = 0;
+ }
+ else
+ *packSizeRes = destPos;
+ /* needInitState = True; */
+ }
+ LzmaEnc_RestoreState(p->enc);
+ return SZ_OK;
+ }
+ {
+ size_t destPos = 0;
+ UInt32 u = unpackSize - 1;
+ UInt32 pm = (UInt32)(packSize - 1);
+ unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0);
+
+ PRF(printf(" "));
+
+ outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F));
+ outBuf[destPos++] = (Byte)(u >> 8);
+ outBuf[destPos++] = (Byte)u;
+ outBuf[destPos++] = (Byte)(pm >> 8);
+ outBuf[destPos++] = (Byte)pm;
+
+ if (p->needInitProp)
+ outBuf[destPos++] = p->props;
+
+ p->needInitProp = False;
+ p->needInitState = False;
+ destPos += packSize;
+ p->srcPos += unpackSize;
+
+ if (outStream)
+ if (outStream->Write(outStream, outBuf, destPos) != destPos)
+ return SZ_ERROR_WRITE;
+ *packSizeRes = destPos;
+ return SZ_OK;
+ }
+}
+
+/* ---------- Lzma2 Props ---------- */
+
+void Lzma2EncProps_Init(CLzma2EncProps *p)
+{
+ LzmaEncProps_Init(&p->lzmaProps);
+ p->numTotalThreads = -1;
+ p->numBlockThreads = -1;
+ p->blockSize = 0;
+}
+
+void Lzma2EncProps_Normalize(CLzma2EncProps *p)
+{
+ int t1, t1n, t2, t3;
+ {
+ CLzmaEncProps lzmaProps = p->lzmaProps;
+ LzmaEncProps_Normalize(&lzmaProps);
+ t1n = lzmaProps.numThreads;
+ }
+
+ t1 = p->lzmaProps.numThreads;
+ t2 = p->numBlockThreads;
+ t3 = p->numTotalThreads;
+
+ if (t2 > NUM_MT_CODER_THREADS_MAX)
+ t2 = NUM_MT_CODER_THREADS_MAX;
+
+ if (t3 <= 0)
+ {
+ if (t2 <= 0)
+ t2 = 1;
+ t3 = t1n * t2;
+ }
+ else if (t2 <= 0)
+ {
+ t2 = t3 / t1n;
+ if (t2 == 0)
+ {
+ t1 = 1;
+ t2 = t3;
+ }
+ if (t2 > NUM_MT_CODER_THREADS_MAX)
+ t2 = NUM_MT_CODER_THREADS_MAX;
+ }
+ else if (t1 <= 0)
+ {
+ t1 = t3 / t2;
+ if (t1 == 0)
+ t1 = 1;
+ }
+ else
+ t3 = t1n * t2;
+
+ p->lzmaProps.numThreads = t1;
+ p->numBlockThreads = t2;
+ p->numTotalThreads = t3;
+ LzmaEncProps_Normalize(&p->lzmaProps);
+
+ if (p->blockSize == 0)
+ {
+ UInt32 dictSize = p->lzmaProps.dictSize;
+ UInt64 blockSize = (UInt64)dictSize << 2;
+ const UInt32 kMinSize = (UInt32)1 << 20;
+ const UInt32 kMaxSize = (UInt32)1 << 28;
+ if (blockSize < kMinSize) blockSize = kMinSize;
+ if (blockSize > kMaxSize) blockSize = kMaxSize;
+ if (blockSize < dictSize) blockSize = dictSize;
+ p->blockSize = (size_t)blockSize;
+ }
+}
+
+static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
+{
+ return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
+}
+
+/* ---------- Lzma2 ---------- */
+
+typedef struct
+{
+ Byte propEncoded;
+ CLzma2EncProps props;
+
+ Byte *outBuf;
+
+ ISzAlloc *alloc;
+ ISzAlloc *allocBig;
+
+ CLzma2EncInt coders[NUM_MT_CODER_THREADS_MAX];
+
+ #ifndef _7ZIP_ST
+ CMtCoder mtCoder;
+ #endif
+
+} CLzma2Enc;
+
+
+/* ---------- Lzma2EncThread ---------- */
+
+static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
+{
+ UInt64 packTotal = 0;
+ SRes res = SZ_OK;
+
+ if (mainEncoder->outBuf == 0)
+ {
+ mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX);
+ if (mainEncoder->outBuf == 0)
+ return SZ_ERROR_MEM;
+ }
+ RINOK(Lzma2EncInt_Init(p, &mainEncoder->props));
+ RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE,
+ mainEncoder->alloc, mainEncoder->allocBig));
+ for (;;)
+ {
+ size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX;
+ res = Lzma2EncInt_EncodeSubblock(p, mainEncoder->outBuf, &packSize, outStream);
+ if (res != SZ_OK)
+ break;
+ packTotal += packSize;
+ res = Progress(progress, p->srcPos, packTotal);
+ if (res != SZ_OK)
+ break;
+ if (packSize == 0)
+ break;
+ }
+ LzmaEnc_Finish(p->enc);
+ if (res == SZ_OK)
+ {
+ Byte b = 0;
+ if (outStream->Write(outStream, &b, 1) != 1)
+ return SZ_ERROR_WRITE;
+ }
+ return res;
+}
+
+#ifndef _7ZIP_ST
+
+typedef struct
+{
+ IMtCoderCallback funcTable;
+ CLzma2Enc *lzma2Enc;
+} CMtCallbackImp;
+
+static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *destSize,
+ const Byte *src, size_t srcSize, int finished)
+{
+ CMtCallbackImp *imp = (CMtCallbackImp *)pp;
+ CLzma2Enc *mainEncoder = imp->lzma2Enc;
+ CLzma2EncInt *p = &mainEncoder->coders[index];
+
+ SRes res = SZ_OK;
+ {
+ size_t destLim = *destSize;
+ *destSize = 0;
+
+ if (srcSize != 0)
+ {
+ RINOK(Lzma2EncInt_Init(p, &mainEncoder->props));
+
+ RINOK(LzmaEnc_MemPrepare(p->enc, src, srcSize, LZMA2_KEEP_WINDOW_SIZE,
+ mainEncoder->alloc, mainEncoder->allocBig));
+
+ while (p->srcPos < srcSize)
+ {
+ size_t packSize = destLim - *destSize;
+ res = Lzma2EncInt_EncodeSubblock(p, dest + *destSize, &packSize, NULL);
+ if (res != SZ_OK)
+ break;
+ *destSize += packSize;
+
+ if (packSize == 0)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+
+ if (MtProgress_Set(&mainEncoder->mtCoder.mtProgress, index, p->srcPos, *destSize) != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ LzmaEnc_Finish(p->enc);
+ if (res != SZ_OK)
+ return res;
+ }
+ if (finished)
+ {
+ if (*destSize == destLim)
+ return SZ_ERROR_OUTPUT_EOF;
+ dest[(*destSize)++] = 0;
+ }
+ }
+ return res;
+}
+
+#endif
+
+/* ---------- Lzma2Enc ---------- */
+
+CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc));
+ if (p == 0)
+ return NULL;
+ Lzma2EncProps_Init(&p->props);
+ Lzma2EncProps_Normalize(&p->props);
+ p->outBuf = 0;
+ p->alloc = alloc;
+ p->allocBig = allocBig;
+ {
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ p->coders[i].enc = 0;
+ }
+ #ifndef _7ZIP_ST
+ MtCoder_Construct(&p->mtCoder);
+ #endif
+
+ return p;
+}
+
+void Lzma2Enc_Destroy(CLzma2EncHandle pp)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ {
+ CLzma2EncInt *t = &p->coders[i];
+ if (t->enc)
+ {
+ LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig);
+ t->enc = 0;
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ MtCoder_Destruct(&p->mtCoder);
+ #endif
+
+ IAlloc_Free(p->alloc, p->outBuf);
+ IAlloc_Free(p->alloc, pp);
+}
+
+SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ CLzmaEncProps lzmaProps = props->lzmaProps;
+ LzmaEncProps_Normalize(&lzmaProps);
+ if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX)
+ return SZ_ERROR_PARAM;
+ p->props = *props;
+ Lzma2EncProps_Normalize(&p->props);
+ return SZ_OK;
+}
+
+Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ unsigned i;
+ UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps);
+ for (i = 0; i < 40; i++)
+ if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i))
+ break;
+ return (Byte)i;
+}
+
+SRes Lzma2Enc_Encode(CLzma2EncHandle pp,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
+{
+ CLzma2Enc *p = (CLzma2Enc *)pp;
+ int i;
+
+ for (i = 0; i < p->props.numBlockThreads; i++)
+ {
+ CLzma2EncInt *t = &p->coders[i];
+ if (t->enc == NULL)
+ {
+ t->enc = LzmaEnc_Create(p->alloc);
+ if (t->enc == NULL)
+ return SZ_ERROR_MEM;
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ if (p->props.numBlockThreads <= 1)
+ #endif
+ return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress);
+
+ #ifndef _7ZIP_ST
+
+ {
+ CMtCallbackImp mtCallback;
+
+ mtCallback.funcTable.Code = MtCallbackImp_Code;
+ mtCallback.lzma2Enc = p;
+
+ p->mtCoder.progress = progress;
+ p->mtCoder.inStream = inStream;
+ p->mtCoder.outStream = outStream;
+ p->mtCoder.alloc = p->alloc;
+ p->mtCoder.mtCallback = &mtCallback.funcTable;
+
+ p->mtCoder.blockSize = p->props.blockSize;
+ p->mtCoder.destBlockSize = p->props.blockSize + (p->props.blockSize >> 10) + 16;
+ p->mtCoder.numThreads = p->props.numBlockThreads;
+
+ return MtCoder_Code(&p->mtCoder);
+ }
+ #endif
+}
diff --git a/src/libs/7zip/win/C/Lzma2Enc.h b/src/libs/7zip/win/C/Lzma2Enc.h
new file mode 100644
index 000000000..283525581
--- /dev/null
+++ b/src/libs/7zip/win/C/Lzma2Enc.h
@@ -0,0 +1,66 @@
+/* Lzma2Enc.h -- LZMA2 Encoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA2_ENC_H
+#define __LZMA2_ENC_H
+
+#include "LzmaEnc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+ CLzmaEncProps lzmaProps;
+ size_t blockSize;
+ int numBlockThreads;
+ int numTotalThreads;
+} CLzma2EncProps;
+
+void Lzma2EncProps_Init(CLzma2EncProps *p);
+void Lzma2EncProps_Normalize(CLzma2EncProps *p);
+
+/* ---------- CLzmaEnc2Handle Interface ---------- */
+
+/* Lzma2Enc_* functions can return the following exit codes:
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - Write callback error
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzma2EncHandle;
+
+CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig);
+void Lzma2Enc_Destroy(CLzma2EncHandle p);
+SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props);
+Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p);
+SRes Lzma2Enc_Encode(CLzma2EncHandle p,
+ ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress);
+
+/* ---------- One Call Interface ---------- */
+
+/* Lzma2Encode
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+/*
+SRes Lzma2Encode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/Lzma86.h b/src/libs/7zip/win/C/Lzma86.h
new file mode 100644
index 000000000..6acbd888a
--- /dev/null
+++ b/src/libs/7zip/win/C/Lzma86.h
@@ -0,0 +1,111 @@
+/* Lzma86.h -- LZMA + x86 (BCJ) Filter
+2009-08-14 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA86_H
+#define __LZMA86_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+#define LZMA86_SIZE_OFFSET (1 + 5)
+#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
+
+/*
+It's an example for LZMA + x86 Filter use.
+You can use .lzma86 extension, if you write that stream to file.
+.lzma86 header adds one additional byte to standard .lzma header.
+.lzma86 header (14 bytes):
+ Offset Size Description
+ 0 1 = 0 - no filter, pure LZMA
+ = 1 - x86 filter + LZMA
+ 1 1 lc, lp and pb in encoded form
+ 2 4 dictSize (little endian)
+ 6 8 uncompressed size (little endian)
+
+
+Lzma86_Encode
+-------------
+level - compression level: 0 <= level <= 9, the default value for "level" is 5.
+
+dictSize - The dictionary size in bytes. The maximum value is
+ 128 MB = (1 << 27) bytes for 32-bit version
+ 1 GB = (1 << 30) bytes for 64-bit version
+ The default value is 16 MB = (1 << 24) bytes, for level = 5.
+ It's recommended to use the dictionary that is larger than 4 KB and
+ that can be calculated as (1 << N) or (3 << N) sizes.
+ For better compression ratio dictSize must be >= inSize.
+
+filterMode:
+ SZ_FILTER_NO - no Filter
+ SZ_FILTER_YES - x86 Filter
+ SZ_FILTER_AUTO - it tries both alternatives to select best.
+ Encoder will use 2 or 3 passes:
+ 2 passes when FILTER_NO provides better compression.
+ 3 passes when FILTER_YES provides better compression.
+
+Lzma86Encode allocates Data with MyAlloc functions.
+RAM Requirements for compressing:
+ RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize
+ filterMode FilterBlockSize
+ SZ_FILTER_NO 0
+ SZ_FILTER_YES inSize
+ SZ_FILTER_AUTO inSize
+
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+enum ESzFilterMode
+{
+ SZ_FILTER_NO,
+ SZ_FILTER_YES,
+ SZ_FILTER_AUTO
+};
+
+SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
+ int level, UInt32 dictSize, int filterMode);
+
+
+/*
+Lzma86_GetUnpackSize:
+ In:
+ src - input data
+ srcLen - input data size
+ Out:
+ unpackSize - size of uncompressed stream
+ Return code:
+ SZ_OK - OK
+ SZ_ERROR_INPUT_EOF - Error in headers
+*/
+
+SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize);
+
+/*
+Lzma86_Decode:
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+ Return code:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - unsupported file
+ SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer
+*/
+
+SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/Lzma86Dec.c b/src/libs/7zip/win/C/Lzma86Dec.c
new file mode 100644
index 000000000..fe7726097
--- /dev/null
+++ b/src/libs/7zip/win/C/Lzma86Dec.c
@@ -0,0 +1,56 @@
+/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder
+2009-08-14 : Igor Pavlov : Public domain */
+
+#include "Lzma86.h"
+
+#include "Alloc.h"
+#include "Bra.h"
+#include "LzmaDec.h"
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+
+SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize)
+{
+ unsigned i;
+ if (srcLen < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+ *unpackSize = 0;
+ for (i = 0; i < sizeof(UInt64); i++)
+ *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i);
+ return SZ_OK;
+}
+
+SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
+{
+ ISzAlloc g_Alloc = { SzAlloc, SzFree };
+ SRes res;
+ int useFilter;
+ SizeT inSizePure;
+ ELzmaStatus status;
+
+ if (*srcLen < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+
+ useFilter = src[0];
+
+ if (useFilter > 1)
+ {
+ *destLen = 0;
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ inSizePure = *srcLen - LZMA86_HEADER_SIZE;
+ res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure,
+ src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc);
+ *srcLen = inSizePure + LZMA86_HEADER_SIZE;
+ if (res != SZ_OK)
+ return res;
+ if (useFilter == 1)
+ {
+ UInt32 x86State;
+ x86_Convert_Init(x86State);
+ x86_Convert(dest, *destLen, 0, &x86State, 0);
+ }
+ return SZ_OK;
+}
diff --git a/src/libs/7zip/win/C/Lzma86Enc.c b/src/libs/7zip/win/C/Lzma86Enc.c
new file mode 100644
index 000000000..2ea4ac2da
--- /dev/null
+++ b/src/libs/7zip/win/C/Lzma86Enc.c
@@ -0,0 +1,108 @@
+/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
+2009-08-14 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "Lzma86.h"
+
+#include "Alloc.h"
+#include "Bra.h"
+#include "LzmaEnc.h"
+
+#define SZE_OUT_OVERFLOW SZE_DATA_ERROR
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+
+int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
+ int level, UInt32 dictSize, int filterMode)
+{
+ ISzAlloc g_Alloc = { SzAlloc, SzFree };
+ size_t outSize2 = *destLen;
+ Byte *filteredStream;
+ Bool useFilter;
+ int mainResult = SZ_ERROR_OUTPUT_EOF;
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ props.level = level;
+ props.dictSize = dictSize;
+
+ *destLen = 0;
+ if (outSize2 < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ {
+ int i;
+ UInt64 t = srcLen;
+ for (i = 0; i < 8; i++, t >>= 8)
+ dest[LZMA86_SIZE_OFFSET + i] = (Byte)t;
+ }
+
+ filteredStream = 0;
+ useFilter = (filterMode != SZ_FILTER_NO);
+ if (useFilter)
+ {
+ if (srcLen != 0)
+ {
+ filteredStream = (Byte *)MyAlloc(srcLen);
+ if (filteredStream == 0)
+ return SZ_ERROR_MEM;
+ memcpy(filteredStream, src, srcLen);
+ }
+ {
+ UInt32 x86State;
+ x86_Convert_Init(x86State);
+ x86_Convert(filteredStream, srcLen, 0, &x86State, 1);
+ }
+ }
+
+ {
+ size_t minSize = 0;
+ Bool bestIsFiltered = False;
+
+ /* passes for SZ_FILTER_AUTO:
+ 0 - BCJ + LZMA
+ 1 - LZMA
+ 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better.
+ */
+ int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1;
+
+ int i;
+ for (i = 0; i < numPasses; i++)
+ {
+ size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE;
+ size_t outPropsSize = 5;
+ SRes curRes;
+ Bool curModeIsFiltered = (numPasses > 1 && i == numPasses - 1);
+ if (curModeIsFiltered && !bestIsFiltered)
+ break;
+ if (useFilter && i == 0)
+ curModeIsFiltered = True;
+
+ curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed,
+ curModeIsFiltered ? filteredStream : src, srcLen,
+ &props, dest + 1, &outPropsSize, 0,
+ NULL, &g_Alloc, &g_Alloc);
+
+ if (curRes != SZ_ERROR_OUTPUT_EOF)
+ {
+ if (curRes != SZ_OK)
+ {
+ mainResult = curRes;
+ break;
+ }
+ if (outSizeProcessed <= minSize || mainResult != SZ_OK)
+ {
+ minSize = outSizeProcessed;
+ bestIsFiltered = curModeIsFiltered;
+ mainResult = SZ_OK;
+ }
+ }
+ }
+ dest[0] = (bestIsFiltered ? 1 : 0);
+ *destLen = LZMA86_HEADER_SIZE + minSize;
+ }
+ if (useFilter)
+ MyFree(filteredStream);
+ return mainResult;
+}
diff --git a/src/libs/7zip/win/C/LzmaDec.c b/src/libs/7zip/win/C/LzmaDec.c
new file mode 100644
index 000000000..2036761bf
--- /dev/null
+++ b/src/libs/7zip/win/C/LzmaDec.c
@@ -0,0 +1,999 @@
+/* LzmaDec.c -- LZMA Decoder
+2009-09-20 : Igor Pavlov : Public domain */
+
+#include "LzmaDec.h"
+
+#include <string.h>
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_INIT_SIZE 5
+
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p); i = (i + i); A0; } else \
+ { UPDATE_1(p); i = (i + i) + 1; A1; }
+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
+
+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ i -= 0x40; }
+#endif
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/* First LZMA-symbol is always decoded.
+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
+Out:
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : Flush marker
+ = kMatchSpecLenStart + 2 : State Init Marker
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = p->probs;
+
+ unsigned state = p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
+ unsigned lc = p->prop.lc;
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = processedPos & pbMask;
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (checkDicSize != 0 || processedPos != 0)
+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+
+ if (state < kNumLitStates)
+ {
+ state -= (state < 4) ? state : 3;
+ symbol = 1;
+ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ state -= (state < 10) ? 3 : 6;
+ symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ dic[dicPos++] = (Byte)symbol;
+ processedPos++;
+ continue;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob);
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob);
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = (1 << kLenNumMidBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance);
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ int numDirectBits = (int)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos + distance - posSlot - 1;
+ {
+ UInt32 mask = 1;
+ unsigned i = 1;
+ do
+ {
+ GET_BIT2(prob + i, i, ; , distance |= mask);
+ mask <<= 1;
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ GET_BIT2(prob + i, i, ; , distance |= 1);
+ GET_BIT2(prob + i, i, ; , distance |= 2);
+ GET_BIT2(prob + i, i, ; , distance |= 4);
+ GET_BIT2(prob + i, i, ; , distance |= 8);
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len += kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ if (checkDicSize == 0)
+ {
+ if (distance >= processedPos)
+ return SZ_ERROR_DATA;
+ }
+ else if (distance >= checkDicSize)
+ return SZ_ERROR_DATA;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ }
+
+ len += kMatchMinLen;
+
+ if (limit == dicPos)
+ return SZ_ERROR_DATA;
+ {
+ SizeT rem = limit - dicPos;
+ unsigned curLen = ((rem < len) ? (unsigned)rem : len);
+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (pos + curLen <= dicBufSize)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += curLen;
+ do
+ *(dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+ NORMALIZE;
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = len;
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = state;
+
+ return SZ_OK;
+}
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
+ {
+ Byte *dic = p->dic;
+ SizeT dicPos = p->dicPos;
+ SizeT dicBufSize = p->dicBufSize;
+ unsigned len = p->remainLen;
+ UInt32 rep0 = p->reps[0];
+ if (limit - dicPos < len)
+ len = (unsigned)(limit - dicPos);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len-- != 0)
+ {
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ do
+ {
+ SizeT limit2 = limit;
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit2 = p->dicPos + rem;
+ }
+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
+ if (p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ p->remainLen = kMatchSpecLenStart;
+ }
+ return 0;
+}
+
+typedef enum
+{
+ DUMMY_ERROR, /* unexpected end of input stream */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = buf + inSize;
+ CLzmaProb *probs = p->probs;
+ unsigned state = p->state;
+ ELzmaDummy res;
+
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += (LZMA_LIT_SIZE *
+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK;
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ NORMALIZE_CHECK;
+ return DUMMY_REP;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumMidBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ do
+ {
+ GET_BIT_CHECK(prob + i, i);
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+
+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
+{
+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->needFlush = 1;
+ p->remainLen = 0;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->needInitState = 1;
+ }
+ if (initState)
+ p->needInitState = 1;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+static void LzmaDec_InitStateReal(CLzmaDec *p)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
+ UInt32 i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ p->needInitState = 0;
+}
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ LzmaDec_WriteRem(p, dicLimit);
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int checkEndMarkNow;
+
+ if (p->needFlush != 0)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitRc(p, p->tempBuf);
+ p->tempBufSize = 0;
+ }
+
+ checkEndMarkNow = 0;
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ checkEndMarkNow = 1;
+ }
+
+ if (p->needInitState)
+ LzmaDec_InitStateReal(p);
+
+ if (p->tempBufSize == 0)
+ {
+ SizeT processed;
+ const Byte *bufLimit;
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, src, inSize);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ memcpy(p->tempBuf, src, inSize);
+ p->tempBufSize = (unsigned)inSize;
+ (*srcLen) += inSize;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ bufLimit = src;
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+ p->buf = src;
+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
+ return SZ_ERROR_DATA;
+ processed = (SizeT)(p->buf - src);
+ (*srcLen) += processed;
+ src += processed;
+ inSize -= processed;
+ }
+ else
+ {
+ unsigned rem = p->tempBufSize, lookAhead = 0;
+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
+ p->tempBuf[rem++] = src[lookAhead++];
+ p->tempBufSize = rem;
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ (*srcLen) += lookAhead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ }
+ p->buf = p->tempBuf;
+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
+ return SZ_ERROR_DATA;
+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+ if (p->code == 0)
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+}
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->probs);
+ p->probs = 0;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->dic);
+ p->dic = 0;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = d % 9;
+ d /= 9;
+ p->pb = d / 5;
+ p->lp = d % 5;
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (p->probs == 0 || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ p->numProbs = numProbs;
+ if (p->probs == 0)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ dicBufSize = propNew.dicSize;
+ if (p->dic == 0 || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+ if (p->dic == 0)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT inSize = *srcLen;
+ SizeT outSize = *destLen;
+ *srcLen = *destLen = 0;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+
+ LzmaDec_Construct(&p);
+ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
+ if (res != 0)
+ return res;
+ p.dic = dest;
+ p.dicBufSize = outSize;
+
+ LzmaDec_Init(&p);
+
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+
+ (*destLen) = p.dicPos;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/src/libs/7zip/win/C/LzmaDec.h b/src/libs/7zip/win/C/LzmaDec.h
new file mode 100644
index 000000000..bf7f084ba
--- /dev/null
+++ b/src/libs/7zip/win/C/LzmaDec.h
@@ -0,0 +1,231 @@
+/* LzmaDec.h -- LZMA Decoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_DEC_H
+#define __LZMA_DEC_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ unsigned lc, lp, pb;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ Byte *dic;
+ const Byte *buf;
+ UInt32 range, code;
+ SizeT dicPos;
+ SizeT dicBufSize;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ unsigned state;
+ UInt32 reps[4];
+ unsigned remainLen;
+ int needFlush;
+ int needInitState;
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Constr()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/LzmaEnc.c b/src/libs/7zip/win/C/LzmaEnc.c
new file mode 100644
index 000000000..cf131388a
--- /dev/null
+++ b/src/libs/7zip/win/C/LzmaEnc.c
@@ -0,0 +1,2268 @@
+/* LzmaEnc.c -- LZMA Encoder
+2010-04-16 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+/* #define SHOW_STAT */
+/* #define SHOW_STAT2 */
+
+#if defined(SHOW_STAT) || defined(SHOW_STAT2)
+#include <stdio.h>
+#endif
+
+#include "LzmaEnc.h"
+
+#include "LzFind.h"
+#ifndef _7ZIP_ST
+#include "LzFindMt.h"
+#endif
+
+#ifdef SHOW_STAT
+static int ttt = 0;
+#endif
+
+#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
+
+#define kBlockSize (9 << 10)
+#define kUnpackBlockSize (1 << 18)
+#define kMatchArraySize (1 << 21)
+#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
+
+#define kNumMaxDirectBits (31)
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+#define kProbInitValue (kBitModelTotal >> 1)
+
+#define kNumMoveReducingBits 4
+#define kNumBitPriceShiftBits 4
+#define kBitPrice (1 << kNumBitPriceShiftBits)
+
+void LzmaEncProps_Init(CLzmaEncProps *p)
+{
+ p->level = 5;
+ p->dictSize = p->mc = 0;
+ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
+ p->writeEndMark = 0;
+}
+
+void LzmaEncProps_Normalize(CLzmaEncProps *p)
+{
+ int level = p->level;
+ if (level < 0) level = 5;
+ p->level = level;
+ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
+ if (p->lc < 0) p->lc = 3;
+ if (p->lp < 0) p->lp = 0;
+ if (p->pb < 0) p->pb = 2;
+ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
+ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
+ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
+ if (p->numHashBytes < 0) p->numHashBytes = 4;
+ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
+ if (p->numThreads < 0)
+ p->numThreads =
+ #ifndef _7ZIP_ST
+ ((p->btMode && p->algo) ? 2 : 1);
+ #else
+ 1;
+ #endif
+}
+
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+{
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+ return props.dictSize;
+}
+
+/* #define LZMA_LOG_BSR */
+/* Define it for Intel's CPU */
+
+
+#ifdef LZMA_LOG_BSR
+
+#define kDicLogSizeMaxCompress 30
+
+#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
+
+UInt32 GetPosSlot1(UInt32 pos)
+{
+ UInt32 res;
+ BSR2_RET(pos, res);
+ return res;
+}
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
+
+#else
+
+#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
+#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+
+void LzmaEnc_FastPosInit(Byte *g_FastPos)
+{
+ int c = 2, slotFast;
+ g_FastPos[0] = 0;
+ g_FastPos[1] = 1;
+
+ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
+ {
+ UInt32 k = (1 << ((slotFast >> 1) - 1));
+ UInt32 j;
+ for (j = 0; j < k; j++, c++)
+ g_FastPos[c] = (Byte)slotFast;
+ }
+}
+
+#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
+ res = p->g_FastPos[pos >> i] + (i * 2); }
+/*
+#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
+ p->g_FastPos[pos >> 6] + 12 : \
+ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
+*/
+
+#define GetPosSlot1(pos) p->g_FastPos[pos]
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
+
+#endif
+
+
+#define LZMA_NUM_REPS 4
+
+typedef unsigned CState;
+
+typedef struct
+{
+ UInt32 price;
+
+ CState state;
+ int prev1IsChar;
+ int prev2;
+
+ UInt32 posPrev2;
+ UInt32 backPrev2;
+
+ UInt32 posPrev;
+ UInt32 backPrev;
+ UInt32 backs[LZMA_NUM_REPS];
+} COptimal;
+
+#define kNumOpts (1 << 12)
+
+#define kNumLenToPosStates 4
+#define kNumPosSlotBits 6
+#define kDicLogSizeMin 0
+#define kDicLogSizeMax 32
+#define kDistTableSizeMax (kDicLogSizeMax * 2)
+
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+#define kAlignMask (kAlignTableSize - 1)
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
+
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+#define LZMA_PB_MAX 4
+#define LZMA_LC_MAX 8
+#define LZMA_LP_MAX 4
+
+#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
+
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define LZMA_MATCH_LEN_MIN 2
+#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
+
+#define kNumStates 12
+
+typedef struct
+{
+ CLzmaProb choice;
+ CLzmaProb choice2;
+ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
+ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
+ CLzmaProb high[kLenNumHighSymbols];
+} CLenEnc;
+
+typedef struct
+{
+ CLenEnc p;
+ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
+ UInt32 tableSize;
+ UInt32 counters[LZMA_NUM_PB_STATES_MAX];
+} CLenPriceEnc;
+
+typedef struct
+{
+ UInt32 range;
+ Byte cache;
+ UInt64 low;
+ UInt64 cacheSize;
+ Byte *buf;
+ Byte *bufLim;
+ Byte *bufBase;
+ ISeqOutStream *outStream;
+ UInt64 processed;
+ SRes res;
+} CRangeEnc;
+
+typedef struct
+{
+ CLzmaProb *litProbs;
+
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+} CSaveState;
+
+typedef struct
+{
+ IMatchFinder matchFinder;
+ void *matchFinderObj;
+
+ #ifndef _7ZIP_ST
+ Bool mtMode;
+ CMatchFinderMt matchFinderMt;
+ #endif
+
+ CMatchFinder matchFinderBase;
+
+ #ifndef _7ZIP_ST
+ Byte pad[128];
+ #endif
+
+ UInt32 optimumEndIndex;
+ UInt32 optimumCurrentIndex;
+
+ UInt32 longestMatchLength;
+ UInt32 numPairs;
+ UInt32 numAvail;
+ COptimal opt[kNumOpts];
+
+ #ifndef LZMA_LOG_BSR
+ Byte g_FastPos[1 << kNumLogBits];
+ #endif
+
+ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
+ UInt32 numFastBytes;
+ UInt32 additionalOffset;
+ UInt32 reps[LZMA_NUM_REPS];
+ UInt32 state;
+
+ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
+ UInt32 alignPrices[kAlignTableSize];
+ UInt32 alignPriceCount;
+
+ UInt32 distTableSize;
+
+ unsigned lc, lp, pb;
+ unsigned lpMask, pbMask;
+
+ CLzmaProb *litProbs;
+
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ unsigned lclp;
+
+ Bool fastMode;
+
+ CRangeEnc rc;
+
+ Bool writeEndMark;
+ UInt64 nowPos64;
+ UInt32 matchPriceCount;
+ Bool finished;
+ Bool multiThread;
+
+ SRes result;
+ UInt32 dictSize;
+ UInt32 matchFinderCycles;
+
+ int needInit;
+
+ CSaveState saveState;
+} CLzmaEnc;
+
+void LzmaEnc_SaveState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CSaveState *dest = &p->saveState;
+ int i;
+ dest->lenEnc = p->lenEnc;
+ dest->repLenEnc = p->repLenEnc;
+ dest->state = p->state;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+ }
+ for (i = 0; i < kNumLenToPosStates; i++)
+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+ memcpy(dest->reps, p->reps, sizeof(p->reps));
+ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+}
+
+void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *dest = (CLzmaEnc *)pp;
+ const CSaveState *p = &dest->saveState;
+ int i;
+ dest->lenEnc = p->lenEnc;
+ dest->repLenEnc = p->repLenEnc;
+ dest->state = p->state;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+ }
+ for (i = 0; i < kNumLenToPosStates; i++)
+ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+ memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+ memcpy(dest->reps, p->reps, sizeof(p->reps));
+ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
+}
+
+SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+
+ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
+ props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30))
+ return SZ_ERROR_PARAM;
+ p->dictSize = props.dictSize;
+ p->matchFinderCycles = props.mc;
+ {
+ unsigned fb = props.fb;
+ if (fb < 5)
+ fb = 5;
+ if (fb > LZMA_MATCH_LEN_MAX)
+ fb = LZMA_MATCH_LEN_MAX;
+ p->numFastBytes = fb;
+ }
+ p->lc = props.lc;
+ p->lp = props.lp;
+ p->pb = props.pb;
+ p->fastMode = (props.algo == 0);
+ p->matchFinderBase.btMode = props.btMode;
+ {
+ UInt32 numHashBytes = 4;
+ if (props.btMode)
+ {
+ if (props.numHashBytes < 2)
+ numHashBytes = 2;
+ else if (props.numHashBytes < 4)
+ numHashBytes = props.numHashBytes;
+ }
+ p->matchFinderBase.numHashBytes = numHashBytes;
+ }
+
+ p->matchFinderBase.cutValue = props.mc;
+
+ p->writeEndMark = props.writeEndMark;
+
+ #ifndef _7ZIP_ST
+ /*
+ if (newMultiThread != _multiThread)
+ {
+ ReleaseMatchFinder();
+ _multiThread = newMultiThread;
+ }
+ */
+ p->multiThread = (props.numThreads > 1);
+ #endif
+
+ return SZ_OK;
+}
+
+static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
+static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+#define IsCharState(s) ((s) < 7)
+
+#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
+
+#define kInfinityPrice (1 << 30)
+
+static void RangeEnc_Construct(CRangeEnc *p)
+{
+ p->outStream = 0;
+ p->bufBase = 0;
+}
+
+#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
+
+#define RC_BUF_SIZE (1 << 16)
+static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
+{
+ if (p->bufBase == 0)
+ {
+ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
+ if (p->bufBase == 0)
+ return 0;
+ p->bufLim = p->bufBase + RC_BUF_SIZE;
+ }
+ return 1;
+}
+
+static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->bufBase);
+ p->bufBase = 0;
+}
+
+static void RangeEnc_Init(CRangeEnc *p)
+{
+ /* Stream.Init(); */
+ p->low = 0;
+ p->range = 0xFFFFFFFF;
+ p->cacheSize = 1;
+ p->cache = 0;
+
+ p->buf = p->bufBase;
+
+ p->processed = 0;
+ p->res = SZ_OK;
+}
+
+static void RangeEnc_FlushStream(CRangeEnc *p)
+{
+ size_t num;
+ if (p->res != SZ_OK)
+ return;
+ num = p->buf - p->bufBase;
+ if (num != p->outStream->Write(p->outStream, p->bufBase, num))
+ p->res = SZ_ERROR_WRITE;
+ p->processed += num;
+ p->buf = p->bufBase;
+}
+
+static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
+{
+ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
+ {
+ Byte temp = p->cache;
+ do
+ {
+ Byte *buf = p->buf;
+ *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
+ p->buf = buf;
+ if (buf == p->bufLim)
+ RangeEnc_FlushStream(p);
+ temp = 0xFF;
+ }
+ while (--p->cacheSize != 0);
+ p->cache = (Byte)((UInt32)p->low >> 24);
+ }
+ p->cacheSize++;
+ p->low = (UInt32)p->low << 8;
+}
+
+static void RangeEnc_FlushData(CRangeEnc *p)
+{
+ int i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
+{
+ do
+ {
+ p->range >>= 1;
+ p->low += p->range & (0 - ((value >> --numBits) & 1));
+ if (p->range < kTopValue)
+ {
+ p->range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+ }
+ while (numBits != 0);
+}
+
+static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
+{
+ UInt32 ttt = *prob;
+ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
+ if (symbol == 0)
+ {
+ p->range = newBound;
+ ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
+ }
+ else
+ {
+ p->low += newBound;
+ p->range -= newBound;
+ ttt -= ttt >> kNumMoveBits;
+ }
+ *prob = (CLzmaProb)ttt;
+ if (p->range < kTopValue)
+ {
+ p->range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
+{
+ symbol |= 0x100;
+ do
+ {
+ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
+ symbol <<= 1;
+ }
+ while (symbol < 0x10000);
+}
+
+static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
+{
+ UInt32 offs = 0x100;
+ symbol |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
+ symbol <<= 1;
+ offs &= ~(matchByte ^ symbol);
+ }
+ while (symbol < 0x10000);
+}
+
+void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+{
+ UInt32 i;
+ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
+ {
+ const int kCyclesBits = kNumBitPriceShiftBits;
+ UInt32 w = i;
+ UInt32 bitCount = 0;
+ int j;
+ for (j = 0; j < kCyclesBits; j++)
+ {
+ w = w * w;
+ bitCount <<= 1;
+ while (w >= ((UInt32)1 << 16))
+ {
+ w >>= 1;
+ bitCount++;
+ }
+ }
+ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
+ }
+}
+
+
+#define GET_PRICE(prob, symbol) \
+ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICEa(prob, symbol) \
+ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ symbol |= 0x100;
+ do
+ {
+ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
+ symbol <<= 1;
+ }
+ while (symbol < 0x10000);
+ return price;
+}
+
+static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 offs = 0x100;
+ symbol |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
+ symbol <<= 1;
+ offs &= ~(matchByte ^ symbol);
+ }
+ while (symbol < 0x10000);
+ return price;
+}
+
+
+static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
+{
+ UInt32 m = 1;
+ int i;
+ for (i = numBitLevels; i != 0;)
+ {
+ UInt32 bit;
+ i--;
+ bit = (symbol >> i) & 1;
+ RangeEnc_EncodeBit(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ }
+}
+
+static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
+{
+ UInt32 m = 1;
+ int i;
+ for (i = 0; i < numBitLevels; i++)
+ {
+ UInt32 bit = symbol & 1;
+ RangeEnc_EncodeBit(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ symbol >>= 1;
+ }
+}
+
+static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ symbol |= (1 << numBitLevels);
+ while (symbol != 1)
+ {
+ price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
+ symbol >>= 1;
+ }
+ return price;
+}
+
+static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 m = 1;
+ int i;
+ for (i = numBitLevels; i != 0; i--)
+ {
+ UInt32 bit = symbol & 1;
+ symbol >>= 1;
+ price += GET_PRICEa(probs[m], bit);
+ m = (m << 1) | bit;
+ }
+ return price;
+}
+
+
+static void LenEnc_Init(CLenEnc *p)
+{
+ unsigned i;
+ p->choice = p->choice2 = kProbInitValue;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
+ p->low[i] = kProbInitValue;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
+ p->mid[i] = kProbInitValue;
+ for (i = 0; i < kLenNumHighSymbols; i++)
+ p->high[i] = kProbInitValue;
+}
+
+static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
+{
+ if (symbol < kLenNumLowSymbols)
+ {
+ RangeEnc_EncodeBit(rc, &p->choice, 0);
+ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
+ }
+ else
+ {
+ RangeEnc_EncodeBit(rc, &p->choice, 1);
+ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
+ {
+ RangeEnc_EncodeBit(rc, &p->choice2, 0);
+ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
+ }
+ else
+ {
+ RangeEnc_EncodeBit(rc, &p->choice2, 1);
+ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
+ }
+ }
+}
+
+static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
+{
+ UInt32 a0 = GET_PRICE_0a(p->choice);
+ UInt32 a1 = GET_PRICE_1a(p->choice);
+ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
+ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
+ UInt32 i = 0;
+ for (i = 0; i < kLenNumLowSymbols; i++)
+ {
+ if (i >= numSymbols)
+ return;
+ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
+ }
+ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
+ {
+ if (i >= numSymbols)
+ return;
+ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
+ }
+ for (; i < numSymbols; i++)
+ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
+}
+
+static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
+{
+ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
+ p->counters[posState] = p->tableSize;
+}
+
+static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
+{
+ UInt32 posState;
+ for (posState = 0; posState < numPosStates; posState++)
+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
+}
+
+static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
+{
+ LenEnc_Encode(&p->p, rc, symbol, posState);
+ if (updatePrice)
+ if (--p->counters[posState] == 0)
+ LenPriceEnc_UpdateTable(p, posState, ProbPrices);
+}
+
+
+
+
+static void MovePos(CLzmaEnc *p, UInt32 num)
+{
+ #ifdef SHOW_STAT
+ ttt += num;
+ printf("\n MovePos %d", num);
+ #endif
+ if (num != 0)
+ {
+ p->additionalOffset += num;
+ p->matchFinder.Skip(p->matchFinderObj, num);
+ }
+}
+
+static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
+{
+ UInt32 lenRes = 0, numPairs;
+ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
+ #ifdef SHOW_STAT
+ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2);
+ ttt++;
+ {
+ UInt32 i;
+ for (i = 0; i < numPairs; i += 2)
+ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]);
+ }
+ #endif
+ if (numPairs > 0)
+ {
+ lenRes = p->matches[numPairs - 2];
+ if (lenRes == p->numFastBytes)
+ {
+ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ UInt32 distance = p->matches[numPairs - 1] + 1;
+ UInt32 numAvail = p->numAvail;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ {
+ const Byte *pby2 = pby - distance;
+ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
+ }
+ }
+ }
+ p->additionalOffset++;
+ *numDistancePairsRes = numPairs;
+ return lenRes;
+}
+
+
+#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
+#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
+#define IsShortRep(p) ((p)->backPrev == 0)
+
+static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
+{
+ return
+ GET_PRICE_0(p->isRepG0[state]) +
+ GET_PRICE_0(p->isRep0Long[state][posState]);
+}
+
+static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
+{
+ UInt32 price;
+ if (repIndex == 0)
+ {
+ price = GET_PRICE_0(p->isRepG0[state]);
+ price += GET_PRICE_1(p->isRep0Long[state][posState]);
+ }
+ else
+ {
+ price = GET_PRICE_1(p->isRepG0[state]);
+ if (repIndex == 1)
+ price += GET_PRICE_0(p->isRepG1[state]);
+ else
+ {
+ price += GET_PRICE_1(p->isRepG1[state]);
+ price += GET_PRICE(p->isRepG2[state], repIndex - 2);
+ }
+ }
+ return price;
+}
+
+static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
+{
+ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
+ GetPureRepPrice(p, repIndex, state, posState);
+}
+
+static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
+{
+ UInt32 posMem = p->opt[cur].posPrev;
+ UInt32 backMem = p->opt[cur].backPrev;
+ p->optimumEndIndex = cur;
+ do
+ {
+ if (p->opt[cur].prev1IsChar)
+ {
+ MakeAsChar(&p->opt[posMem])
+ p->opt[posMem].posPrev = posMem - 1;
+ if (p->opt[cur].prev2)
+ {
+ p->opt[posMem - 1].prev1IsChar = False;
+ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
+ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
+ }
+ }
+ {
+ UInt32 posPrev = posMem;
+ UInt32 backCur = backMem;
+
+ backMem = p->opt[posPrev].backPrev;
+ posMem = p->opt[posPrev].posPrev;
+
+ p->opt[posPrev].backPrev = backCur;
+ p->opt[posPrev].posPrev = cur;
+ cur = posPrev;
+ }
+ }
+ while (cur != 0);
+ *backRes = p->opt[0].backPrev;
+ p->optimumCurrentIndex = p->opt[0].posPrev;
+ return p->optimumCurrentIndex;
+}
+
+#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
+
+static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
+{
+ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
+ UInt32 matchPrice, repMatchPrice, normalMatchPrice;
+ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
+ UInt32 *matches;
+ const Byte *data;
+ Byte curByte, matchByte;
+ if (p->optimumEndIndex != p->optimumCurrentIndex)
+ {
+ const COptimal *opt = &p->opt[p->optimumCurrentIndex];
+ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
+ *backRes = opt->backPrev;
+ p->optimumCurrentIndex = opt->posPrev;
+ return lenRes;
+ }
+ p->optimumCurrentIndex = p->optimumEndIndex = 0;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLength;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ if (numAvail < 2)
+ {
+ *backRes = (UInt32)(-1);
+ return 1;
+ }
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ repMaxIndex = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 lenTest;
+ const Byte *data2;
+ reps[i] = p->reps[i];
+ data2 = data - (reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ {
+ repLens[i] = 0;
+ continue;
+ }
+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
+ repLens[i] = lenTest;
+ if (lenTest > repLens[repMaxIndex])
+ repMaxIndex = i;
+ }
+ if (repLens[repMaxIndex] >= p->numFastBytes)
+ {
+ UInt32 lenRes;
+ *backRes = repMaxIndex;
+ lenRes = repLens[repMaxIndex];
+ MovePos(p, lenRes - 1);
+ return lenRes;
+ }
+
+ matches = p->matches;
+ if (mainLen >= p->numFastBytes)
+ {
+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 1);
+ return mainLen;
+ }
+ curByte = *data;
+ matchByte = *(data - (reps[0] + 1));
+
+ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
+ {
+ *backRes = (UInt32)-1;
+ return 1;
+ }
+
+ p->opt[0].state = (CState)p->state;
+
+ posState = (position & p->pbMask);
+
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
+ (!IsCharState(p->state) ?
+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ MakeAsChar(&p->opt[1]);
+
+ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
+
+ if (matchByte == curByte)
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
+ if (shortRepPrice < p->opt[1].price)
+ {
+ p->opt[1].price = shortRepPrice;
+ MakeAsShortRep(&p->opt[1]);
+ }
+ }
+ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
+
+ if (lenEnd < 2)
+ {
+ *backRes = p->opt[1].backPrev;
+ return 1;
+ }
+
+ p->opt[1].posPrev = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ p->opt[0].backs[i] = reps[i];
+
+ len = lenEnd;
+ do
+ p->opt[len--].price = kInfinityPrice;
+ while (len >= 2);
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 repLen = repLens[i];
+ UInt32 price;
+ if (repLen < 2)
+ continue;
+ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
+ do
+ {
+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
+ COptimal *opt = &p->opt[repLen];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = 0;
+ opt->backPrev = i;
+ opt->prev1IsChar = False;
+ }
+ }
+ while (--repLen >= 2);
+ }
+
+ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
+
+ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
+ if (len <= mainLen)
+ {
+ UInt32 offs = 0;
+ while (len > matches[offs])
+ offs += 2;
+ for (; ; len++)
+ {
+ COptimal *opt;
+ UInt32 distance = matches[offs + 1];
+
+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
+ UInt32 lenToPosState = GetLenToPosState(len);
+ if (distance < kNumFullDistances)
+ curAndLenPrice += p->distancesPrices[lenToPosState][distance];
+ else
+ {
+ UInt32 slot;
+ GetPosSlot2(distance, slot);
+ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
+ }
+ opt = &p->opt[len];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = 0;
+ opt->backPrev = distance + LZMA_NUM_REPS;
+ opt->prev1IsChar = False;
+ }
+ if (len == matches[offs])
+ {
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ }
+ }
+ }
+
+ cur = 0;
+
+ #ifdef SHOW_STAT2
+ if (position >= 0)
+ {
+ unsigned i;
+ printf("\n pos = %4X", position);
+ for (i = cur; i <= lenEnd; i++)
+ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
+ }
+ #endif
+
+ for (;;)
+ {
+ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
+ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
+ Bool nextIsChar;
+ Byte curByte, matchByte;
+ const Byte *data;
+ COptimal *curOpt;
+ COptimal *nextOpt;
+
+ cur++;
+ if (cur == lenEnd)
+ return Backward(p, backRes, cur);
+
+ newLen = ReadMatchDistances(p, &numPairs);
+ if (newLen >= p->numFastBytes)
+ {
+ p->numPairs = numPairs;
+ p->longestMatchLength = newLen;
+ return Backward(p, backRes, cur);
+ }
+ position++;
+ curOpt = &p->opt[cur];
+ posPrev = curOpt->posPrev;
+ if (curOpt->prev1IsChar)
+ {
+ posPrev--;
+ if (curOpt->prev2)
+ {
+ state = p->opt[curOpt->posPrev2].state;
+ if (curOpt->backPrev2 < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+ else
+ state = p->opt[posPrev].state;
+ state = kLiteralNextStates[state];
+ }
+ else
+ state = p->opt[posPrev].state;
+ if (posPrev == cur - 1)
+ {
+ if (IsShortRep(curOpt))
+ state = kShortRepNextStates[state];
+ else
+ state = kLiteralNextStates[state];
+ }
+ else
+ {
+ UInt32 pos;
+ const COptimal *prevOpt;
+ if (curOpt->prev1IsChar && curOpt->prev2)
+ {
+ posPrev = curOpt->posPrev2;
+ pos = curOpt->backPrev2;
+ state = kRepNextStates[state];
+ }
+ else
+ {
+ pos = curOpt->backPrev;
+ if (pos < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+ prevOpt = &p->opt[posPrev];
+ if (pos < LZMA_NUM_REPS)
+ {
+ UInt32 i;
+ reps[0] = prevOpt->backs[pos];
+ for (i = 1; i <= pos; i++)
+ reps[i] = prevOpt->backs[i - 1];
+ for (; i < LZMA_NUM_REPS; i++)
+ reps[i] = prevOpt->backs[i];
+ }
+ else
+ {
+ UInt32 i;
+ reps[0] = (pos - LZMA_NUM_REPS);
+ for (i = 1; i < LZMA_NUM_REPS; i++)
+ reps[i] = prevOpt->backs[i - 1];
+ }
+ }
+ curOpt->state = (CState)state;
+
+ curOpt->backs[0] = reps[0];
+ curOpt->backs[1] = reps[1];
+ curOpt->backs[2] = reps[2];
+ curOpt->backs[3] = reps[3];
+
+ curPrice = curOpt->price;
+ nextIsChar = False;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ curByte = *data;
+ matchByte = *(data - (reps[0] + 1));
+
+ posState = (position & p->pbMask);
+
+ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ curAnd1Price +=
+ (!IsCharState(state) ?
+ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ nextOpt = &p->opt[cur + 1];
+
+ if (curAnd1Price < nextOpt->price)
+ {
+ nextOpt->price = curAnd1Price;
+ nextOpt->posPrev = cur;
+ MakeAsChar(nextOpt);
+ nextIsChar = True;
+ }
+
+ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
+
+ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
+ if (shortRepPrice <= nextOpt->price)
+ {
+ nextOpt->price = shortRepPrice;
+ nextOpt->posPrev = cur;
+ MakeAsShortRep(nextOpt);
+ nextIsChar = True;
+ }
+ }
+ numAvailFull = p->numAvail;
+ {
+ UInt32 temp = kNumOpts - 1 - cur;
+ if (temp < numAvailFull)
+ numAvailFull = temp;
+ }
+
+ if (numAvailFull < 2)
+ continue;
+ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
+
+ if (!nextIsChar && matchByte != curByte) /* speed optimization */
+ {
+ /* try Literal + rep0 */
+ UInt32 temp;
+ UInt32 lenTest2;
+ const Byte *data2 = data - (reps[0] + 1);
+ UInt32 limit = p->numFastBytes + 1;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+
+ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
+ lenTest2 = temp - 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kLiteralNextStates[state];
+ UInt32 posStateNext = (position + 1) & p->pbMask;
+ UInt32 nextRepMatchPrice = curAnd1Price +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ UInt32 offset = cur + 1 + lenTest2;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = False;
+ }
+ }
+ }
+ }
+
+ startLen = 2; /* speed optimization */
+ {
+ UInt32 repIndex;
+ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
+ {
+ UInt32 lenTest;
+ UInt32 lenTestTemp;
+ UInt32 price;
+ const Byte *data2 = data - (reps[repIndex] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
+ while (lenEnd < cur + lenTest)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ lenTestTemp = lenTest;
+ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
+ do
+ {
+ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
+ COptimal *opt = &p->opt[cur + lenTest];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur;
+ opt->backPrev = repIndex;
+ opt->prev1IsChar = False;
+ }
+ }
+ while (--lenTest >= 2);
+ lenTest = lenTestTemp;
+
+ if (repIndex == 0)
+ startLen = lenTest + 1;
+
+ /* if (_maxMode) */
+ {
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = lenTest2 + p->numFastBytes;
+ UInt32 nextRepMatchPrice;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kRepNextStates[state];
+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
+ UInt32 curAndLenCharPrice =
+ price + p->repLenEnc.prices[posState][lenTest - 2] +
+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
+ data[lenTest], data2[lenTest], p->ProbPrices);
+ state2 = kLiteralNextStates[state2];
+ posStateNext = (position + lenTest + 1) & p->pbMask;
+ nextRepMatchPrice = curAndLenCharPrice +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ UInt32 offset = cur + lenTest + 1 + lenTest2;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + lenTest + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = True;
+ opt->posPrev2 = cur;
+ opt->backPrev2 = repIndex;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
+ if (newLen > numAvail)
+ {
+ newLen = numAvail;
+ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
+ matches[numPairs] = newLen;
+ numPairs += 2;
+ }
+ if (newLen >= startLen)
+ {
+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
+ UInt32 offs, curBack, posSlot;
+ UInt32 lenTest;
+ while (lenEnd < cur + newLen)
+ p->opt[++lenEnd].price = kInfinityPrice;
+
+ offs = 0;
+ while (startLen > matches[offs])
+ offs += 2;
+ curBack = matches[offs + 1];
+ GetPosSlot2(curBack, posSlot);
+ for (lenTest = /*2*/ startLen; ; lenTest++)
+ {
+ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
+ UInt32 lenToPosState = GetLenToPosState(lenTest);
+ COptimal *opt;
+ if (curBack < kNumFullDistances)
+ curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
+ else
+ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
+
+ opt = &p->opt[cur + lenTest];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur;
+ opt->backPrev = curBack + LZMA_NUM_REPS;
+ opt->prev1IsChar = False;
+ }
+
+ if (/*_maxMode && */lenTest == matches[offs])
+ {
+ /* Try Match + Literal + Rep0 */
+ const Byte *data2 = data - (curBack + 1);
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = lenTest2 + p->numFastBytes;
+ UInt32 nextRepMatchPrice;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ UInt32 state2 = kMatchNextStates[state];
+ UInt32 posStateNext = (position + lenTest) & p->pbMask;
+ UInt32 curAndLenCharPrice = curAndLenPrice +
+ GET_PRICE_0(p->isMatch[state2][posStateNext]) +
+ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
+ data[lenTest], data2[lenTest], p->ProbPrices);
+ state2 = kLiteralNextStates[state2];
+ posStateNext = (posStateNext + 1) & p->pbMask;
+ nextRepMatchPrice = curAndLenCharPrice +
+ GET_PRICE_1(p->isMatch[state2][posStateNext]) +
+ GET_PRICE_1(p->isRep[state2]);
+
+ /* for (; lenTest2 >= 2; lenTest2--) */
+ {
+ UInt32 offset = cur + lenTest + 1 + lenTest2;
+ UInt32 curAndLenPrice;
+ COptimal *opt;
+ while (lenEnd < offset)
+ p->opt[++lenEnd].price = kInfinityPrice;
+ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
+ opt = &p->opt[offset];
+ if (curAndLenPrice < opt->price)
+ {
+ opt->price = curAndLenPrice;
+ opt->posPrev = cur + lenTest + 1;
+ opt->backPrev = 0;
+ opt->prev1IsChar = True;
+ opt->prev2 = True;
+ opt->posPrev2 = cur;
+ opt->backPrev2 = curBack + LZMA_NUM_REPS;
+ }
+ }
+ }
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ curBack = matches[offs + 1];
+ if (curBack >= kNumFullDistances)
+ GetPosSlot2(curBack, posSlot);
+ }
+ }
+ }
+ }
+}
+
+#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
+
+static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
+{
+ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
+ const Byte *data;
+ const UInt32 *matches;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLength;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ *backRes = (UInt32)-1;
+ if (numAvail < 2)
+ return 1;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+
+ repLen = repIndex = 0;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 len;
+ const Byte *data2 = data - (p->reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++);
+ if (len >= p->numFastBytes)
+ {
+ *backRes = i;
+ MovePos(p, len - 1);
+ return len;
+ }
+ if (len > repLen)
+ {
+ repIndex = i;
+ repLen = len;
+ }
+ }
+
+ matches = p->matches;
+ if (mainLen >= p->numFastBytes)
+ {
+ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 1);
+ return mainLen;
+ }
+
+ mainDist = 0; /* for GCC */
+ if (mainLen >= 2)
+ {
+ mainDist = matches[numPairs - 1];
+ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
+ {
+ if (!ChangePair(matches[numPairs - 3], mainDist))
+ break;
+ numPairs -= 2;
+ mainLen = matches[numPairs - 2];
+ mainDist = matches[numPairs - 1];
+ }
+ if (mainLen == 2 && mainDist >= 0x80)
+ mainLen = 1;
+ }
+
+ if (repLen >= 2 && (
+ (repLen + 1 >= mainLen) ||
+ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
+ (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
+ {
+ *backRes = repIndex;
+ MovePos(p, repLen - 1);
+ return repLen;
+ }
+
+ if (mainLen < 2 || numAvail <= 2)
+ return 1;
+
+ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
+ if (p->longestMatchLength >= 2)
+ {
+ UInt32 newDistance = matches[p->numPairs - 1];
+ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
+ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
+ (p->longestMatchLength > mainLen + 1) ||
+ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
+ return 1;
+ }
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ UInt32 len, limit;
+ const Byte *data2 = data - (p->reps[i] + 1);
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ limit = mainLen - 1;
+ for (len = 2; len < limit && data[len] == data2[len]; len++);
+ if (len >= limit)
+ return 1;
+ }
+ *backRes = mainDist + LZMA_NUM_REPS;
+ MovePos(p, mainLen - 2);
+ return mainLen;
+}
+
+static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
+{
+ UInt32 len;
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
+ p->state = kMatchNextStates[p->state];
+ len = LZMA_MATCH_LEN_MIN;
+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
+ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
+}
+
+static SRes CheckErrors(CLzmaEnc *p)
+{
+ if (p->result != SZ_OK)
+ return p->result;
+ if (p->rc.res != SZ_OK)
+ p->result = SZ_ERROR_WRITE;
+ if (p->matchFinderBase.result != SZ_OK)
+ p->result = SZ_ERROR_READ;
+ if (p->result != SZ_OK)
+ p->finished = True;
+ return p->result;
+}
+
+static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
+{
+ /* ReleaseMFStream(); */
+ p->finished = True;
+ if (p->writeEndMark)
+ WriteEndMarker(p, nowPos & p->pbMask);
+ RangeEnc_FlushData(&p->rc);
+ RangeEnc_FlushStream(&p->rc);
+ return CheckErrors(p);
+}
+
+static void FillAlignPrices(CLzmaEnc *p)
+{
+ UInt32 i;
+ for (i = 0; i < kAlignTableSize; i++)
+ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
+ p->alignPriceCount = 0;
+}
+
+static void FillDistancesPrices(CLzmaEnc *p)
+{
+ UInt32 tempPrices[kNumFullDistances];
+ UInt32 i, lenToPosState;
+ for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
+ {
+ UInt32 posSlot = GetPosSlot1(i);
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
+ }
+
+ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
+ {
+ UInt32 posSlot;
+ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
+ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
+ for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
+ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
+ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
+ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
+
+ {
+ UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
+ UInt32 i;
+ for (i = 0; i < kStartPosModelIndex; i++)
+ distancesPrices[i] = posSlotPrices[i];
+ for (; i < kNumFullDistances; i++)
+ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
+ }
+ }
+ p->matchPriceCount = 0;
+}
+
+void LzmaEnc_Construct(CLzmaEnc *p)
+{
+ RangeEnc_Construct(&p->rc);
+ MatchFinder_Construct(&p->matchFinderBase);
+ #ifndef _7ZIP_ST
+ MatchFinderMt_Construct(&p->matchFinderMt);
+ p->matchFinderMt.MatchFinder = &p->matchFinderBase;
+ #endif
+
+ {
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ LzmaEnc_SetProps(p, &props);
+ }
+
+ #ifndef LZMA_LOG_BSR
+ LzmaEnc_FastPosInit(p->g_FastPos);
+ #endif
+
+ LzmaEnc_InitPriceTables(p->ProbPrices);
+ p->litProbs = 0;
+ p->saveState.litProbs = 0;
+}
+
+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
+{
+ void *p;
+ p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
+ if (p != 0)
+ LzmaEnc_Construct((CLzmaEnc *)p);
+ return p;
+}
+
+void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->litProbs);
+ alloc->Free(alloc, p->saveState.litProbs);
+ p->litProbs = 0;
+ p->saveState.litProbs = 0;
+}
+
+void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ #ifndef _7ZIP_ST
+ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+ #endif
+ MatchFinder_Free(&p->matchFinderBase, allocBig);
+ LzmaEnc_FreeLits(p, alloc);
+ RangeEnc_Free(&p->rc, alloc);
+}
+
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
+ alloc->Free(alloc, p);
+}
+
+static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
+{
+ UInt32 nowPos32, startPos32;
+ if (p->needInit)
+ {
+ p->matchFinder.Init(p->matchFinderObj);
+ p->needInit = 0;
+ }
+
+ if (p->finished)
+ return p->result;
+ RINOK(CheckErrors(p));
+
+ nowPos32 = (UInt32)p->nowPos64;
+ startPos32 = nowPos32;
+
+ if (p->nowPos64 == 0)
+ {
+ UInt32 numPairs;
+ Byte curByte;
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ return Flush(p, nowPos32);
+ ReadMatchDistances(p, &numPairs);
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
+ p->state = kLiteralNextStates[p->state];
+ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
+ LitEnc_Encode(&p->rc, p->litProbs, curByte);
+ p->additionalOffset--;
+ nowPos32++;
+ }
+
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
+ for (;;)
+ {
+ UInt32 pos, len, posState;
+
+ if (p->fastMode)
+ len = GetOptimumFast(p, &pos);
+ else
+ len = GetOptimum(p, nowPos32, &pos);
+
+ #ifdef SHOW_STAT2
+ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos);
+ #endif
+
+ posState = nowPos32 & p->pbMask;
+ if (len == 1 && pos == (UInt32)-1)
+ {
+ Byte curByte;
+ CLzmaProb *probs;
+ const Byte *data;
+
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+ curByte = *data;
+ probs = LIT_PROBS(nowPos32, *(data - 1));
+ if (IsCharState(p->state))
+ LitEnc_Encode(&p->rc, probs, curByte);
+ else
+ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
+ p->state = kLiteralNextStates[p->state];
+ }
+ else
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
+ if (pos < LZMA_NUM_REPS)
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
+ if (pos == 0)
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
+ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
+ }
+ else
+ {
+ UInt32 distance = p->reps[pos];
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
+ if (pos == 1)
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
+ else
+ {
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
+ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
+ if (pos == 3)
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ }
+ p->reps[1] = p->reps[0];
+ p->reps[0] = distance;
+ }
+ if (len == 1)
+ p->state = kShortRepNextStates[p->state];
+ else
+ {
+ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ p->state = kRepNextStates[p->state];
+ }
+ }
+ else
+ {
+ UInt32 posSlot;
+ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
+ p->state = kMatchNextStates[p->state];
+ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
+ pos -= LZMA_NUM_REPS;
+ GetPosSlot(pos, posSlot);
+ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
+
+ if (posSlot >= kStartPosModelIndex)
+ {
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ UInt32 posReduced = pos - base;
+
+ if (posSlot < kEndPosModelIndex)
+ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
+ else
+ {
+ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
+ p->alignPriceCount++;
+ }
+ }
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ p->reps[1] = p->reps[0];
+ p->reps[0] = pos;
+ p->matchPriceCount++;
+ }
+ }
+ p->additionalOffset -= len;
+ nowPos32 += len;
+ if (p->additionalOffset == 0)
+ {
+ UInt32 processed;
+ if (!p->fastMode)
+ {
+ if (p->matchPriceCount >= (1 << 7))
+ FillDistancesPrices(p);
+ if (p->alignPriceCount >= kAlignTableSize)
+ FillAlignPrices(p);
+ }
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ break;
+ processed = nowPos32 - startPos32;
+ if (useLimits)
+ {
+ if (processed + kNumOpts + 300 >= maxUnpackSize ||
+ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
+ break;
+ }
+ else if (processed >= (1 << 15))
+ {
+ p->nowPos64 += nowPos32 - startPos32;
+ return CheckErrors(p);
+ }
+ }
+ }
+ p->nowPos64 += nowPos32 - startPos32;
+ return Flush(p, nowPos32);
+}
+
+#define kBigHashDicLimit ((UInt32)1 << 24)
+
+static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ UInt32 beforeSize = kNumOpts;
+ Bool btMode;
+ if (!RangeEnc_Alloc(&p->rc, alloc))
+ return SZ_ERROR_MEM;
+ btMode = (p->matchFinderBase.btMode != 0);
+ #ifndef _7ZIP_ST
+ p->mtMode = (p->multiThread && !p->fastMode && btMode);
+ #endif
+
+ {
+ unsigned lclp = p->lc + p->lp;
+ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
+ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
+ if (p->litProbs == 0 || p->saveState.litProbs == 0)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ p->lclp = lclp;
+ }
+ }
+
+ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
+
+ if (beforeSize + p->dictSize < keepWindowSize)
+ beforeSize = keepWindowSize - p->dictSize;
+
+ #ifndef _7ZIP_ST
+ if (p->mtMode)
+ {
+ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
+ p->matchFinderObj = &p->matchFinderMt;
+ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
+ }
+ else
+ #endif
+ {
+ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
+ return SZ_ERROR_MEM;
+ p->matchFinderObj = &p->matchFinderBase;
+ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
+ }
+ return SZ_OK;
+}
+
+void LzmaEnc_Init(CLzmaEnc *p)
+{
+ UInt32 i;
+ p->state = 0;
+ for (i = 0 ; i < LZMA_NUM_REPS; i++)
+ p->reps[i] = 0;
+
+ RangeEnc_Init(&p->rc);
+
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ UInt32 j;
+ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
+ {
+ p->isMatch[i][j] = kProbInitValue;
+ p->isRep0Long[i][j] = kProbInitValue;
+ }
+ p->isRep[i] = kProbInitValue;
+ p->isRepG0[i] = kProbInitValue;
+ p->isRepG1[i] = kProbInitValue;
+ p->isRepG2[i] = kProbInitValue;
+ }
+
+ {
+ UInt32 num = 0x300 << (p->lp + p->lc);
+ for (i = 0; i < num; i++)
+ p->litProbs[i] = kProbInitValue;
+ }
+
+ {
+ for (i = 0; i < kNumLenToPosStates; i++)
+ {
+ CLzmaProb *probs = p->posSlotEncoder[i];
+ UInt32 j;
+ for (j = 0; j < (1 << kNumPosSlotBits); j++)
+ probs[j] = kProbInitValue;
+ }
+ }
+ {
+ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
+ p->posEncoders[i] = kProbInitValue;
+ }
+
+ LenEnc_Init(&p->lenEnc.p);
+ LenEnc_Init(&p->repLenEnc.p);
+
+ for (i = 0; i < (1 << kNumAlignBits); i++)
+ p->posAlignEncoder[i] = kProbInitValue;
+
+ p->optimumEndIndex = 0;
+ p->optimumCurrentIndex = 0;
+ p->additionalOffset = 0;
+
+ p->pbMask = (1 << p->pb) - 1;
+ p->lpMask = (1 << p->lp) - 1;
+}
+
+void LzmaEnc_InitPrices(CLzmaEnc *p)
+{
+ if (!p->fastMode)
+ {
+ FillDistancesPrices(p);
+ FillAlignPrices(p);
+ }
+
+ p->lenEnc.tableSize =
+ p->repLenEnc.tableSize =
+ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
+ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
+ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
+}
+
+static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ UInt32 i;
+ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
+ if (p->dictSize <= ((UInt32)1 << i))
+ break;
+ p->distTableSize = i * 2;
+
+ p->finished = False;
+ p->result = SZ_OK;
+ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ p->nowPos64 = 0;
+ return SZ_OK;
+}
+
+static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ p->matchFinderBase.stream = inStream;
+ p->needInit = 1;
+ p->rc.outStream = outStream;
+ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+}
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
+ ISeqInStream *inStream, UInt32 keepWindowSize,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ p->matchFinderBase.stream = inStream;
+ p->needInit = 1;
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
+{
+ p->matchFinderBase.directInput = 1;
+ p->matchFinderBase.bufferBase = (Byte *)src;
+ p->matchFinderBase.directInputRem = srcLen;
+}
+
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+ p->needInit = 1;
+
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+void LzmaEnc_Finish(CLzmaEncHandle pp)
+{
+ #ifndef _7ZIP_ST
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ if (p->mtMode)
+ MatchFinderMt_ReleaseStream(&p->matchFinderMt);
+ #else
+ pp = pp;
+ #endif
+}
+
+typedef struct
+{
+ ISeqOutStream funcTable;
+ Byte *data;
+ SizeT rem;
+ Bool overflow;
+} CSeqOutStreamBuf;
+
+static size_t MyWrite(void *pp, const void *data, size_t size)
+{
+ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
+ if (p->rem < size)
+ {
+ size = p->rem;
+ p->overflow = True;
+ }
+ memcpy(p->data, data, size);
+ p->rem -= size;
+ p->data += size;
+ return size;
+}
+
+
+UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+}
+
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+}
+
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ UInt64 nowPos64;
+ SRes res;
+ CSeqOutStreamBuf outStream;
+
+ outStream.funcTable.Write = MyWrite;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = False;
+ p->finished = False;
+ p->result = SZ_OK;
+
+ if (reInit)
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ nowPos64 = p->nowPos64;
+ RangeEnc_Init(&p->rc);
+ p->rc.outStream = &outStream.funcTable;
+
+ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
+
+ *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ return res;
+}
+
+static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
+{
+ SRes res = SZ_OK;
+
+ #ifndef _7ZIP_ST
+ Byte allocaDummy[0x300];
+ int i = 0;
+ for (i = 0; i < 16; i++)
+ allocaDummy[i] = (Byte)i;
+ #endif
+
+ for (;;)
+ {
+ res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
+ if (res != SZ_OK || p->finished != 0)
+ break;
+ if (progress != 0)
+ {
+ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
+ if (res != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ }
+ LzmaEnc_Finish(p);
+ return res;
+}
+
+SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+ ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
+ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
+}
+
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ int i;
+ UInt32 dictSize = p->dictSize;
+ if (*size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_PARAM;
+ *size = LZMA_PROPS_SIZE;
+ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
+
+ for (i = 11; i <= 30; i++)
+ {
+ if (dictSize <= ((UInt32)2 << i))
+ {
+ dictSize = (2 << i);
+ break;
+ }
+ if (dictSize <= ((UInt32)3 << i))
+ {
+ dictSize = (3 << i);
+ break;
+ }
+ }
+
+ for (i = 0; i < 4; i++)
+ props[1 + i] = (Byte)(dictSize >> (8 * i));
+ return SZ_OK;
+}
+
+SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ SRes res;
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+
+ CSeqOutStreamBuf outStream;
+
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+
+ outStream.funcTable.Write = MyWrite;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = writeEndMark;
+
+ p->rc.outStream = &outStream.funcTable;
+ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
+ if (res == SZ_OK)
+ res = LzmaEnc_Encode2(p, progress);
+
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+ return res;
+}
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+ SRes res;
+ if (p == 0)
+ return SZ_ERROR_MEM;
+
+ res = LzmaEnc_SetProps(p, props);
+ if (res == SZ_OK)
+ {
+ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+ if (res == SZ_OK)
+ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+ writeEndMark, progress, alloc, allocBig);
+ }
+
+ LzmaEnc_Destroy(p, alloc, allocBig);
+ return res;
+}
diff --git a/src/libs/7zip/win/C/LzmaEnc.h b/src/libs/7zip/win/C/LzmaEnc.h
new file mode 100644
index 000000000..200d60eb8
--- /dev/null
+++ b/src/libs/7zip/win/C/LzmaEnc.h
@@ -0,0 +1,80 @@
+/* LzmaEnc.h -- LZMA Encoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_ENC_H
+#define __LZMA_ENC_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaEncProps
+{
+ int level; /* 0 <= level <= 9 */
+ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
+ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version
+ default = (1 << 24) */
+ int lc; /* 0 <= lc <= 8, default = 3 */
+ int lp; /* 0 <= lp <= 4, default = 0 */
+ int pb; /* 0 <= pb <= 4, default = 2 */
+ int algo; /* 0 - fast, 1 - normal, default = 1 */
+ int fb; /* 5 <= fb <= 273, default = 32 */
+ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
+ int numHashBytes; /* 2, 3 or 4, default = 4 */
+ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
+ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
+ int numThreads; /* 1 or 2, default = 2 */
+} CLzmaEncProps;
+
+void LzmaEncProps_Init(CLzmaEncProps *p);
+void LzmaEncProps_Normalize(CLzmaEncProps *p);
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+
+
+/* ---------- CLzmaEncHandle Interface ---------- */
+
+/* LzmaEnc_* functions can return the following exit codes:
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - Write callback error.
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzmaEncHandle;
+
+CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaEncode
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/LzmaLib.c b/src/libs/7zip/win/C/LzmaLib.c
new file mode 100644
index 000000000..02a511857
--- /dev/null
+++ b/src/libs/7zip/win/C/LzmaLib.c
@@ -0,0 +1,46 @@
+/* LzmaLib.c -- LZMA library wrapper
+2008-08-05
+Igor Pavlov
+Public domain */
+
+#include "LzmaEnc.h"
+#include "LzmaDec.h"
+#include "Alloc.h"
+#include "LzmaLib.h"
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
+ unsigned char *outProps, size_t *outPropsSize,
+ int level, /* 0 <= level <= 9, default = 5 */
+ unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */
+ int lc, /* 0 <= lc <= 8, default = 3 */
+ int lp, /* 0 <= lp <= 4, default = 0 */
+ int pb, /* 0 <= pb <= 4, default = 2 */
+ int fb, /* 5 <= fb <= 273, default = 32 */
+ int numThreads /* 1 or 2, default = 2 */
+)
+{
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ props.level = level;
+ props.dictSize = dictSize;
+ props.lc = lc;
+ props.lp = lp;
+ props.pb = pb;
+ props.fb = fb;
+ props.numThreads = numThreads;
+
+ return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0,
+ NULL, &g_Alloc, &g_Alloc);
+}
+
+
+MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen,
+ const unsigned char *props, size_t propsSize)
+{
+ ELzmaStatus status;
+ return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc);
+}
diff --git a/src/libs/7zip/win/C/LzmaLib.h b/src/libs/7zip/win/C/LzmaLib.h
new file mode 100644
index 000000000..76c99ce75
--- /dev/null
+++ b/src/libs/7zip/win/C/LzmaLib.h
@@ -0,0 +1,135 @@
+/* LzmaLib.h -- LZMA library interface
+2009-04-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_LIB_H
+#define __LZMA_LIB_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MY_STDAPI int MY_STD_CALL
+
+#define LZMA_PROPS_SIZE 5
+
+/*
+RAM requirements for LZMA:
+ for compression: (dictSize * 11.5 + 6 MB) + state_size
+ for decompression: dictSize + state_size
+ state_size = (4 + (1.5 << (lc + lp))) KB
+ by default (lc=3, lp=0), state_size = 16 KB.
+
+LZMA properties (5 bytes) format
+ Offset Size Description
+ 0 1 lc, lp and pb in encoded form.
+ 1 4 dictSize (little endian).
+*/
+
+/*
+LzmaCompress
+------------
+
+outPropsSize -
+ In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
+ Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
+
+ LZMA Encoder will use defult values for any parameter, if it is
+ -1 for any from: level, loc, lp, pb, fb, numThreads
+ 0 for dictSize
+
+level - compression level: 0 <= level <= 9;
+
+ level dictSize algo fb
+ 0: 16 KB 0 32
+ 1: 64 KB 0 32
+ 2: 256 KB 0 32
+ 3: 1 MB 0 32
+ 4: 4 MB 0 32
+ 5: 16 MB 1 32
+ 6: 32 MB 1 32
+ 7+: 64 MB 1 64
+
+ The default value for "level" is 5.
+
+ algo = 0 means fast method
+ algo = 1 means normal method
+
+dictSize - The dictionary size in bytes. The maximum value is
+ 128 MB = (1 << 27) bytes for 32-bit version
+ 1 GB = (1 << 30) bytes for 64-bit version
+ The default value is 16 MB = (1 << 24) bytes.
+ It's recommended to use the dictionary that is larger than 4 KB and
+ that can be calculated as (1 << N) or (3 << N) sizes.
+
+lc - The number of literal context bits (high bits of previous literal).
+ It can be in the range from 0 to 8. The default value is 3.
+ Sometimes lc=4 gives the gain for big files.
+
+lp - The number of literal pos bits (low bits of current position for literals).
+ It can be in the range from 0 to 4. The default value is 0.
+ The lp switch is intended for periodical data when the period is equal to 2^lp.
+ For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's
+ better to set lc=0, if you change lp switch.
+
+pb - The number of pos bits (low bits of current position).
+ It can be in the range from 0 to 4. The default value is 2.
+ The pb switch is intended for periodical data when the period is equal 2^pb.
+
+fb - Word size (the number of fast bytes).
+ It can be in the range from 5 to 273. The default value is 32.
+ Usually, a big number gives a little bit better compression ratio and
+ slower compression process.
+
+numThreads - The number of thereads. 1 or 2. The default value is 2.
+ Fast mode (algo = 0) can use only 1 thread.
+
+Out:
+ destLen - processed output size
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
+ unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
+ int level, /* 0 <= level <= 9, default = 5 */
+ unsigned dictSize, /* default = (1 << 24) */
+ int lc, /* 0 <= lc <= 8, default = 3 */
+ int lp, /* 0 <= lp <= 4, default = 0 */
+ int pb, /* 0 <= pb <= 4, default = 2 */
+ int fb, /* 5 <= fb <= 273, default = 32 */
+ int numThreads /* 1 or 2, default = 2 */
+ );
+
+/*
+LzmaUncompress
+--------------
+In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+Out:
+ destLen - processed output size
+ srcLen - processed input size
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation arror
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src)
+*/
+
+MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen,
+ const unsigned char *props, size_t propsSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/MtCoder.c b/src/libs/7zip/win/C/MtCoder.c
new file mode 100644
index 000000000..946fbbc70
--- /dev/null
+++ b/src/libs/7zip/win/C/MtCoder.c
@@ -0,0 +1,327 @@
+/* MtCoder.c -- Multi-thread Coder
+2010-09-24 : Igor Pavlov : Public domain */
+
+#include <stdio.h>
+
+#include "MtCoder.h"
+
+void LoopThread_Construct(CLoopThread *p)
+{
+ Thread_Construct(&p->thread);
+ Event_Construct(&p->startEvent);
+ Event_Construct(&p->finishedEvent);
+}
+
+void LoopThread_Close(CLoopThread *p)
+{
+ Thread_Close(&p->thread);
+ Event_Close(&p->startEvent);
+ Event_Close(&p->finishedEvent);
+}
+
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE LoopThreadFunc(void *pp)
+{
+ CLoopThread *p = (CLoopThread *)pp;
+ for (;;)
+ {
+ if (Event_Wait(&p->startEvent) != 0)
+ return SZ_ERROR_THREAD;
+ if (p->stop)
+ return 0;
+ p->res = p->func(p->param);
+ if (Event_Set(&p->finishedEvent) != 0)
+ return SZ_ERROR_THREAD;
+ }
+}
+
+WRes LoopThread_Create(CLoopThread *p)
+{
+ p->stop = 0;
+ RINOK(AutoResetEvent_CreateNotSignaled(&p->startEvent));
+ RINOK(AutoResetEvent_CreateNotSignaled(&p->finishedEvent));
+ return Thread_Create(&p->thread, LoopThreadFunc, p);
+}
+
+WRes LoopThread_StopAndWait(CLoopThread *p)
+{
+ p->stop = 1;
+ if (Event_Set(&p->startEvent) != 0)
+ return SZ_ERROR_THREAD;
+ return Thread_Wait(&p->thread);
+}
+
+WRes LoopThread_StartSubThread(CLoopThread *p) { return Event_Set(&p->startEvent); }
+WRes LoopThread_WaitSubThread(CLoopThread *p) { return Event_Wait(&p->finishedEvent); }
+
+static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
+{
+ return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
+}
+
+static void MtProgress_Init(CMtProgress *p, ICompressProgress *progress)
+{
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ p->inSizes[i] = p->outSizes[i] = 0;
+ p->totalInSize = p->totalOutSize = 0;
+ p->progress = progress;
+ p->res = SZ_OK;
+}
+
+static void MtProgress_Reinit(CMtProgress *p, unsigned index)
+{
+ p->inSizes[index] = 0;
+ p->outSizes[index] = 0;
+}
+
+#define UPDATE_PROGRESS(size, prev, total) \
+ if (size != (UInt64)(Int64)-1) { total += size - prev; prev = size; }
+
+SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize)
+{
+ SRes res;
+ CriticalSection_Enter(&p->cs);
+ UPDATE_PROGRESS(inSize, p->inSizes[index], p->totalInSize)
+ UPDATE_PROGRESS(outSize, p->outSizes[index], p->totalOutSize)
+ if (p->res == SZ_OK)
+ p->res = Progress(p->progress, p->totalInSize, p->totalOutSize);
+ res = p->res;
+ CriticalSection_Leave(&p->cs);
+ return res;
+}
+
+static void MtProgress_SetError(CMtProgress *p, SRes res)
+{
+ CriticalSection_Enter(&p->cs);
+ if (p->res == SZ_OK)
+ p->res = res;
+ CriticalSection_Leave(&p->cs);
+}
+
+static void MtCoder_SetError(CMtCoder* p, SRes res)
+{
+ CriticalSection_Enter(&p->cs);
+ if (p->res == SZ_OK)
+ p->res = res;
+ CriticalSection_Leave(&p->cs);
+}
+
+/* ---------- MtThread ---------- */
+
+void CMtThread_Construct(CMtThread *p, CMtCoder *mtCoder)
+{
+ p->mtCoder = mtCoder;
+ p->outBuf = 0;
+ p->inBuf = 0;
+ Event_Construct(&p->canRead);
+ Event_Construct(&p->canWrite);
+ LoopThread_Construct(&p->thread);
+}
+
+#define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; }
+
+static void CMtThread_CloseEvents(CMtThread *p)
+{
+ Event_Close(&p->canRead);
+ Event_Close(&p->canWrite);
+}
+
+static void CMtThread_Destruct(CMtThread *p)
+{
+ CMtThread_CloseEvents(p);
+
+ if (Thread_WasCreated(&p->thread.thread))
+ {
+ LoopThread_StopAndWait(&p->thread);
+ LoopThread_Close(&p->thread);
+ }
+
+ if (p->mtCoder->alloc)
+ IAlloc_Free(p->mtCoder->alloc, p->outBuf);
+ p->outBuf = 0;
+
+ if (p->mtCoder->alloc)
+ IAlloc_Free(p->mtCoder->alloc, p->inBuf);
+ p->inBuf = 0;
+}
+
+#define MY_BUF_ALLOC(buf, size, newSize) \
+ if (buf == 0 || size != newSize) \
+ { IAlloc_Free(p->mtCoder->alloc, buf); \
+ size = newSize; buf = (Byte *)IAlloc_Alloc(p->mtCoder->alloc, size); \
+ if (buf == 0) return SZ_ERROR_MEM; }
+
+static SRes CMtThread_Prepare(CMtThread *p)
+{
+ MY_BUF_ALLOC(p->inBuf, p->inBufSize, p->mtCoder->blockSize)
+ MY_BUF_ALLOC(p->outBuf, p->outBufSize, p->mtCoder->destBlockSize)
+
+ p->stopReading = False;
+ p->stopWriting = False;
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canRead));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canWrite));
+
+ return SZ_OK;
+}
+
+static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize)
+{
+ size_t size = *processedSize;
+ *processedSize = 0;
+ while (size != 0)
+ {
+ size_t curSize = size;
+ SRes res = stream->Read(stream, data, &curSize);
+ *processedSize += curSize;
+ data += curSize;
+ size -= curSize;
+ RINOK(res);
+ if (curSize == 0)
+ return SZ_OK;
+ }
+ return SZ_OK;
+}
+
+#define GET_NEXT_THREAD(p) &p->mtCoder->threads[p->index == p->mtCoder->numThreads - 1 ? 0 : p->index + 1]
+
+static SRes MtThread_Process(CMtThread *p, Bool *stop)
+{
+ CMtThread *next;
+ *stop = True;
+ if (Event_Wait(&p->canRead) != 0)
+ return SZ_ERROR_THREAD;
+
+ next = GET_NEXT_THREAD(p);
+
+ if (p->stopReading)
+ {
+ next->stopReading = True;
+ return Event_Set(&next->canRead) == 0 ? SZ_OK : SZ_ERROR_THREAD;
+ }
+
+ {
+ size_t size = p->mtCoder->blockSize;
+ size_t destSize = p->outBufSize;
+
+ RINOK(FullRead(p->mtCoder->inStream, p->inBuf, &size));
+ next->stopReading = *stop = (size != p->mtCoder->blockSize);
+ if (Event_Set(&next->canRead) != 0)
+ return SZ_ERROR_THREAD;
+
+ RINOK(p->mtCoder->mtCallback->Code(p->mtCoder->mtCallback, p->index,
+ p->outBuf, &destSize, p->inBuf, size, *stop));
+
+ MtProgress_Reinit(&p->mtCoder->mtProgress, p->index);
+
+ if (Event_Wait(&p->canWrite) != 0)
+ return SZ_ERROR_THREAD;
+ if (p->stopWriting)
+ return SZ_ERROR_FAIL;
+ if (p->mtCoder->outStream->Write(p->mtCoder->outStream, p->outBuf, destSize) != destSize)
+ return SZ_ERROR_WRITE;
+ return Event_Set(&next->canWrite) == 0 ? SZ_OK : SZ_ERROR_THREAD;
+ }
+}
+
+static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp)
+{
+ CMtThread *p = (CMtThread *)pp;
+ for (;;)
+ {
+ Bool stop;
+ CMtThread *next = GET_NEXT_THREAD(p);
+ SRes res = MtThread_Process(p, &stop);
+ if (res != SZ_OK)
+ {
+ MtCoder_SetError(p->mtCoder, res);
+ MtProgress_SetError(&p->mtCoder->mtProgress, res);
+ next->stopReading = True;
+ next->stopWriting = True;
+ Event_Set(&next->canRead);
+ Event_Set(&next->canWrite);
+ return res;
+ }
+ if (stop)
+ return 0;
+ }
+}
+
+void MtCoder_Construct(CMtCoder* p)
+{
+ unsigned i;
+ p->alloc = 0;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ t->index = i;
+ CMtThread_Construct(t, p);
+ }
+ CriticalSection_Init(&p->cs);
+ CriticalSection_Init(&p->mtProgress.cs);
+}
+
+void MtCoder_Destruct(CMtCoder* p)
+{
+ unsigned i;
+ for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++)
+ CMtThread_Destruct(&p->threads[i]);
+ CriticalSection_Delete(&p->cs);
+ CriticalSection_Delete(&p->mtProgress.cs);
+}
+
+SRes MtCoder_Code(CMtCoder *p)
+{
+ unsigned i, numThreads = p->numThreads;
+ SRes res = SZ_OK;
+ p->res = SZ_OK;
+
+ MtProgress_Init(&p->mtProgress, p->progress);
+
+ for (i = 0; i < numThreads; i++)
+ {
+ RINOK(CMtThread_Prepare(&p->threads[i]));
+ }
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ CLoopThread *lt = &t->thread;
+
+ if (!Thread_WasCreated(&lt->thread))
+ {
+ lt->func = ThreadFunc;
+ lt->param = t;
+
+ if (LoopThread_Create(lt) != SZ_OK)
+ {
+ res = SZ_ERROR_THREAD;
+ break;
+ }
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ unsigned j;
+ for (i = 0; i < numThreads; i++)
+ {
+ CMtThread *t = &p->threads[i];
+ if (LoopThread_StartSubThread(&t->thread) != SZ_OK)
+ {
+ res = SZ_ERROR_THREAD;
+ p->threads[0].stopReading = True;
+ break;
+ }
+ }
+
+ Event_Set(&p->threads[0].canWrite);
+ Event_Set(&p->threads[0].canRead);
+
+ for (j = 0; j < i; j++)
+ LoopThread_WaitSubThread(&p->threads[j].thread);
+ }
+
+ for (i = 0; i < numThreads; i++)
+ CMtThread_CloseEvents(&p->threads[i]);
+ return (res == SZ_OK) ? p->res : res;
+}
diff --git a/src/libs/7zip/win/C/MtCoder.h b/src/libs/7zip/win/C/MtCoder.h
new file mode 100644
index 000000000..f0f06da28
--- /dev/null
+++ b/src/libs/7zip/win/C/MtCoder.h
@@ -0,0 +1,98 @@
+/* MtCoder.h -- Multi-thread Coder
+2009-11-19 : Igor Pavlov : Public domain */
+
+#ifndef __MT_CODER_H
+#define __MT_CODER_H
+
+#include "Threads.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ CThread thread;
+ CAutoResetEvent startEvent;
+ CAutoResetEvent finishedEvent;
+ int stop;
+
+ THREAD_FUNC_TYPE func;
+ LPVOID param;
+ THREAD_FUNC_RET_TYPE res;
+} CLoopThread;
+
+void LoopThread_Construct(CLoopThread *p);
+void LoopThread_Close(CLoopThread *p);
+WRes LoopThread_Create(CLoopThread *p);
+WRes LoopThread_StopAndWait(CLoopThread *p);
+WRes LoopThread_StartSubThread(CLoopThread *p);
+WRes LoopThread_WaitSubThread(CLoopThread *p);
+
+#ifndef _7ZIP_ST
+#define NUM_MT_CODER_THREADS_MAX 32
+#else
+#define NUM_MT_CODER_THREADS_MAX 1
+#endif
+
+typedef struct
+{
+ UInt64 totalInSize;
+ UInt64 totalOutSize;
+ ICompressProgress *progress;
+ SRes res;
+ CCriticalSection cs;
+ UInt64 inSizes[NUM_MT_CODER_THREADS_MAX];
+ UInt64 outSizes[NUM_MT_CODER_THREADS_MAX];
+} CMtProgress;
+
+SRes MtProgress_Set(CMtProgress *p, unsigned index, UInt64 inSize, UInt64 outSize);
+
+struct _CMtCoder;
+
+typedef struct
+{
+ struct _CMtCoder *mtCoder;
+ Byte *outBuf;
+ size_t outBufSize;
+ Byte *inBuf;
+ size_t inBufSize;
+ unsigned index;
+ CLoopThread thread;
+
+ Bool stopReading;
+ Bool stopWriting;
+ CAutoResetEvent canRead;
+ CAutoResetEvent canWrite;
+} CMtThread;
+
+typedef struct
+{
+ SRes (*Code)(void *p, unsigned index, Byte *dest, size_t *destSize,
+ const Byte *src, size_t srcSize, int finished);
+} IMtCoderCallback;
+
+typedef struct _CMtCoder
+{
+ size_t blockSize;
+ size_t destBlockSize;
+ unsigned numThreads;
+
+ ISeqInStream *inStream;
+ ISeqOutStream *outStream;
+ ICompressProgress *progress;
+ ISzAlloc *alloc;
+
+ IMtCoderCallback *mtCallback;
+ CCriticalSection cs;
+ SRes res;
+
+ CMtProgress mtProgress;
+ CMtThread threads[NUM_MT_CODER_THREADS_MAX];
+} CMtCoder;
+
+void MtCoder_Construct(CMtCoder* p);
+void MtCoder_Destruct(CMtCoder* p);
+SRes MtCoder_Code(CMtCoder *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/Ppmd.h b/src/libs/7zip/win/C/Ppmd.h
new file mode 100644
index 000000000..72a1cc52f
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd.h
@@ -0,0 +1,81 @@
+/* Ppmd.h -- PPMD codec common code
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#ifndef __PPMD_H
+#define __PPMD_H
+
+#include "Types.h"
+#include "CpuArch.h"
+
+EXTERN_C_BEGIN
+
+#ifdef MY_CPU_32BIT
+ #define PPMD_32BIT
+#endif
+
+#define PPMD_INT_BITS 7
+#define PPMD_PERIOD_BITS 7
+#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
+
+#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
+#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
+#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
+#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
+
+#define PPMD_N1 4
+#define PPMD_N2 4
+#define PPMD_N3 4
+#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
+#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
+
+/* SEE-contexts for PPM-contexts with masked symbols */
+typedef struct
+{
+ UInt16 Summ; /* Freq */
+ Byte Shift; /* Speed of Freq change; low Shift is for fast change */
+ Byte Count; /* Count to next change of Shift */
+} CPpmd_See;
+
+#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
+ { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
+
+typedef struct
+{
+ Byte Symbol;
+ Byte Freq;
+ UInt16 SuccessorLow;
+ UInt16 SuccessorHigh;
+} CPpmd_State;
+
+typedef
+ #ifdef PPMD_32BIT
+ CPpmd_State *
+ #else
+ UInt32
+ #endif
+ CPpmd_State_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ void *
+ #else
+ UInt32
+ #endif
+ CPpmd_Void_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ Byte *
+ #else
+ UInt32
+ #endif
+ CPpmd_Byte_Ref;
+
+#define PPMD_SetAllBitsIn256Bytes(p) \
+ { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \
+ p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }}
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/Ppmd7.c b/src/libs/7zip/win/C/Ppmd7.c
new file mode 100644
index 000000000..060d86d2e
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd7.c
@@ -0,0 +1,708 @@
+/* Ppmd7.c -- PPMdH codec
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include <memory.h>
+
+#include "Ppmd7.h"
+
+const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(nu) - 1])
+#define I2U(indx) (p->Indx2Units[indx])
+
+#ifdef PPMD_32BIT
+ #define REF(ptr) (ptr)
+#else
+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
+#endif
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+#define STATS(ctx) Ppmd7_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+typedef CPpmd7_Context * CTX_PTR;
+
+struct CPpmd7_Node_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Node_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Node_Ref;
+
+typedef struct CPpmd7_Node_
+{
+ UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
+ UInt16 NU;
+ CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
+ CPpmd7_Node_Ref Prev;
+} CPpmd7_Node;
+
+#ifdef PPMD_32BIT
+ #define NODE(ptr) (ptr)
+#else
+ #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))
+#endif
+
+void Ppmd7_Construct(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = 0;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while(--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 3; i++)
+ p->NS2Indx[i] = (Byte)i;
+ for (m = i, k = 1; i < 256; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 2;
+ }
+
+ memset(p->HB2Flag, 0, 0x40);
+ memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
+}
+
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = 0;
+}
+
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
+{
+ if (p->Base == 0 || p->Size != size)
+ {
+ Ppmd7_Free(p, alloc);
+ p->AlignOffset =
+ #ifdef PPMD_32BIT
+ (4 - size) & 3;
+ #else
+ 4 - (size & 3);
+ #endif
+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size
+ #ifndef PPMD_32BIT
+ + UNIT_SIZE
+ #endif
+ )) == 0)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+static void InsertNode(CPpmd7 *p, void *node, unsigned indx)
+{
+ *((CPpmd_Void_Ref *)node) = p->FreeList[indx];
+ p->FreeList[indx] = REF(node);
+}
+
+static void *RemoveNode(CPpmd7 *p, unsigned indx)
+{
+ CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
+ p->FreeList[indx] = *node;
+ return node;
+}
+
+static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ InsertNode(p, ptr, i);
+}
+
+static void GlueFreeBlocks(CPpmd7 *p)
+{
+ #ifdef PPMD_32BIT
+ CPpmd7_Node headItem;
+ CPpmd7_Node_Ref head = &headItem;
+ #else
+ CPpmd7_Node_Ref head = p->AlignOffset + p->Size;
+ #endif
+
+ CPpmd7_Node_Ref n = head;
+ unsigned i;
+
+ p->GlueCount = 255;
+
+ /* create doubly-linked list of free blocks */
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ UInt16 nu = I2U(i);
+ CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ CPpmd7_Node *node = NODE(next);
+ node->Next = n;
+ n = NODE(n)->Prev = next;
+ next = *(const CPpmd7_Node_Ref *)node;
+ node->Stamp = 0;
+ node->NU = (UInt16)nu;
+ }
+ }
+ NODE(head)->Stamp = 1;
+ NODE(head)->Next = n;
+ NODE(n)->Prev = head;
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;
+
+ /* Glue free blocks */
+ while (n != head)
+ {
+ CPpmd7_Node *node = NODE(n);
+ UInt32 nu = (UInt32)node->NU;
+ for (;;)
+ {
+ CPpmd7_Node *node2 = NODE(n) + nu;
+ nu += node2->NU;
+ if (node2->Stamp != 0 || nu >= 0x10000)
+ break;
+ NODE(node2->Prev)->Next = node2->Next;
+ NODE(node2->Next)->Prev = node2->Prev;
+ node->NU = (UInt16)nu;
+ }
+ n = node->Next;
+ }
+
+ /* Fill lists of free blocks */
+ for (n = NODE(head)->Next; n != head;)
+ {
+ CPpmd7_Node *node = NODE(n);
+ unsigned nu;
+ CPpmd7_Node_Ref next = node->Next;
+ for (nu = node->NU; nu > 128; nu -= 128, node += 128)
+ InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, node + k, nu - k - 1);
+ }
+ InsertNode(p, node, i);
+ n = next;
+ }
+}
+
+static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)
+{
+ unsigned i;
+ void *retVal;
+ if (p->GlueCount == 0)
+ {
+ GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ }
+ i = indx;
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ p->GlueCount--;
+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
+ }
+ }
+ while (p->FreeList[i] == 0);
+ retVal = RemoveNode(p, i);
+ SplitBlock(p, retVal, i, indx);
+ return retVal;
+}
+
+static void *AllocUnits(CPpmd7 *p, unsigned indx)
+{
+ UInt32 numBytes;
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ numBytes = U2B(I2U(indx));
+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
+ {
+ void *retVal = p->LoUnit;
+ p->LoUnit += numBytes;
+ return retVal;
+ }
+ return AllocUnitsRare(p, indx);
+}
+
+#define MyMem12Cpy(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }
+
+static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = RemoveNode(p, i1);
+ MyMem12Cpy(ptr, oldPtr, newNU);
+ InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+
+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
+
+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
+}
+
+static void RestartModel(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+ p->Text = p->Base + p->AlignOffset;
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ p->MinContext->Suffix = 0;
+ p->MinContext->NumStats = 256;
+ p->MinContext->SummFreq = 256 + 1;
+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+ p->LoUnit += U2B(256 / 2);
+ p->MinContext->Stats = REF(p->FoundState);
+ for (i = 0; i < 256; i++)
+ {
+ CPpmd_State *s = &p->FoundState[i];
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ SetSuccessor(s, 0);
+ }
+
+ for (i = 0; i < 128; i++)
+ for (k = 0; k < 8; k++)
+ {
+ UInt16 *dest = p->BinSumm[i] + k;
+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));
+ for (m = 0; m < 64; m += 8)
+ dest[m] = val;
+ }
+
+ for (i = 0; i < 25; i++)
+ for (k = 0; k < 16; k++)
+ {
+ CPpmd_See *s = &p->See[i][k];
+ s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));
+ s->Count = 4;
+ }
+}
+
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
+{
+ p->MaxOrder = maxOrder;
+ RestartModel(p);
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Count = 64; /* unused */
+}
+
+static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
+{
+ CPpmd_State upState;
+ CTX_PTR c = p->MinContext;
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ CPpmd_State *ps[PPMD7_MAX_ORDER];
+ unsigned numPs = 0;
+
+ if (!skip)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+ if (c->NumStats != 1)
+ {
+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
+ }
+ else
+ s = ONE_STATE(c);
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+ c = CTX(successor);
+ if (numPs == 0)
+ return c;
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+ upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
+ SetSuccessor(&upState, upBranch + 1);
+
+ if (c->NumStats == 1)
+ upState.Freq = ONE_STATE(c)->Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != upState.Symbol; s++);
+ cf = s->Freq - 1;
+ s0 = c->SummFreq - c->NumStats - cf;
+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
+ }
+
+ do
+ {
+ /* Create Child */
+ CTX_PTR c1; /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (CTX_PTR)RemoveNode(p, 0);
+ else
+ {
+ c1 = (CTX_PTR)AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+ c1->NumStats = 1;
+ *ONE_STATE(c1) = upState;
+ c1->Suffix = REF(c);
+ SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
+{
+ CPpmd_State tmp = *t1;
+ *t1 = *t2;
+ *t2 = tmp;
+}
+
+static void UpdateModel(CPpmd7 *p)
+{
+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
+ CTX_PTR c;
+ unsigned s0, ns;
+
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 1)
+ {
+ CPpmd_State *s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ CPpmd_State *s = STATS(c);
+ if (s->Symbol != p->FoundState->Symbol)
+ {
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ s--;
+ }
+ }
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ }
+
+ if (p->OrderFall == 0)
+ {
+ p->MinContext = p->MaxContext = CreateSuccessors(p, True);
+ if (p->MinContext == 0)
+ {
+ RestartModel(p);
+ return;
+ }
+ SetSuccessor(p->FoundState, REF(p->MinContext));
+ return;
+ }
+
+ *p->Text++ = p->FoundState->Symbol;
+ successor = REF(p->Text);
+ if (p->Text >= p->UnitsStart)
+ {
+ RestartModel(p);
+ return;
+ }
+
+ if (fSuccessor)
+ {
+ if (fSuccessor <= successor)
+ {
+ CTX_PTR cs = CreateSuccessors(p, False);
+ if (cs == NULL)
+ {
+ RestartModel(p);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+ if (--p->OrderFall == 0)
+ {
+ successor = fSuccessor;
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ }
+ else
+ {
+ SetSuccessor(p->FoundState, successor);
+ fSuccessor = REF(p->MinContext);
+ }
+
+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);
+
+ for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))
+ {
+ unsigned ns1;
+ UInt32 cf, sf;
+ if ((ns1 = c->NumStats) != 1)
+ {
+ if ((ns1 & 1) == 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = ns1 >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I(oldNU + 1))
+ {
+ void *ptr = AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ RestartModel(p);
+ return;
+ }
+ oldPtr = STATS(c);
+ MyMem12Cpy(ptr, oldPtr, oldNU);
+ InsertNode(p, oldPtr, i);
+ c->Stats = STATS_REF(ptr);
+ }
+ }
+ c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));
+ }
+ else
+ {
+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
+ if (!s)
+ {
+ RestartModel(p);
+ return;
+ }
+ *s = *ONE_STATE(c);
+ c->Stats = REF(s);
+ if (s->Freq < MAX_FREQ / 4 - 1)
+ s->Freq <<= 1;
+ else
+ s->Freq = MAX_FREQ - 4;
+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));
+ }
+ cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);
+ sf = (UInt32)s0 + c->SummFreq;
+ if (cf < 6 * sf)
+ {
+ cf = 1 + (cf > sf) + (cf >= 4 * sf);
+ c->SummFreq += 3;
+ }
+ else
+ {
+ cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
+ c->SummFreq = (UInt16)(c->SummFreq + cf);
+ }
+ {
+ CPpmd_State *s = STATS(c) + ns1;
+ SetSuccessor(s, successor);
+ s->Symbol = p->FoundState->Symbol;
+ s->Freq = (Byte)cf;
+ c->NumStats = (UInt16)(ns1 + 1);
+ }
+ }
+ p->MaxContext = p->MinContext = CTX(fSuccessor);
+}
+
+static void Rescale(CPpmd7 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+ {
+ CPpmd_State tmp = *s;
+ for (; s != stats; s--)
+ s[0] = s[-1];
+ *s = tmp;
+ }
+ escFreq = p->MinContext->SummFreq - s->Freq;
+ s->Freq += 4;
+ adder = (p->OrderFall != 0);
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq = s->Freq;
+
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ escFreq -= (++s)->Freq;
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq += s->Freq;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ CPpmd_State *s1 = s;
+ CPpmd_State tmp = *s1;
+ do
+ s1[0] = s1[-1];
+ while (--s1 != stats && tmp.Freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ unsigned numStats = p->MinContext->NumStats;
+ unsigned n0, n1;
+ do { i++; } while ((--s)->Freq == 0);
+ escFreq += i;
+ p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);
+ if (p->MinContext->NumStats == 1)
+ {
+ CPpmd_State tmp = *stats;
+ do
+ {
+ tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));
+ escFreq >>= 1;
+ }
+ while (escFreq > 1);
+ InsertNode(p, stats, U2I(((numStats + 1) >> 1)));
+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
+ return;
+ }
+ n0 = (numStats + 1) >> 1;
+ n1 = (p->MinContext->NumStats + 1) >> 1;
+ if (n0 != n1)
+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ }
+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ p->FoundState = STATS(p->MinContext);
+}
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ unsigned nonMasked = p->MinContext->NumStats - numMasked;
+ if (p->MinContext->NumStats != 256)
+ {
+ see = p->See[p->NS2Indx[nonMasked - 1]] +
+ (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
+ 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
+ 4 * (numMasked > nonMasked) +
+ p->HiBitsFlag;
+ {
+ unsigned r = (see->Summ >> see->Shift);
+ see->Summ = (UInt16)(see->Summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+static void NextContext(CPpmd7 *p)
+{
+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (Byte *)c > p->Text)
+ p->MinContext = p->MaxContext = c;
+ else
+ UpdateModel(p);
+}
+
+void Ppmd7_Update1(CPpmd7 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ s->Freq += 4;
+ p->MinContext->SummFreq += 4;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ p->FoundState = --s;
+ if (s->Freq > MAX_FREQ)
+ Rescale(p);
+ }
+ NextContext(p);
+}
+
+void Ppmd7_Update1_0(CPpmd7 *p)
+{
+ p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
+ p->RunLength += p->PrevSuccess;
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ NextContext(p);
+}
+
+void Ppmd7_UpdateBin(CPpmd7 *p)
+{
+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ NextContext(p);
+}
+
+void Ppmd7_Update2(CPpmd7 *p)
+{
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ p->RunLength = p->InitRL;
+ UpdateModel(p);
+}
diff --git a/src/libs/7zip/win/C/Ppmd7.h b/src/libs/7zip/win/C/Ppmd7.h
new file mode 100644
index 000000000..96521c31f
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd7.h
@@ -0,0 +1,140 @@
+/* Ppmd7.h -- PPMdH compression codec
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+/* This code supports virtual RangeDecoder and includes the implementation
+of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.
+If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */
+
+#ifndef __PPMD7_H
+#define __PPMD7_H
+
+#include "Ppmd.h"
+
+EXTERN_C_BEGIN
+
+#define PPMD7_MIN_ORDER 2
+#define PPMD7_MAX_ORDER 64
+
+#define PPMD7_MIN_MEM_SIZE (1 << 11)
+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
+
+struct CPpmd7_Context_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Context_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Context_Ref;
+
+typedef struct CPpmd7_Context_
+{
+ UInt16 NumStats;
+ UInt16 SummFreq;
+ CPpmd_State_Ref Stats;
+ CPpmd7_Context_Ref Suffix;
+} CPpmd7_Context;
+
+#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
+
+typedef struct
+{
+ CPpmd7_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+ UInt32 AlignOffset;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES];
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+ Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
+ CPpmd_See DummySee, See[25][16];
+ UInt16 BinSumm[128][64];
+} CPpmd7;
+
+void Ppmd7_Construct(CPpmd7 *p);
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc);
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
+#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
+
+
+/* ---------- Internal Functions ---------- */
+
+extern const Byte PPMD7_kExpEscape[16];
+
+#ifdef PPMD_32BIT
+ #define Ppmd7_GetPtr(p, ptr) (ptr)
+ #define Ppmd7_GetContext(p, ptr) (ptr)
+ #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)
+#else
+ #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
+ #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))
+ #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))
+#endif
+
+void Ppmd7_Update1(CPpmd7 *p);
+void Ppmd7_Update1_0(CPpmd7 *p);
+void Ppmd7_Update2(CPpmd7 *p);
+void Ppmd7_UpdateBin(CPpmd7 *p);
+
+#define Ppmd7_GetBinSumm(p) \
+ &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
+ p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
+ (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
+ 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \
+ ((p->RunLength >> 26) & 0x20)]
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
+
+
+/* ---------- Decode ---------- */
+
+typedef struct
+{
+ UInt32 (*GetThreshold)(void *p, UInt32 total);
+ void (*Decode)(void *p, UInt32 start, UInt32 size);
+ UInt32 (*DecodeBit)(void *p, UInt32 size0);
+} IPpmd7_RangeDec;
+
+typedef struct
+{
+ IPpmd7_RangeDec p;
+ UInt32 Range;
+ UInt32 Code;
+ IByteIn *Stream;
+} CPpmd7z_RangeDec;
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p);
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p);
+#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc);
+
+
+/* ---------- Encode ---------- */
+
+typedef struct
+{
+ UInt64 Low;
+ UInt32 Range;
+ Byte Cache;
+ UInt64 CacheSize;
+ IByteOut *Stream;
+} CPpmd7z_RangeEnc;
+
+void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p);
+void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p);
+
+void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/Ppmd7Dec.c b/src/libs/7zip/win/C/Ppmd7Dec.c
new file mode 100644
index 000000000..68438d5ce
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd7Dec.c
@@ -0,0 +1,187 @@
+/* Ppmd7Dec.c -- PPMdH Decoder
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Ppmd7.h"
+
+#define kTopValue (1 << 24)
+
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
+{
+ unsigned i;
+ p->Code = 0;
+ p->Range = 0xFFFFFFFF;
+ if (p->Stream->Read((void *)p->Stream) != 0)
+ return False;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ return (p->Code) / (p->Range /= total);
+}
+
+static void Range_Normalize(CPpmd7z_RangeDec *p)
+{
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ }
+ }
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ p->Code -= start * p->Range;
+ p->Range *= size;
+ Range_Normalize(p);
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ UInt32 newBound = (p->Range >> 14) * size0;
+ UInt32 symbol;
+ if (p->Code < newBound)
+ {
+ symbol = 0;
+ p->Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ p->Code -= newBound;
+ p->Range -= newBound;
+ }
+ Range_Normalize(p);
+ return symbol;
+}
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
+{
+ p->p.GetThreshold = Range_GetThreshold;
+ p->p.Decode = Range_Decode;
+ p->p.DecodeBit = Range_DecodeBit;
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
+ {
+ Byte symbol;
+ rc->Decode(rc, 0, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1_0(p);
+ return symbol;
+ }
+ p->PrevSuccess = 0;
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ if ((hiCnt += (++s)->Freq) > count)
+ {
+ Byte symbol;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1(p);
+ return symbol;
+ }
+ }
+ while (--i);
+ if (count >= p->MinContext->SummFreq)
+ return -2;
+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
+ rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats - 1;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ if (rc->DecodeBit(rc, *prob) == 0)
+ {
+ Byte symbol;
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
+ Ppmd7_UpdateBin(p);
+ return symbol;
+ }
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ for (;;)
+ {
+ CPpmd_State *ps[256], *s;
+ UInt32 freqSum, count, hiCnt;
+ CPpmd_See *see;
+ unsigned i, num, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return -1;
+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+ hiCnt = 0;
+ s = Ppmd7_GetStats(p, p->MinContext);
+ i = 0;
+ num = p->MinContext->NumStats - numMasked;
+ do
+ {
+ int k = (int)(MASK(s->Symbol));
+ hiCnt += (s->Freq & k);
+ ps[i] = s++;
+ i -= k;
+ }
+ while (i != num);
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+ count = rc->GetThreshold(rc, freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte symbol;
+ CPpmd_State **pps = ps;
+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
+ s = *pps;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ Ppmd_See_Update(see);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update2(p);
+ return symbol;
+ }
+ if (count >= freqSum)
+ return -2;
+ rc->Decode(rc, hiCnt, freqSum - hiCnt);
+ see->Summ = (UInt16)(see->Summ + freqSum);
+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
+ }
+}
diff --git a/src/libs/7zip/win/C/Ppmd7Enc.c b/src/libs/7zip/win/C/Ppmd7Enc.c
new file mode 100644
index 000000000..8247757d0
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd7Enc.c
@@ -0,0 +1,185 @@
+/* Ppmd7Enc.c -- PPMdH Encoder
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Ppmd7.h"
+
+#define kTopValue (1 << 24)
+
+void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p)
+{
+ p->Low = 0;
+ p->Range = 0xFFFFFFFF;
+ p->Cache = 0;
+ p->CacheSize = 1;
+}
+
+static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
+{
+ if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0)
+ {
+ Byte temp = p->Cache;
+ do
+ {
+ p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32)));
+ temp = 0xFF;
+ }
+ while(--p->CacheSize != 0);
+ p->Cache = (Byte)((UInt32)p->Low >> 24);
+ }
+ p->CacheSize++;
+ p->Low = (UInt32)p->Low << 8;
+}
+
+static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)
+{
+ p->Low += start * (p->Range /= total);
+ p->Range *= size;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0)
+{
+ p->Range = (p->Range >> 14) * size0;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0)
+{
+ UInt32 newBound = (p->Range >> 14) * size0;
+ p->Low += newBound;
+ p->Range -= newBound;
+ while (p->Range < kTopValue)
+ {
+ p->Range <<= 8;
+ RangeEnc_ShiftLow(p);
+ }
+}
+
+void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p)
+{
+ unsigned i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ UInt32 sum;
+ unsigned i;
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd7_Update1_0(p);
+ return;
+ }
+ p->PrevSuccess = 0;
+ sum = s->Freq;
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ if ((++s)->Symbol == symbol)
+ {
+ RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd7_Update1(p);
+ return;
+ }
+ sum += s->Freq;
+ }
+ while (--i);
+
+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats - 1;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_EncodeBit_0(rc, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ p->FoundState = s;
+ Ppmd7_UpdateBin(p);
+ return;
+ }
+ else
+ {
+ RangeEnc_EncodeBit_1(rc, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ }
+ for (;;)
+ {
+ UInt32 escFreq;
+ CPpmd_See *see;
+ CPpmd_State *s;
+ UInt32 sum;
+ unsigned i, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return; /* EndMarker (symbol = -1) */
+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
+ s = Ppmd7_GetStats(p, p->MinContext);
+ sum = 0;
+ i = p->MinContext->NumStats;
+ do
+ {
+ int cur = s->Symbol;
+ if (cur == symbol)
+ {
+ UInt32 low = sum;
+ CPpmd_State *s1 = s;
+ do
+ {
+ sum += (s->Freq & (int)(MASK(s->Symbol)));
+ s++;
+ }
+ while (--i);
+ RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq);
+ Ppmd_See_Update(see);
+ p->FoundState = s1;
+ Ppmd7_Update2(p);
+ return;
+ }
+ sum += (s->Freq & (int)(MASK(cur)));
+ MASK(cur) = 0;
+ s++;
+ }
+ while (--i);
+
+ RangeEnc_Encode(rc, sum, escFreq, sum + escFreq);
+ see->Summ = (UInt16)(see->Summ + sum + escFreq);
+ }
+}
diff --git a/src/libs/7zip/win/C/Ppmd8.c b/src/libs/7zip/win/C/Ppmd8.c
new file mode 100644
index 000000000..9187a88ef
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd8.c
@@ -0,0 +1,1120 @@
+/* Ppmd8.c -- PPMdI codec
+2010-03-24 : Igor Pavlov : Public domain
+This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */
+
+#include <memory.h>
+
+#include "Ppmd8.h"
+
+const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(nu) - 1])
+#define I2U(indx) (p->Indx2Units[indx])
+
+#ifdef PPMD_32BIT
+ #define REF(ptr) (ptr)
+#else
+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
+#endif
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref))
+#define STATS(ctx) Ppmd8_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+typedef CPpmd8_Context * CTX_PTR;
+
+struct CPpmd8_Node_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd8_Node_ *
+ #else
+ UInt32
+ #endif
+ CPpmd8_Node_Ref;
+
+typedef struct CPpmd8_Node_
+{
+ UInt32 Stamp;
+ CPpmd8_Node_Ref Next;
+ UInt32 NU;
+} CPpmd8_Node;
+
+#ifdef PPMD_32BIT
+ #define NODE(ptr) (ptr)
+#else
+ #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs)))
+#endif
+
+#define EMPTY_NODE 0xFFFFFFFF
+
+void Ppmd8_Construct(CPpmd8 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = 0;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while(--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 5; i++)
+ p->NS2Indx[i] = (Byte)i;
+ for (m = i, k = 1; i < 260; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 4;
+ }
+}
+
+void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = 0;
+}
+
+Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc)
+{
+ if (p->Base == 0 || p->Size != size)
+ {
+ Ppmd8_Free(p, alloc);
+ p->AlignOffset =
+ #ifdef PPMD_32BIT
+ (4 - size) & 3;
+ #else
+ 4 - (size & 3);
+ #endif
+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size)) == 0)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+static void InsertNode(CPpmd8 *p, void *node, unsigned indx)
+{
+ ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE;
+ ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx];
+ ((CPpmd8_Node *)node)->NU = I2U(indx);
+ p->FreeList[indx] = REF(node);
+ p->Stamps[indx]++;
+}
+
+static void *RemoveNode(CPpmd8 *p, unsigned indx)
+{
+ CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]);
+ p->FreeList[indx] = node->Next;
+ p->Stamps[indx]--;
+ return node;
+}
+
+static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ InsertNode(p, ptr, i);
+}
+
+static void GlueFreeBlocks(CPpmd8 *p)
+{
+ CPpmd8_Node_Ref head = 0;
+ CPpmd8_Node_Ref *prev = &head;
+ unsigned i;
+
+ p->GlueCount = 1 << 13;
+ memset(p->Stamps, 0, sizeof(p->Stamps));
+
+ /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end.
+ All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd8_Node *)p->LoUnit)->Stamp = 0;
+
+ /* Glue free blocks */
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ CPpmd8_Node *node = NODE(next);
+ if (node->NU != 0)
+ {
+ CPpmd8_Node *node2;
+ *prev = next;
+ prev = &(node->Next);
+ while ((node2 = node + node->NU)->Stamp == EMPTY_NODE)
+ {
+ node->NU += node2->NU;
+ node2->NU = 0;
+ }
+ }
+ next = node->Next;
+ }
+ }
+ *prev = 0;
+
+ /* Fill lists of free blocks */
+ while (head != 0)
+ {
+ CPpmd8_Node *node = NODE(head);
+ unsigned nu;
+ head = node->Next;
+ nu = node->NU;
+ if (nu == 0)
+ continue;
+ for (; nu > 128; nu -= 128, node += 128)
+ InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, node + k, nu - k - 1);
+ }
+ InsertNode(p, node, i);
+ }
+}
+
+static void *AllocUnitsRare(CPpmd8 *p, unsigned indx)
+{
+ unsigned i;
+ void *retVal;
+ if (p->GlueCount == 0)
+ {
+ GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ }
+ i = indx;
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ p->GlueCount--;
+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
+ }
+ }
+ while (p->FreeList[i] == 0);
+ retVal = RemoveNode(p, i);
+ SplitBlock(p, retVal, i, indx);
+ return retVal;
+}
+
+static void *AllocUnits(CPpmd8 *p, unsigned indx)
+{
+ UInt32 numBytes;
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ numBytes = U2B(I2U(indx));
+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
+ {
+ void *retVal = p->LoUnit;
+ p->LoUnit += numBytes;
+ return retVal;
+ }
+ return AllocUnitsRare(p, indx);
+}
+
+#define MyMem12Cpy(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }
+
+static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = RemoveNode(p, i1);
+ MyMem12Cpy(ptr, oldPtr, newNU);
+ InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+
+static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu)
+{
+ InsertNode(p, ptr, U2I(nu));
+}
+
+static void SpecialFreeUnit(CPpmd8 *p, void *ptr)
+{
+ if ((Byte *)ptr != p->UnitsStart)
+ InsertNode(p, ptr, 0);
+ else
+ {
+ #ifdef PPMD8_FREEZE_SUPPORT
+ *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */
+ #endif
+ p->UnitsStart += UNIT_SIZE;
+ }
+}
+
+static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu)
+{
+ unsigned indx = U2I(nu);
+ void *ptr;
+ if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx])
+ return oldPtr;
+ ptr = RemoveNode(p, indx);
+ MyMem12Cpy(ptr, oldPtr, nu);
+ if ((Byte*)oldPtr != p->UnitsStart)
+ InsertNode(p, oldPtr, indx);
+ else
+ p->UnitsStart += U2B(I2U(indx));
+ return ptr;
+}
+
+static void ExpandTextArea(CPpmd8 *p)
+{
+ UInt32 count[PPMD_NUM_INDEXES];
+ unsigned i;
+ memset(count, 0, sizeof(count));
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd8_Node *)p->LoUnit)->Stamp = 0;
+
+ {
+ CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart;
+ for (; node->Stamp == EMPTY_NODE; node += node->NU)
+ {
+ node->Stamp = 0;
+ count[U2I(node->NU)]++;
+ }
+ p->UnitsStart = (Byte *)node;
+ }
+
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i];
+ while (count[i] != 0)
+ {
+ CPpmd8_Node *node = NODE(*next);
+ while (node->Stamp == 0)
+ {
+ *next = node->Next;
+ node = NODE(*next);
+ p->Stamps[i]--;
+ if (--count[i] == 0)
+ break;
+ }
+ next = &node->Next;
+ }
+ }
+}
+
+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
+
+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
+}
+
+#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); }
+
+static void RestartModel(CPpmd8 *p)
+{
+ unsigned i, k, m, r;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+ memset(p->Stamps, 0, sizeof(p->Stamps));
+ RESET_TEXT(0);
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ p->MinContext->Suffix = 0;
+ p->MinContext->NumStats = 255;
+ p->MinContext->Flags = 0;
+ p->MinContext->SummFreq = 256 + 1;
+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+ p->LoUnit += U2B(256 / 2);
+ p->MinContext->Stats = REF(p->FoundState);
+ for (i = 0; i < 256; i++)
+ {
+ CPpmd_State *s = &p->FoundState[i];
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ SetSuccessor(s, 0);
+ }
+
+ for (i = m = 0; m < 25; m++)
+ {
+ while (p->NS2Indx[i] == m)
+ i++;
+ for (k = 0; k < 8; k++)
+ {
+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1));
+ UInt16 *dest = p->BinSumm[m] + k;
+ for (r = 0; r < 64; r += 8)
+ dest[r] = val;
+ }
+ }
+
+ for (i = m = 0; m < 24; m++)
+ {
+ while (p->NS2Indx[i + 3] == m + 3)
+ i++;
+ for (k = 0; k < 32; k++)
+ {
+ CPpmd_See *s = &p->See[m][k];
+ s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4));
+ s->Count = 7;
+ }
+ }
+}
+
+void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
+{
+ p->MaxOrder = maxOrder;
+ p->RestoreMethod = restoreMethod;
+ RestartModel(p);
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Count = 64; /* unused */
+}
+
+static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale)
+{
+ unsigned i = ctx->NumStats, escFreq, sumFreq, flags;
+ CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1);
+ ctx->Stats = REF(s);
+ #ifdef PPMD8_FREEZE_SUPPORT
+ /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */
+ scale |= (ctx->SummFreq >= ((UInt32)1 << 15));
+ #endif
+ flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40);
+ escFreq = ctx->SummFreq - s->Freq;
+ sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale));
+ do
+ {
+ escFreq -= (++s)->Freq;
+ sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale));
+ flags |= 0x08 * (s->Symbol >= 0x40);
+ }
+ while (--i);
+ ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale));
+ ctx->Flags = (Byte)flags;
+}
+
+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
+{
+ CPpmd_State tmp = *t1;
+ *t1 = *t2;
+ *t2 = tmp;
+}
+
+static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order)
+{
+ int i;
+ unsigned tmp;
+ CPpmd_State *s;
+
+ if (!ctx->NumStats)
+ {
+ s = ONE_STATE(ctx);
+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart)
+ {
+ if (order < p->MaxOrder)
+ SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1));
+ else
+ SetSuccessor(s, 0);
+ if (SUCCESSOR(s) || order <= 9) /* O_BOUND */
+ return REF(ctx);
+ }
+ SpecialFreeUnit(p, ctx);
+ return 0;
+ }
+
+ ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1));
+
+ for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--)
+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart)
+ {
+ CPpmd_State *s2 = STATS(ctx) + (i--);
+ SetSuccessor(s, 0);
+ SwapStates(s, s2);
+ }
+ else if (order < p->MaxOrder)
+ SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1));
+ else
+ SetSuccessor(s, 0);
+
+ if (i != ctx->NumStats && order)
+ {
+ ctx->NumStats = (Byte)i;
+ s = STATS(ctx);
+ if (i < 0)
+ {
+ FreeUnits(p, s, tmp);
+ SpecialFreeUnit(p, ctx);
+ return 0;
+ }
+ if (i == 0)
+ {
+ ctx->Flags = (ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40);
+ *ONE_STATE(ctx) = *s;
+ FreeUnits(p, s, tmp);
+ ONE_STATE(ctx)->Freq = (Byte)((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3;
+ }
+ else
+ Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i);
+ }
+ return REF(ctx);
+}
+
+#ifdef PPMD8_FREEZE_SUPPORT
+static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order)
+{
+ CPpmd_State *s;
+ if (!ctx->NumStats)
+ {
+ s = ONE_STATE(ctx);
+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder)
+ SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1));
+ else
+ SetSuccessor(s, 0);
+ /* Suffix context can be removed already, since different (high-order)
+ Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */
+ if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF))
+ {
+ FreeUnits(p, ctx, 1);
+ return 0;
+ }
+ else
+ return REF(ctx);
+ }
+
+ for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--)
+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder)
+ SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1));
+ else
+ SetSuccessor(s, 0);
+
+ return REF(ctx);
+}
+#endif
+
+static UInt32 GetUsedMemory(const CPpmd8 *p)
+{
+ UInt32 v = 0;
+ unsigned i;
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ v += p->Stamps[i] * I2U(i);
+ return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v);
+}
+
+#ifdef PPMD8_FREEZE_SUPPORT
+ #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor)
+#else
+ #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1)
+#endif
+
+static void RestoreModel(CPpmd8 *p, CTX_PTR c1
+ #ifdef PPMD8_FREEZE_SUPPORT
+ , CTX_PTR fSuccessor
+ #endif
+ )
+{
+ CTX_PTR c;
+ CPpmd_State *s;
+ RESET_TEXT(0);
+ for (c = p->MaxContext; c != c1; c = SUFFIX(c))
+ if (--(c->NumStats) == 0)
+ {
+ s = STATS(c);
+ c->Flags = (c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40);
+ *ONE_STATE(c) = *s;
+ SpecialFreeUnit(p, s);
+ ONE_STATE(c)->Freq = (ONE_STATE(c)->Freq + 11) >> 3;
+ }
+ else
+ Refresh(p, c, (c->NumStats+3) >> 1, 0);
+
+ for (; c != p->MinContext; c = SUFFIX(c))
+ if (!c->NumStats)
+ ONE_STATE(c)->Freq -= ONE_STATE(c)->Freq >> 1;
+ else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats)
+ Refresh(p, c, (c->NumStats + 2) >> 1, 1);
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ p->MaxContext = fSuccessor;
+ p->GlueCount += !(p->Stamps[1] & 1);
+ }
+ else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ while (p->MaxContext->Suffix)
+ p->MaxContext = SUFFIX(p->MaxContext);
+ RemoveBinContexts(p, p->MaxContext, 0);
+ p->RestoreMethod++;
+ p->GlueCount = 0;
+ p->OrderFall = p->MaxOrder;
+ }
+ else
+ #endif
+ if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1))
+ RestartModel(p);
+ else
+ {
+ while (p->MaxContext->Suffix)
+ p->MaxContext = SUFFIX(p->MaxContext);
+ do
+ {
+ CutOff(p, p->MaxContext, 0);
+ ExpandTextArea(p);
+ }
+ while (GetUsedMemory(p) > 3 * (p->Size >> 2));
+ p->GlueCount = 0;
+ p->OrderFall = p->MaxOrder;
+ }
+}
+
+static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c)
+{
+ CPpmd_State upState;
+ Byte flags;
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ /* fixed over Shkarin's code. Maybe it could work without + 1 too. */
+ CPpmd_State *ps[PPMD8_MAX_ORDER + 1];
+ unsigned numPs = 0;
+
+ if (!skip)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+ if (s1)
+ {
+ s = s1;
+ s1 = NULL;
+ }
+ else if (c->NumStats != 0)
+ {
+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq++;
+ c->SummFreq++;
+ }
+ }
+ else
+ {
+ s = ONE_STATE(c);
+ s->Freq += (!SUFFIX(c)->NumStats & (s->Freq < 24));
+ }
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+ c = CTX(successor);
+ if (numPs == 0)
+ return c;
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+ upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch);
+ SetSuccessor(&upState, upBranch + 1);
+ flags = 0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40);
+
+ if (c->NumStats == 0)
+ upState.Freq = ONE_STATE(c)->Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != upState.Symbol; s++);
+ cf = s->Freq - 1;
+ s0 = c->SummFreq - c->NumStats - cf;
+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0)));
+ }
+
+ do
+ {
+ /* Create Child */
+ CTX_PTR c1; /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (CTX_PTR)RemoveNode(p, 0);
+ else
+ {
+ c1 = (CTX_PTR)AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+ c1->NumStats = 0;
+ c1->Flags = flags;
+ *ONE_STATE(c1) = upState;
+ c1->Suffix = REF(c);
+ SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c)
+{
+ CPpmd_State *s = NULL;
+ CTX_PTR c1 = c;
+ CPpmd_Void_Ref upBranch = REF(p->Text);
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */
+ CPpmd_State *ps[PPMD8_MAX_ORDER + 1];
+ unsigned numPs = 0;
+ ps[numPs++] = p->FoundState;
+ #endif
+
+ SetSuccessor(p->FoundState, upBranch);
+ p->OrderFall++;
+
+ for (;;)
+ {
+ if (s1)
+ {
+ c = SUFFIX(c);
+ s = s1;
+ s1 = NULL;
+ }
+ else
+ {
+ if (!c->Suffix)
+ {
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
+ RESET_TEXT(1);
+ p->OrderFall = 1;
+ }
+ #endif
+ return c;
+ }
+ c = SUFFIX(c);
+ if (c->NumStats)
+ {
+ if ((s = STATS(c))->Symbol != p->FoundState->Symbol)
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ else
+ {
+ s = ONE_STATE(c);
+ s->Freq += (s->Freq < 32);
+ }
+ }
+ if (SUCCESSOR(s))
+ break;
+ #ifdef PPMD8_FREEZE_SUPPORT
+ ps[numPs++] = s;
+ #endif
+ SetSuccessor(s, upBranch);
+ p->OrderFall++;
+ }
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ c = CTX(SUCCESSOR(s));
+ do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
+ RESET_TEXT(1);
+ p->OrderFall = 1;
+ return c;
+ }
+ else
+ #endif
+ if (SUCCESSOR(s) <= upBranch)
+ {
+ CTX_PTR successor;
+ CPpmd_State *s1 = p->FoundState;
+ p->FoundState = s;
+
+ successor = CreateSuccessors(p, False, NULL, c);
+ if (successor == NULL)
+ SetSuccessor(s, 0);
+ else
+ SetSuccessor(s, REF(successor));
+ p->FoundState = s1;
+ }
+
+ if (p->OrderFall == 1 && c1 == p->MaxContext)
+ {
+ SetSuccessor(p->FoundState, SUCCESSOR(s));
+ p->Text--;
+ }
+ if (SUCCESSOR(s) == 0)
+ return NULL;
+ return CTX(SUCCESSOR(s));
+}
+
+static void UpdateModel(CPpmd8 *p)
+{
+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
+ CTX_PTR c;
+ unsigned s0, ns, fFreq = p->FoundState->Freq;
+ Byte flag, fSymbol = p->FoundState->Symbol;
+ CPpmd_State *s = NULL;
+
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 0)
+ {
+ s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ s = STATS(c);
+ if (s->Symbol != p->FoundState->Symbol)
+ {
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ s--;
+ }
+ }
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ }
+
+ c = p->MaxContext;
+ if (p->OrderFall == 0 && fSuccessor)
+ {
+ CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext);
+ if (cs == 0)
+ {
+ SetSuccessor(p->FoundState, 0);
+ RESTORE_MODEL(c, CTX(fSuccessor));
+ }
+ else
+ {
+ SetSuccessor(p->FoundState, REF(cs));
+ p->MaxContext = cs;
+ }
+ return;
+ }
+
+ *p->Text++ = p->FoundState->Symbol;
+ successor = REF(p->Text);
+ if (p->Text >= p->UnitsStart)
+ {
+ RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */
+ return;
+ }
+
+ if (!fSuccessor)
+ {
+ CTX_PTR cs = ReduceOrder(p, s, p->MinContext);
+ if (cs == NULL)
+ {
+ RESTORE_MODEL(c, 0);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+ else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart)
+ {
+ CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext);
+ if (cs == NULL)
+ {
+ RESTORE_MODEL(c, 0);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+
+ if (--p->OrderFall == 0)
+ {
+ successor = fSuccessor;
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ #ifdef PPMD8_FREEZE_SUPPORT
+ else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ successor = fSuccessor;
+ RESET_TEXT(0);
+ p->OrderFall = 0;
+ }
+ #endif
+
+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq;
+ flag = 0x08 * (fSymbol >= 0x40);
+
+ for (; c != p->MinContext; c = SUFFIX(c))
+ {
+ unsigned ns1;
+ UInt32 cf, sf;
+ if ((ns1 = c->NumStats) != 0)
+ {
+ if ((ns1 & 1) != 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = (ns1 + 1) >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I(oldNU + 1))
+ {
+ void *ptr = AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ RESTORE_MODEL(c, CTX(fSuccessor));
+ return;
+ }
+ oldPtr = STATS(c);
+ MyMem12Cpy(ptr, oldPtr, oldNU);
+ InsertNode(p, oldPtr, i);
+ c->Stats = STATS_REF(ptr);
+ }
+ }
+ c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns));
+ }
+ else
+ {
+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
+ if (!s)
+ {
+ RESTORE_MODEL(c, CTX(fSuccessor));
+ return;
+ }
+ *s = *ONE_STATE(c);
+ c->Stats = REF(s);
+ if (s->Freq < MAX_FREQ / 4 - 1)
+ s->Freq <<= 1;
+ else
+ s->Freq = MAX_FREQ - 4;
+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 2));
+ }
+ cf = 2 * fFreq * (c->SummFreq + 6);
+ sf = (UInt32)s0 + c->SummFreq;
+ if (cf < 6 * sf)
+ {
+ cf = 1 + (cf > sf) + (cf >= 4 * sf);
+ c->SummFreq += 4;
+ }
+ else
+ {
+ cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf);
+ c->SummFreq = (UInt16)(c->SummFreq + cf);
+ }
+ {
+ CPpmd_State *s = STATS(c) + ns1 + 1;
+ SetSuccessor(s, successor);
+ s->Symbol = fSymbol;
+ s->Freq = (Byte)cf;
+ c->Flags |= flag;
+ c->NumStats = (Byte)(ns1 + 1);
+ }
+ }
+ p->MaxContext = p->MinContext = CTX(fSuccessor);
+}
+
+static void Rescale(CPpmd8 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+ {
+ CPpmd_State tmp = *s;
+ for (; s != stats; s--)
+ s[0] = s[-1];
+ *s = tmp;
+ }
+ escFreq = p->MinContext->SummFreq - s->Freq;
+ s->Freq += 4;
+ adder = (p->OrderFall != 0
+ #ifdef PPMD8_FREEZE_SUPPORT
+ || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE
+ #endif
+ );
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq = s->Freq;
+
+ i = p->MinContext->NumStats;
+ do
+ {
+ escFreq -= (++s)->Freq;
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq += s->Freq;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ CPpmd_State *s1 = s;
+ CPpmd_State tmp = *s1;
+ do
+ s1[0] = s1[-1];
+ while (--s1 != stats && tmp.Freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ unsigned numStats = p->MinContext->NumStats;
+ unsigned n0, n1;
+ do { i++; } while ((--s)->Freq == 0);
+ escFreq += i;
+ p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i);
+ if (p->MinContext->NumStats == 0)
+ {
+ CPpmd_State tmp = *stats;
+ tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq);
+ if (tmp.Freq > MAX_FREQ / 3)
+ tmp.Freq = MAX_FREQ / 3;
+ InsertNode(p, stats, U2I((numStats + 2) >> 1));
+ p->MinContext->Flags = (p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40);
+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
+ return;
+ }
+ n0 = (numStats + 2) >> 1;
+ n1 = (p->MinContext->NumStats + 2) >> 1;
+ if (n0 != n1)
+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ p->MinContext->Flags &= ~0x08;
+ p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40);
+ i = p->MinContext->NumStats;
+ do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i);
+ }
+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ p->MinContext->Flags |= 0x4;
+ p->FoundState = STATS(p->MinContext);
+}
+
+CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ if (p->MinContext->NumStats != 0xFF)
+ {
+ see = p->See[p->NS2Indx[p->MinContext->NumStats + 2] - 3] +
+ (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) +
+ 2 * (2 * (unsigned)p->MinContext->NumStats <
+ ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) +
+ p->MinContext->Flags;
+ {
+ unsigned r = (see->Summ >> see->Shift);
+ see->Summ = (UInt16)(see->Summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+static void NextContext(CPpmd8 *p)
+{
+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart)
+ p->MinContext = p->MaxContext = c;
+ else
+ {
+ UpdateModel(p);
+ p->MinContext = p->MaxContext;
+ }
+}
+
+void Ppmd8_Update1(CPpmd8 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ s->Freq += 4;
+ p->MinContext->SummFreq += 4;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ p->FoundState = --s;
+ if (s->Freq > MAX_FREQ)
+ Rescale(p);
+ }
+ NextContext(p);
+}
+
+void Ppmd8_Update1_0(CPpmd8 *p)
+{
+ p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq);
+ p->RunLength += p->PrevSuccess;
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ NextContext(p);
+}
+
+void Ppmd8_UpdateBin(CPpmd8 *p)
+{
+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196));
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ NextContext(p);
+}
+
+void Ppmd8_Update2(CPpmd8 *p)
+{
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ p->RunLength = p->InitRL;
+ UpdateModel(p);
+ p->MinContext = p->MaxContext;
+}
+
+/* H->I changes:
+ NS2Indx
+ GlewCount, and Glue method
+ BinSum
+ See / EscFreq
+ CreateSuccessors updates more suffix contexts
+ UpdateModel consts.
+ PrevSuccess Update
+*/
diff --git a/src/libs/7zip/win/C/Ppmd8.h b/src/libs/7zip/win/C/Ppmd8.h
new file mode 100644
index 000000000..870dc9dd8
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd8.h
@@ -0,0 +1,133 @@
+/* Ppmd8.h -- PPMdI codec
+2010-03-24 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#ifndef __PPMD8_H
+#define __PPMD8_H
+
+#include "Ppmd.h"
+
+EXTERN_C_BEGIN
+
+#define PPMD8_MIN_ORDER 2
+#define PPMD8_MAX_ORDER 16
+
+struct CPpmd8_Context_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd8_Context_ *
+ #else
+ UInt32
+ #endif
+ CPpmd8_Context_Ref;
+
+typedef struct CPpmd8_Context_
+{
+ Byte NumStats;
+ Byte Flags;
+ UInt16 SummFreq;
+ CPpmd_State_Ref Stats;
+ CPpmd8_Context_Ref Suffix;
+} CPpmd8_Context;
+
+#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
+
+/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed
+ code is not compatible with original code for some files compressed
+ in FREEZE mode. So we disable FREEZE mode support. */
+
+enum
+{
+ PPMD8_RESTORE_METHOD_RESTART,
+ PPMD8_RESTORE_METHOD_CUT_OFF
+ #ifdef PPMD8_FREEZE_SUPPORT
+ , PPMD8_RESTORE_METHOD_FREEZE
+ #endif
+};
+
+typedef struct
+{
+ CPpmd8_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+ UInt32 AlignOffset;
+ unsigned RestoreMethod;
+
+ /* Range Coder */
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ union
+ {
+ IByteIn *In;
+ IByteOut *Out;
+ } Stream;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES];
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+ UInt32 Stamps[PPMD_NUM_INDEXES];
+
+ Byte NS2BSIndx[256], NS2Indx[260];
+ CPpmd_See DummySee, See[24][32];
+ UInt16 BinSumm[25][64];
+} CPpmd8;
+
+void Ppmd8_Construct(CPpmd8 *p);
+Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc);
+void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc);
+void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod);
+#define Ppmd8_WasAllocated(p) ((p)->Base != NULL)
+
+
+/* ---------- Internal Functions ---------- */
+
+extern const Byte PPMD8_kExpEscape[16];
+
+#ifdef PPMD_32BIT
+ #define Ppmd8_GetPtr(p, ptr) (ptr)
+ #define Ppmd8_GetContext(p, ptr) (ptr)
+ #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats)
+#else
+ #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
+ #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs)))
+ #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats)))
+#endif
+
+void Ppmd8_Update1(CPpmd8 *p);
+void Ppmd8_Update1_0(CPpmd8 *p);
+void Ppmd8_Update2(CPpmd8 *p);
+void Ppmd8_UpdateBin(CPpmd8 *p);
+
+#define Ppmd8_GetBinSumm(p) \
+ &p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \
+ p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \
+ p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)]
+
+CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale);
+
+
+/* ---------- Decode ---------- */
+
+Bool Ppmd8_RangeDec_Init(CPpmd8 *p);
+#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */
+
+
+/* ---------- Encode ---------- */
+
+#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; }
+void Ppmd8_RangeEnc_FlushData(CPpmd8 *p);
+void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/Ppmd8Dec.c b/src/libs/7zip/win/C/Ppmd8Dec.c
new file mode 100644
index 000000000..c54e02ab2
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd8Dec.c
@@ -0,0 +1,155 @@
+/* Ppmd8Dec.c -- PPMdI Decoder
+2010-04-16 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "Ppmd8.h"
+
+#define kTop (1 << 24)
+#define kBot (1 << 15)
+
+Bool Ppmd8_RangeDec_Init(CPpmd8 *p)
+{
+ unsigned i;
+ p->Low = 0;
+ p->Range = 0xFFFFFFFF;
+ p->Code = 0;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total)
+{
+ return p->Code / (p->Range /= total);
+}
+
+static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size)
+{
+ start *= p->Range;
+ p->Low += start;
+ p->Code -= start;
+ p->Range *= size;
+
+ while ((p->Low ^ (p->Low + p->Range)) < kTop ||
+ (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))
+ {
+ p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);
+ p->Range <<= 8;
+ p->Low <<= 8;
+ }
+}
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+int Ppmd8_DecodeSymbol(CPpmd8 *p)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 0)
+ {
+ CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
+ {
+ Byte symbol;
+ RangeDec_Decode(p, 0, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd8_Update1_0(p);
+ return symbol;
+ }
+ p->PrevSuccess = 0;
+ i = p->MinContext->NumStats;
+ do
+ {
+ if ((hiCnt += (++s)->Freq) > count)
+ {
+ Byte symbol;
+ RangeDec_Decode(p, hiCnt - s->Freq, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd8_Update1(p);
+ return symbol;
+ }
+ }
+ while (--i);
+ if (count >= p->MinContext->SummFreq)
+ return -2;
+ RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt);
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd8_GetBinSumm(p);
+ if (((p->Code / (p->Range >>= 14)) < *prob))
+ {
+ Byte symbol;
+ RangeDec_Decode(p, 0, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol;
+ Ppmd8_UpdateBin(p);
+ return symbol;
+ }
+ RangeDec_Decode(p, *prob, (1 << 14) - *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD8_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ for (;;)
+ {
+ CPpmd_State *ps[256], *s;
+ UInt32 freqSum, count, hiCnt;
+ CPpmd_See *see;
+ unsigned i, num, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return -1;
+ p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+ hiCnt = 0;
+ s = Ppmd8_GetStats(p, p->MinContext);
+ i = 0;
+ num = p->MinContext->NumStats - numMasked;
+ do
+ {
+ int k = (int)(MASK(s->Symbol));
+ hiCnt += (s->Freq & k);
+ ps[i] = s++;
+ i -= k;
+ }
+ while (i != num);
+
+ see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+ count = RangeDec_GetThreshold(p, freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte symbol;
+ CPpmd_State **pps = ps;
+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
+ s = *pps;
+ RangeDec_Decode(p, hiCnt - s->Freq, s->Freq);
+ Ppmd_See_Update(see);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd8_Update2(p);
+ return symbol;
+ }
+ if (count >= freqSum)
+ return -2;
+ RangeDec_Decode(p, hiCnt, freqSum - hiCnt);
+ see->Summ = (UInt16)(see->Summ + freqSum);
+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
+ }
+}
diff --git a/src/libs/7zip/win/C/Ppmd8Enc.c b/src/libs/7zip/win/C/Ppmd8Enc.c
new file mode 100644
index 000000000..8da727eb2
--- /dev/null
+++ b/src/libs/7zip/win/C/Ppmd8Enc.c
@@ -0,0 +1,161 @@
+/* Ppmd8Enc.c -- PPMdI Encoder
+2010-04-16 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "Ppmd8.h"
+
+#define kTop (1 << 24)
+#define kBot (1 << 15)
+
+void Ppmd8_RangeEnc_FlushData(CPpmd8 *p)
+{
+ unsigned i;
+ for (i = 0; i < 4; i++, p->Low <<= 8 )
+ p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24));
+}
+
+static void RangeEnc_Normalize(CPpmd8 *p)
+{
+ while ((p->Low ^ (p->Low + p->Range)) < kTop ||
+ (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))
+ {
+ p->Stream.Out->Write(p->Stream.Out, (Byte)(p->Low >> 24));
+ p->Range <<= 8;
+ p->Low <<= 8;
+ }
+}
+
+static void RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total)
+{
+ p->Low += start * (p->Range /= total);
+ p->Range *= size;
+ RangeEnc_Normalize(p);
+}
+
+static void RangeEnc_EncodeBit_0(CPpmd8 *p, UInt32 size0)
+{
+ p->Range >>= 14;
+ p->Range *= size0;
+ RangeEnc_Normalize(p);
+}
+
+static void RangeEnc_EncodeBit_1(CPpmd8 *p, UInt32 size0)
+{
+ p->Low += size0 * (p->Range >>= 14);
+ p->Range *= ((1 << 14) - size0);
+ RangeEnc_Normalize(p);
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 0)
+ {
+ CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);
+ UInt32 sum;
+ unsigned i;
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_Encode(p, 0, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd8_Update1_0(p);
+ return;
+ }
+ p->PrevSuccess = 0;
+ sum = s->Freq;
+ i = p->MinContext->NumStats;
+ do
+ {
+ if ((++s)->Symbol == symbol)
+ {
+ RangeEnc_Encode(p, sum, s->Freq, p->MinContext->SummFreq);
+ p->FoundState = s;
+ Ppmd8_Update1(p);
+ return;
+ }
+ sum += s->Freq;
+ }
+ while (--i);
+
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ RangeEnc_Encode(p, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd8_GetBinSumm(p);
+ CPpmd_State *s = Ppmd8Context_OneState(p->MinContext);
+ if (s->Symbol == symbol)
+ {
+ RangeEnc_EncodeBit_0(p, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ p->FoundState = s;
+ Ppmd8_UpdateBin(p);
+ return;
+ }
+ else
+ {
+ RangeEnc_EncodeBit_1(p, *prob);
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD8_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ }
+ for (;;)
+ {
+ UInt32 escFreq;
+ CPpmd_See *see;
+ CPpmd_State *s;
+ UInt32 sum;
+ unsigned i, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return; /* EndMarker (symbol = -1) */
+ p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+
+ see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq);
+ s = Ppmd8_GetStats(p, p->MinContext);
+ sum = 0;
+ i = p->MinContext->NumStats + 1;
+ do
+ {
+ int cur = s->Symbol;
+ if (cur == symbol)
+ {
+ UInt32 low = sum;
+ CPpmd_State *s1 = s;
+ do
+ {
+ sum += (s->Freq & (int)(MASK(s->Symbol)));
+ s++;
+ }
+ while (--i);
+ RangeEnc_Encode(p, low, s1->Freq, sum + escFreq);
+ Ppmd_See_Update(see);
+ p->FoundState = s1;
+ Ppmd8_Update2(p);
+ return;
+ }
+ sum += (s->Freq & (int)(MASK(cur)));
+ MASK(cur) = 0;
+ s++;
+ }
+ while (--i);
+
+ RangeEnc_Encode(p, sum, escFreq, sum + escFreq);
+ see->Summ = (UInt16)(see->Summ + sum + escFreq);
+ }
+}
diff --git a/src/libs/7zip/win/C/RotateDefs.h b/src/libs/7zip/win/C/RotateDefs.h
new file mode 100644
index 000000000..c3a1385ce
--- /dev/null
+++ b/src/libs/7zip/win/C/RotateDefs.h
@@ -0,0 +1,20 @@
+/* RotateDefs.h -- Rotate functions
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __ROTATE_DEFS_H
+#define __ROTATE_DEFS_H
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+#define rotlFixed(x, n) _rotl((x), (n))
+#define rotrFixed(x, n) _rotr((x), (n))
+
+#else
+
+#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
+
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/Sha256.c b/src/libs/7zip/win/C/Sha256.c
new file mode 100644
index 000000000..eb4fc61fc
--- /dev/null
+++ b/src/libs/7zip/win/C/Sha256.c
@@ -0,0 +1,204 @@
+/* Crypto/Sha256.c -- SHA-256 Hash
+2010-06-11 : Igor Pavlov : Public domain
+This code is based on public domain code from Wei Dai's Crypto++ library. */
+
+#include "RotateDefs.h"
+#include "Sha256.h"
+
+/* define it for speed optimization */
+/* #define _SHA256_UNROLL */
+/* #define _SHA256_UNROLL2 */
+
+void Sha256_Init(CSha256 *p)
+{
+ p->state[0] = 0x6a09e667;
+ p->state[1] = 0xbb67ae85;
+ p->state[2] = 0x3c6ef372;
+ p->state[3] = 0xa54ff53a;
+ p->state[4] = 0x510e527f;
+ p->state[5] = 0x9b05688c;
+ p->state[6] = 0x1f83d9ab;
+ p->state[7] = 0x5be0cd19;
+ p->count = 0;
+}
+
+#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22))
+#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25))
+#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3))
+#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10))
+
+#define blk0(i) (W[i] = data[i])
+#define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15]))
+
+#define Ch(x,y,z) (z^(x&(y^z)))
+#define Maj(x,y,z) ((x&y)|(z&(x|y)))
+
+#define a(i) T[(0-(i))&7]
+#define b(i) T[(1-(i))&7]
+#define c(i) T[(2-(i))&7]
+#define d(i) T[(3-(i))&7]
+#define e(i) T[(4-(i))&7]
+#define f(i) T[(5-(i))&7]
+#define g(i) T[(6-(i))&7]
+#define h(i) T[(7-(i))&7]
+
+
+#ifdef _SHA256_UNROLL2
+
+#define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\
+ d += h; h += S0(a) + Maj(a, b, c)
+
+#define RX_8(i) \
+ R(a,b,c,d,e,f,g,h, i); \
+ R(h,a,b,c,d,e,f,g, i+1); \
+ R(g,h,a,b,c,d,e,f, i+2); \
+ R(f,g,h,a,b,c,d,e, i+3); \
+ R(e,f,g,h,a,b,c,d, i+4); \
+ R(d,e,f,g,h,a,b,c, i+5); \
+ R(c,d,e,f,g,h,a,b, i+6); \
+ R(b,c,d,e,f,g,h,a, i+7)
+
+#else
+
+#define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\
+ d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i))
+
+#ifdef _SHA256_UNROLL
+
+#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7);
+
+#endif
+
+#endif
+
+static const UInt32 K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+static void Sha256_Transform(UInt32 *state, const UInt32 *data)
+{
+ UInt32 W[16];
+ unsigned j;
+ #ifdef _SHA256_UNROLL2
+ UInt32 a,b,c,d,e,f,g,h;
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ f = state[5];
+ g = state[6];
+ h = state[7];
+ #else
+ UInt32 T[8];
+ for (j = 0; j < 8; j++)
+ T[j] = state[j];
+ #endif
+
+ for (j = 0; j < 64; j += 16)
+ {
+ #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2)
+ RX_8(0); RX_8(8);
+ #else
+ unsigned i;
+ for (i = 0; i < 16; i++) { R(i); }
+ #endif
+ }
+
+ #ifdef _SHA256_UNROLL2
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ state[5] += f;
+ state[6] += g;
+ state[7] += h;
+ #else
+ for (j = 0; j < 8; j++)
+ state[j] += T[j];
+ #endif
+
+ /* Wipe variables */
+ /* memset(W, 0, sizeof(W)); */
+ /* memset(T, 0, sizeof(T)); */
+}
+
+#undef S0
+#undef S1
+#undef s0
+#undef s1
+
+static void Sha256_WriteByteBlock(CSha256 *p)
+{
+ UInt32 data32[16];
+ unsigned i;
+ for (i = 0; i < 16; i++)
+ data32[i] =
+ ((UInt32)(p->buffer[i * 4 ]) << 24) +
+ ((UInt32)(p->buffer[i * 4 + 1]) << 16) +
+ ((UInt32)(p->buffer[i * 4 + 2]) << 8) +
+ ((UInt32)(p->buffer[i * 4 + 3]));
+ Sha256_Transform(p->state, data32);
+}
+
+void Sha256_Update(CSha256 *p, const Byte *data, size_t size)
+{
+ UInt32 curBufferPos = (UInt32)p->count & 0x3F;
+ while (size > 0)
+ {
+ p->buffer[curBufferPos++] = *data++;
+ p->count++;
+ size--;
+ if (curBufferPos == 64)
+ {
+ curBufferPos = 0;
+ Sha256_WriteByteBlock(p);
+ }
+ }
+}
+
+void Sha256_Final(CSha256 *p, Byte *digest)
+{
+ UInt64 lenInBits = (p->count << 3);
+ UInt32 curBufferPos = (UInt32)p->count & 0x3F;
+ unsigned i;
+ p->buffer[curBufferPos++] = 0x80;
+ while (curBufferPos != (64 - 8))
+ {
+ curBufferPos &= 0x3F;
+ if (curBufferPos == 0)
+ Sha256_WriteByteBlock(p);
+ p->buffer[curBufferPos++] = 0;
+ }
+ for (i = 0; i < 8; i++)
+ {
+ p->buffer[curBufferPos++] = (Byte)(lenInBits >> 56);
+ lenInBits <<= 8;
+ }
+ Sha256_WriteByteBlock(p);
+
+ for (i = 0; i < 8; i++)
+ {
+ *digest++ = (Byte)(p->state[i] >> 24);
+ *digest++ = (Byte)(p->state[i] >> 16);
+ *digest++ = (Byte)(p->state[i] >> 8);
+ *digest++ = (Byte)(p->state[i]);
+ }
+ Sha256_Init(p);
+}
diff --git a/src/libs/7zip/win/C/Sha256.h b/src/libs/7zip/win/C/Sha256.h
new file mode 100644
index 000000000..530f513ec
--- /dev/null
+++ b/src/libs/7zip/win/C/Sha256.h
@@ -0,0 +1,26 @@
+/* Sha256.h -- SHA-256 Hash
+2010-06-11 : Igor Pavlov : Public domain */
+
+#ifndef __CRYPTO_SHA256_H
+#define __CRYPTO_SHA256_H
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+#define SHA256_DIGEST_SIZE 32
+
+typedef struct
+{
+ UInt32 state[8];
+ UInt64 count;
+ Byte buffer[64];
+} CSha256;
+
+void Sha256_Init(CSha256 *p);
+void Sha256_Update(CSha256 *p, const Byte *data, size_t size);
+void Sha256_Final(CSha256 *p, Byte *digest);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/Sort.c b/src/libs/7zip/win/C/Sort.c
new file mode 100644
index 000000000..388d22893
--- /dev/null
+++ b/src/libs/7zip/win/C/Sort.c
@@ -0,0 +1,93 @@
+/* Sort.c -- Sort functions
+2010-09-17 : Igor Pavlov : Public domain */
+
+#include "Sort.h"
+
+#define HeapSortDown(p, k, size, temp) \
+ { for (;;) { \
+ UInt32 s = (k << 1); \
+ if (s > size) break; \
+ if (s < size && p[s + 1] > p[s]) s++; \
+ if (temp >= p[s]) break; \
+ p[k] = p[s]; k = s; \
+ } p[k] = temp; }
+
+void HeapSort(UInt32 *p, UInt32 size)
+{
+ if (size <= 1)
+ return;
+ p--;
+ {
+ UInt32 i = size / 2;
+ do
+ {
+ UInt32 temp = p[i];
+ UInt32 k = i;
+ HeapSortDown(p, k, size, temp)
+ }
+ while (--i != 0);
+ }
+ /*
+ do
+ {
+ UInt32 k = 1;
+ UInt32 temp = p[size];
+ p[size--] = p[1];
+ HeapSortDown(p, k, size, temp)
+ }
+ while (size > 1);
+ */
+ while (size > 3)
+ {
+ UInt32 temp = p[size];
+ UInt32 k = (p[3] > p[2]) ? 3 : 2;
+ p[size--] = p[1];
+ p[1] = p[k];
+ HeapSortDown(p, k, size, temp)
+ }
+ {
+ UInt32 temp = p[size];
+ p[size] = p[1];
+ if (size > 2 && p[2] < temp)
+ {
+ p[1] = p[2];
+ p[2] = temp;
+ }
+ else
+ p[1] = temp;
+ }
+}
+
+/*
+#define HeapSortRefDown(p, vals, n, size, temp) \
+ { UInt32 k = n; UInt32 val = vals[temp]; for (;;) { \
+ UInt32 s = (k << 1); \
+ if (s > size) break; \
+ if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \
+ if (val >= vals[p[s]]) break; \
+ p[k] = p[s]; k = s; \
+ } p[k] = temp; }
+
+void HeapSortRef(UInt32 *p, UInt32 *vals, UInt32 size)
+{
+ if (size <= 1)
+ return;
+ p--;
+ {
+ UInt32 i = size / 2;
+ do
+ {
+ UInt32 temp = p[i];
+ HeapSortRefDown(p, vals, i, size, temp);
+ }
+ while (--i != 0);
+ }
+ do
+ {
+ UInt32 temp = p[size];
+ p[size--] = p[1];
+ HeapSortRefDown(p, vals, 1, size, temp);
+ }
+ while (size > 1);
+}
+*/
diff --git a/src/libs/7zip/win/C/Sort.h b/src/libs/7zip/win/C/Sort.h
new file mode 100644
index 000000000..65dfc6f6a
--- /dev/null
+++ b/src/libs/7zip/win/C/Sort.h
@@ -0,0 +1,20 @@
+/* Sort.h -- Sort functions
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_SORT_H
+#define __7Z_SORT_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HeapSort(UInt32 *p, UInt32 size);
+/* void HeapSortRef(UInt32 *p, UInt32 *vals, UInt32 size); */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/Threads.c b/src/libs/7zip/win/C/Threads.c
new file mode 100644
index 000000000..7af1da2e2
--- /dev/null
+++ b/src/libs/7zip/win/C/Threads.c
@@ -0,0 +1,84 @@
+/* Threads.c -- multithreading library
+2009-09-20 : Igor Pavlov : Public domain */
+
+#ifndef _WIN32_WCE
+#include <process.h>
+#endif
+
+#include "Threads.h"
+
+static WRes GetError()
+{
+ DWORD res = GetLastError();
+ return (res) ? (WRes)(res) : 1;
+}
+
+WRes HandleToWRes(HANDLE h) { return (h != 0) ? 0 : GetError(); }
+WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
+
+WRes HandlePtr_Close(HANDLE *p)
+{
+ if (*p != NULL)
+ if (!CloseHandle(*p))
+ return GetError();
+ *p = NULL;
+ return 0;
+}
+
+WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); }
+
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
+{
+ unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+ *p =
+ #ifdef UNDER_CE
+ CreateThread(0, 0, func, param, 0, &threadId);
+ #else
+ (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId);
+ #endif
+ /* maybe we must use errno here, but probably GetLastError() is also OK. */
+ return HandleToWRes(*p);
+}
+
+WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
+{
+ *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
+ return HandleToWRes(*p);
+}
+
+WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
+WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
+
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
+ return HandleToWRes(*p);
+}
+
+static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
+ { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
+ { return Semaphore_Release(p, (LONG)num, NULL); }
+WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
+
+WRes CriticalSection_Init(CCriticalSection *p)
+{
+ /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */
+ #ifdef _MSC_VER
+ __try
+ #endif
+ {
+ InitializeCriticalSection(p);
+ /* InitializeCriticalSectionAndSpinCount(p, 0); */
+ }
+ #ifdef _MSC_VER
+ __except (EXCEPTION_EXECUTE_HANDLER) { return 1; }
+ #endif
+ return 0;
+}
diff --git a/src/libs/7zip/win/C/Threads.h b/src/libs/7zip/win/C/Threads.h
new file mode 100644
index 000000000..d0ddd80e2
--- /dev/null
+++ b/src/libs/7zip/win/C/Threads.h
@@ -0,0 +1,59 @@
+/* Threads.h -- multithreading library
+2009-03-27 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_THREADS_H
+#define __7Z_THREADS_H
+
+#include "Types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+WRes HandlePtr_Close(HANDLE *h);
+WRes Handle_WaitObject(HANDLE h);
+
+typedef HANDLE CThread;
+#define Thread_Construct(p) *(p) = NULL
+#define Thread_WasCreated(p) (*(p) != NULL)
+#define Thread_Close(p) HandlePtr_Close(p)
+#define Thread_Wait(p) Handle_WaitObject(*(p))
+typedef unsigned THREAD_FUNC_RET_TYPE;
+#define THREAD_FUNC_CALL_TYPE MY_STD_CALL
+#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
+typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param);
+
+typedef HANDLE CEvent;
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+#define Event_Construct(p) *(p) = NULL
+#define Event_IsCreated(p) (*(p) != NULL)
+#define Event_Close(p) HandlePtr_Close(p)
+#define Event_Wait(p) Handle_WaitObject(*(p))
+WRes Event_Set(CEvent *p);
+WRes Event_Reset(CEvent *p);
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
+
+typedef HANDLE CSemaphore;
+#define Semaphore_Construct(p) (*p) = NULL
+#define Semaphore_Close(p) HandlePtr_Close(p)
+#define Semaphore_Wait(p) Handle_WaitObject(*(p))
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+WRes Semaphore_Release1(CSemaphore *p);
+
+typedef CRITICAL_SECTION CCriticalSection;
+WRes CriticalSection_Init(CCriticalSection *p);
+#define CriticalSection_Delete(p) DeleteCriticalSection(p)
+#define CriticalSection_Enter(p) EnterCriticalSection(p)
+#define CriticalSection_Leave(p) LeaveCriticalSection(p)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/Types.h b/src/libs/7zip/win/C/Types.h
new file mode 100644
index 000000000..7732c240c
--- /dev/null
+++ b/src/libs/7zip/win/C/Types.h
@@ -0,0 +1,254 @@
+/* Types.h -- Basic types
+2010-10-09 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#include <stddef.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+#ifdef _WIN32
+typedef DWORD WRes;
+#else
+typedef int WRes;
+#endif
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#define UINT64_CONST(n) n
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#define UINT64_CONST(n) n ## ULL
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+
+#ifdef _WIN32
+#define MY_STD_CALL __stdcall
+#else
+#define MY_STD_CALL
+#endif
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else
+
+#define MY_CDECL
+#define MY_FAST_CALL
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
+} IByteIn;
+
+typedef struct
+{
+ void (*Write)(void *p, Byte b);
+} IByteOut;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+} ISeqInStream;
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
+
+typedef struct
+{
+ size_t (*Write)(void *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+} ISeqOutStream;
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ISeekInStream;
+
+typedef struct
+{
+ SRes (*Look)(void *p, const void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(void *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ILookInStream;
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
+
+#define LookToRead_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ ILookInStream s;
+ ISeekInStream *realStream;
+ size_t pos;
+ size_t size;
+ Byte buf[LookToRead_BUF_SIZE];
+} CLookToRead;
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
+void LookToRead_Init(CLookToRead *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+typedef struct
+{
+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+} ICompressProgress;
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
+#define IAlloc_Free(p, a) (p)->Free((p), a)
+
+#ifdef _WIN32
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/Xz.c b/src/libs/7zip/win/C/Xz.c
new file mode 100644
index 000000000..18caba2c1
--- /dev/null
+++ b/src/libs/7zip/win/C/Xz.c
@@ -0,0 +1,88 @@
+/* Xz.c - Xz
+2009-04-15 : Igor Pavlov : Public domain */
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+#include "Xz.h"
+#include "XzCrc64.h"
+
+Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 };
+Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' };
+
+unsigned Xz_WriteVarInt(Byte *buf, UInt64 v)
+{
+ unsigned i = 0;
+ do
+ {
+ buf[i++] = (Byte)((v & 0x7F) | 0x80);
+ v >>= 7;
+ }
+ while (v != 0);
+ buf[i - 1] &= 0x7F;
+ return i;
+}
+
+void Xz_Construct(CXzStream *p)
+{
+ p->numBlocks = p->numBlocksAllocated = 0;
+ p->blocks = 0;
+ p->flags = 0;
+}
+
+void Xz_Free(CXzStream *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->blocks);
+ p->numBlocks = p->numBlocksAllocated = 0;
+ p->blocks = 0;
+}
+
+unsigned XzFlags_GetCheckSize(CXzStreamFlags f)
+{
+ int t = XzFlags_GetCheckType(f);
+ return (t == 0) ? 0 : (4 << ((t - 1) / 3));
+}
+
+void XzCheck_Init(CXzCheck *p, int mode)
+{
+ p->mode = mode;
+ switch (mode)
+ {
+ case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
+ case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
+ case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break;
+ }
+}
+
+void XzCheck_Update(CXzCheck *p, const void *data, size_t size)
+{
+ switch (p->mode)
+ {
+ case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break;
+ case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break;
+ case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break;
+ }
+}
+
+int XzCheck_Final(CXzCheck *p, Byte *digest)
+{
+ switch (p->mode)
+ {
+ case XZ_CHECK_CRC32:
+ SetUi32(digest, CRC_GET_DIGEST(p->crc));
+ break;
+ case XZ_CHECK_CRC64:
+ {
+ int i;
+ UInt64 v = CRC64_GET_DIGEST(p->crc64);
+ for (i = 0; i < 8; i++, v >>= 8)
+ digest[i] = (Byte)(v & 0xFF);
+ break;
+ }
+ case XZ_CHECK_SHA256:
+ Sha256_Final(&p->sha, digest);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/libs/7zip/win/C/Xz.h b/src/libs/7zip/win/C/Xz.h
new file mode 100644
index 000000000..2cfa1b789
--- /dev/null
+++ b/src/libs/7zip/win/C/Xz.h
@@ -0,0 +1,252 @@
+/* Xz.h - Xz interface
+2010-09-17 : Igor Pavlov : Public domain */
+
+#ifndef __XZ_H
+#define __XZ_H
+
+#include "Sha256.h"
+
+EXTERN_C_BEGIN
+
+#define XZ_ID_Subblock 1
+#define XZ_ID_Delta 3
+#define XZ_ID_X86 4
+#define XZ_ID_PPC 5
+#define XZ_ID_IA64 6
+#define XZ_ID_ARM 7
+#define XZ_ID_ARMT 8
+#define XZ_ID_SPARC 9
+#define XZ_ID_LZMA2 0x21
+
+unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value);
+unsigned Xz_WriteVarInt(Byte *buf, UInt64 v);
+
+/* ---------- xz block ---------- */
+
+#define XZ_BLOCK_HEADER_SIZE_MAX 1024
+
+#define XZ_NUM_FILTERS_MAX 4
+#define XZ_BF_NUM_FILTERS_MASK 3
+#define XZ_BF_PACK_SIZE (1 << 6)
+#define XZ_BF_UNPACK_SIZE (1 << 7)
+
+#define XZ_FILTER_PROPS_SIZE_MAX 20
+
+typedef struct
+{
+ UInt64 id;
+ UInt32 propsSize;
+ Byte props[XZ_FILTER_PROPS_SIZE_MAX];
+} CXzFilter;
+
+typedef struct
+{
+ UInt64 packSize;
+ UInt64 unpackSize;
+ Byte flags;
+ CXzFilter filters[XZ_NUM_FILTERS_MAX];
+} CXzBlock;
+
+#define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1)
+#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0)
+#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0)
+
+SRes XzBlock_Parse(CXzBlock *p, const Byte *header);
+SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes);
+
+/* ---------- xz stream ---------- */
+
+#define XZ_SIG_SIZE 6
+#define XZ_FOOTER_SIG_SIZE 2
+
+extern Byte XZ_SIG[XZ_SIG_SIZE];
+extern Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE];
+
+#define XZ_STREAM_FLAGS_SIZE 2
+#define XZ_STREAM_CRC_SIZE 4
+
+#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE)
+#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4)
+
+#define XZ_CHECK_MASK 0xF
+#define XZ_CHECK_NO 0
+#define XZ_CHECK_CRC32 1
+#define XZ_CHECK_CRC64 4
+#define XZ_CHECK_SHA256 10
+
+typedef struct
+{
+ int mode;
+ UInt32 crc;
+ UInt64 crc64;
+ CSha256 sha;
+} CXzCheck;
+
+void XzCheck_Init(CXzCheck *p, int mode);
+void XzCheck_Update(CXzCheck *p, const void *data, size_t size);
+int XzCheck_Final(CXzCheck *p, Byte *digest);
+
+typedef UInt16 CXzStreamFlags;
+
+#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK)
+#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK)
+#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32)
+unsigned XzFlags_GetCheckSize(CXzStreamFlags f);
+
+SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf);
+SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream);
+
+typedef struct
+{
+ UInt64 unpackSize;
+ UInt64 totalSize;
+} CXzBlockSizes;
+
+typedef struct
+{
+ CXzStreamFlags flags;
+ size_t numBlocks;
+ size_t numBlocksAllocated;
+ CXzBlockSizes *blocks;
+ UInt64 startOffset;
+} CXzStream;
+
+void Xz_Construct(CXzStream *p);
+void Xz_Free(CXzStream *p, ISzAlloc *alloc);
+
+#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1)
+
+UInt64 Xz_GetUnpackSize(const CXzStream *p);
+UInt64 Xz_GetPackSize(const CXzStream *p);
+
+typedef struct
+{
+ size_t num;
+ size_t numAllocated;
+ CXzStream *streams;
+} CXzs;
+
+void Xzs_Construct(CXzs *p);
+void Xzs_Free(CXzs *p, ISzAlloc *alloc);
+SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc);
+
+UInt64 Xzs_GetNumBlocks(const CXzs *p);
+UInt64 Xzs_GetUnpackSize(const CXzs *p);
+
+typedef enum
+{
+ CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ CODER_STATUS_NOT_FINISHED, /* stream was not finished */
+ CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
+} ECoderStatus;
+
+typedef enum
+{
+ CODER_FINISH_ANY, /* finish at any point */
+ CODER_FINISH_END /* block must be finished at the end */
+} ECoderFinishMode;
+
+typedef struct _IStateCoder
+{
+ void *p;
+ void (*Free)(void *p, ISzAlloc *alloc);
+ SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc);
+ void (*Init)(void *p);
+ SRes (*Code)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished);
+} IStateCoder;
+
+#define MIXCODER_NUM_FILTERS_MAX 4
+
+typedef struct
+{
+ ISzAlloc *alloc;
+ Byte *buf;
+ int numCoders;
+ int finished[MIXCODER_NUM_FILTERS_MAX - 1];
+ size_t pos[MIXCODER_NUM_FILTERS_MAX - 1];
+ size_t size[MIXCODER_NUM_FILTERS_MAX - 1];
+ UInt64 ids[MIXCODER_NUM_FILTERS_MAX];
+ IStateCoder coders[MIXCODER_NUM_FILTERS_MAX];
+} CMixCoder;
+
+void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc);
+void MixCoder_Free(CMixCoder *p);
+void MixCoder_Init(CMixCoder *p);
+SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId);
+SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status);
+
+typedef enum
+{
+ XZ_STATE_STREAM_HEADER,
+ XZ_STATE_STREAM_INDEX,
+ XZ_STATE_STREAM_INDEX_CRC,
+ XZ_STATE_STREAM_FOOTER,
+ XZ_STATE_STREAM_PADDING,
+ XZ_STATE_BLOCK_HEADER,
+ XZ_STATE_BLOCK,
+ XZ_STATE_BLOCK_FOOTER
+} EXzState;
+
+typedef struct
+{
+ EXzState state;
+ UInt32 pos;
+ unsigned alignPos;
+ unsigned indexPreSize;
+
+ CXzStreamFlags streamFlags;
+
+ UInt32 blockHeaderSize;
+ UInt64 packSize;
+ UInt64 unpackSize;
+
+ UInt64 numBlocks;
+ UInt64 indexSize;
+ UInt64 indexPos;
+ UInt64 padSize;
+
+ UInt64 numStreams;
+
+ UInt32 crc;
+ CMixCoder decoder;
+ CXzBlock block;
+ CXzCheck check;
+ CSha256 sha;
+ Byte shaDigest[SHA256_DIGEST_SIZE];
+ Byte buf[XZ_BLOCK_HEADER_SIZE_MAX];
+} CXzUnpacker;
+
+SRes XzUnpacker_Create(CXzUnpacker *p, ISzAlloc *alloc);
+void XzUnpacker_Free(CXzUnpacker *p);
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+
+SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, /* int srcWasFinished, */ int finishMode,
+ ECoderStatus *status);
+
+Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/XzCrc64.c b/src/libs/7zip/win/C/XzCrc64.c
new file mode 100644
index 000000000..0369554b7
--- /dev/null
+++ b/src/libs/7zip/win/C/XzCrc64.c
@@ -0,0 +1,33 @@
+/* XzCrc64.c -- CRC64 calculation
+2010-04-16 : Igor Pavlov : Public domain */
+
+#include "XzCrc64.h"
+
+#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
+UInt64 g_Crc64Table[256];
+
+void MY_FAST_CALL Crc64GenerateTable(void)
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt64 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ ((UInt64)kCrc64Poly & ~((r & 1) - 1));
+ g_Crc64Table[i] = r;
+ }
+}
+
+UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 ; size--, p++)
+ v = CRC64_UPDATE_BYTE(v, *p);
+ return v;
+}
+
+UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size)
+{
+ return CRC64_GET_DIGEST(Crc64Update(CRC64_INIT_VAL, data, size));
+}
diff --git a/src/libs/7zip/win/C/XzCrc64.h b/src/libs/7zip/win/C/XzCrc64.h
new file mode 100644
index 000000000..0e8efd7ea
--- /dev/null
+++ b/src/libs/7zip/win/C/XzCrc64.h
@@ -0,0 +1,26 @@
+/* XzCrc64.h -- CRC64 calculation
+2010-04-16 : Igor Pavlov : Public domain */
+
+#ifndef __XZ_CRC64_H
+#define __XZ_CRC64_H
+
+#include <stddef.h>
+
+#include "Types.h"
+
+EXTERN_C_BEGIN
+
+extern UInt64 g_Crc64Table[];
+
+void MY_FAST_CALL Crc64GenerateTable(void);
+
+#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF)
+#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL)
+#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size);
+UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/libs/7zip/win/C/XzDec.c b/src/libs/7zip/win/C/XzDec.c
new file mode 100644
index 000000000..40f1a2a45
--- /dev/null
+++ b/src/libs/7zip/win/C/XzDec.c
@@ -0,0 +1,875 @@
+/* XzDec.c -- Xz Decode
+2010-04-16 : Igor Pavlov : Public domain */
+
+/* #define XZ_DUMP */
+
+#ifdef XZ_DUMP
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Alloc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "Delta.h"
+#include "Lzma2Dec.h"
+
+#ifdef USE_SUBBLOCK
+#include "SbDec.h"
+#endif
+
+#include "Xz.h"
+
+#define XZ_CHECK_SIZE_MAX 64
+
+#define CODER_BUF_SIZE (1 << 17)
+
+unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
+{
+ int i, limit;
+ *value = 0;
+ limit = (maxSize > 9) ? 9 : (int)maxSize;
+
+ for (i = 0; i < limit;)
+ {
+ Byte b = p[i];
+ *value |= (UInt64)(b & 0x7F) << (7 * i++);
+ if ((b & 0x80) == 0)
+ return (b == 0 && i != 1) ? 0 : i;
+ }
+ return 0;
+}
+
+/* ---------- BraState ---------- */
+
+#define BRA_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ size_t bufPos;
+ size_t bufConv;
+ size_t bufTotal;
+
+ UInt32 methodId;
+ int encodeMode;
+ UInt32 delta;
+ UInt32 ip;
+ UInt32 x86State;
+ Byte deltaState[DELTA_STATE_SIZE];
+
+ Byte buf[BRA_BUF_SIZE];
+} CBraState;
+
+void BraState_Free(void *pp, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, pp);
+}
+
+SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ CBraState *p = ((CBraState *)pp);
+ alloc = alloc;
+ p->encodeMode = 0;
+ p->ip = 0;
+ if (p->methodId == XZ_ID_Delta)
+ {
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ p->delta = (unsigned)props[0] + 1;
+ }
+ else
+ {
+ if (propSize == 4)
+ {
+ UInt32 v = GetUi32(props);
+ switch(p->methodId)
+ {
+ case XZ_ID_PPC:
+ case XZ_ID_ARM:
+ case XZ_ID_SPARC:
+ if ((v & 3) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ case XZ_ID_ARMT:
+ if ((v & 1) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ case XZ_ID_IA64:
+ if ((v & 0xF) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ }
+ p->ip = v;
+ }
+ else if (propSize != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ return SZ_OK;
+}
+
+void BraState_Init(void *pp)
+{
+ CBraState *p = ((CBraState *)pp);
+ p->bufPos = p->bufConv = p->bufTotal = 0;
+ x86_Convert_Init(p->x86State);
+ if (p->methodId == XZ_ID_Delta)
+ Delta_Init(p->deltaState);
+}
+
+#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break;
+
+static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ CBraState *p = ((CBraState *)pp);
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ finishMode = finishMode;
+ *wasFinished = 0;
+ while (destLenOrig > 0)
+ {
+ if (p->bufPos != p->bufConv)
+ {
+ size_t curSize = p->bufConv - p->bufPos;
+ if (curSize > destLenOrig)
+ curSize = destLenOrig;
+ memcpy(dest, p->buf + p->bufPos, curSize);
+ p->bufPos += curSize;
+ *destLen += curSize;
+ dest += curSize;
+ destLenOrig -= curSize;
+ continue;
+ }
+ p->bufTotal -= p->bufPos;
+ memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
+ p->bufPos = 0;
+ p->bufConv = 0;
+ {
+ size_t curSize = BRA_BUF_SIZE - p->bufTotal;
+ if (curSize > srcLenOrig)
+ curSize = srcLenOrig;
+ memcpy(p->buf + p->bufTotal, src, curSize);
+ *srcLen += curSize;
+ src += curSize;
+ srcLenOrig -= curSize;
+ p->bufTotal += curSize;
+ }
+ if (p->bufTotal == 0)
+ break;
+ switch(p->methodId)
+ {
+ case XZ_ID_Delta:
+ if (p->encodeMode)
+ Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal);
+ else
+ Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal);
+ p->bufConv = p->bufTotal;
+ break;
+ case XZ_ID_X86:
+ p->bufConv = x86_Convert(p->buf, p->bufTotal, p->ip, &p->x86State, p->encodeMode);
+ break;
+ CASE_BRA_CONV(PPC)
+ CASE_BRA_CONV(IA64)
+ CASE_BRA_CONV(ARM)
+ CASE_BRA_CONV(ARMT)
+ CASE_BRA_CONV(SPARC)
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ p->ip += (UInt32)p->bufConv;
+
+ if (p->bufConv == 0)
+ {
+ if (!srcWasFinished)
+ break;
+ p->bufConv = p->bufTotal;
+ }
+ }
+ if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished)
+ *wasFinished = 1;
+ return SZ_OK;
+}
+
+SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, ISzAlloc *alloc)
+{
+ CBraState *decoder;
+ if (id != XZ_ID_Delta &&
+ id != XZ_ID_X86 &&
+ id != XZ_ID_PPC &&
+ id != XZ_ID_IA64 &&
+ id != XZ_ID_ARM &&
+ id != XZ_ID_ARMT &&
+ id != XZ_ID_SPARC)
+ return SZ_ERROR_UNSUPPORTED;
+ p->p = 0;
+ decoder = alloc->Alloc(alloc, sizeof(CBraState));
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ decoder->methodId = (UInt32)id;
+ p->p = decoder;
+ p->Free = BraState_Free;
+ p->SetProps = BraState_SetProps;
+ p->Init = BraState_Init;
+ p->Code = BraState_Code;
+ return SZ_OK;
+}
+
+/* ---------- SbState ---------- */
+
+#ifdef USE_SUBBLOCK
+
+static void SbState_Free(void *pp, ISzAlloc *alloc)
+{
+ CSubblockDec *p = (CSubblockDec *)pp;
+ SubblockDec_Free(p, alloc);
+ alloc->Free(alloc, pp);
+}
+
+static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ pp = pp;
+ props = props;
+ alloc = alloc;
+ return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static void SbState_Init(void *pp)
+{
+ SubblockDec_Init((CSubblockDec *)pp);
+}
+
+static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ ECoderStatus status;
+ SRes res = SubblockDec_Decode((CSubblockDec *)pp, dest, destLen, src, srcLen, finishMode, &status);
+ srcWasFinished = srcWasFinished;
+ *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
+ return res;
+}
+
+SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
+{
+ CSubblockDec *decoder;
+ p->p = 0;
+ decoder = alloc->Alloc(alloc, sizeof(CSubblockDec));
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ p->p = decoder;
+ p->Free = SbState_Free;
+ p->SetProps = SbState_SetProps;
+ p->Init = SbState_Init;
+ p->Code = SbState_Code;
+ SubblockDec_Construct(decoder);
+ return SZ_OK;
+}
+#endif
+
+/* ---------- Lzma2State ---------- */
+
+static void Lzma2State_Free(void *pp, ISzAlloc *alloc)
+{
+ Lzma2Dec_Free((CLzma2Dec *)pp, alloc);
+ alloc->Free(alloc, pp);
+}
+
+static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
+{
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc);
+}
+
+static void Lzma2State_Init(void *pp)
+{
+ Lzma2Dec_Init((CLzma2Dec *)pp);
+}
+
+static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
+{
+ ELzmaStatus status;
+ /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
+ SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, finishMode, &status);
+ srcWasFinished = srcWasFinished;
+ *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
+ return res;
+}
+
+static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
+{
+ CLzma2Dec *decoder = alloc->Alloc(alloc, sizeof(CLzma2Dec));
+ p->p = decoder;
+ if (decoder == 0)
+ return SZ_ERROR_MEM;
+ p->Free = Lzma2State_Free;
+ p->SetProps = Lzma2State_SetProps;
+ p->Init = Lzma2State_Init;
+ p->Code = Lzma2State_Code;
+ Lzma2Dec_Construct(decoder);
+ return SZ_OK;
+}
+
+
+void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc)
+{
+ int i;
+ p->alloc = alloc;
+ p->buf = 0;
+ p->numCoders = 0;
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
+ p->coders[i].p = NULL;
+}
+
+void MixCoder_Free(CMixCoder *p)
+{
+ int i;
+ for (i = 0; i < p->numCoders; i++)
+ {
+ IStateCoder *sc = &p->coders[i];
+ if (p->alloc && sc->p)
+ sc->Free(sc->p, p->alloc);
+ }
+ p->numCoders = 0;
+ if (p->buf)
+ p->alloc->Free(p->alloc, p->buf);
+}
+
+void MixCoder_Init(CMixCoder *p)
+{
+ int i;
+ for (i = 0; i < p->numCoders - 1; i++)
+ {
+ p->size[i] = 0;
+ p->pos[i] = 0;
+ p->finished[i] = 0;
+ }
+ for (i = 0; i < p->numCoders; i++)
+ {
+ IStateCoder *coder = &p->coders[i];
+ coder->Init(coder->p);
+ }
+}
+
+SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId)
+{
+ IStateCoder *sc = &p->coders[coderIndex];
+ p->ids[coderIndex] = methodId;
+ switch(methodId)
+ {
+ case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, p->alloc);
+ #ifdef USE_SUBBLOCK
+ case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);
+ #endif
+ }
+ if (coderIndex == 0)
+ return SZ_ERROR_UNSUPPORTED;
+ return BraState_SetFromMethod(sc, methodId, p->alloc);
+}
+
+SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ Bool allFinished = True;
+ *destLen = 0;
+ *srcLen = 0;
+ *status = CODER_STATUS_NOT_FINISHED;
+
+ if (p->buf == 0)
+ {
+ p->buf = p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
+ if (p->buf == 0)
+ return SZ_ERROR_MEM;
+ }
+
+ if (p->numCoders != 1)
+ finishMode = CODER_FINISH_ANY;
+
+ for (;;)
+ {
+ Bool processed = False;
+ int i;
+ /*
+ if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY)
+ break;
+ */
+
+ for (i = 0; i < p->numCoders; i++)
+ {
+ SRes res;
+ IStateCoder *coder = &p->coders[i];
+ Byte *destCur;
+ SizeT destLenCur, srcLenCur;
+ const Byte *srcCur;
+ int srcFinishedCur;
+ int encodingWasFinished;
+
+ if (i == 0)
+ {
+ srcCur = src;
+ srcLenCur = srcLenOrig - *srcLen;
+ srcFinishedCur = srcWasFinished;
+ }
+ else
+ {
+ srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1];
+ srcLenCur = p->size[i - 1] - p->pos[i - 1];
+ srcFinishedCur = p->finished[i - 1];
+ }
+
+ if (i == p->numCoders - 1)
+ {
+ destCur = dest;
+ destLenCur = destLenOrig - *destLen;
+ }
+ else
+ {
+ if (p->pos[i] != p->size[i])
+ continue;
+ destCur = p->buf + (CODER_BUF_SIZE * i);
+ destLenCur = CODER_BUF_SIZE;
+ }
+
+ res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished);
+
+ if (!encodingWasFinished)
+ allFinished = False;
+
+ if (i == 0)
+ {
+ *srcLen += srcLenCur;
+ src += srcLenCur;
+ }
+ else
+ {
+ p->pos[i - 1] += srcLenCur;
+ }
+
+ if (i == p->numCoders - 1)
+ {
+ *destLen += destLenCur;
+ dest += destLenCur;
+ }
+ else
+ {
+ p->size[i] = destLenCur;
+ p->pos[i] = 0;
+ p->finished[i] = encodingWasFinished;
+ }
+
+ if (res != SZ_OK)
+ return res;
+
+ if (destLenCur != 0 || srcLenCur != 0)
+ processed = True;
+ }
+ if (!processed)
+ break;
+ }
+ if (allFinished)
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+}
+
+SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
+{
+ *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
+ if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) !=
+ GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE))
+ return SZ_ERROR_NO_ARCHIVE;
+ return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
+{
+ return
+ indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) &&
+ (GetUi32(buf) == CrcCalc(buf + 4, 6) &&
+ flags == GetBe16(buf + 8) &&
+ memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0);
+}
+
+#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
+ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
+ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
+
+
+SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
+{
+ unsigned pos;
+ int numFilters, i;
+ UInt32 headerSize = (UInt32)header[0] << 2;
+
+ if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
+ return SZ_ERROR_ARCHIVE;
+
+ pos = 1;
+ if (pos == headerSize)
+ return SZ_ERROR_ARCHIVE;
+ p->flags = header[pos++];
+
+ if (XzBlock_HasPackSize(p))
+ {
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize);
+ if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ if (XzBlock_HasUnpackSize(p))
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize);
+
+ numFilters = XzBlock_GetNumFilters(p);
+ for (i = 0; i < numFilters; i++)
+ {
+ CXzFilter *filter = p->filters + i;
+ UInt64 size;
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id);
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &size);
+ if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX)
+ return SZ_ERROR_ARCHIVE;
+ filter->propsSize = (UInt32)size;
+ memcpy(filter->props, header + pos, (size_t)size);
+ pos += (unsigned)size;
+
+ #ifdef XZ_DUMP
+ printf("\nf[%d] = %2X: ", i, filter->id);
+ {
+ int i;
+ for (i = 0; i < size; i++)
+ printf(" %2X", filter->props[i]);
+ }
+ #endif
+ }
+
+ while (pos < headerSize)
+ if (header[pos++] != 0)
+ return SZ_ERROR_ARCHIVE;
+ return SZ_OK;
+}
+
+SRes XzDec_Init(CMixCoder *p, const CXzBlock *block)
+{
+ int i;
+ Bool needReInit = True;
+ int numFilters = XzBlock_GetNumFilters(block);
+ if (numFilters == p->numCoders)
+ {
+ for (i = 0; i < numFilters; i++)
+ if (p->ids[i] != block->filters[numFilters - 1 - i].id)
+ break;
+ needReInit = (i != numFilters);
+ }
+ if (needReInit)
+ {
+ MixCoder_Free(p);
+ p->numCoders = numFilters;
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &block->filters[numFilters - 1 - i];
+ RINOK(MixCoder_SetFromMethod(p, i, f->id));
+ }
+ }
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &block->filters[numFilters - 1 - i];
+ IStateCoder *sc = &p->coders[i];
+ RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc));
+ }
+ MixCoder_Init(p);
+ return SZ_OK;
+}
+
+SRes XzUnpacker_Create(CXzUnpacker *p, ISzAlloc *alloc)
+{
+ MixCoder_Construct(&p->decoder, alloc);
+ p->state = XZ_STATE_STREAM_HEADER;
+ p->pos = 0;
+ p->numStreams = 0;
+ return SZ_OK;
+}
+
+void XzUnpacker_Free(CXzUnpacker *p)
+{
+ MixCoder_Free(&p->decoder);
+}
+
+SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int finishMode, ECoderStatus *status)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ *status = CODER_STATUS_NOT_SPECIFIED;
+ for (;;)
+ {
+ SizeT srcRem = srcLenOrig - *srcLen;
+
+ if (p->state == XZ_STATE_BLOCK)
+ {
+ SizeT destLen2 = destLenOrig - *destLen;
+ SizeT srcLen2 = srcLenOrig - *srcLen;
+ SRes res;
+ if (srcLen2 == 0 && destLen2 == 0)
+ {
+ *status = CODER_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+
+ res = MixCoder_Code(&p->decoder, dest, &destLen2, src, &srcLen2, False, finishMode, status);
+ XzCheck_Update(&p->check, dest, destLen2);
+
+ (*srcLen) += srcLen2;
+ src += srcLen2;
+ p->packSize += srcLen2;
+
+ (*destLen) += destLen2;
+ dest += destLen2;
+ p->unpackSize += destLen2;
+
+ RINOK(res);
+
+ if (*status == CODER_STATUS_FINISHED_WITH_MARK)
+ {
+ Byte temp[32];
+ unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags));
+ num += Xz_WriteVarInt(temp + num, p->unpackSize);
+ Sha256_Update(&p->sha, temp, num);
+ p->indexSize += num;
+ p->numBlocks++;
+
+ p->state = XZ_STATE_BLOCK_FOOTER;
+ p->pos = 0;
+ p->alignPos = 0;
+ }
+ else if (srcLen2 == 0 && destLen2 == 0)
+ return SZ_OK;
+
+ continue;
+ }
+
+ if (srcRem == 0)
+ {
+ *status = CODER_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ switch(p->state)
+ {
+ case XZ_STATE_STREAM_HEADER:
+ {
+ if (p->pos < XZ_STREAM_HEADER_SIZE)
+ {
+ if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos])
+ return SZ_ERROR_NO_ARCHIVE;
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ }
+ else
+ {
+ RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
+ p->state = XZ_STATE_BLOCK_HEADER;
+ Sha256_Init(&p->sha);
+ p->indexSize = 0;
+ p->numBlocks = 0;
+ p->pos = 0;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_HEADER:
+ {
+ if (p->pos == 0)
+ {
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ if (p->buf[0] == 0)
+ {
+ p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks);
+ p->indexPos = p->indexPreSize;
+ p->indexSize += p->indexPreSize;
+ Sha256_Final(&p->sha, p->shaDigest);
+ Sha256_Init(&p->sha);
+ p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
+ p->state = XZ_STATE_STREAM_INDEX;
+ }
+ p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
+ }
+ else if (p->pos != p->blockHeaderSize)
+ {
+ UInt32 cur = p->blockHeaderSize - p->pos;
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ }
+ else
+ {
+ RINOK(XzBlock_Parse(&p->block, p->buf));
+ p->state = XZ_STATE_BLOCK;
+ p->packSize = 0;
+ p->unpackSize = 0;
+ XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
+ RINOK(XzDec_Init(&p->decoder, &p->block));
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_FOOTER:
+ {
+ if (((p->packSize + p->alignPos) & 3) != 0)
+ {
+ (*srcLen)++;
+ p->alignPos++;
+ if (*src++ != 0)
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
+ UInt32 cur = checkSize - p->pos;
+ if (cur != 0)
+ {
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ }
+ else
+ {
+ Byte digest[XZ_CHECK_SIZE_MAX];
+ p->state = XZ_STATE_BLOCK_HEADER;
+ p->pos = 0;
+ if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
+ return SZ_ERROR_CRC;
+ }
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_INDEX:
+ {
+ if (p->pos < p->indexPreSize)
+ {
+ (*srcLen)++;
+ if (*src++ != p->buf[p->pos++])
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ if (p->indexPos < p->indexSize)
+ {
+ UInt64 cur = p->indexSize - p->indexPos;
+ if (srcRem > cur)
+ srcRem = (SizeT)cur;
+ p->crc = CrcUpdate(p->crc, src, srcRem);
+ Sha256_Update(&p->sha, src, srcRem);
+ (*srcLen) += srcRem;
+ src += srcRem;
+ p->indexPos += srcRem;
+ }
+ else if ((p->indexPos & 3) != 0)
+ {
+ Byte b = *src++;
+ p->crc = CRC_UPDATE_BYTE(p->crc, b);
+ (*srcLen)++;
+ p->indexPos++;
+ p->indexSize++;
+ if (b != 0)
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ Byte digest[SHA256_DIGEST_SIZE];
+ p->state = XZ_STATE_STREAM_INDEX_CRC;
+ p->indexSize += 4;
+ p->pos = 0;
+ Sha256_Final(&p->sha, digest);
+ if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
+ return SZ_ERROR_CRC;
+ }
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_INDEX_CRC:
+ {
+ if (p->pos < 4)
+ {
+ (*srcLen)++;
+ p->buf[p->pos++] = *src++;
+ }
+ else
+ {
+ p->state = XZ_STATE_STREAM_FOOTER;
+ p->pos = 0;
+ if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))
+ return SZ_ERROR_CRC;
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_FOOTER:
+ {
+ UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ if (p->pos == XZ_STREAM_FOOTER_SIZE)
+ {
+ p->state = XZ_STATE_STREAM_PADDING;
+ p->numStreams++;
+ p->padSize = 0;
+ if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf))
+ return SZ_ERROR_CRC;
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_PADDING:
+ {
+ if (*src != 0)
+ {
+ if (((UInt32)p->padSize & 3) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ p->pos = 0;
+ p->state = XZ_STATE_STREAM_HEADER;
+ }
+ else
+ {
+ (*srcLen)++;
+ src++;
+ p->padSize++;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK: break; /* to disable GCC warning */
+ }
+ }
+ /*
+ if (p->state == XZ_STATE_FINISHED)
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ */
+}
+
+Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p)
+{
+ return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
+}
diff --git a/src/libs/7zip/win/C/XzEnc.c b/src/libs/7zip/win/C/XzEnc.c
new file mode 100644
index 000000000..721b4e765
--- /dev/null
+++ b/src/libs/7zip/win/C/XzEnc.c
@@ -0,0 +1,497 @@
+/* XzEnc.c -- Xz Encode
+2009-06-04 : Igor Pavlov : Public domain */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Alloc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#ifdef USE_SUBBLOCK
+#include "SbEnc.h"
+#endif
+
+#include "XzEnc.h"
+
+static void *SzBigAlloc(void *p, size_t size) { p = p; return BigAlloc(size); }
+static void SzBigFree(void *p, void *address) { p = p; BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+#define XzBlock_ClearFlags(p) (p)->flags = 0;
+#define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1);
+#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE;
+#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE;
+
+static SRes WriteBytes(ISeqOutStream *s, const void *buf, UInt32 size)
+{
+ return (s->Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
+}
+
+static SRes WriteBytesAndCrc(ISeqOutStream *s, const void *buf, UInt32 size, UInt32 *crc)
+{
+ *crc = CrcUpdate(*crc, buf, size);
+ return WriteBytes(s, buf, size);
+}
+
+SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
+{
+ UInt32 crc;
+ Byte header[XZ_STREAM_HEADER_SIZE];
+ memcpy(header, XZ_SIG, XZ_SIG_SIZE);
+ header[XZ_SIG_SIZE] = (Byte)(f >> 8);
+ header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
+ crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
+ SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc);
+ return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
+}
+
+SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
+{
+ Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
+
+ unsigned pos = 1;
+ int numFilters, i;
+ header[pos++] = p->flags;
+
+ if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
+ if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
+ numFilters = XzBlock_GetNumFilters(p);
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &p->filters[i];
+ pos += Xz_WriteVarInt(header + pos, f->id);
+ pos += Xz_WriteVarInt(header + pos, f->propsSize);
+ memcpy(header + pos, f->props, f->propsSize);
+ pos += f->propsSize;
+ }
+ while((pos & 3) != 0)
+ header[pos++] = 0;
+ header[0] = (Byte)(pos >> 2);
+ SetUi32(header + pos, CrcCalc(header, pos));
+ return WriteBytes(s, header, pos + 4);
+}
+
+SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
+{
+ Byte buf[32];
+ UInt64 globalPos;
+ {
+ UInt32 crc = CRC_INIT_VAL;
+ unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
+ size_t i;
+
+ globalPos = pos;
+ buf[0] = 0;
+ RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
+ for (i = 0; i < p->numBlocks; i++)
+ {
+ const CXzBlockSizes *block = &p->blocks[i];
+ pos = Xz_WriteVarInt(buf, block->totalSize);
+ pos += Xz_WriteVarInt(buf + pos, block->unpackSize);
+ globalPos += pos;
+ RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
+ }
+ pos = ((unsigned)globalPos & 3);
+ if (pos != 0)
+ {
+ buf[0] = buf[1] = buf[2] = 0;
+ RINOK(WriteBytesAndCrc(s, buf, 4 - pos, &crc));
+ globalPos += 4 - pos;
+ }
+ {
+ SetUi32(buf, CRC_GET_DIGEST(crc));
+ RINOK(WriteBytes(s, buf, 4));
+ globalPos += 4;
+ }
+ }
+
+ {
+ UInt32 indexSize = (UInt32)((globalPos >> 2) - 1);
+ SetUi32(buf + 4, indexSize);
+ buf[8] = (Byte)(p->flags >> 8);
+ buf[9] = (Byte)(p->flags & 0xFF);
+ SetUi32(buf, CrcCalc(buf + 4, 6));
+ memcpy(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE);
+ return WriteBytes(s, buf, 12);
+ }
+}
+
+SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc)
+{
+ if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks)
+ {
+ size_t num = (p->numBlocks + 1) * 2;
+ size_t newSize = sizeof(CXzBlockSizes) * num;
+ CXzBlockSizes *blocks;
+ if (newSize / sizeof(CXzBlockSizes) != num)
+ return SZ_ERROR_MEM;
+ blocks = alloc->Alloc(alloc, newSize);
+ if (blocks == 0)
+ return SZ_ERROR_MEM;
+ if (p->numBlocks != 0)
+ {
+ memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes));
+ Xz_Free(p, alloc);
+ }
+ p->blocks = blocks;
+ p->numBlocksAllocated = num;
+ }
+ {
+ CXzBlockSizes *block = &p->blocks[p->numBlocks++];
+ block->totalSize = totalSize;
+ block->unpackSize = unpackSize;
+ }
+ return SZ_OK;
+}
+
+/* ---------- CSeqCheckInStream ---------- */
+
+typedef struct
+{
+ ISeqInStream p;
+ ISeqInStream *realStream;
+ UInt64 processed;
+ CXzCheck check;
+} CSeqCheckInStream;
+
+void SeqCheckInStream_Init(CSeqCheckInStream *p, int mode)
+{
+ p->processed = 0;
+ XzCheck_Init(&p->check, mode);
+}
+
+void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
+{
+ XzCheck_Final(&p->check, digest);
+}
+
+static SRes SeqCheckInStream_Read(void *pp, void *data, size_t *size)
+{
+ CSeqCheckInStream *p = (CSeqCheckInStream *)pp;
+ SRes res = p->realStream->Read(p->realStream, data, size);
+ XzCheck_Update(&p->check, data, *size);
+ p->processed += *size;
+ return res;
+}
+
+/* ---------- CSeqSizeOutStream ---------- */
+
+typedef struct
+{
+ ISeqOutStream p;
+ ISeqOutStream *realStream;
+ UInt64 processed;
+} CSeqSizeOutStream;
+
+static size_t MyWrite(void *pp, const void *data, size_t size)
+{
+ CSeqSizeOutStream *p = (CSeqSizeOutStream *)pp;
+ size = p->realStream->Write(p->realStream, data, size);
+ p->processed += size;
+ return size;
+}
+
+/* ---------- CSeqInFilter ---------- */
+
+/*
+typedef struct _IFilter
+{
+ void *p;
+ void (*Free)(void *p, ISzAlloc *alloc);
+ SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc);
+ void (*Init)(void *p);
+ size_t (*Filter)(void *p, Byte *data, SizeT destLen);
+} IFilter;
+
+#define FILT_BUF_SIZE (1 << 19)
+
+typedef struct
+{
+ ISeqInStream p;
+ ISeqInStream *realStream;
+ UInt32 x86State;
+ UInt32 ip;
+ UInt64 processed;
+ CXzCheck check;
+ Byte buf[FILT_BUF_SIZE];
+ UInt32 bufferPos;
+ UInt32 convertedPosBegin;
+ UInt32 convertedPosEnd;
+ IFilter *filter;
+} CSeqInFilter;
+
+static SRes SeqInFilter_Read(void *pp, void *data, size_t *size)
+{
+ CSeqInFilter *p = (CSeqInFilter *)pp;
+ size_t remSize = *size;
+ *size = 0;
+
+ while (remSize > 0)
+ {
+ int i;
+ if (p->convertedPosBegin != p->convertedPosEnd)
+ {
+ UInt32 sizeTemp = p->convertedPosEnd - p->convertedPosBegin;
+ if (remSize < sizeTemp)
+ sizeTemp = (UInt32)remSize;
+ memmove(data, p->buf + p->convertedPosBegin, sizeTemp);
+ p->convertedPosBegin += sizeTemp;
+ data = (void *)((Byte *)data + sizeTemp);
+ remSize -= sizeTemp;
+ *size += sizeTemp;
+ break;
+ }
+ for (i = 0; p->convertedPosEnd + i < p->bufferPos; i++)
+ p->buf[i] = p->buf[i + p->convertedPosEnd];
+ p->bufferPos = i;
+ p->convertedPosBegin = p->convertedPosEnd = 0;
+ {
+ size_t processedSizeTemp = FILT_BUF_SIZE - p->bufferPos;
+ RINOK(p->realStream->Read(p->realStream, p->buf + p->bufferPos, &processedSizeTemp));
+ p->bufferPos = p->bufferPos + (UInt32)processedSizeTemp;
+ }
+ p->convertedPosEnd = (UInt32)p->filter->Filter(p->filter->p, p->buf, p->bufferPos);
+ if (p->convertedPosEnd == 0)
+ {
+ if (p->bufferPos == 0)
+ break;
+ else
+ {
+ p->convertedPosEnd = p->bufferPos;
+ continue;
+ }
+ }
+ if (p->convertedPosEnd > p->bufferPos)
+ {
+ for (; p->bufferPos < p->convertedPosEnd; p->bufferPos++)
+ p->buf[p->bufferPos] = 0;
+ p->convertedPosEnd = (UInt32)p->filter->Filter(p->filter->p, p->buf, p->bufferPos);
+ }
+ }
+ return SZ_OK;
+}
+*/
+
+/*
+typedef struct
+{
+ ISeqInStream p;
+ ISeqInStream *realStream;
+ CMixCoder mixCoder;
+ Byte buf[FILT_BUF_SIZE];
+ UInt32 bufPos;
+ UInt32 bufSize;
+} CMixCoderSeqInStream;
+
+static SRes CMixCoderSeqInStream_Read(void *pp, void *data, size_t *size)
+{
+ CMixCoderSeqInStream *p = (CMixCoderSeqInStream *)pp;
+ SRes res = SZ_OK;
+ size_t remSize = *size;
+ *size = 0;
+ while (remSize > 0)
+ {
+ if (p->bufPos == p->bufSize)
+ {
+ size_t curSize;
+ p->bufPos = p->bufSize = 0;
+ if (*size != 0)
+ break;
+ curSize = FILT_BUF_SIZE;
+ RINOK(p->realStream->Read(p->realStream, p->buf, &curSize));
+ p->bufSize = (UInt32)curSize;
+ }
+ {
+ SizeT destLen = remSize;
+ SizeT srcLen = p->bufSize - p->bufPos;
+ res = MixCoder_Code(&p->mixCoder, data, &destLen, p->buf + p->bufPos, &srcLen, 0);
+ data = (void *)((Byte *)data + destLen);
+ remSize -= destLen;
+ *size += destLen;
+ p->bufPos += srcLen;
+ }
+ }
+ return res;
+}
+*/
+
+#ifdef USE_SUBBLOCK
+typedef struct
+{
+ ISeqInStream p;
+ CSubblockEnc sb;
+ UInt64 processed;
+} CSbEncInStream;
+
+void SbEncInStream_Init(CSbEncInStream *p)
+{
+ p->processed = 0;
+ SubblockEnc_Init(&p->sb);
+}
+
+static SRes SbEncInStream_Read(void *pp, void *data, size_t *size)
+{
+ CSbEncInStream *p = (CSbEncInStream *)pp;
+ SRes res = SubblockEnc_Read(&p->sb, data, size);
+ p->processed += *size;
+ return res;
+}
+#endif
+
+typedef struct
+{
+ /* CMixCoderSeqInStream inStream; */
+ CLzma2EncHandle lzma2;
+ #ifdef USE_SUBBLOCK
+ CSbEncInStream sb;
+ #endif
+ ISzAlloc *alloc;
+ ISzAlloc *bigAlloc;
+} CLzma2WithFilters;
+
+
+static void Lzma2WithFilters_Construct(CLzma2WithFilters *p, ISzAlloc *alloc, ISzAlloc *bigAlloc)
+{
+ p->alloc = alloc;
+ p->bigAlloc = bigAlloc;
+ p->lzma2 = NULL;
+ #ifdef USE_SUBBLOCK
+ p->sb.p.Read = SbEncInStream_Read;
+ SubblockEnc_Construct(&p->sb.sb, p->alloc);
+ #endif
+}
+
+static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p)
+{
+ p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc);
+ if (p->lzma2 == 0)
+ return SZ_ERROR_MEM;
+ return SZ_OK;
+}
+
+static void Lzma2WithFilters_Free(CLzma2WithFilters *p)
+{
+ #ifdef USE_SUBBLOCK
+ SubblockEnc_Free(&p->sb.sb);
+ #endif
+ if (p->lzma2)
+ {
+ Lzma2Enc_Destroy(p->lzma2);
+ p->lzma2 = NULL;
+ }
+}
+
+static SRes Xz_Compress(CXzStream *xz,
+ CLzma2WithFilters *lzmaf,
+ ISeqOutStream *outStream,
+ ISeqInStream *inStream,
+ const CLzma2EncProps *lzma2Props,
+ Bool useSubblock,
+ ICompressProgress *progress)
+{
+ xz->flags = XZ_CHECK_CRC32;
+
+ RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, lzma2Props));
+ RINOK(Xz_WriteHeader(xz->flags, outStream));
+
+ {
+ CSeqCheckInStream checkInStream;
+ CSeqSizeOutStream seqSizeOutStream;
+ CXzBlock block;
+ int filterIndex = 0;
+
+ XzBlock_ClearFlags(&block);
+ XzBlock_SetNumFilters(&block, 1 + (useSubblock ? 1 : 0));
+
+ if (useSubblock)
+ {
+ CXzFilter *f = &block.filters[filterIndex++];
+ f->id = XZ_ID_Subblock;
+ f->propsSize = 0;
+ }
+
+ {
+ CXzFilter *f = &block.filters[filterIndex++];
+ f->id = XZ_ID_LZMA2;
+ f->propsSize = 1;
+ f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
+ }
+
+ seqSizeOutStream.p.Write = MyWrite;
+ seqSizeOutStream.realStream = outStream;
+ seqSizeOutStream.processed = 0;
+
+ RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.p));
+
+ checkInStream.p.Read = SeqCheckInStream_Read;
+ checkInStream.realStream = inStream;
+ SeqCheckInStream_Init(&checkInStream, XzFlags_GetCheckType(xz->flags));
+
+ #ifdef USE_SUBBLOCK
+ if (useSubblock)
+ {
+ lzmaf->sb.sb.inStream = &checkInStream.p;
+ SubblockEnc_Init(&lzmaf->sb.sb);
+ }
+ #endif
+
+ {
+ UInt64 packPos = seqSizeOutStream.processed;
+ SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p,
+ #ifdef USE_SUBBLOCK
+ useSubblock ? &lzmaf->sb.p:
+ #endif
+ &checkInStream.p,
+ progress);
+ RINOK(res);
+ block.unpackSize = checkInStream.processed;
+ block.packSize = seqSizeOutStream.processed - packPos;
+ }
+
+ {
+ unsigned padSize = 0;
+ Byte buf[128];
+ while((((unsigned)block.packSize + padSize) & 3) != 0)
+ buf[padSize++] = 0;
+ SeqCheckInStream_GetDigest(&checkInStream, buf + padSize);
+ RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags)));
+ RINOK(Xz_AddIndexRecord(xz, block.unpackSize, seqSizeOutStream.processed - padSize, &g_Alloc));
+ }
+ }
+ return Xz_WriteFooter(xz, outStream);
+}
+
+SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
+ const CLzma2EncProps *lzma2Props, Bool useSubblock,
+ ICompressProgress *progress)
+{
+ SRes res;
+ CXzStream xz;
+ CLzma2WithFilters lzmaf;
+ Xz_Construct(&xz);
+ Lzma2WithFilters_Construct(&lzmaf, &g_Alloc, &g_BigAlloc);
+ res = Lzma2WithFilters_Create(&lzmaf);
+ if (res == SZ_OK)
+ res = Xz_Compress(&xz, &lzmaf, outStream, inStream,
+ lzma2Props, useSubblock, progress);
+ Lzma2WithFilters_Free(&lzmaf);
+ Xz_Free(&xz, &g_Alloc);
+ return res;
+}
+
+SRes Xz_EncodeEmpty(ISeqOutStream *outStream)
+{
+ SRes res;
+ CXzStream xz;
+ Xz_Construct(&xz);
+ res = Xz_WriteHeader(xz.flags, outStream);
+ if (res == SZ_OK)
+ res = Xz_WriteFooter(&xz, outStream);
+ Xz_Free(&xz, &g_Alloc);
+ return res;
+}
diff --git a/src/libs/7zip/win/C/XzEnc.h b/src/libs/7zip/win/C/XzEnc.h
new file mode 100644
index 000000000..13390df8b
--- /dev/null
+++ b/src/libs/7zip/win/C/XzEnc.h
@@ -0,0 +1,25 @@
+/* XzEnc.h -- Xz Encode
+2009-04-15 : Igor Pavlov : Public domain */
+
+#ifndef __XZ_ENC_H
+#define __XZ_ENC_H
+
+#include "Lzma2Enc.h"
+
+#include "Xz.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
+ const CLzma2EncProps *lzma2Props, Bool useSubblock,
+ ICompressProgress *progress);
+
+SRes Xz_EncodeEmpty(ISeqOutStream *outStream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/C/XzIn.c b/src/libs/7zip/win/C/XzIn.c
new file mode 100644
index 000000000..7f0f6af8d
--- /dev/null
+++ b/src/libs/7zip/win/C/XzIn.c
@@ -0,0 +1,306 @@
+/* XzIn.c - Xz input
+2009-06-19 : Igor Pavlov : Public domain */
+
+#include <string.h>
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+#include "Xz.h"
+
+SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream)
+{
+ Byte sig[XZ_STREAM_HEADER_SIZE];
+ RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE));
+ if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ return Xz_ParseHeader(p, sig);
+}
+
+#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
+ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
+ if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
+
+SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes)
+{
+ Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
+ unsigned headerSize;
+ *headerSizeRes = 0;
+ RINOK(SeqInStream_ReadByte(inStream, &header[0]));
+ headerSize = ((unsigned)header[0] << 2) + 4;
+ if (headerSize == 0)
+ {
+ *headerSizeRes = 1;
+ *isIndex = True;
+ return SZ_OK;
+ }
+
+ *isIndex = False;
+ *headerSizeRes = headerSize;
+ RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));
+ return XzBlock_Parse(p, header);
+}
+
+#define ADD_SIZE_CHECH(size, val) \
+ { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
+
+UInt64 Xz_GetUnpackSize(const CXzStream *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->numBlocks; i++)
+ ADD_SIZE_CHECH(size, p->blocks[i].unpackSize);
+ return size;
+}
+
+UInt64 Xz_GetPackSize(const CXzStream *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->numBlocks; i++)
+ ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3);
+ return size;
+}
+
+/*
+SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream)
+{
+ return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
+}
+*/
+
+static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc)
+{
+ size_t i, numBlocks, crcStartPos, pos = 1;
+ UInt32 crc;
+
+ if (size < 5 || buf[0] != 0)
+ return SZ_ERROR_ARCHIVE;
+
+ size -= 4;
+ crc = CrcCalc(buf, size);
+ if (crc != GetUi32(buf + size))
+ return SZ_ERROR_ARCHIVE;
+
+ {
+ UInt64 numBlocks64;
+ READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64);
+ numBlocks = (size_t)numBlocks64;
+ if (numBlocks != numBlocks64 || numBlocks * 2 > size)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ crcStartPos = pos;
+ Xz_Free(p, alloc);
+ if (numBlocks != 0)
+ {
+ p->numBlocks = numBlocks;
+ p->numBlocksAllocated = numBlocks;
+ p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
+ if (p->blocks == 0)
+ return SZ_ERROR_MEM;
+ for (i = 0; i < numBlocks; i++)
+ {
+ CXzBlockSizes *block = &p->blocks[i];
+ READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize);
+ READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize);
+ if (block->totalSize == 0)
+ return SZ_ERROR_ARCHIVE;
+ }
+ }
+ while ((pos & 3) != 0)
+ if (buf[pos++] != 0)
+ return SZ_ERROR_ARCHIVE;
+ return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+}
+
+static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc)
+{
+ SRes res;
+ size_t size;
+ Byte *buf;
+ if (indexSize > ((UInt32)1 << 31))
+ return SZ_ERROR_UNSUPPORTED;
+ size = (size_t)indexSize;
+ if (size != indexSize)
+ return SZ_ERROR_UNSUPPORTED;
+ buf = alloc->Alloc(alloc, size);
+ if (buf == 0)
+ return SZ_ERROR_MEM;
+ res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
+ if (res == SZ_OK)
+ res = Xz_ReadIndex2(p, buf, size, alloc);
+ alloc->Free(alloc, buf);
+ return res;
+}
+
+static SRes SeekFromCur(ILookInStream *inStream, Int64 *res)
+{
+ return inStream->Seek(inStream, res, SZ_SEEK_CUR);
+}
+
+static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc)
+{
+ UInt64 indexSize;
+ Byte buf[XZ_STREAM_FOOTER_SIZE];
+
+ if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset = -XZ_STREAM_FOOTER_SIZE;
+ RINOK(SeekFromCur(stream, startOffset));
+
+ RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
+
+ if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
+ {
+ Int64 i = 0;
+ *startOffset += XZ_STREAM_FOOTER_SIZE;
+ for (;;)
+ {
+ int j;
+ size_t processedSize;
+ #define TEMP_BUF_SIZE (1 << 10)
+ Byte tempBuf[TEMP_BUF_SIZE];
+ if (*startOffset < XZ_STREAM_FOOTER_SIZE || i > (1 << 16))
+ return SZ_ERROR_NO_ARCHIVE;
+ processedSize = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset;
+ i += processedSize;
+ *startOffset = -(Int64)processedSize;
+ RINOK(SeekFromCur(stream, startOffset));
+ RINOK(LookInStream_Read2(stream, tempBuf, processedSize, SZ_ERROR_NO_ARCHIVE));
+ for (j = (int)processedSize; j >= 0; j--)
+ if (tempBuf[j -1] != 0)
+ break;
+ if (j != 0)
+ {
+ if ((j & 3) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset += j;
+ if (*startOffset < XZ_STREAM_FOOTER_SIZE)
+ return SZ_ERROR_NO_ARCHIVE;
+ *startOffset -= XZ_STREAM_FOOTER_SIZE;
+ RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
+ RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
+ if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ break;
+ }
+ }
+ }
+
+ p->flags = (CXzStreamFlags)GetBe16(buf + 8);
+
+ if (!XzFlags_IsSupported(p->flags))
+ return SZ_ERROR_UNSUPPORTED;
+
+ if (GetUi32(buf) != CrcCalc(buf + 4, 6))
+ return SZ_ERROR_ARCHIVE;
+
+ indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2;
+
+ *startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE);
+ RINOK(SeekFromCur(stream, startOffset));
+
+ RINOK(Xz_ReadIndex(p, stream, indexSize, alloc));
+
+ {
+ UInt64 totalSize = Xz_GetPackSize(p);
+ UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize;
+ if (totalSize == XZ_SIZE_OVERFLOW ||
+ sum >= ((UInt64)1 << 63) ||
+ totalSize >= ((UInt64)1 << 63))
+ return SZ_ERROR_ARCHIVE;
+ *startOffset = -(Int64)sum;
+ RINOK(SeekFromCur(stream, startOffset));
+ }
+ {
+ CXzStreamFlags headerFlags;
+ CSecToRead secToRead;
+ SecToRead_CreateVTable(&secToRead);
+ secToRead.realStream = stream;
+
+ RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s));
+ return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
+ }
+}
+
+
+/* ---------- Xz Streams ---------- */
+
+void Xzs_Construct(CXzs *p)
+{
+ p->num = p->numAllocated = 0;
+ p->streams = 0;
+}
+
+void Xzs_Free(CXzs *p, ISzAlloc *alloc)
+{
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ Xz_Free(&p->streams[i], alloc);
+ alloc->Free(alloc, p->streams);
+ p->num = p->numAllocated = 0;
+ p->streams = 0;
+}
+
+UInt64 Xzs_GetNumBlocks(const CXzs *p)
+{
+ UInt64 num = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ num += p->streams[i].numBlocks;
+ return num;
+}
+
+UInt64 Xzs_GetUnpackSize(const CXzs *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ ADD_SIZE_CHECH(size, Xz_GetUnpackSize(&p->streams[i]));
+ return size;
+}
+
+/*
+UInt64 Xzs_GetPackSize(const CXzs *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ ADD_SIZE_CHECH(size, Xz_GetTotalSize(&p->streams[i]));
+ return size;
+}
+*/
+
+SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc)
+{
+ Int64 endOffset = 0;
+ RINOK(stream->Seek(stream, &endOffset, SZ_SEEK_END));
+ *startOffset = endOffset;
+ for (;;)
+ {
+ CXzStream st;
+ SRes res;
+ Xz_Construct(&st);
+ res = Xz_ReadBackward(&st, stream, startOffset, alloc);
+ st.startOffset = *startOffset;
+ RINOK(res);
+ if (p->num == p->numAllocated)
+ {
+ size_t newNum = p->num + p->num / 4 + 1;
+ Byte *data = (Byte *)alloc->Alloc(alloc, newNum * sizeof(CXzStream));
+ if (data == 0)
+ return SZ_ERROR_MEM;
+ p->numAllocated = newNum;
+ memcpy(data, p->streams, p->num * sizeof(CXzStream));
+ alloc->Free(alloc, p->streams);
+ p->streams = (CXzStream *)data;
+ }
+ p->streams[p->num++] = st;
+ if (*startOffset == 0)
+ break;
+ RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
+ if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
+ return SZ_ERROR_PROGRESS;
+ }
+ return SZ_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.cpp
new file mode 100644
index 000000000..6774fc482
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.cpp
@@ -0,0 +1,3 @@
+// CompressionMethod.cpp
+
+#include "StdAfx.h"
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.h
new file mode 100644
index 000000000..55bbc68ee
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.h
@@ -0,0 +1,50 @@
+// 7zCompressionMode.h
+
+#ifndef __7Z_COMPRESSION_MODE_H
+#define __7Z_COMPRESSION_MODE_H
+
+#include "../../../Common/MyString.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CMethodFull: public CMethod
+{
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+ bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBind
+{
+ UInt32 InCoder;
+ UInt32 InStream;
+ UInt32 OutCoder;
+ UInt32 OutStream;
+};
+
+struct CCompressionMethodMode
+{
+ CObjectVector<CMethodFull> Methods;
+ CRecordVector<CBind> Binds;
+ #ifndef _7ZIP_ST
+ UInt32 NumThreads;
+ #endif
+ bool PasswordIsDefined;
+ UString Password;
+
+ bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
+ CCompressionMethodMode(): PasswordIsDefined(false)
+ #ifndef _7ZIP_ST
+ , NumThreads(1)
+ #endif
+ {}
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.cpp
new file mode 100644
index 000000000..425a34157
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.cpp
@@ -0,0 +1,332 @@
+// 7zDecode.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/LockedStream.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+
+#include "7zDecode.h"
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertFolderItemInfoToBindInfo(const CFolder &folder,
+ CBindInfoEx &bindInfo)
+{
+ bindInfo.Clear();
+ int i;
+ for (i = 0; i < folder.BindPairs.Size(); i++)
+ {
+ NCoderMixer::CBindPair bindPair;
+ bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex;
+ bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex;
+ bindInfo.BindPairs.Add(bindPair);
+ }
+ UInt32 outStreamIndex = 0;
+ for (i = 0; i < folder.Coders.Size(); i++)
+ {
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ const CCoderInfo &coderInfo = folder.Coders[i];
+ coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams;
+ coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams;
+ bindInfo.Coders.Add(coderStreamsInfo);
+ bindInfo.CoderMethodIDs.Add(coderInfo.MethodID);
+ for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++)
+ if (folder.FindBindPairForOutStream(outStreamIndex) < 0)
+ bindInfo.OutStreams.Add(outStreamIndex);
+ }
+ for (i = 0; i < folder.PackStreams.Size(); i++)
+ bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]);
+}
+
+static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1,
+ const NCoderMixer::CCoderStreamsInfo &a2)
+{
+ return (a1.NumInStreams == a2.NumInStreams) &&
+ (a1.NumOutStreams == a2.NumOutStreams);
+}
+
+static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2)
+{
+ return (a1.InIndex == a2.InIndex) &&
+ (a1.OutIndex == a2.OutIndex);
+}
+
+static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
+{
+ if (a1.Coders.Size() != a2.Coders.Size())
+ return false;
+ int i;
+ for (i = 0; i < a1.Coders.Size(); i++)
+ if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
+ return false;
+ if (a1.BindPairs.Size() != a2.BindPairs.Size())
+ return false;
+ for (i = 0; i < a1.BindPairs.Size(); i++)
+ if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i]))
+ return false;
+ for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
+ if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
+ return false;
+ if (a1.InStreams.Size() != a2.InStreams.Size())
+ return false;
+ if (a1.OutStreams.Size() != a2.OutStreams.Size())
+ return false;
+ return true;
+}
+
+CDecoder::CDecoder(bool multiThread)
+{
+ #ifndef _ST_MODE
+ multiThread = true;
+ #endif
+ _multiThread = multiThread;
+ _bindInfoExPrevIsDefined = false;
+}
+
+HRESULT CDecoder::Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ UInt64 startPos,
+ const UInt64 *packSizes,
+ const CFolder &folderInfo,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *compressProgress
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , bool mtMode, UInt32 numThreads
+ #endif
+ )
+{
+ if (!folderInfo.CheckStructure())
+ return E_NOTIMPL;
+ #ifndef _NO_CRYPTO
+ passwordIsDefined = false;
+ #endif
+ CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
+
+ CLockedInStream lockedInStream;
+ lockedInStream.Init(inStream);
+
+ for (int j = 0; j < folderInfo.PackStreams.Size(); j++)
+ {
+ CLockedSequentialInStreamImp *lockedStreamImpSpec = new
+ CLockedSequentialInStreamImp;
+ CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec;
+ lockedStreamImpSpec->Init(&lockedInStream, startPos);
+ startPos += packSizes[j];
+
+ CLimitedSequentialInStream *streamSpec = new
+ CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream = streamSpec;
+ streamSpec->SetStream(lockedStreamImp);
+ streamSpec->Init(packSizes[j]);
+ inStreams.Add(inStream);
+ }
+
+ int numCoders = folderInfo.Coders.Size();
+
+ CBindInfoEx bindInfo;
+ ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo);
+ bool createNewCoders;
+ if (!_bindInfoExPrevIsDefined)
+ createNewCoders = true;
+ else
+ createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev);
+ if (createNewCoders)
+ {
+ int i;
+ _decoders.Clear();
+ // _decoders2.Clear();
+
+ _mixerCoder.Release();
+
+ if (_multiThread)
+ {
+ _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT;
+ _mixerCoder = _mixerCoderMTSpec;
+ _mixerCoderCommon = _mixerCoderMTSpec;
+ }
+ else
+ {
+ #ifdef _ST_MODE
+ _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST;
+ _mixerCoder = _mixerCoderSTSpec;
+ _mixerCoderCommon = _mixerCoderSTSpec;
+ #endif
+ }
+ RINOK(_mixerCoderCommon->SetBindInfo(bindInfo));
+
+ for (i = 0; i < numCoders; i++)
+ {
+ const CCoderInfo &coderInfo = folderInfo.Coders[i];
+
+
+ CMyComPtr<ICompressCoder> decoder;
+ CMyComPtr<ICompressCoder2> decoder2;
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ coderInfo.MethodID, decoder, decoder2, false));
+ CMyComPtr<IUnknown> decoderUnknown;
+ if (coderInfo.IsSimpleCoder())
+ {
+ if (decoder == 0)
+ return E_NOTIMPL;
+
+ decoderUnknown = (IUnknown *)decoder;
+
+ if (_multiThread)
+ _mixerCoderMTSpec->AddCoder(decoder);
+ #ifdef _ST_MODE
+ else
+ _mixerCoderSTSpec->AddCoder(decoder, false);
+ #endif
+ }
+ else
+ {
+ if (decoder2 == 0)
+ return E_NOTIMPL;
+ decoderUnknown = (IUnknown *)decoder2;
+ if (_multiThread)
+ _mixerCoderMTSpec->AddCoder2(decoder2);
+ #ifdef _ST_MODE
+ else
+ _mixerCoderSTSpec->AddCoder2(decoder2, false);
+ #endif
+ }
+ _decoders.Add(decoderUnknown);
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+ }
+ #endif
+ }
+ _bindInfoExPrev = bindInfo;
+ _bindInfoExPrevIsDefined = true;
+ }
+ int i;
+ _mixerCoderCommon->ReInit();
+
+ UInt32 packStreamIndex = 0, unpackStreamIndex = 0;
+ UInt32 coderIndex = 0;
+ // UInt32 coder2Index = 0;
+
+ for (i = 0; i < numCoders; i++)
+ {
+ const CCoderInfo &coderInfo = folderInfo.Coders[i];
+ CMyComPtr<IUnknown> &decoder = _decoders[coderIndex];
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ const CByteBuffer &props = coderInfo.Props;
+ size_t size = props.GetCapacity();
+ if (size > 0xFFFFFFFF)
+ return E_NOTIMPL;
+ // if (size > 0)
+ {
+ RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size));
+ }
+ }
+ }
+
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ if (mtMode)
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(numThreads));
+ }
+ }
+ #endif
+
+ #ifndef _NO_CRYPTO
+ {
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+ if (cryptoSetPassword)
+ {
+ if (getTextPassword == 0)
+ return E_FAIL;
+ CMyComBSTR passwordBSTR;
+ RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR));
+ CByteBuffer buffer;
+ passwordIsDefined = true;
+ const UString password(passwordBSTR);
+ const UInt32 sizeInBytes = password.Length() * 2;
+ buffer.SetCapacity(sizeInBytes);
+ for (int i = 0; i < password.Length(); i++)
+ {
+ wchar_t c = password[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+ }
+ }
+ #endif
+
+ coderIndex++;
+
+ UInt32 numInStreams = (UInt32)coderInfo.NumInStreams;
+ UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams;
+ CRecordVector<const UInt64 *> packSizesPointers;
+ CRecordVector<const UInt64 *> unpackSizesPointers;
+ packSizesPointers.Reserve(numInStreams);
+ unpackSizesPointers.Reserve(numOutStreams);
+ UInt32 j;
+ for (j = 0; j < numOutStreams; j++, unpackStreamIndex++)
+ unpackSizesPointers.Add(&folderInfo.UnpackSizes[unpackStreamIndex]);
+
+ for (j = 0; j < numInStreams; j++, packStreamIndex++)
+ {
+ int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex);
+ if (bindPairIndex >= 0)
+ packSizesPointers.Add(
+ &folderInfo.UnpackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]);
+ else
+ {
+ int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex);
+ if (index < 0)
+ return E_FAIL;
+ packSizesPointers.Add(&packSizes[index]);
+ }
+ }
+
+ _mixerCoderCommon->SetCoderInfo(i,
+ &packSizesPointers.Front(),
+ &unpackSizesPointers.Front());
+ }
+ UInt32 mainCoder, temp;
+ bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp);
+
+ if (_multiThread)
+ _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder);
+ /*
+ else
+ _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);;
+ */
+
+ if (numCoders == 0)
+ return 0;
+ CRecordVector<ISequentialInStream *> inStreamPointers;
+ inStreamPointers.Reserve(inStreams.Size());
+ for (i = 0; i < inStreams.Size(); i++)
+ inStreamPointers.Add(inStreams[i]);
+ ISequentialOutStream *outStreamPointer = outStream;
+ return _mixerCoder->Code(&inStreamPointers.Front(), NULL,
+ inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.h
new file mode 100644
index 000000000..d8a424a36
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.h
@@ -0,0 +1,68 @@
+// 7zDecode.h
+
+#ifndef __7Z_DECODE_H
+#define __7Z_DECODE_H
+
+#include "../../IStream.h"
+#include "../../IPassword.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+
+#include "../../Common/CreateCoder.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CBindInfoEx: public NCoderMixer::CBindInfo
+{
+ CRecordVector<CMethodId> CoderMethodIDs;
+ void Clear()
+ {
+ CBindInfo::Clear();
+ CoderMethodIDs.Clear();
+ }
+};
+
+class CDecoder
+{
+ bool _bindInfoExPrevIsDefined;
+ CBindInfoEx _bindInfoExPrev;
+
+ bool _multiThread;
+ #ifdef _ST_MODE
+ NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec;
+ #endif
+ NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec;
+ NCoderMixer::CCoderMixer2 *_mixerCoderCommon;
+
+ CMyComPtr<ICompressCoder2> _mixerCoder;
+ CObjectVector<CMyComPtr<IUnknown> > _decoders;
+ // CObjectVector<CMyComPtr<ICompressCoder2> > _decoders2;
+public:
+ CDecoder(bool multiThread);
+ HRESULT Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ UInt64 startPos,
+ const UInt64 *packSizes,
+ const CFolder &folder,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *compressProgress
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPasswordSpec, bool &passwordIsDefined
+ #endif
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , bool mtMode, UInt32 numThreads
+ #endif
+ );
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.cpp
new file mode 100644
index 000000000..87996bc0e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.cpp
@@ -0,0 +1,444 @@
+// 7zEncode.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/InOutTempBuffer.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+
+#include "7zEncode.h"
+#include "7zSpecStream.h"
+
+static const UInt64 k_Delta = 0x03;
+static const UInt64 k_BCJ = 0x03030103;
+static const UInt64 k_BCJ2 = 0x0303011B;
+
+namespace NArchive {
+namespace N7z {
+
+static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo,
+ const CRecordVector<CMethodId> decompressionMethods,
+ CFolder &folder)
+{
+ folder.Coders.Clear();
+ // bindInfo.CoderMethodIDs.Clear();
+ // folder.OutStreams.Clear();
+ folder.PackStreams.Clear();
+ folder.BindPairs.Clear();
+ int i;
+ for (i = 0; i < bindInfo.BindPairs.Size(); i++)
+ {
+ CBindPair bindPair;
+ bindPair.InIndex = bindInfo.BindPairs[i].InIndex;
+ bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex;
+ folder.BindPairs.Add(bindPair);
+ }
+ for (i = 0; i < bindInfo.Coders.Size(); i++)
+ {
+ CCoderInfo coderInfo;
+ const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i];
+ coderInfo.NumInStreams = coderStreamsInfo.NumInStreams;
+ coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams;
+ coderInfo.MethodID = decompressionMethods[i];
+ folder.Coders.Add(coderInfo);
+ }
+ for (i = 0; i < bindInfo.InStreams.Size(); i++)
+ folder.PackStreams.Add(bindInfo.InStreams[i]);
+}
+
+HRESULT CEncoder::CreateMixerCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const UInt64 *inSizeForReduce)
+{
+ _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT;
+ _mixerCoder = _mixerCoderSpec;
+ RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo));
+ for (int i = 0; i < _options.Methods.Size(); i++)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ _codersInfo.Add(CCoderInfo());
+ CCoderInfo &encodingInfo = _codersInfo.Back();
+ encodingInfo.MethodID = methodFull.Id;
+ CMyComPtr<ICompressCoder> encoder;
+ CMyComPtr<ICompressCoder2> encoder2;
+
+
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodFull.Id, encoder, encoder2, true));
+
+ if (!encoder && !encoder2)
+ return E_FAIL;
+
+ CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2;
+
+ #ifndef _7ZIP_ST
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
+ }
+ }
+ #endif
+
+
+ RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon));
+
+ /*
+ CMyComPtr<ICryptoResetSalt> resetSalt;
+ encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
+ if (resetSalt != NULL)
+ {
+ resetSalt->ResetSalt();
+ }
+ */
+
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo));
+ }
+ #endif
+
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+
+ if (cryptoSetPassword)
+ {
+ CByteBuffer buffer;
+ const UInt32 sizeInBytes = _options.Password.Length() * 2;
+ buffer.SetCapacity(sizeInBytes);
+ for (int i = 0; i < _options.Password.Length(); i++)
+ {
+ wchar_t c = _options.Password[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+ }
+
+ if (encoder)
+ _mixerCoderSpec->AddCoder(encoder);
+ else
+ _mixerCoderSpec->AddCoder2(encoder2);
+ }
+ return S_OK;
+}
+
+HRESULT CEncoder::Encode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream,
+ const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
+ CFolder &folderItem,
+ ISequentialOutStream *outStream,
+ CRecordVector<UInt64> &packSizes,
+ ICompressProgressInfo *compressProgress)
+{
+ RINOK(EncoderConstr());
+
+ if (_mixerCoderSpec == NULL)
+ {
+ RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
+ }
+ _mixerCoderSpec->ReInit();
+ // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress);
+
+ CObjectVector<CInOutTempBuffer> inOutTempBuffers;
+ CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs;
+ CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
+ int numMethods = _bindInfo.Coders.Size();
+ int i;
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ inOutTempBuffers.Add(CInOutTempBuffer());
+ inOutTempBuffers.Back().Create();
+ inOutTempBuffers.Back().InitWriting();
+ }
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ CSequentialOutTempBufferImp *tempBufferSpec = new CSequentialOutTempBufferImp;
+ CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
+ tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
+ tempBuffers.Add(tempBuffer);
+ tempBufferSpecs.Add(tempBufferSpec);
+ }
+
+ for (i = 0; i < numMethods; i++)
+ _mixerCoderSpec->SetCoderInfo(i, NULL, NULL);
+
+ if (_bindInfo.InStreams.IsEmpty())
+ return E_FAIL;
+ UInt32 mainCoderIndex, mainStreamIndex;
+ _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex);
+
+ if (inStreamSize != NULL)
+ {
+ CRecordVector<const UInt64 *> sizePointers;
+ for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++)
+ if (i == mainStreamIndex)
+ sizePointers.Add(inStreamSize);
+ else
+ sizePointers.Add(NULL);
+ _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL);
+ }
+
+
+ // UInt64 outStreamStartPos;
+ // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos));
+
+ CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
+ CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+ CSequentialOutStreamSizeCount *outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
+ CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec;
+
+ inStreamSizeCountSpec->Init(inStream);
+ outStreamSizeCountSpec->SetStream(outStream);
+ outStreamSizeCountSpec->Init();
+
+ CRecordVector<ISequentialInStream *> inStreamPointers;
+ CRecordVector<ISequentialOutStream *> outStreamPointers;
+ inStreamPointers.Add(inStreamSizeCount);
+ outStreamPointers.Add(outStreamSizeCount);
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ outStreamPointers.Add(tempBuffers[i - 1]);
+
+ for (i = 0; i < _codersInfo.Size(); i++)
+ {
+ CCoderInfo &encodingInfo = _codersInfo[i];
+
+ CMyComPtr<ICryptoResetInitVector> resetInitVector;
+ _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
+ if (resetInitVector != NULL)
+ {
+ resetInitVector->ResetInitVector();
+ }
+
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+ _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+ if (writeCoderProperties != NULL)
+ {
+ CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init();
+ writeCoderProperties->WriteCoderProperties(outStream);
+ outStreamSpec->CopyToBuffer(encodingInfo.Props);
+ }
+ }
+
+ UInt32 progressIndex = mainCoderIndex;
+
+ for (i = 0; i + 1 < _codersInfo.Size(); i++)
+ {
+ UInt64 m = _codersInfo[i].MethodID;
+ if (m == k_Delta || m == k_BCJ || m == k_BCJ2)
+ progressIndex = i + 1;
+ }
+
+ _mixerCoderSpec->SetProgressCoderIndex(progressIndex);
+
+ RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1,
+ &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress));
+
+ ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem);
+
+ packSizes.Add(outStreamSizeCountSpec->GetSize());
+
+ for (i = 1; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
+ RINOK(inOutTempBuffer.WriteToStream(outStream));
+ packSizes.Add(inOutTempBuffer.GetDataSize());
+ }
+
+ for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++)
+ {
+ int binder = _bindInfo.FindBinderForInStream(
+ _bindReverseConverter->DestOutToSrcInMap[i]);
+ UInt64 streamSize;
+ if (binder < 0)
+ streamSize = inStreamSizeCountSpec->GetSize();
+ else
+ streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder);
+ folderItem.UnpackSizes.Add(streamSize);
+ }
+ for (i = numMethods - 1; i >= 0; i--)
+ folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props;
+ return S_OK;
+}
+
+
+CEncoder::CEncoder(const CCompressionMethodMode &options):
+ _bindReverseConverter(0),
+ _constructed(false)
+{
+ if (options.IsEmpty())
+ throw 1;
+
+ _options = options;
+ _mixerCoderSpec = NULL;
+}
+
+HRESULT CEncoder::EncoderConstr()
+{
+ if (_constructed)
+ return S_OK;
+ if (_options.Methods.IsEmpty())
+ {
+ // it has only password method;
+ if (!_options.PasswordIsDefined)
+ throw 1;
+ if (!_options.Binds.IsEmpty())
+ throw 1;
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ CMethodFull method;
+
+ method.NumInStreams = 1;
+ method.NumOutStreams = 1;
+ coderStreamsInfo.NumInStreams = 1;
+ coderStreamsInfo.NumOutStreams = 1;
+ method.Id = k_AES;
+
+ _options.Methods.Add(method);
+ _bindInfo.Coders.Add(coderStreamsInfo);
+
+ _bindInfo.InStreams.Add(0);
+ _bindInfo.OutStreams.Add(0);
+ }
+ else
+ {
+
+ UInt32 numInStreams = 0, numOutStreams = 0;
+ int i;
+ for (i = 0; i < _options.Methods.Size(); i++)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ coderStreamsInfo.NumInStreams = methodFull.NumOutStreams;
+ coderStreamsInfo.NumOutStreams = methodFull.NumInStreams;
+ if (_options.Binds.IsEmpty())
+ {
+ if (i < _options.Methods.Size() - 1)
+ {
+ NCoderMixer::CBindPair bindPair;
+ bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams;
+ bindPair.OutIndex = numOutStreams;
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ else
+ _bindInfo.OutStreams.Insert(0, numOutStreams);
+ for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++)
+ _bindInfo.OutStreams.Add(numOutStreams + j);
+ }
+
+ numInStreams += coderStreamsInfo.NumInStreams;
+ numOutStreams += coderStreamsInfo.NumOutStreams;
+
+ _bindInfo.Coders.Add(coderStreamsInfo);
+ }
+
+ if (!_options.Binds.IsEmpty())
+ {
+ for (i = 0; i < _options.Binds.Size(); i++)
+ {
+ NCoderMixer::CBindPair bindPair;
+ const CBind &bind = _options.Binds[i];
+ bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream;
+ bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream;
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ for (i = 0; i < (int)numOutStreams; i++)
+ if (_bindInfo.FindBinderForOutStream(i) == -1)
+ _bindInfo.OutStreams.Add(i);
+ }
+
+ for (i = 0; i < (int)numInStreams; i++)
+ if (_bindInfo.FindBinderForInStream(i) == -1)
+ _bindInfo.InStreams.Add(i);
+
+ if (_bindInfo.InStreams.IsEmpty())
+ throw 1; // this is error
+
+ // Make main stream first in list
+ int inIndex = _bindInfo.InStreams[0];
+ for (;;)
+ {
+ UInt32 coderIndex, coderStreamIndex;
+ _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex);
+ UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
+ int binder = _bindInfo.FindBinderForOutStream(outIndex);
+ if (binder >= 0)
+ {
+ inIndex = _bindInfo.BindPairs[binder].InIndex;
+ continue;
+ }
+ for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
+ if (_bindInfo.OutStreams[i] == outIndex)
+ {
+ _bindInfo.OutStreams.Delete(i);
+ _bindInfo.OutStreams.Insert(0, outIndex);
+ break;
+ }
+ break;
+ }
+
+ if (_options.PasswordIsDefined)
+ {
+ int numCryptoStreams = _bindInfo.OutStreams.Size();
+
+ for (i = 0; i < numCryptoStreams; i++)
+ {
+ NCoderMixer::CBindPair bindPair;
+ bindPair.InIndex = numInStreams + i;
+ bindPair.OutIndex = _bindInfo.OutStreams[i];
+ _bindInfo.BindPairs.Add(bindPair);
+ }
+ _bindInfo.OutStreams.Clear();
+
+ /*
+ if (numCryptoStreams == 0)
+ numCryptoStreams = 1;
+ */
+
+ for (i = 0; i < numCryptoStreams; i++)
+ {
+ NCoderMixer::CCoderStreamsInfo coderStreamsInfo;
+ CMethodFull method;
+ method.NumInStreams = 1;
+ method.NumOutStreams = 1;
+ coderStreamsInfo.NumInStreams = method.NumOutStreams;
+ coderStreamsInfo.NumOutStreams = method.NumInStreams;
+ method.Id = k_AES;
+
+ _options.Methods.Add(method);
+ _bindInfo.Coders.Add(coderStreamsInfo);
+ _bindInfo.OutStreams.Add(numOutStreams + i);
+ }
+ }
+
+ }
+
+ for (int i = _options.Methods.Size() - 1; i >= 0; i--)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ _decompressionMethods.Add(methodFull.Id);
+ }
+
+ _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo);
+ _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo);
+ _constructed = true;
+ return S_OK;
+}
+
+CEncoder::~CEncoder()
+{
+ delete _bindReverseConverter;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.h
new file mode 100644
index 000000000..4909a6e89
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.h
@@ -0,0 +1,55 @@
+// 7zEncode.h
+
+#ifndef __7Z_ENCODE_H
+#define __7Z_ENCODE_H
+
+// #include "../../Common/StreamObjects.h"
+
+#include "7zCompressionMode.h"
+
+#include "../Common/CoderMixer2.h"
+#include "../Common/CoderMixer2MT.h"
+#ifdef _ST_MODE
+#include "../Common/CoderMixer2ST.h"
+#endif
+#include "7zItem.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CEncoder
+{
+ NCoderMixer::CCoderMixer2MT *_mixerCoderSpec;
+ CMyComPtr<ICompressCoder2> _mixerCoder;
+
+ CObjectVector<CCoderInfo> _codersInfo;
+
+ CCompressionMethodMode _options;
+ NCoderMixer::CBindInfo _bindInfo;
+ NCoderMixer::CBindInfo _decompressBindInfo;
+ NCoderMixer::CBindReverseConverter *_bindReverseConverter;
+ CRecordVector<CMethodId> _decompressionMethods;
+
+ HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS
+ const UInt64 *inSizeForReduce);
+
+ bool _constructed;
+public:
+ CEncoder(const CCompressionMethodMode &options);
+ ~CEncoder();
+ HRESULT EncoderConstr();
+ HRESULT Encode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream,
+ const UInt64 *inStreamSize, const UInt64 *inSizeForReduce,
+ CFolder &folderItem,
+ ISequentialOutStream *outStream,
+ CRecordVector<UInt64> &packSizes,
+ ICompressProgressInfo *compressProgress);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zExtract.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zExtract.cpp
new file mode 100644
index 000000000..d55f38e13
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zExtract.cpp
@@ -0,0 +1,270 @@
+// 7zExtract.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../Common/ProgressUtils.h"
+
+#include "7zDecode.h"
+// #include "7z1Decode.h"
+#include "7zFolderOutStream.h"
+#include "7zHandler.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CExtractFolderInfo
+{
+ #ifdef _7Z_VOL
+ int VolumeIndex;
+ #endif
+ CNum FileIndex;
+ CNum FolderIndex;
+ CBoolVector ExtractStatuses;
+ UInt64 UnpackSize;
+ CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ int volumeIndex,
+ #endif
+ CNum fileIndex, CNum folderIndex):
+ #ifdef _7Z_VOL
+ VolumeIndex(volumeIndex),
+ #endif
+ FileIndex(fileIndex),
+ FolderIndex(folderIndex),
+ UnpackSize(0)
+ {
+ if (fileIndex != kNumNoIndex)
+ {
+ ExtractStatuses.Reserve(1);
+ ExtractStatuses.Add(true);
+ }
+ };
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
+{
+ COM_TRY_BEGIN
+ bool testMode = (testModeSpec != 0);
+ CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+ UInt64 importantTotalUnpacked = 0;
+
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems =
+ #ifdef _7Z_VOL
+ _refs.Size();
+ #else
+ _db.Files.Size();
+ #endif
+
+ if(numItems == 0)
+ return S_OK;
+
+ /*
+ if(_volumes.Size() != 1)
+ return E_FAIL;
+ const CVolume &volume = _volumes.Front();
+ const CArchiveDatabaseEx &_db = volume.Database;
+ IInStream *_inStream = volume.Stream;
+ */
+
+ CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
+ for (UInt32 ii = 0; ii < numItems; ii++)
+ {
+ // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
+ UInt32 ref2Index = allFilesMode ? ii : indices[ii];
+ // const CRef2 &ref2 = _refs[ref2Index];
+
+ // for (UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
+ {
+ #ifdef _7Z_VOL
+ // const CRef &ref = ref2.Refs[ri];
+ const CRef &ref = _refs[ref2Index];
+
+ int volumeIndex = ref.VolumeIndex;
+ const CVolume &volume = _volumes[volumeIndex];
+ const CArchiveDatabaseEx &db = volume.Database;
+ UInt32 fileIndex = ref.ItemIndex;
+ #else
+ const CArchiveDatabaseEx &db = _db;
+ UInt32 fileIndex = ref2Index;
+ #endif
+
+ CNum folderIndex = db.FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex == kNumNoIndex)
+ {
+ extractFolderInfoVector.Add(CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ volumeIndex,
+ #endif
+ fileIndex, kNumNoIndex));
+ continue;
+ }
+ if (extractFolderInfoVector.IsEmpty() ||
+ folderIndex != extractFolderInfoVector.Back().FolderIndex
+ #ifdef _7Z_VOL
+ || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
+ #endif
+ )
+ {
+ extractFolderInfoVector.Add(CExtractFolderInfo(
+ #ifdef _7Z_VOL
+ volumeIndex,
+ #endif
+ kNumNoIndex, folderIndex));
+ const CFolder &folderInfo = db.Folders[folderIndex];
+ UInt64 unpackSize = folderInfo.GetUnpackSize();
+ importantTotalUnpacked += unpackSize;
+ extractFolderInfoVector.Back().UnpackSize = unpackSize;
+ }
+
+ CExtractFolderInfo &efi = extractFolderInfoVector.Back();
+
+ // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
+ CNum startIndex = db.FolderStartFileIndex[folderIndex];
+ for (CNum index = efi.ExtractStatuses.Size();
+ index <= fileIndex - startIndex; index++)
+ {
+ // UInt64 unpackSize = _db.Files[startIndex + index].UnpackSize;
+ // Count partial_folder_size
+ // efi.UnpackSize += unpackSize;
+ // importantTotalUnpacked += unpackSize;
+ efi.ExtractStatuses.Add(index == fileIndex - startIndex);
+ }
+ }
+ }
+
+ RINOK(extractCallback->SetTotal(importantTotalUnpacked));
+
+ CDecoder decoder(
+ #ifdef _ST_MODE
+ false
+ #else
+ true
+ #endif
+ );
+ // CDecoder1 decoder;
+
+ UInt64 totalPacked = 0;
+ UInt64 totalUnpacked = 0;
+ UInt64 curPacked, curUnpacked;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (int i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
+ {
+ lps->OutSize = totalUnpacked;
+ lps->InSize = totalPacked;
+ RINOK(lps->SetCur());
+
+ if (i >= extractFolderInfoVector.Size())
+ break;
+
+ const CExtractFolderInfo &efi = extractFolderInfoVector[i];
+ curUnpacked = efi.UnpackSize;
+ curPacked = 0;
+
+ CFolderOutStream *folderOutStream = new CFolderOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
+
+ #ifdef _7Z_VOL
+ const CVolume &volume = _volumes[efi.VolumeIndex];
+ const CArchiveDatabaseEx &db = volume.Database;
+ #else
+ const CArchiveDatabaseEx &db = _db;
+ #endif
+
+ CNum startIndex;
+ if (efi.FileIndex != kNumNoIndex)
+ startIndex = efi.FileIndex;
+ else
+ startIndex = db.FolderStartFileIndex[efi.FolderIndex];
+
+ HRESULT result = folderOutStream->Init(&db,
+ #ifdef _7Z_VOL
+ volume.StartRef2Index,
+ #else
+ 0,
+ #endif
+ startIndex,
+ &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0);
+
+ RINOK(result);
+
+ if (efi.FileIndex != kNumNoIndex)
+ continue;
+
+ CNum folderIndex = efi.FolderIndex;
+ const CFolder &folderInfo = db.Folders[folderIndex];
+
+ curPacked = _db.GetFolderFullPackSize(folderIndex);
+
+ CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex];
+ UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0);
+
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ if (extractCallback)
+ extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ #endif
+
+ try
+ {
+ #ifndef _NO_CRYPTO
+ bool passwordIsDefined;
+ #endif
+
+ HRESULT result = decoder.Decode(
+ EXTERNAL_CODECS_VARS
+ #ifdef _7Z_VOL
+ volume.Stream,
+ #else
+ _inStream,
+ #endif
+ folderStartPackPos,
+ &db.PackSizes[packStreamIndex],
+ folderInfo,
+ outStream,
+ progress
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , true, _numThreads
+ #endif
+ );
+
+ if (result == S_FALSE)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ if (result == E_NOTIMPL)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ if (result != S_OK)
+ return result;
+ if (folderOutStream->WasWritingFinished() != S_OK)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ }
+ catch(...)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.cpp
new file mode 100644
index 000000000..edd276bc1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.cpp
@@ -0,0 +1,123 @@
+// 7zFolderInStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderInStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderInStream::CFolderInStream()
+{
+ _inStreamWithHashSpec = new CSequentialInStreamWithCRC;
+ _inStreamWithHash = _inStreamWithHashSpec;
+}
+
+void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
+ const UInt32 *fileIndices, UInt32 numFiles)
+{
+ _updateCallback = updateCallback;
+ _numFiles = numFiles;
+ _fileIndex = 0;
+ _fileIndices = fileIndices;
+ Processed.Clear();
+ CRCs.Clear();
+ Sizes.Clear();
+ _fileIsOpen = false;
+ _currentSizeIsDefined = false;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+ _filePos = 0;
+ while (_fileIndex < _numFiles)
+ {
+ CMyComPtr<ISequentialInStream> stream;
+ HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream);
+ if (result != S_OK && result != S_FALSE)
+ return result;
+ _fileIndex++;
+ _inStreamWithHashSpec->SetStream(stream);
+ _inStreamWithHashSpec->Init();
+ if (stream)
+ {
+ _fileIsOpen = true;
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+ if (streamGetSize)
+ {
+ RINOK(streamGetSize->GetSize(&_currentSize));
+ _currentSizeIsDefined = true;
+ }
+ return S_OK;
+ }
+ RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ Sizes.Add(0);
+ Processed.Add(result == S_OK);
+ AddDigest();
+ }
+ return S_OK;
+}
+
+void CFolderInStream::AddDigest()
+{
+ CRCs.Add(_inStreamWithHashSpec->GetCRC());
+}
+
+HRESULT CFolderInStream::CloseStream()
+{
+ RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ _inStreamWithHashSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentSizeIsDefined = false;
+ Processed.Add(true);
+ Sizes.Add(_filePos);
+ AddDigest();
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != 0)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 processed2;
+ RINOK(_inStreamWithHash->Read(data, size, &processed2));
+ if (processed2 == 0)
+ {
+ RINOK(CloseStream());
+ continue;
+ }
+ if (processedSize != 0)
+ *processedSize = processed2;
+ _filePos += processed2;
+ break;
+ }
+ if (_fileIndex >= _numFiles)
+ break;
+ RINOK(OpenStream());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
+{
+ *value = 0;
+ int index2 = (int)subStream;
+ if (index2 < 0 || subStream > Sizes.Size())
+ return E_FAIL;
+ if (index2 < Sizes.Size())
+ {
+ *value = Sizes[index2];
+ return S_OK;
+ }
+ if (!_currentSizeIsDefined)
+ return S_FALSE;
+ *value = _currentSize;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.h
new file mode 100644
index 000000000..6df3672a1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.h
@@ -0,0 +1,58 @@
+// 7zFolderInStream.h
+
+#ifndef __7Z_FOLDER_IN_STREAM_H
+#define __7Z_FOLDER_IN_STREAM_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+#include "../Common/InStreamWithCRC.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderInStream:
+ public ISequentialInStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ CSequentialInStreamWithCRC *_inStreamWithHashSpec;
+ CMyComPtr<ISequentialInStream> _inStreamWithHash;
+ CMyComPtr<IArchiveUpdateCallback> _updateCallback;
+
+ bool _currentSizeIsDefined;
+ bool _fileIsOpen;
+ UInt64 _currentSize;
+ UInt64 _filePos;
+ const UInt32 *_fileIndices;
+ UInt32 _numFiles;
+ UInt32 _fileIndex;
+
+ HRESULT OpenStream();
+ HRESULT CloseStream();
+ void AddDigest();
+
+public:
+ CRecordVector<bool> Processed;
+ CRecordVector<UInt32> CRCs;
+ CRecordVector<UInt64> Sizes;
+
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+
+ CFolderInStream();
+ void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles);
+ UInt64 GetFullSize() const
+ {
+ UInt64 size = 0;
+ for (int i = 0; i < Sizes.Size(); i++)
+ size += Sizes[i];
+ return size;
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
new file mode 100644
index 000000000..22c4600ec
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
@@ -0,0 +1,149 @@
+// 7zFolderOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zFolderOutStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+CFolderOutStream::CFolderOutStream()
+{
+ _crcStreamSpec = new COutStreamWithCRC;
+ _crcStream = _crcStreamSpec;
+}
+
+HRESULT CFolderOutStream::Init(
+ const CArchiveDatabaseEx *db,
+ UInt32 ref2Offset, UInt32 startIndex,
+ const CBoolVector *extractStatuses,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode, bool checkCrc)
+{
+ _db = db;
+ _ref2Offset = ref2Offset;
+ _startIndex = startIndex;
+
+ _extractStatuses = extractStatuses;
+ _extractCallback = extractCallback;
+ _testMode = testMode;
+ _checkCrc = checkCrc;
+
+ _currentIndex = 0;
+ _fileIsOpen = false;
+ return ProcessEmptyFiles();
+}
+
+HRESULT CFolderOutStream::OpenFile()
+{
+ Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract) :
+ NExtract::NAskMode::kSkip;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ UInt32 index = _startIndex + _currentIndex;
+ RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
+ _crcStreamSpec->SetStream(realOutStream);
+ _crcStreamSpec->Init(_checkCrc);
+ _fileIsOpen = true;
+ const CFileItem &fi = _db->Files[index];
+ _rem = fi.Size;
+ if (askMode == NExtract::NAskMode::kExtract && !realOutStream &&
+ !_db->IsItemAnti(index) && !fi.IsDir)
+ askMode = NExtract::NAskMode::kSkip;
+ return _extractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res)
+{
+ _crcStreamSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentIndex++;
+ return _extractCallback->SetOperationResult(res);
+}
+
+HRESULT CFolderOutStream::CloseFileAndSetResult()
+{
+ const CFileItem &fi = _db->Files[_startIndex + _currentIndex];
+ return CloseFileAndSetResult(
+ (fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kCRCError);
+}
+
+HRESULT CFolderOutStream::ProcessEmptyFiles()
+{
+ while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
+ {
+ RINOK(OpenFile());
+ RINOK(CloseFileAndSetResult());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = size < _rem ? size : (UInt32)_rem;
+ RINOK(_crcStream->Write(data, cur, &cur));
+ if (cur == 0)
+ break;
+ data = (const Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (processedSize != NULL)
+ *processedSize += cur;
+ if (_rem == 0)
+ {
+ RINOK(CloseFileAndSetResult());
+ RINOK(ProcessEmptyFiles());
+ continue;
+ }
+ }
+ else
+ {
+ RINOK(ProcessEmptyFiles());
+ if (_currentIndex == _extractStatuses->Size())
+ {
+ // we support partial extracting
+ if (processedSize != NULL)
+ *processedSize += size;
+ break;
+ }
+ RINOK(OpenFile());
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
+{
+ *value = 0;
+ if ((int)subStream >= _extractStatuses->Size())
+ return S_FALSE;
+ *value = _db->Files[_startIndex + (int)subStream].Size;
+ return S_OK;
+}
+
+HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
+{
+ while (_currentIndex < _extractStatuses->Size())
+ {
+ if (_fileIsOpen)
+ {
+ RINOK(CloseFileAndSetResult(resultEOperationResult));
+ }
+ else
+ {
+ RINOK(OpenFile());
+ }
+ }
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.h
new file mode 100644
index 000000000..f9bb1af42
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.h
@@ -0,0 +1,58 @@
+// 7zFolderOutStream.h
+
+#ifndef __7Z_FOLDER_OUT_STREAM_H
+#define __7Z_FOLDER_OUT_STREAM_H
+
+#include "../../IStream.h"
+#include "../IArchive.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CFolderOutStream:
+ public ISequentialOutStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ COutStreamWithCRC *_crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> _crcStream;
+ const CArchiveDatabaseEx *_db;
+ const CBoolVector *_extractStatuses;
+ CMyComPtr<IArchiveExtractCallback> _extractCallback;
+ UInt32 _ref2Offset;
+ UInt32 _startIndex;
+ int _currentIndex;
+ bool _testMode;
+ bool _checkCrc;
+ bool _fileIsOpen;
+ UInt64 _rem;
+
+ HRESULT OpenFile();
+ HRESULT CloseFileAndSetResult(Int32 res);
+ HRESULT CloseFileAndSetResult();
+ HRESULT ProcessEmptyFiles();
+public:
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+ CFolderOutStream();
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+
+ HRESULT Init(
+ const CArchiveDatabaseEx *db,
+ UInt32 ref2Offset, UInt32 startIndex,
+ const CBoolVector *extractStatuses,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode, bool checkCrc);
+ HRESULT FlushCorrupted(Int32 resultEOperationResult);
+ HRESULT WasWritingFinished() const
+ { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.cpp
new file mode 100644
index 000000000..4ab7afa87
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.cpp
@@ -0,0 +1,482 @@
+// 7zHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+
+#ifndef __7Z_SET_PROPERTIES
+#include "../../../Windows/System.h"
+#endif
+
+#include "../Common/ItemNameUtils.h"
+
+#include "7zHandler.h"
+#include "7zProperties.h"
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+#include "../Common/ParseProperties.h"
+#endif
+#endif
+
+using namespace NWindows;
+
+extern UString ConvertMethodIdToString(UInt64 id);
+
+namespace NArchive {
+namespace N7z {
+
+CHandler::CHandler()
+{
+ _crcSize = 4;
+
+ #ifndef _NO_CRYPTO
+ _passwordIsDefined = false;
+ #endif
+
+ #ifdef EXTRACT_ONLY
+ #ifdef __7Z_SET_PROPERTIES
+ _numThreads = NSystem::GetNumberOfProcessors();
+ #endif
+ #else
+ Init();
+ #endif
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.Files.Size();
+ return S_OK;
+}
+
+#ifdef _SFX
+
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
+ BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
+{
+ return E_NOTIMPL;
+}
+
+
+#else
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidSolid, VT_BOOL},
+ { NULL, kpidNumBlocks, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8}
+};
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ UString resString;
+ CRecordVector<UInt64> ids;
+ int i;
+ for (i = 0; i < _db.Folders.Size(); i++)
+ {
+ const CFolder &f = _db.Folders[i];
+ for (int j = f.Coders.Size() - 1; j >= 0; j--)
+ ids.AddToUniqueSorted(f.Coders[j].MethodID);
+ }
+
+ for (i = 0; i < ids.Size(); i++)
+ {
+ UInt64 id = ids[i];
+ UString methodName;
+ /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
+ if (methodName.IsEmpty())
+ methodName = ConvertMethodIdToString(id);
+ if (!resString.IsEmpty())
+ resString += L' ';
+ resString += methodName;
+ }
+ prop = resString;
+ break;
+ }
+ case kpidSolid: prop = _db.IsSolid(); break;
+ case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break;
+ case kpidHeadersSize: prop = _db.HeadersSize; break;
+ case kpidPhySize: prop = _db.PhySize; break;
+ case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+IMP_IInArchive_ArcProps
+
+#endif
+
+static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop)
+{
+ UInt64 value;
+ if (v.GetItem(index, value))
+ {
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)value;
+ ft.dwHighDateTime = (DWORD)(value >> 32);
+ prop = ft;
+ }
+}
+
+#ifndef _SFX
+
+static UString ConvertUInt32ToString(UInt32 value)
+{
+ wchar_t buffer[32];
+ ConvertUInt64ToString(value, buffer);
+ return buffer;
+}
+
+static UString GetStringForSizeValue(UInt32 value)
+{
+ for (int i = 31; i >= 0; i--)
+ if ((UInt32(1) << i) == value)
+ return ConvertUInt32ToString(i);
+ UString result;
+ if (value % (1 << 20) == 0)
+ {
+ result += ConvertUInt32ToString(value >> 20);
+ result += L"m";
+ }
+ else if (value % (1 << 10) == 0)
+ {
+ result += ConvertUInt32ToString(value >> 10);
+ result += L"k";
+ }
+ else
+ {
+ result += ConvertUInt32ToString(value);
+ result += L"b";
+ }
+ return result;
+}
+
+static const UInt64 k_Copy = 0x0;
+static const UInt64 k_Delta = 3;
+static const UInt64 k_LZMA2 = 0x21;
+static const UInt64 k_LZMA = 0x030101;
+static const UInt64 k_PPMD = 0x030401;
+
+static wchar_t GetHex(Byte value)
+{
+ return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
+}
+static inline void AddHexToString(UString &res, Byte value)
+{
+ res += GetHex((Byte)(value >> 4));
+ res += GetHex((Byte)(value & 0xF));
+}
+
+#endif
+
+bool CHandler::IsEncrypted(UInt32 index2) const
+{
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ return _db.Folders[folderIndex].IsEncrypted();
+ return false;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ /*
+ const CRef2 &ref2 = _refs[index];
+ if (ref2.Refs.IsEmpty())
+ return E_FAIL;
+ const CRef &ref = ref2.Refs.Front();
+ */
+
+ const CFileItem &item = _db.Files[index];
+ UInt32 index2 = index;
+
+ switch(propID)
+ {
+ case kpidPath:
+ if (!item.Name.IsEmpty())
+ prop = NItemName::GetOSName(item.Name);
+ break;
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidSize:
+ {
+ prop = item.Size;
+ // prop = ref2.Size;
+ break;
+ }
+ case kpidPackSize:
+ {
+ // prop = ref2.PackSize;
+ {
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ {
+ if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
+ prop = _db.GetFolderFullPackSize(folderIndex);
+ /*
+ else
+ prop = (UInt64)0;
+ */
+ }
+ else
+ prop = (UInt64)0;
+ }
+ break;
+ }
+ case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; }
+ case kpidCTime: SetPropFromUInt64Def(_db.CTime, index2, prop); break;
+ case kpidATime: SetPropFromUInt64Def(_db.ATime, index2, prop); break;
+ case kpidMTime: SetPropFromUInt64Def(_db.MTime, index2, prop); break;
+ case kpidAttrib: if (item.AttribDefined) prop = item.Attrib; break;
+ case kpidCRC: if (item.CrcDefined) prop = item.Crc; break;
+ case kpidEncrypted: prop = IsEncrypted(index2); break;
+ case kpidIsAnti: prop = _db.IsItemAnti(index2); break;
+ #ifndef _SFX
+ case kpidMethod:
+ {
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ {
+ const CFolder &folderInfo = _db.Folders[folderIndex];
+ UString methodsString;
+ for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
+ {
+ const CCoderInfo &coder = folderInfo.Coders[i];
+ if (!methodsString.IsEmpty())
+ methodsString += L' ';
+
+ UString methodName, propsString;
+ bool methodIsKnown = FindMethod(
+ EXTERNAL_CODECS_VARS
+ coder.MethodID, methodName);
+
+ if (!methodIsKnown)
+ methodsString += ConvertMethodIdToString(coder.MethodID);
+ else
+ {
+ methodsString += methodName;
+ if (coder.MethodID == k_Delta && coder.Props.GetCapacity() == 1)
+ propsString = ConvertUInt32ToString((UInt32)coder.Props[0] + 1);
+ else if (coder.MethodID == k_LZMA && coder.Props.GetCapacity() == 5)
+ {
+ UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
+ propsString = GetStringForSizeValue(dicSize);
+ }
+ else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1)
+ {
+ Byte p = coder.Props[0];
+ UInt32 dicSize = (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11));
+ propsString = GetStringForSizeValue(dicSize);
+ }
+ else if (coder.MethodID == k_PPMD && coder.Props.GetCapacity() == 5)
+ {
+ Byte order = *(const Byte *)coder.Props;
+ propsString = L'o';
+ propsString += ConvertUInt32ToString(order);
+ propsString += L":mem";
+ UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
+ propsString += GetStringForSizeValue(dicSize);
+ }
+ else if (coder.MethodID == k_AES && coder.Props.GetCapacity() >= 1)
+ {
+ const Byte *data = (const Byte *)coder.Props;
+ Byte firstByte = *data++;
+ UInt32 numCyclesPower = firstByte & 0x3F;
+ propsString = ConvertUInt32ToString(numCyclesPower);
+ /*
+ if ((firstByte & 0xC0) != 0)
+ {
+ UInt32 saltSize = (firstByte >> 7) & 1;
+ UInt32 ivSize = (firstByte >> 6) & 1;
+ if (coder.Props.GetCapacity() >= 2)
+ {
+ Byte secondByte = *data++;
+ saltSize += (secondByte >> 4);
+ ivSize += (secondByte & 0x0F);
+ }
+ }
+ */
+ }
+ }
+ if (!propsString.IsEmpty())
+ {
+ methodsString += L':';
+ methodsString += propsString;
+ }
+ else if (coder.Props.GetCapacity() > 0)
+ {
+ methodsString += L":[";
+ for (size_t bi = 0; bi < coder.Props.GetCapacity(); bi++)
+ {
+ if (bi > 5 && bi + 1 < coder.Props.GetCapacity())
+ {
+ methodsString += L"..";
+ break;
+ }
+ else
+ AddHexToString(methodsString, coder.Props[bi]);
+ }
+ methodsString += L']';
+ }
+ }
+ prop = methodsString;
+ }
+ }
+ break;
+ case kpidBlock:
+ {
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ prop = (UInt32)folderIndex;
+ }
+ break;
+ case kpidPackedSize0:
+ case kpidPackedSize1:
+ case kpidPackedSize2:
+ case kpidPackedSize3:
+ case kpidPackedSize4:
+ {
+ CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ {
+ const CFolder &folderInfo = _db.Folders[folderIndex];
+ if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
+ folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
+ {
+ prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
+ }
+ else
+ prop = (UInt64)0;
+ }
+ else
+ prop = (UInt64)0;
+ }
+ break;
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ Close();
+ #ifndef _SFX
+ _fileInfoPopIDs.Clear();
+ #endif
+ try
+ {
+ CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
+
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ if (openArchiveCallback)
+ {
+ openArchiveCallbackTemp.QueryInterface(
+ IID_ICryptoGetTextPassword, &getTextPassword);
+ }
+ #endif
+ CInArchive archive;
+ RINOK(archive.Open(stream, maxCheckStartPosition));
+ #ifndef _NO_CRYPTO
+ _passwordIsDefined = false;
+ UString password;
+ #endif
+ HRESULT result = archive.ReadDatabase(
+ EXTERNAL_CODECS_VARS
+ _db
+ #ifndef _NO_CRYPTO
+ , getTextPassword, _passwordIsDefined
+ #endif
+ );
+ RINOK(result);
+ _db.Fill();
+ _inStream = stream;
+ }
+ catch(...)
+ {
+ Close();
+ return S_FALSE;
+ }
+ // _inStream = stream;
+ #ifndef _SFX
+ FillPopIDs();
+ #endif
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ COM_TRY_BEGIN
+ _inStream.Release();
+ _db.Clear();
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifdef __7Z_SET_PROPERTIES
+#ifdef EXTRACT_ONLY
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+ COM_TRY_BEGIN
+ const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+ _numThreads = numProcessors;
+
+ for (int i = 0; i < numProperties; i++)
+ {
+ UString name = names[i];
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &value = values[i];
+ UInt32 number;
+ int index = ParseStringToUInt32(name, number);
+ if (index == 0)
+ {
+ if(name.Left(2).CompareNoCase(L"MT") == 0)
+ {
+ RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
+ continue;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+#endif
+#endif
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.h
new file mode 100644
index 000000000..56062d464
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.h
@@ -0,0 +1,119 @@
+// 7z/Handler.h
+
+#ifndef __7Z_HANDLER_H
+#define __7Z_HANDLER_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#ifndef EXTRACT_ONLY
+#include "../Common/HandlerOut.h"
+#endif
+
+#include "7zCompressionMode.h"
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+#ifndef __7Z_SET_PROPERTIES
+
+#ifdef EXTRACT_ONLY
+#if !defined(_7ZIP_ST) && !defined(_SFX)
+#define __7Z_SET_PROPERTIES
+#endif
+#else
+#define __7Z_SET_PROPERTIES
+#endif
+
+#endif
+
+
+class CHandler:
+ #ifndef EXTRACT_ONLY
+ public NArchive::COutHandler,
+ #endif
+ public IInArchive,
+ #ifdef __7Z_SET_PROPERTIES
+ public ISetProperties,
+ #endif
+ #ifndef EXTRACT_ONLY
+ public IOutArchive,
+ #endif
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ #ifdef __7Z_SET_PROPERTIES
+ MY_QUERYINTERFACE_ENTRY(ISetProperties)
+ #endif
+ #ifndef EXTRACT_ONLY
+ MY_QUERYINTERFACE_ENTRY(IOutArchive)
+ #endif
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+
+ #ifdef __7Z_SET_PROPERTIES
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+ #endif
+
+ #ifndef EXTRACT_ONLY
+ INTERFACE_IOutArchive(;)
+ #endif
+
+ DECL_ISetCompressCodecsInfo
+
+ CHandler();
+
+private:
+ CMyComPtr<IInStream> _inStream;
+ NArchive::N7z::CArchiveDatabaseEx _db;
+ #ifndef _NO_CRYPTO
+ bool _passwordIsDefined;
+ #endif
+
+ #ifdef EXTRACT_ONLY
+
+ #ifdef __7Z_SET_PROPERTIES
+ UInt32 _numThreads;
+ #endif
+
+ UInt32 _crcSize;
+
+ #else
+
+ CRecordVector<CBind> _binds;
+
+ HRESULT SetCompressionMethod(CCompressionMethodMode &method,
+ CObjectVector<COneMethodInfo> &methodsInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ );
+
+ HRESULT SetCompressionMethod(
+ CCompressionMethodMode &method,
+ CCompressionMethodMode &headerMethod);
+
+ #endif
+
+ bool IsEncrypted(UInt32 index2) const;
+ #ifndef _SFX
+
+ CRecordVector<UInt64> _fileInfoPopIDs;
+ void FillPopIDs();
+
+ #endif
+
+ DECL_EXTERNAL_CODECS_VARS
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandlerOut.cpp
new file mode 100644
index 000000000..a8ccab6df
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandlerOut.cpp
@@ -0,0 +1,483 @@
+// 7zHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../ICoder.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/ParseProperties.h"
+
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace N7z {
+
+static const wchar_t *kLZMAMethodName = L"LZMA";
+static const wchar_t *kCopyMethod = L"Copy";
+static const wchar_t *kDefaultMethodName = kLZMAMethodName;
+
+static const UInt32 kLzmaAlgorithmX5 = 1;
+static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
+static const UInt32 kDictionaryForHeaders =
+ #ifdef UNDER_CE
+ 1 << 18
+ #else
+ 1 << 20
+ #endif
+;
+static const UInt32 kNumFastBytesForHeaders = 273;
+static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5;
+
+static inline bool IsCopyMethod(const UString &methodName)
+ { return (methodName.CompareNoCase(kCopyMethod) == 0); }
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+{
+ *type = NFileTimeType::kWindows;
+ return S_OK;
+}
+
+HRESULT CHandler::SetCompressionMethod(
+ CCompressionMethodMode &methodMode,
+ CCompressionMethodMode &headerMethod)
+{
+ HRESULT res = SetCompressionMethod(methodMode, _methods
+ #ifndef _7ZIP_ST
+ , _numThreads
+ #endif
+ );
+ RINOK(res);
+ methodMode.Binds = _binds;
+
+ if (_compressHeaders)
+ {
+ // headerMethod.Methods.Add(methodMode.Methods.Back());
+
+ CObjectVector<COneMethodInfo> headerMethodInfoVector;
+ COneMethodInfo oneMethodInfo;
+ oneMethodInfo.MethodName = kLZMAMethodName;
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kMatchFinder;
+ prop.Value = kLzmaMatchFinderForHeaders;
+ oneMethodInfo.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kAlgorithm;
+ prop.Value = kAlgorithmForHeaders;
+ oneMethodInfo.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kNumFastBytes;
+ prop.Value = (UInt32)kNumFastBytesForHeaders;
+ oneMethodInfo.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kDictionarySize;
+ prop.Value = (UInt32)kDictionaryForHeaders;
+ oneMethodInfo.Props.Add(prop);
+ }
+ headerMethodInfoVector.Add(oneMethodInfo);
+ HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector
+ #ifndef _7ZIP_ST
+ , 1
+ #endif
+ );
+ RINOK(res);
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::SetCompressionMethod(
+ CCompressionMethodMode &methodMode,
+ CObjectVector<COneMethodInfo> &methodsInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ )
+{
+ UInt32 level = _level;
+
+ if (methodsInfo.IsEmpty())
+ {
+ COneMethodInfo oneMethodInfo;
+ oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName);
+ methodsInfo.Add(oneMethodInfo);
+ }
+
+ bool needSolid = false;
+ for(int i = 0; i < methodsInfo.Size(); i++)
+ {
+ COneMethodInfo &oneMethodInfo = methodsInfo[i];
+ SetCompressionMethod2(oneMethodInfo
+ #ifndef _7ZIP_ST
+ , numThreads
+ #endif
+ );
+
+ if (!IsCopyMethod(oneMethodInfo.MethodName))
+ needSolid = true;
+
+ CMethodFull methodFull;
+
+ if (!FindMethod(
+ EXTERNAL_CODECS_VARS
+ oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams))
+ return E_INVALIDARG;
+ methodFull.Props = oneMethodInfo.Props;
+ methodMode.Methods.Add(methodFull);
+
+ if (!_numSolidBytesDefined)
+ {
+ for (int j = 0; j < methodFull.Props.Size(); j++)
+ {
+ const CProp &prop = methodFull.Props[j];
+ if ((prop.Id == NCoderPropID::kDictionarySize ||
+ prop.Id == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4)
+ {
+ _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7;
+ const UInt64 kMinSize = (1 << 24);
+ if (_numSolidBytes < kMinSize)
+ _numSolidBytes = kMinSize;
+ _numSolidBytesDefined = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!needSolid && !_numSolidBytesDefined)
+ {
+ _numSolidBytesDefined = true;
+ _numSolidBytes = 0;
+ }
+ return S_OK;
+}
+
+static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool writeTime, PROPID propID, UInt64 &ft, bool &ftDefined)
+{
+ ft = 0;
+ ftDefined = false;
+ if (!writeTime)
+ return S_OK;
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ {
+ ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
+ ftDefined = true;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ COM_TRY_BEGIN
+
+ const CArchiveDatabaseEx *db = 0;
+ #ifdef _7Z_VOL
+ if (_volumes.Size() > 1)
+ return E_FAIL;
+ const CVolume *volume = 0;
+ if (_volumes.Size() == 1)
+ {
+ volume = &_volumes.Front();
+ db = &volume->Database;
+ }
+ #else
+ if (_inStream != 0)
+ db = &_db;
+ #endif
+
+ CObjectVector<CUpdateItem> updateItems;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+ CUpdateItem ui;
+ ui.NewProps = IntToBool(newProps);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArchive = indexInArchive;
+ ui.IndexInClient = i;
+ ui.IsAnti = false;
+ ui.Size = 0;
+
+ if (ui.IndexInArchive != -1)
+ {
+ if (db == 0 || ui.IndexInArchive >= db->Files.Size())
+ return E_INVALIDARG;
+ const CFileItem &fi = db->Files[ui.IndexInArchive];
+ ui.Name = fi.Name;
+ ui.IsDir = fi.IsDir;
+ ui.Size = fi.Size;
+ ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);
+
+ ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);
+ ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);
+ ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
+ }
+
+ if (ui.NewProps)
+ {
+ bool nameIsDefined;
+ bool folderStatusIsDefined;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.AttribDefined = false;
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ {
+ ui.Attrib = prop.ulVal;
+ ui.AttribDefined = true;
+ }
+ }
+
+ // we need MTime to sort files.
+ RINOK(GetTime(updateCallback, i, WriteCTime, kpidCTime, ui.CTime, ui.CTimeDefined));
+ RINOK(GetTime(updateCallback, i, WriteATime, kpidATime, ui.ATime, ui.ATimeDefined));
+ RINOK(GetTime(updateCallback, i, true, kpidMTime, ui.MTime, ui.MTimeDefined));
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidPath, &prop));
+ if (prop.vt == VT_EMPTY)
+ nameIsDefined = false;
+ else if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ else
+ {
+ ui.Name = NItemName::MakeLegalName(prop.bstrVal);
+ nameIsDefined = true;
+ }
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop));
+ if (prop.vt == VT_EMPTY)
+ folderStatusIsDefined = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ {
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ folderStatusIsDefined = true;
+ }
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.IsAnti = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ if (ui.IsAnti)
+ {
+ ui.AttribDefined = false;
+
+ ui.CTimeDefined = false;
+ ui.ATimeDefined = false;
+ ui.MTimeDefined = false;
+
+ ui.Size = 0;
+ }
+
+ if (!folderStatusIsDefined && ui.AttribDefined)
+ ui.SetDirStatusFromAttrib();
+ }
+
+ if (ui.NewData)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ ui.Size = (UInt64)prop.uhVal.QuadPart;
+ if (ui.Size != 0 && ui.IsAnti)
+ return E_INVALIDARG;
+ }
+ updateItems.Add(ui);
+ }
+
+ CCompressionMethodMode methodMode, headerMethod;
+ RINOK(SetCompressionMethod(methodMode, headerMethod));
+ #ifndef _7ZIP_ST
+ methodMode.NumThreads = _numThreads;
+ headerMethod.NumThreads = 1;
+ #endif
+
+ CMyComPtr<ICryptoGetTextPassword2> getPassword2;
+ updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
+
+ if (getPassword2)
+ {
+ CMyComBSTR password;
+ Int32 passwordIsDefined;
+ RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
+ methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
+ if (methodMode.PasswordIsDefined)
+ methodMode.Password = password;
+ }
+ else
+ methodMode.PasswordIsDefined = false;
+
+ bool compressMainHeader = _compressHeaders; // check it
+
+ bool encryptHeaders = false;
+
+ if (methodMode.PasswordIsDefined)
+ {
+ if (_encryptHeadersSpecified)
+ encryptHeaders = _encryptHeaders;
+ #ifndef _NO_CRYPTO
+ else
+ encryptHeaders = _passwordIsDefined;
+ #endif
+ compressMainHeader = true;
+ if (encryptHeaders)
+ {
+ headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
+ headerMethod.Password = methodMode.Password;
+ }
+ }
+
+ if (numItems < 2)
+ compressMainHeader = false;
+
+ CUpdateOptions options;
+ options.Method = &methodMode;
+ options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0;
+ options.UseFilters = _level != 0 && _autoFilter;
+ options.MaxFilter = _level >= 8;
+
+ options.HeaderOptions.CompressMainHeader = compressMainHeader;
+ options.HeaderOptions.WriteCTime = WriteCTime;
+ options.HeaderOptions.WriteATime = WriteATime;
+ options.HeaderOptions.WriteMTime = WriteMTime;
+
+ options.NumSolidFiles = _numSolidFiles;
+ options.NumSolidBytes = _numSolidBytes;
+ options.SolidExtension = _solidExtension;
+ options.RemoveSfxBlock = _removeSfxBlock;
+ options.VolumeMode = _volumeMode;
+
+ COutArchive archive;
+ CArchiveDatabase newDatabase;
+
+ CMyComPtr<ICryptoGetTextPassword> getPassword;
+ updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
+
+ HRESULT res = Update(
+ EXTERNAL_CODECS_VARS
+ #ifdef _7Z_VOL
+ volume ? volume->Stream: 0,
+ volume ? db : 0,
+ #else
+ _inStream,
+ db,
+ #endif
+ updateItems,
+ archive, newDatabase, outStream, updateCallback, options
+ #ifndef _NO_CRYPTO
+ , getPassword
+ #endif
+ );
+
+ RINOK(res);
+
+ updateItems.ClearAndFree();
+
+ return archive.WriteDatabase(EXTERNAL_CODECS_VARS
+ newDatabase, options.HeaderMethod, options.HeaderOptions);
+
+ COM_TRY_END
+}
+
+static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
+{
+ stream = 0;
+ int index = ParseStringToUInt32(srcString, coder);
+ if (index == 0)
+ return E_INVALIDARG;
+ srcString.Delete(0, index);
+ if (srcString[0] == 'S')
+ {
+ srcString.Delete(0);
+ int index = ParseStringToUInt32(srcString, stream);
+ if (index == 0)
+ return E_INVALIDARG;
+ srcString.Delete(0, index);
+ }
+ return S_OK;
+}
+
+static HRESULT GetBindInfo(UString &srcString, CBind &bind)
+{
+ RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream));
+ if (srcString[0] != ':')
+ return E_INVALIDARG;
+ srcString.Delete(0);
+ RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream));
+ if (!srcString.IsEmpty())
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+ COM_TRY_BEGIN
+ _binds.Clear();
+ BeforeSetProperty();
+
+ for (int i = 0; i < numProperties; i++)
+ {
+ UString name = names[i];
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &value = values[i];
+
+ if (name[0] == 'B')
+ {
+ name.Delete(0);
+ CBind bind;
+ RINOK(GetBindInfo(name, bind));
+ _binds.Add(bind);
+ continue;
+ }
+
+ RINOK(SetProperty(name, value));
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.cpp
new file mode 100644
index 000000000..5b5f2fb37
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.cpp
@@ -0,0 +1,14 @@
+// 7zHeader.cpp
+
+#include "StdAfx.h"
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+#ifdef _7Z_VOL
+Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1};
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.h
new file mode 100644
index 000000000..30622b90e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.h
@@ -0,0 +1,97 @@
+// 7z/7zHeader.h
+
+#ifndef __7Z_HEADER_H
+#define __7Z_HEADER_H
+
+#include "../../../Common/Types.h"
+
+namespace NArchive {
+namespace N7z {
+
+const int kSignatureSize = 6;
+extern Byte kSignature[kSignatureSize];
+
+// #define _7Z_VOL
+// 7z-MultiVolume is not finished yet.
+// It can work already, but I still do not like some
+// things of that new multivolume format.
+// So please keep it commented.
+
+#ifdef _7Z_VOL
+extern Byte kFinishSignature[kSignatureSize];
+#endif
+
+struct CArchiveVersion
+{
+ Byte Major;
+ Byte Minor;
+};
+
+const Byte kMajorVersion = 0;
+
+struct CStartHeader
+{
+ UInt64 NextHeaderOffset;
+ UInt64 NextHeaderSize;
+ UInt32 NextHeaderCRC;
+};
+
+const UInt32 kStartHeaderSize = 20;
+
+#ifdef _7Z_VOL
+struct CFinishHeader: public CStartHeader
+{
+ UInt64 ArchiveStartOffset; // data offset from end if that struct
+ UInt64 AdditionalStartBlockSize; // start signature & start header size
+};
+
+const UInt32 kFinishHeaderSize = kStartHeaderSize + 16;
+#endif
+
+namespace NID
+{
+ enum EEnum
+ {
+ kEnd,
+
+ kHeader,
+
+ kArchiveProperties,
+
+ kAdditionalStreamsInfo,
+ kMainStreamsInfo,
+ kFilesInfo,
+
+ kPackInfo,
+ kUnpackInfo,
+ kSubStreamsInfo,
+
+ kSize,
+ kCRC,
+
+ kFolder,
+
+ kCodersUnpackSize,
+ kNumUnpackStream,
+
+ kEmptyStream,
+ kEmptyFile,
+ kAnti,
+
+ kName,
+ kCTime,
+ kATime,
+ kMTime,
+ kWinAttributes,
+ kComment,
+
+ kEncodedHeader,
+
+ kStartPos,
+ kDummy
+ };
+}
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.cpp
new file mode 100644
index 000000000..0feb81d2c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.cpp
@@ -0,0 +1,1276 @@
+// 7zIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "7zDecode.h"
+#include "7zIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+// define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader
+#ifndef _SFX
+#define FORMAT_7Z_RECOVERY
+#endif
+
+namespace NArchive {
+namespace N7z {
+
+static void BoolVector_Fill_False(CBoolVector &v, int size)
+{
+ v.Clear();
+ v.Reserve(size);
+ for (int i = 0; i < size; i++)
+ v.Add(false);
+}
+
+static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index)
+{
+ if (index >= (UInt32)v.Size())
+ return true;
+ bool res = v[index];
+ v[index] = true;
+ return res;
+}
+
+bool CFolder::CheckStructure() const
+{
+ const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it
+ const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax
+ const int kNumBindsMax = 32;
+
+ if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax)
+ return false;
+
+ {
+ CBoolVector v;
+ BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size());
+
+ int i;
+ for (i = 0; i < BindPairs.Size(); i++)
+ if (BoolVector_GetAndSet(v, BindPairs[i].InIndex))
+ return false;
+ for (i = 0; i < PackStreams.Size(); i++)
+ if (BoolVector_GetAndSet(v, PackStreams[i]))
+ return false;
+
+ BoolVector_Fill_False(v, UnpackSizes.Size());
+ for (i = 0; i < BindPairs.Size(); i++)
+ if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex))
+ return false;
+ }
+
+ UInt32 mask[kMaskSize];
+ int i;
+ for (i = 0; i < kMaskSize; i++)
+ mask[i] = 0;
+
+ {
+ CIntVector inStreamToCoder, outStreamToCoder;
+ for (i = 0; i < Coders.Size(); i++)
+ {
+ CNum j;
+ const CCoderInfo &coder = Coders[i];
+ for (j = 0; j < coder.NumInStreams; j++)
+ inStreamToCoder.Add(i);
+ for (j = 0; j < coder.NumOutStreams; j++)
+ outStreamToCoder.Add(i);
+ }
+
+ for (i = 0; i < BindPairs.Size(); i++)
+ {
+ const CBindPair &bp = BindPairs[i];
+ mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]);
+ }
+ }
+
+ for (i = 0; i < kMaskSize; i++)
+ for (int j = 0; j < kMaskSize; j++)
+ if (((1 << j) & mask[i]) != 0)
+ mask[i] |= mask[j];
+
+ for (i = 0; i < kMaskSize; i++)
+ if (((1 << i) & mask[i]) != 0)
+ return false;
+
+ return true;
+}
+
+class CInArchiveException {};
+
+static void ThrowException() { throw CInArchiveException(); }
+static inline void ThrowEndOfData() { ThrowException(); }
+static inline void ThrowUnsupported() { ThrowException(); }
+static inline void ThrowIncorrect() { ThrowException(); }
+static inline void ThrowUnsupportedVersion() { ThrowException(); }
+
+/*
+class CInArchiveException
+{
+public:
+ enum CCauseType
+ {
+ kUnsupportedVersion = 0,
+ kUnsupported,
+ kIncorrect,
+ kEndOfData
+ } Cause;
+ CInArchiveException(CCauseType cause): Cause(cause) {};
+};
+
+static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
+static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); }
+static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
+static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); }
+static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
+*/
+
+class CStreamSwitch
+{
+ CInArchive *_archive;
+ bool _needRemove;
+public:
+ CStreamSwitch(): _needRemove(false) {}
+ ~CStreamSwitch() { Remove(); }
+ void Remove();
+ void Set(CInArchive *archive, const Byte *data, size_t size);
+ void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
+ void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
+};
+
+void CStreamSwitch::Remove()
+{
+ if (_needRemove)
+ {
+ _archive->DeleteByteStream();
+ _needRemove = false;
+ }
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
+{
+ Remove();
+ _archive = archive;
+ _archive->AddByteStream(data, size);
+ _needRemove = true;
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
+{
+ Set(archive, byteBuffer, byteBuffer.GetCapacity());
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
+{
+ Remove();
+ Byte external = archive->ReadByte();
+ if (external != 0)
+ {
+ int dataIndex = (int)archive->ReadNum();
+ if (dataIndex < 0 || dataIndex >= dataVector->Size())
+ ThrowIncorrect();
+ Set(archive, (*dataVector)[dataIndex]);
+ }
+}
+
+Byte CInByte2::ReadByte()
+{
+ if (_pos >= _size)
+ ThrowEndOfData();
+ return _buffer[_pos++];
+}
+
+void CInByte2::ReadBytes(Byte *data, size_t size)
+{
+ if (size > _size - _pos)
+ ThrowEndOfData();
+ for (size_t i = 0; i < size; i++)
+ data[i] = _buffer[_pos++];
+}
+
+void CInByte2::SkipData(UInt64 size)
+{
+ if (size > _size - _pos)
+ ThrowEndOfData();
+ _pos += (size_t)size;
+}
+
+void CInByte2::SkipData()
+{
+ SkipData(ReadNumber());
+}
+
+UInt64 CInByte2::ReadNumber()
+{
+ if (_pos >= _size)
+ ThrowEndOfData();
+ Byte firstByte = _buffer[_pos++];
+ Byte mask = 0x80;
+ UInt64 value = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if ((firstByte & mask) == 0)
+ {
+ UInt64 highPart = firstByte & (mask - 1);
+ value += (highPart << (i * 8));
+ return value;
+ }
+ if (_pos >= _size)
+ ThrowEndOfData();
+ value |= ((UInt64)_buffer[_pos++] << (8 * i));
+ mask >>= 1;
+ }
+ return value;
+}
+
+CNum CInByte2::ReadNum()
+{
+ UInt64 value = ReadNumber();
+ if (value > kNumMax)
+ ThrowUnsupported();
+ return (CNum)value;
+}
+
+UInt32 CInByte2::ReadUInt32()
+{
+ if (_pos + 4 > _size)
+ ThrowEndOfData();
+ UInt32 res = Get32(_buffer + _pos);
+ _pos += 4;
+ return res;
+}
+
+UInt64 CInByte2::ReadUInt64()
+{
+ if (_pos + 8 > _size)
+ ThrowEndOfData();
+ UInt64 res = Get64(_buffer + _pos);
+ _pos += 8;
+ return res;
+}
+
+void CInByte2::ReadString(UString &s)
+{
+ const Byte *buf = _buffer + _pos;
+ size_t rem = (_size - _pos) / 2 * 2;
+ {
+ size_t i;
+ for (i = 0; i < rem; i += 2)
+ if (buf[i] == 0 && buf[i + 1] == 0)
+ break;
+ if (i == rem)
+ ThrowEndOfData();
+ rem = i;
+ }
+ int len = (int)(rem / 2);
+ if (len < 0 || (size_t)len * 2 != rem)
+ ThrowUnsupported();
+ wchar_t *p = s.GetBuffer(len);
+ int i;
+ for (i = 0; i < len; i++, buf += 2)
+ p[i] = (wchar_t)Get16(buf);
+ s.ReleaseBuffer(len);
+ _pos += rem + 2;
+}
+
+static inline bool TestSignature(const Byte *p)
+{
+ for (int i = 0; i < kSignatureSize; i++)
+ if (p[i] != kSignature[i])
+ return false;
+ return CrcCalc(p + 12, 20) == GetUi32(p + 8);
+}
+
+#ifdef FORMAT_7Z_RECOVERY
+static inline bool TestSignature2(const Byte *p)
+{
+ int i;
+ for (i = 0; i < kSignatureSize; i++)
+ if (p[i] != kSignature[i])
+ return false;
+ if (CrcCalc(p + 12, 20) == GetUi32(p + 8))
+ return true;
+ for (i = 8; i < kHeaderSize; i++)
+ if (p[i] != 0)
+ return false;
+ return (p[6] != 0 || p[7] != 0);
+}
+#else
+#define TestSignature2(p) TestSignature(p)
+#endif
+
+HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ RINOK(ReadStream_FALSE(stream, _header, kHeaderSize));
+
+ if (TestSignature2(_header))
+ return S_OK;
+
+ CByteBuffer byteBuffer;
+ const UInt32 kBufferSize = (1 << 16);
+ byteBuffer.SetCapacity(kBufferSize);
+ Byte *buffer = byteBuffer;
+ UInt32 numPrevBytes = kHeaderSize;
+ memcpy(buffer, _header, kHeaderSize);
+ UInt64 curTestPos = _arhiveBeginStreamPosition;
+ for (;;)
+ {
+ if (searchHeaderSizeLimit != NULL)
+ if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
+ break;
+ do
+ {
+ UInt32 numReadBytes = kBufferSize - numPrevBytes;
+ UInt32 processedSize;
+ RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
+ numPrevBytes += processedSize;
+ if (processedSize == 0)
+ return S_FALSE;
+ }
+ while (numPrevBytes <= kHeaderSize);
+ UInt32 numTests = numPrevBytes - kHeaderSize;
+ for (UInt32 pos = 0; pos < numTests; pos++)
+ {
+ for (; buffer[pos] != '7' && pos < numTests; pos++);
+ if (pos == numTests)
+ break;
+ if (TestSignature(buffer + pos))
+ {
+ memcpy(_header, buffer + pos, kHeaderSize);
+ curTestPos += pos;
+ _arhiveBeginStreamPosition = curTestPos;
+ return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
+ }
+ }
+ curTestPos += numTests;
+ numPrevBytes -= numTests;
+ memmove(buffer, buffer + numTests, numPrevBytes);
+ }
+ return S_FALSE;
+}
+
+// S_FALSE means that file is not archive
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ HeadersSize = 0;
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
+ RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
+ _stream = stream;
+ return S_OK;
+}
+
+void CInArchive::Close()
+{
+ _stream.Release();
+}
+
+void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
+{
+ for (;;)
+ {
+ if (ReadID() == NID::kEnd)
+ break;
+ SkipData();
+ }
+}
+
+void CInArchive::GetNextFolderItem(CFolder &folder)
+{
+ CNum numCoders = ReadNum();
+
+ folder.Coders.Clear();
+ folder.Coders.Reserve((int)numCoders);
+ CNum numInStreams = 0;
+ CNum numOutStreams = 0;
+ CNum i;
+ for (i = 0; i < numCoders; i++)
+ {
+ folder.Coders.Add(CCoderInfo());
+ CCoderInfo &coder = folder.Coders.Back();
+
+ {
+ Byte mainByte = ReadByte();
+ int idSize = (mainByte & 0xF);
+ Byte longID[15];
+ ReadBytes(longID, idSize);
+ if (idSize > 8)
+ ThrowUnsupported();
+ UInt64 id = 0;
+ for (int j = 0; j < idSize; j++)
+ id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
+ coder.MethodID = id;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ coder.NumInStreams = ReadNum();
+ coder.NumOutStreams = ReadNum();
+ }
+ else
+ {
+ coder.NumInStreams = 1;
+ coder.NumOutStreams = 1;
+ }
+ if ((mainByte & 0x20) != 0)
+ {
+ CNum propsSize = ReadNum();
+ coder.Props.SetCapacity((size_t)propsSize);
+ ReadBytes((Byte *)coder.Props, (size_t)propsSize);
+ }
+ if ((mainByte & 0x80) != 0)
+ ThrowUnsupported();
+ }
+ numInStreams += coder.NumInStreams;
+ numOutStreams += coder.NumOutStreams;
+ }
+
+ CNum numBindPairs = numOutStreams - 1;
+ folder.BindPairs.Clear();
+ folder.BindPairs.Reserve(numBindPairs);
+ for (i = 0; i < numBindPairs; i++)
+ {
+ CBindPair bp;
+ bp.InIndex = ReadNum();
+ bp.OutIndex = ReadNum();
+ folder.BindPairs.Add(bp);
+ }
+
+ if (numInStreams < numBindPairs)
+ ThrowUnsupported();
+ CNum numPackStreams = numInStreams - numBindPairs;
+ folder.PackStreams.Reserve(numPackStreams);
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams; i++)
+ if (folder.FindBindPairForInStream(i) < 0)
+ {
+ folder.PackStreams.Add(i);
+ break;
+ }
+ if (folder.PackStreams.Size() != 1)
+ ThrowUnsupported();
+ }
+ else
+ for (i = 0; i < numPackStreams; i++)
+ folder.PackStreams.Add(ReadNum());
+}
+
+void CInArchive::WaitAttribute(UInt64 attribute)
+{
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type == attribute)
+ return;
+ if (type == NID::kEnd)
+ ThrowIncorrect();
+ SkipData();
+ }
+}
+
+void CInArchive::ReadHashDigests(int numItems,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests)
+{
+ ReadBoolVector2(numItems, digestsDefined);
+ digests.Clear();
+ digests.Reserve(numItems);
+ for (int i = 0; i < numItems; i++)
+ {
+ UInt32 crc = 0;
+ if (digestsDefined[i])
+ crc = ReadUInt32();
+ digests.Add(crc);
+ }
+}
+
+void CInArchive::ReadPackInfo(
+ UInt64 &dataOffset,
+ CRecordVector<UInt64> &packSizes,
+ CBoolVector &packCRCsDefined,
+ CRecordVector<UInt32> &packCRCs)
+{
+ dataOffset = ReadNumber();
+ CNum numPackStreams = ReadNum();
+
+ WaitAttribute(NID::kSize);
+ packSizes.Clear();
+ packSizes.Reserve(numPackStreams);
+ for (CNum i = 0; i < numPackStreams; i++)
+ packSizes.Add(ReadNumber());
+
+ UInt64 type;
+ for (;;)
+ {
+ type = ReadID();
+ if (type == NID::kEnd)
+ break;
+ if (type == NID::kCRC)
+ {
+ ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs);
+ continue;
+ }
+ SkipData();
+ }
+ if (packCRCsDefined.IsEmpty())
+ {
+ BoolVector_Fill_False(packCRCsDefined, numPackStreams);
+ packCRCs.Reserve(numPackStreams);
+ packCRCs.Clear();
+ for (CNum i = 0; i < numPackStreams; i++)
+ packCRCs.Add(0);
+ }
+}
+
+void CInArchive::ReadUnpackInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ CObjectVector<CFolder> &folders)
+{
+ WaitAttribute(NID::kFolder);
+ CNum numFolders = ReadNum();
+
+ {
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, dataVector);
+ folders.Clear();
+ folders.Reserve(numFolders);
+ for (CNum i = 0; i < numFolders; i++)
+ {
+ folders.Add(CFolder());
+ GetNextFolderItem(folders.Back());
+ }
+ }
+
+ WaitAttribute(NID::kCodersUnpackSize);
+
+ CNum i;
+ for (i = 0; i < numFolders; i++)
+ {
+ CFolder &folder = folders[i];
+ CNum numOutStreams = folder.GetNumOutStreams();
+ folder.UnpackSizes.Reserve(numOutStreams);
+ for (CNum j = 0; j < numOutStreams; j++)
+ folder.UnpackSizes.Add(ReadNumber());
+ }
+
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type == NID::kEnd)
+ return;
+ if (type == NID::kCRC)
+ {
+ CBoolVector crcsDefined;
+ CRecordVector<UInt32> crcs;
+ ReadHashDigests(numFolders, crcsDefined, crcs);
+ for (i = 0; i < numFolders; i++)
+ {
+ CFolder &folder = folders[i];
+ folder.UnpackCRCDefined = crcsDefined[i];
+ folder.UnpackCRC = crcs[i];
+ }
+ continue;
+ }
+ SkipData();
+ }
+}
+
+void CInArchive::ReadSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CRecordVector<UInt64> &unpackSizes,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests)
+{
+ numUnpackStreamsInFolders.Clear();
+ numUnpackStreamsInFolders.Reserve(folders.Size());
+ UInt64 type;
+ for (;;)
+ {
+ type = ReadID();
+ if (type == NID::kNumUnpackStream)
+ {
+ for (int i = 0; i < folders.Size(); i++)
+ numUnpackStreamsInFolders.Add(ReadNum());
+ continue;
+ }
+ if (type == NID::kCRC || type == NID::kSize)
+ break;
+ if (type == NID::kEnd)
+ break;
+ SkipData();
+ }
+
+ if (numUnpackStreamsInFolders.IsEmpty())
+ for (int i = 0; i < folders.Size(); i++)
+ numUnpackStreamsInFolders.Add(1);
+
+ int i;
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ {
+ // v3.13 incorrectly worked with empty folders
+ // v4.07: we check that folder is empty
+ CNum numSubstreams = numUnpackStreamsInFolders[i];
+ if (numSubstreams == 0)
+ continue;
+ UInt64 sum = 0;
+ for (CNum j = 1; j < numSubstreams; j++)
+ if (type == NID::kSize)
+ {
+ UInt64 size = ReadNumber();
+ unpackSizes.Add(size);
+ sum += size;
+ }
+ unpackSizes.Add(folders[i].GetUnpackSize() - sum);
+ }
+ if (type == NID::kSize)
+ type = ReadID();
+
+ int numDigests = 0;
+ int numDigestsTotal = 0;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ CNum numSubstreams = numUnpackStreamsInFolders[i];
+ if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
+ numDigests += numSubstreams;
+ numDigestsTotal += numSubstreams;
+ }
+
+ for (;;)
+ {
+ if (type == NID::kCRC)
+ {
+ CBoolVector digestsDefined2;
+ CRecordVector<UInt32> digests2;
+ ReadHashDigests(numDigests, digestsDefined2, digests2);
+ int digestIndex = 0;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ CNum numSubstreams = numUnpackStreamsInFolders[i];
+ const CFolder &folder = folders[i];
+ if (numSubstreams == 1 && folder.UnpackCRCDefined)
+ {
+ digestsDefined.Add(true);
+ digests.Add(folder.UnpackCRC);
+ }
+ else
+ for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
+ {
+ digestsDefined.Add(digestsDefined2[digestIndex]);
+ digests.Add(digests2[digestIndex]);
+ }
+ }
+ }
+ else if (type == NID::kEnd)
+ {
+ if (digestsDefined.IsEmpty())
+ {
+ BoolVector_Fill_False(digestsDefined, numDigestsTotal);
+ digests.Clear();
+ for (int i = 0; i < numDigestsTotal; i++)
+ digests.Add(0);
+ }
+ return;
+ }
+ else
+ SkipData();
+ type = ReadID();
+ }
+}
+
+void CInArchive::ReadStreamsInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ UInt64 &dataOffset,
+ CRecordVector<UInt64> &packSizes,
+ CBoolVector &packCRCsDefined,
+ CRecordVector<UInt32> &packCRCs,
+ CObjectVector<CFolder> &folders,
+ CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CRecordVector<UInt64> &unpackSizes,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests)
+{
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type > ((UInt32)1 << 30))
+ ThrowIncorrect();
+ switch((UInt32)type)
+ {
+ case NID::kEnd:
+ return;
+ case NID::kPackInfo:
+ {
+ ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
+ break;
+ }
+ case NID::kUnpackInfo:
+ {
+ ReadUnpackInfo(dataVector, folders);
+ break;
+ }
+ case NID::kSubStreamsInfo:
+ {
+ ReadSubStreamsInfo(folders, numUnpackStreamsInFolders,
+ unpackSizes, digestsDefined, digests);
+ break;
+ }
+ default:
+ ThrowIncorrect();
+ }
+ }
+}
+
+void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
+{
+ v.Clear();
+ v.Reserve(numItems);
+ Byte b = 0;
+ Byte mask = 0;
+ for (int i = 0; i < numItems; i++)
+ {
+ if (mask == 0)
+ {
+ b = ReadByte();
+ mask = 0x80;
+ }
+ v.Add((b & mask) != 0);
+ mask >>= 1;
+ }
+}
+
+void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
+{
+ Byte allAreDefined = ReadByte();
+ if (allAreDefined == 0)
+ {
+ ReadBoolVector(numItems, v);
+ return;
+ }
+ v.Clear();
+ v.Reserve(numItems);
+ for (int i = 0; i < numItems; i++)
+ v.Add(true);
+}
+
+void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
+ CUInt64DefVector &v, int numFiles)
+{
+ ReadBoolVector2(numFiles, v.Defined);
+
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ v.Values.Reserve(numFiles);
+
+ for (int i = 0; i < numFiles; i++)
+ {
+ UInt64 t = 0;
+ if (v.Defined[i])
+ t = ReadUInt64();
+ v.Values.Add(t);
+ }
+}
+
+HRESULT CInArchive::ReadAndDecodePackedStreams(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 baseOffset,
+ UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ )
+{
+ CRecordVector<UInt64> packSizes;
+ CBoolVector packCRCsDefined;
+ CRecordVector<UInt32> packCRCs;
+ CObjectVector<CFolder> folders;
+
+ CRecordVector<CNum> numUnpackStreamsInFolders;
+ CRecordVector<UInt64> unpackSizes;
+ CBoolVector digestsDefined;
+ CRecordVector<UInt32> digests;
+
+ ReadStreamsInfo(NULL,
+ dataOffset,
+ packSizes,
+ packCRCsDefined,
+ packCRCs,
+ folders,
+ numUnpackStreamsInFolders,
+ unpackSizes,
+ digestsDefined,
+ digests);
+
+ // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
+
+ CNum packIndex = 0;
+ CDecoder decoder(
+ #ifdef _ST_MODE
+ false
+ #else
+ true
+ #endif
+ );
+ UInt64 dataStartPos = baseOffset + dataOffset;
+ for (int i = 0; i < folders.Size(); i++)
+ {
+ const CFolder &folder = folders[i];
+ dataVector.Add(CByteBuffer());
+ CByteBuffer &data = dataVector.Back();
+ UInt64 unpackSize64 = folder.GetUnpackSize();
+ size_t unpackSize = (size_t)unpackSize64;
+ if (unpackSize != unpackSize64)
+ ThrowUnsupported();
+ data.SetCapacity(unpackSize);
+
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->Init(data, unpackSize);
+
+ HRESULT result = decoder.Decode(
+ EXTERNAL_CODECS_LOC_VARS
+ _stream, dataStartPos,
+ &packSizes[packIndex], folder, outStream, NULL
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ , false, 1
+ #endif
+ );
+ RINOK(result);
+
+ if (folder.UnpackCRCDefined)
+ if (CrcCalc(data, unpackSize) != folder.UnpackCRC)
+ ThrowIncorrect();
+ for (int j = 0; j < folder.PackStreams.Size(); j++)
+ {
+ UInt64 packSize = packSizes[packIndex++];
+ dataStartPos += packSize;
+ HeadersSize += packSize;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadHeader(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ )
+{
+ UInt64 type = ReadID();
+
+ if (type == NID::kArchiveProperties)
+ {
+ ReadArchiveProperties(db.ArchiveInfo);
+ type = ReadID();
+ }
+
+ CObjectVector<CByteBuffer> dataVector;
+
+ if (type == NID::kAdditionalStreamsInfo)
+ {
+ HRESULT result = ReadAndDecodePackedStreams(
+ EXTERNAL_CODECS_LOC_VARS
+ db.ArchiveInfo.StartPositionAfterHeader,
+ db.ArchiveInfo.DataStartPosition2,
+ dataVector
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ );
+ RINOK(result);
+ db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
+ type = ReadID();
+ }
+
+ CRecordVector<UInt64> unpackSizes;
+ CBoolVector digestsDefined;
+ CRecordVector<UInt32> digests;
+
+ if (type == NID::kMainStreamsInfo)
+ {
+ ReadStreamsInfo(&dataVector,
+ db.ArchiveInfo.DataStartPosition,
+ db.PackSizes,
+ db.PackCRCsDefined,
+ db.PackCRCs,
+ db.Folders,
+ db.NumUnpackStreamsVector,
+ unpackSizes,
+ digestsDefined,
+ digests);
+ db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader;
+ type = ReadID();
+ }
+ else
+ {
+ for (int i = 0; i < db.Folders.Size(); i++)
+ {
+ db.NumUnpackStreamsVector.Add(1);
+ CFolder &folder = db.Folders[i];
+ unpackSizes.Add(folder.GetUnpackSize());
+ digestsDefined.Add(folder.UnpackCRCDefined);
+ digests.Add(folder.UnpackCRC);
+ }
+ }
+
+ db.Files.Clear();
+
+ if (type == NID::kEnd)
+ return S_OK;
+ if (type != NID::kFilesInfo)
+ ThrowIncorrect();
+
+ CNum numFiles = ReadNum();
+ db.Files.Reserve(numFiles);
+ CNum i;
+ for (i = 0; i < numFiles; i++)
+ db.Files.Add(CFileItem());
+
+ db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
+ if (!db.PackSizes.IsEmpty())
+ db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
+ if (numFiles > 0 && !digests.IsEmpty())
+ db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
+
+ CBoolVector emptyStreamVector;
+ BoolVector_Fill_False(emptyStreamVector, (int)numFiles);
+ CBoolVector emptyFileVector;
+ CBoolVector antiFileVector;
+ CNum numEmptyStreams = 0;
+
+ for (;;)
+ {
+ UInt64 type = ReadID();
+ if (type == NID::kEnd)
+ break;
+ UInt64 size = ReadNumber();
+ size_t ppp = _inByteBack->_pos;
+ bool addPropIdToList = true;
+ bool isKnownType = true;
+ if (type > ((UInt32)1 << 30))
+ isKnownType = false;
+ else switch((UInt32)type)
+ {
+ case NID::kName:
+ {
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ for (int i = 0; i < db.Files.Size(); i++)
+ _inByteBack->ReadString(db.Files[i].Name);
+ break;
+ }
+ case NID::kWinAttributes:
+ {
+ CBoolVector boolVector;
+ ReadBoolVector2(db.Files.Size(), boolVector);
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ for (i = 0; i < numFiles; i++)
+ {
+ CFileItem &file = db.Files[i];
+ file.AttribDefined = boolVector[i];
+ if (file.AttribDefined)
+ file.Attrib = ReadUInt32();
+ }
+ break;
+ }
+ case NID::kEmptyStream:
+ {
+ ReadBoolVector(numFiles, emptyStreamVector);
+ for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
+ if (emptyStreamVector[i])
+ numEmptyStreams++;
+
+ BoolVector_Fill_False(emptyFileVector, numEmptyStreams);
+ BoolVector_Fill_False(antiFileVector, numEmptyStreams);
+
+ break;
+ }
+ case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break;
+ case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break;
+ case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break;
+ case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break;
+ case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break;
+ case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break;
+ case NID::kDummy:
+ {
+ for (UInt64 j = 0; j < size; j++)
+ if (ReadByte() != 0)
+ ThrowIncorrect();
+ addPropIdToList = false;
+ break;
+ }
+ default:
+ addPropIdToList = isKnownType = false;
+ }
+ if (isKnownType)
+ {
+ if(addPropIdToList)
+ db.ArchiveInfo.FileInfoPopIDs.Add(type);
+ }
+ else
+ SkipData(size);
+ bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 ||
+ db.ArchiveInfo.Version.Minor > 2);
+ if (checkRecordsSize && _inByteBack->_pos - ppp != size)
+ ThrowIncorrect();
+ }
+
+ CNum emptyFileIndex = 0;
+ CNum sizeIndex = 0;
+
+ CNum numAntiItems = 0;
+ for (i = 0; i < numEmptyStreams; i++)
+ if (antiFileVector[i])
+ numAntiItems++;
+
+ for (i = 0; i < numFiles; i++)
+ {
+ CFileItem &file = db.Files[i];
+ bool isAnti;
+ file.HasStream = !emptyStreamVector[i];
+ if (file.HasStream)
+ {
+ file.IsDir = false;
+ isAnti = false;
+ file.Size = unpackSizes[sizeIndex];
+ file.Crc = digests[sizeIndex];
+ file.CrcDefined = digestsDefined[sizeIndex];
+ sizeIndex++;
+ }
+ else
+ {
+ file.IsDir = !emptyFileVector[emptyFileIndex];
+ isAnti = antiFileVector[emptyFileIndex];
+ emptyFileIndex++;
+ file.Size = 0;
+ file.CrcDefined = false;
+ }
+ if (numAntiItems != 0)
+ db.IsAnti.Add(isAnti);
+ }
+ return S_OK;
+}
+
+
+void CArchiveDatabaseEx::FillFolderStartPackStream()
+{
+ FolderStartPackStreamIndex.Clear();
+ FolderStartPackStreamIndex.Reserve(Folders.Size());
+ CNum startPos = 0;
+ for (int i = 0; i < Folders.Size(); i++)
+ {
+ FolderStartPackStreamIndex.Add(startPos);
+ startPos += (CNum)Folders[i].PackStreams.Size();
+ }
+}
+
+void CArchiveDatabaseEx::FillStartPos()
+{
+ PackStreamStartPositions.Clear();
+ PackStreamStartPositions.Reserve(PackSizes.Size());
+ UInt64 startPos = 0;
+ for (int i = 0; i < PackSizes.Size(); i++)
+ {
+ PackStreamStartPositions.Add(startPos);
+ startPos += PackSizes[i];
+ }
+}
+
+void CArchiveDatabaseEx::FillFolderStartFileIndex()
+{
+ FolderStartFileIndex.Clear();
+ FolderStartFileIndex.Reserve(Folders.Size());
+ FileIndexToFolderIndexMap.Clear();
+ FileIndexToFolderIndexMap.Reserve(Files.Size());
+
+ int folderIndex = 0;
+ CNum indexInFolder = 0;
+ for (int i = 0; i < Files.Size(); i++)
+ {
+ const CFileItem &file = Files[i];
+ bool emptyStream = !file.HasStream;
+ if (emptyStream && indexInFolder == 0)
+ {
+ FileIndexToFolderIndexMap.Add(kNumNoIndex);
+ continue;
+ }
+ if (indexInFolder == 0)
+ {
+ // v3.13 incorrectly worked with empty folders
+ // v4.07: Loop for skipping empty folders
+ for (;;)
+ {
+ if (folderIndex >= Folders.Size())
+ ThrowIncorrect();
+ FolderStartFileIndex.Add(i); // check it
+ if (NumUnpackStreamsVector[folderIndex] != 0)
+ break;
+ folderIndex++;
+ }
+ }
+ FileIndexToFolderIndexMap.Add(folderIndex);
+ if (emptyStream)
+ continue;
+ indexInFolder++;
+ if (indexInFolder >= NumUnpackStreamsVector[folderIndex])
+ {
+ folderIndex++;
+ indexInFolder = 0;
+ }
+ }
+}
+
+HRESULT CInArchive::ReadDatabase2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ )
+{
+ db.Clear();
+ db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+
+ db.ArchiveInfo.Version.Major = _header[6];
+ db.ArchiveInfo.Version.Minor = _header[7];
+
+ if (db.ArchiveInfo.Version.Major != kMajorVersion)
+ ThrowUnsupportedVersion();
+
+ UInt32 crcFromArchive = Get32(_header + 8);
+ UInt64 nextHeaderOffset = Get64(_header + 0xC);
+ UInt64 nextHeaderSize = Get64(_header + 0x14);
+ UInt32 nextHeaderCRC = Get32(_header + 0x1C);
+ UInt32 crc = CrcCalc(_header + 0xC, 20);
+
+ #ifdef FORMAT_7Z_RECOVERY
+ if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
+ {
+ UInt64 cur, cur2;
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
+ const int kCheckSize = 500;
+ Byte buf[kCheckSize];
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
+ int checkSize = kCheckSize;
+ if (cur2 - cur < kCheckSize)
+ checkSize = (int)(cur2 - cur);
+ RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
+
+ RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));
+
+ int i;
+ for (i = (int)checkSize - 2; i >= 0; i--)
+ if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
+ break;
+ if (i < 0)
+ return S_FALSE;
+ nextHeaderSize = checkSize - i;
+ nextHeaderOffset = cur2 - cur + i;
+ nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
+ RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
+ }
+ else
+ #endif
+ {
+ if (crc != crcFromArchive)
+ ThrowIncorrect();
+ }
+
+ db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
+
+ if (nextHeaderSize == 0)
+ return S_OK;
+
+ if (nextHeaderSize > (UInt64)0xFFFFFFFF)
+ return S_FALSE;
+
+ if ((Int64)nextHeaderOffset < 0)
+ return S_FALSE;
+
+ RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
+
+ CByteBuffer buffer2;
+ buffer2.SetCapacity((size_t)nextHeaderSize);
+
+ RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize));
+ HeadersSize += kHeaderSize + nextHeaderSize;
+ db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
+
+ if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
+ ThrowIncorrect();
+
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, buffer2);
+
+ CObjectVector<CByteBuffer> dataVector;
+
+ UInt64 type = ReadID();
+ if (type != NID::kHeader)
+ {
+ if (type != NID::kEncodedHeader)
+ ThrowIncorrect();
+ HRESULT result = ReadAndDecodePackedStreams(
+ EXTERNAL_CODECS_LOC_VARS
+ db.ArchiveInfo.StartPositionAfterHeader,
+ db.ArchiveInfo.DataStartPosition2,
+ dataVector
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ );
+ RINOK(result);
+ if (dataVector.Size() == 0)
+ return S_OK;
+ if (dataVector.Size() > 1)
+ ThrowIncorrect();
+ streamSwitch.Remove();
+ streamSwitch.Set(this, dataVector.Front());
+ if (ReadID() != NID::kHeader)
+ ThrowIncorrect();
+ }
+
+ db.HeadersSize = HeadersSize;
+
+ return ReadHeader(
+ EXTERNAL_CODECS_LOC_VARS
+ db
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ );
+}
+
+HRESULT CInArchive::ReadDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ )
+{
+ try
+ {
+ return ReadDatabase2(
+ EXTERNAL_CODECS_LOC_VARS db
+ #ifndef _NO_CRYPTO
+ , getTextPassword, passwordIsDefined
+ #endif
+ );
+ }
+ catch(CInArchiveException &) { return S_FALSE; }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.h
new file mode 100644
index 000000000..971f27b2a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.h
@@ -0,0 +1,245 @@
+// 7zIn.h
+
+#ifndef __7Z_IN_H
+#define __7Z_IN_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IPassword.h"
+#include "../../IStream.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/InBuffer.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CInArchiveInfo
+{
+ CArchiveVersion Version;
+ UInt64 StartPosition;
+ UInt64 StartPositionAfterHeader;
+ UInt64 DataStartPosition;
+ UInt64 DataStartPosition2;
+ CRecordVector<UInt64> FileInfoPopIDs;
+ void Clear()
+ {
+ FileInfoPopIDs.Clear();
+ }
+};
+
+struct CArchiveDatabaseEx: public CArchiveDatabase
+{
+ CInArchiveInfo ArchiveInfo;
+ CRecordVector<UInt64> PackStreamStartPositions;
+ CRecordVector<CNum> FolderStartPackStreamIndex;
+ CRecordVector<CNum> FolderStartFileIndex;
+ CRecordVector<CNum> FileIndexToFolderIndexMap;
+
+ UInt64 HeadersSize;
+ UInt64 PhySize;
+
+ void Clear()
+ {
+ CArchiveDatabase::Clear();
+ ArchiveInfo.Clear();
+ PackStreamStartPositions.Clear();
+ FolderStartPackStreamIndex.Clear();
+ FolderStartFileIndex.Clear();
+ FileIndexToFolderIndexMap.Clear();
+
+ HeadersSize = 0;
+ PhySize = 0;
+ }
+
+ void FillFolderStartPackStream();
+ void FillStartPos();
+ void FillFolderStartFileIndex();
+
+ void Fill()
+ {
+ FillFolderStartPackStream();
+ FillStartPos();
+ FillFolderStartFileIndex();
+ }
+
+ UInt64 GetFolderStreamPos(int folderIndex, int indexInFolder) const
+ {
+ return ArchiveInfo.DataStartPosition +
+ PackStreamStartPositions[FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+ }
+
+ UInt64 GetFolderFullPackSize(int folderIndex) const
+ {
+ CNum packStreamIndex = FolderStartPackStreamIndex[folderIndex];
+ const CFolder &folder = Folders[folderIndex];
+ UInt64 size = 0;
+ for (int i = 0; i < folder.PackStreams.Size(); i++)
+ size += PackSizes[packStreamIndex + i];
+ return size;
+ }
+
+ UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
+ {
+ return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+ }
+
+ UInt64 GetFilePackSize(CNum fileIndex) const
+ {
+ CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex != kNumNoIndex)
+ if (FolderStartFileIndex[folderIndex] == fileIndex)
+ return GetFolderFullPackSize(folderIndex);
+ return 0;
+ }
+};
+
+class CInByte2
+{
+ const Byte *_buffer;
+ size_t _size;
+public:
+ size_t _pos;
+ void Init(const Byte *buffer, size_t size)
+ {
+ _buffer = buffer;
+ _size = size;
+ _pos = 0;
+ }
+ Byte ReadByte();
+ void ReadBytes(Byte *data, size_t size);
+ void SkipData(UInt64 size);
+ void SkipData();
+ UInt64 ReadNumber();
+ CNum ReadNum();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ void ReadString(UString &s);
+};
+
+class CStreamSwitch;
+
+const UInt32 kHeaderSize = 32;
+
+class CInArchive
+{
+ friend class CStreamSwitch;
+
+ CMyComPtr<IInStream> _stream;
+
+ CObjectVector<CInByte2> _inByteVector;
+ CInByte2 *_inByteBack;
+
+ UInt64 _arhiveBeginStreamPosition;
+
+ Byte _header[kHeaderSize];
+
+ UInt64 HeadersSize;
+
+ void AddByteStream(const Byte *buffer, size_t size)
+ {
+ _inByteVector.Add(CInByte2());
+ _inByteBack = &_inByteVector.Back();
+ _inByteBack->Init(buffer, size);
+ }
+
+ void DeleteByteStream()
+ {
+ _inByteVector.DeleteBack();
+ if (!_inByteVector.IsEmpty())
+ _inByteBack = &_inByteVector.Back();
+ }
+
+private:
+ HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+
+ void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); }
+ Byte ReadByte() { return _inByteBack->ReadByte(); }
+ UInt64 ReadNumber() { return _inByteBack->ReadNumber(); }
+ CNum ReadNum() { return _inByteBack->ReadNum(); }
+ UInt64 ReadID() { return _inByteBack->ReadNumber(); }
+ UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); }
+ UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
+ void SkipData(UInt64 size) { _inByteBack->SkipData(size); }
+ void SkipData() { _inByteBack->SkipData(); }
+ void WaitAttribute(UInt64 attribute);
+
+ void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
+ void GetNextFolderItem(CFolder &itemInfo);
+ void ReadHashDigests(int numItems,
+ CBoolVector &digestsDefined, CRecordVector<UInt32> &digests);
+
+ void ReadPackInfo(
+ UInt64 &dataOffset,
+ CRecordVector<UInt64> &packSizes,
+ CBoolVector &packCRCsDefined,
+ CRecordVector<UInt32> &packCRCs);
+
+ void ReadUnpackInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ CObjectVector<CFolder> &folders);
+
+ void ReadSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CRecordVector<UInt64> &unpackSizes,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests);
+
+ void ReadStreamsInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ UInt64 &dataOffset,
+ CRecordVector<UInt64> &packSizes,
+ CBoolVector &packCRCsDefined,
+ CRecordVector<UInt32> &packCRCs,
+ CObjectVector<CFolder> &folders,
+ CRecordVector<CNum> &numUnpackStreamsInFolders,
+ CRecordVector<UInt64> &unpackSizes,
+ CBoolVector &digestsDefined,
+ CRecordVector<UInt32> &digests);
+
+
+ void ReadBoolVector(int numItems, CBoolVector &v);
+ void ReadBoolVector2(int numItems, CBoolVector &v);
+ void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
+ CUInt64DefVector &v, int numFiles);
+ HRESULT ReadAndDecodePackedStreams(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 baseOffset, UInt64 &dataOffset,
+ CObjectVector<CByteBuffer> &dataVector
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ );
+ HRESULT ReadHeader(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ );
+ HRESULT ReadDatabase2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ );
+public:
+ HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
+ void Close();
+
+ HRESULT ReadDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CArchiveDatabaseEx &db
+ #ifndef _NO_CRYPTO
+ ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
+ #endif
+ );
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zItem.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zItem.h
new file mode 100644
index 000000000..34f10775c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zItem.h
@@ -0,0 +1,268 @@
+// 7zItem.h
+
+#ifndef __7Z_ITEM_H
+#define __7Z_ITEM_H
+
+#include "../../../Common/Buffer.h"
+#include "../../../Common/MyString.h"
+
+#include "../../Common/MethodId.h"
+
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+const UInt64 k_AES = 0x06F10701;
+
+typedef UInt32 CNum;
+const CNum kNumMax = 0x7FFFFFFF;
+const CNum kNumNoIndex = 0xFFFFFFFF;
+
+struct CCoderInfo
+{
+ CMethodId MethodID;
+ CByteBuffer Props;
+ CNum NumInStreams;
+ CNum NumOutStreams;
+ bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); }
+};
+
+struct CBindPair
+{
+ CNum InIndex;
+ CNum OutIndex;
+};
+
+struct CFolder
+{
+ CObjectVector<CCoderInfo> Coders;
+ CRecordVector<CBindPair> BindPairs;
+ CRecordVector<CNum> PackStreams;
+ CRecordVector<UInt64> UnpackSizes;
+ UInt32 UnpackCRC;
+ bool UnpackCRCDefined;
+
+ CFolder(): UnpackCRCDefined(false) {}
+
+ UInt64 GetUnpackSize() const // test it
+ {
+ if (UnpackSizes.IsEmpty())
+ return 0;
+ for (int i = UnpackSizes.Size() - 1; i >= 0; i--)
+ if (FindBindPairForOutStream(i) < 0)
+ return UnpackSizes[i];
+ throw 1;
+ }
+
+ CNum GetNumOutStreams() const
+ {
+ CNum result = 0;
+ for (int i = 0; i < Coders.Size(); i++)
+ result += Coders[i].NumOutStreams;
+ return result;
+ }
+
+ int FindBindPairForInStream(CNum inStreamIndex) const
+ {
+ for(int i = 0; i < BindPairs.Size(); i++)
+ if (BindPairs[i].InIndex == inStreamIndex)
+ return i;
+ return -1;
+ }
+ int FindBindPairForOutStream(CNum outStreamIndex) const
+ {
+ for(int i = 0; i < BindPairs.Size(); i++)
+ if (BindPairs[i].OutIndex == outStreamIndex)
+ return i;
+ return -1;
+ }
+ int FindPackStreamArrayIndex(CNum inStreamIndex) const
+ {
+ for(int i = 0; i < PackStreams.Size(); i++)
+ if (PackStreams[i] == inStreamIndex)
+ return i;
+ return -1;
+ }
+
+ bool IsEncrypted() const
+ {
+ for (int i = Coders.Size() - 1; i >= 0; i--)
+ if (Coders[i].MethodID == k_AES)
+ return true;
+ return false;
+ }
+
+ bool CheckStructure() const;
+};
+
+struct CUInt64DefVector
+{
+ CRecordVector<UInt64> Values;
+ CRecordVector<bool> Defined;
+
+ void Clear()
+ {
+ Values.Clear();
+ Defined.Clear();
+ }
+
+ void ReserveDown()
+ {
+ Values.ReserveDown();
+ Values.ReserveDown();
+ }
+
+ bool GetItem(int index, UInt64 &value) const
+ {
+ if (index < Defined.Size() && Defined[index])
+ {
+ value = Values[index];
+ return true;
+ }
+ value = 0;
+ return false;
+ }
+
+ void SetItem(int index, bool defined, UInt64 value)
+ {
+ while (index >= Defined.Size())
+ Defined.Add(false);
+ Defined[index] = defined;
+ if (!defined)
+ return;
+ while (index >= Values.Size())
+ Values.Add(0);
+ Values[index] = value;
+ }
+
+ bool CheckSize(int size) const { return Defined.Size() == size || Defined.Size() == 0; }
+};
+
+struct CFileItem
+{
+ UInt64 Size;
+ UInt32 Attrib;
+ UInt32 Crc;
+ UString Name;
+
+ bool HasStream; // Test it !!! it means that there is
+ // stream in some folder. It can be empty stream
+ bool IsDir;
+ bool CrcDefined;
+ bool AttribDefined;
+
+ CFileItem():
+ HasStream(true),
+ IsDir(false),
+ CrcDefined(false),
+ AttribDefined(false)
+ {}
+ void SetAttrib(UInt32 attrib)
+ {
+ AttribDefined = true;
+ Attrib = attrib;
+ }
+};
+
+struct CFileItem2
+{
+ UInt64 CTime;
+ UInt64 ATime;
+ UInt64 MTime;
+ UInt64 StartPos;
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+ bool StartPosDefined;
+ bool IsAnti;
+};
+
+struct CArchiveDatabase
+{
+ CRecordVector<UInt64> PackSizes;
+ CRecordVector<bool> PackCRCsDefined;
+ CRecordVector<UInt32> PackCRCs;
+ CObjectVector<CFolder> Folders;
+ CRecordVector<CNum> NumUnpackStreamsVector;
+ CObjectVector<CFileItem> Files;
+
+ CUInt64DefVector CTime;
+ CUInt64DefVector ATime;
+ CUInt64DefVector MTime;
+ CUInt64DefVector StartPos;
+ CRecordVector<bool> IsAnti;
+
+ void Clear()
+ {
+ PackSizes.Clear();
+ PackCRCsDefined.Clear();
+ PackCRCs.Clear();
+ Folders.Clear();
+ NumUnpackStreamsVector.Clear();
+ Files.Clear();
+ CTime.Clear();
+ ATime.Clear();
+ MTime.Clear();
+ StartPos.Clear();
+ IsAnti.Clear();
+ }
+
+ void ReserveDown()
+ {
+ PackSizes.ReserveDown();
+ PackCRCsDefined.ReserveDown();
+ PackCRCs.ReserveDown();
+ Folders.ReserveDown();
+ NumUnpackStreamsVector.ReserveDown();
+ Files.ReserveDown();
+ CTime.ReserveDown();
+ ATime.ReserveDown();
+ MTime.ReserveDown();
+ StartPos.ReserveDown();
+ IsAnti.ReserveDown();
+ }
+
+ bool IsEmpty() const
+ {
+ return (PackSizes.IsEmpty() &&
+ PackCRCsDefined.IsEmpty() &&
+ PackCRCs.IsEmpty() &&
+ Folders.IsEmpty() &&
+ NumUnpackStreamsVector.IsEmpty() &&
+ Files.IsEmpty());
+ }
+
+ bool CheckNumFiles() const
+ {
+ int size = Files.Size();
+ return (
+ CTime.CheckSize(size) &&
+ ATime.CheckSize(size) &&
+ MTime.CheckSize(size) &&
+ StartPos.CheckSize(size) &&
+ (size == IsAnti.Size() || IsAnti.Size() == 0));
+ }
+
+ bool IsSolid() const
+ {
+ for (int i = 0; i < NumUnpackStreamsVector.Size(); i++)
+ if (NumUnpackStreamsVector[i] > 1)
+ return true;
+ return false;
+ }
+ bool IsItemAnti(int index) const { return (index < IsAnti.Size() && IsAnti[index]); }
+ void SetItemAnti(int index, bool isAnti)
+ {
+ while (index >= IsAnti.Size())
+ IsAnti.Add(false);
+ IsAnti[index] = isAnti;
+ }
+
+ void GetFile(int index, CFileItem &file, CFileItem2 &file2) const;
+ void AddFile(const CFileItem &file, const CFileItem2 &file2);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp
new file mode 100644
index 000000000..0c8aa7e8c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp
@@ -0,0 +1,866 @@
+// 7zOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/AutoPtr.h"
+
+#include "../../Common/StreamObjects.h"
+
+#include "7zOut.h"
+
+static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size)
+{
+ while (size > 0)
+ {
+ UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF);
+ UInt32 processedSize;
+ RINOK(stream->Write(data, curSize, &processedSize));
+ if (processedSize == 0)
+ return E_FAIL;
+ data = (const void *)((const Byte *)data + processedSize);
+ size -= processedSize;
+ }
+ return S_OK;
+}
+
+namespace NArchive {
+namespace N7z {
+
+HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
+{
+ return ::WriteBytes(SeqStream, data, size);
+}
+
+HRESULT COutArchive::WriteSignature()
+{
+ Byte buf[8];
+ memcpy(buf, kSignature, kSignatureSize);
+ buf[kSignatureSize] = kMajorVersion;
+ buf[kSignatureSize + 1] = 3;
+ return WriteDirect(buf, 8);
+}
+
+#ifdef _7Z_VOL
+HRESULT COutArchive::WriteFinishSignature()
+{
+ RINOK(WriteDirect(kFinishSignature, kSignatureSize));
+ CArchiveVersion av;
+ av.Major = kMajorVersion;
+ av.Minor = 2;
+ RINOK(WriteDirectByte(av.Major));
+ return WriteDirectByte(av.Minor);
+}
+#endif
+
+static void SetUInt32(Byte *p, UInt32 d)
+{
+ for (int i = 0; i < 4; i++, d >>= 8)
+ p[i] = (Byte)d;
+}
+
+static void SetUInt64(Byte *p, UInt64 d)
+{
+ for (int i = 0; i < 8; i++, d >>= 8)
+ p[i] = (Byte)d;
+}
+
+HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
+{
+ Byte buf[24];
+ SetUInt64(buf + 4, h.NextHeaderOffset);
+ SetUInt64(buf + 12, h.NextHeaderSize);
+ SetUInt32(buf + 20, h.NextHeaderCRC);
+ SetUInt32(buf, CrcCalc(buf + 4, 20));
+ return WriteDirect(buf, 24);
+}
+
+#ifdef _7Z_VOL
+HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h)
+{
+ CCRC crc;
+ crc.UpdateUInt64(h.NextHeaderOffset);
+ crc.UpdateUInt64(h.NextHeaderSize);
+ crc.UpdateUInt32(h.NextHeaderCRC);
+ crc.UpdateUInt64(h.ArchiveStartOffset);
+ crc.UpdateUInt64(h.AdditionalStartBlockSize);
+ RINOK(WriteDirectUInt32(crc.GetDigest()));
+ RINOK(WriteDirectUInt64(h.NextHeaderOffset));
+ RINOK(WriteDirectUInt64(h.NextHeaderSize));
+ RINOK(WriteDirectUInt32(h.NextHeaderCRC));
+ RINOK(WriteDirectUInt64(h.ArchiveStartOffset));
+ return WriteDirectUInt64(h.AdditionalStartBlockSize);
+}
+#endif
+
+HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
+{
+ Close();
+ #ifdef _7Z_VOL
+ // endMarker = false;
+ _endMarker = endMarker;
+ #endif
+ SeqStream = stream;
+ if (!endMarker)
+ {
+ SeqStream.QueryInterface(IID_IOutStream, &Stream);
+ if (!Stream)
+ {
+ return E_NOTIMPL;
+ // endMarker = true;
+ }
+ }
+ #ifdef _7Z_VOL
+ if (endMarker)
+ {
+ /*
+ CStartHeader sh;
+ sh.NextHeaderOffset = (UInt32)(Int32)-1;
+ sh.NextHeaderSize = (UInt32)(Int32)-1;
+ sh.NextHeaderCRC = 0;
+ WriteStartHeader(sh);
+ */
+ }
+ else
+ #endif
+ {
+ if (!Stream)
+ return E_FAIL;
+ RINOK(WriteSignature());
+ RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
+ }
+ return S_OK;
+}
+
+void COutArchive::Close()
+{
+ SeqStream.Release();
+ Stream.Release();
+}
+
+HRESULT COutArchive::SkipPrefixArchiveHeader()
+{
+ #ifdef _7Z_VOL
+ if (_endMarker)
+ return S_OK;
+ #endif
+ return Stream->Seek(24, STREAM_SEEK_CUR, NULL);
+}
+
+UInt64 COutArchive::GetPos() const
+{
+ if (_countMode)
+ return _countSize;
+ if (_writeToStream)
+ return _outByte.GetProcessedSize();
+ return _outByte2.GetPos();
+}
+
+void COutArchive::WriteBytes(const void *data, size_t size)
+{
+ if (_countMode)
+ _countSize += size;
+ else if (_writeToStream)
+ {
+ _outByte.WriteBytes(data, size);
+ _crc = CrcUpdate(_crc, data, size);
+ }
+ else
+ _outByte2.WriteBytes(data, size);
+}
+
+void COutArchive::WriteByte(Byte b)
+{
+ if (_countMode)
+ _countSize++;
+ else if (_writeToStream)
+ {
+ _outByte.WriteByte(b);
+ _crc = CRC_UPDATE_BYTE(_crc, b);
+ }
+ else
+ _outByte2.WriteByte(b);
+}
+
+void COutArchive::WriteUInt32(UInt32 value)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteUInt64(UInt64 value)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteNumber(UInt64 value)
+{
+ Byte firstByte = 0;
+ Byte mask = 0x80;
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ if (value < ((UInt64(1) << ( 7 * (i + 1)))))
+ {
+ firstByte |= Byte(value >> (8 * i));
+ break;
+ }
+ firstByte |= mask;
+ mask >>= 1;
+ }
+ WriteByte(firstByte);
+ for (;i > 0; i--)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+static UInt32 GetBigNumberSize(UInt64 value)
+{
+ int i;
+ for (i = 1; i < 9; i++)
+ if (value < (((UInt64)1 << (i * 7))))
+ break;
+ return i;
+}
+
+#ifdef _7Z_VOL
+UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
+{
+ UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
+ if (nameLength != 0)
+ {
+ nameLength = (nameLength + 1) * 2;
+ result += nameLength + GetBigNumberSize(nameLength) + 2;
+ }
+ if (props)
+ {
+ result += 20;
+ }
+ if (result >= 128)
+ result++;
+ result += kSignatureSize + 2 + kFinishHeaderSize;
+ return result;
+}
+
+UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
+{
+ UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
+ int testSize;
+ if (volSize > headersSizeBase)
+ testSize = volSize - headersSizeBase;
+ else
+ testSize = 1;
+ UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
+ UInt64 pureSize = 1;
+ if (volSize > headersSize)
+ pureSize = volSize - headersSize;
+ return pureSize;
+}
+#endif
+
+void COutArchive::WriteFolder(const CFolder &folder)
+{
+ WriteNumber(folder.Coders.Size());
+ int i;
+ for (i = 0; i < folder.Coders.Size(); i++)
+ {
+ const CCoderInfo &coder = folder.Coders[i];
+ {
+ size_t propsSize = coder.Props.GetCapacity();
+
+ UInt64 id = coder.MethodID;
+ int idSize;
+ for (idSize = 1; idSize < sizeof(id); idSize++)
+ if ((id >> (8 * idSize)) == 0)
+ break;
+ BYTE longID[15];
+ for (int t = idSize - 1; t >= 0 ; t--, id >>= 8)
+ longID[t] = (Byte)(id & 0xFF);
+ Byte b;
+ b = (Byte)(idSize & 0xF);
+ bool isComplex = !coder.IsSimpleCoder();
+ b |= (isComplex ? 0x10 : 0);
+ b |= ((propsSize != 0) ? 0x20 : 0 );
+ WriteByte(b);
+ WriteBytes(longID, idSize);
+ if (isComplex)
+ {
+ WriteNumber(coder.NumInStreams);
+ WriteNumber(coder.NumOutStreams);
+ }
+ if (propsSize == 0)
+ continue;
+ WriteNumber(propsSize);
+ WriteBytes(coder.Props, propsSize);
+ }
+ }
+ for (i = 0; i < folder.BindPairs.Size(); i++)
+ {
+ const CBindPair &bindPair = folder.BindPairs[i];
+ WriteNumber(bindPair.InIndex);
+ WriteNumber(bindPair.OutIndex);
+ }
+ if (folder.PackStreams.Size() > 1)
+ for (i = 0; i < folder.PackStreams.Size(); i++)
+ {
+ WriteNumber(folder.PackStreams[i]);
+ }
+}
+
+void COutArchive::WriteBoolVector(const CBoolVector &boolVector)
+{
+ Byte b = 0;
+ Byte mask = 0x80;
+ for (int i = 0; i < boolVector.Size(); i++)
+ {
+ if (boolVector[i])
+ b |= mask;
+ mask >>= 1;
+ if (mask == 0)
+ {
+ WriteByte(b);
+ mask = 0x80;
+ b = 0;
+ }
+ }
+ if (mask != 0x80)
+ WriteByte(b);
+}
+
+
+void COutArchive::WriteHashDigests(
+ const CRecordVector<bool> &digestsDefined,
+ const CRecordVector<UInt32> &digests)
+{
+ int numDefined = 0;
+ int i;
+ for (i = 0; i < digestsDefined.Size(); i++)
+ if (digestsDefined[i])
+ numDefined++;
+ if (numDefined == 0)
+ return;
+
+ WriteByte(NID::kCRC);
+ if (numDefined == digestsDefined.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(digestsDefined);
+ }
+ for (i = 0; i < digests.Size(); i++)
+ if (digestsDefined[i])
+ WriteUInt32(digests[i]);
+}
+
+void COutArchive::WritePackInfo(
+ UInt64 dataOffset,
+ const CRecordVector<UInt64> &packSizes,
+ const CRecordVector<bool> &packCRCsDefined,
+ const CRecordVector<UInt32> &packCRCs)
+{
+ if (packSizes.IsEmpty())
+ return;
+ WriteByte(NID::kPackInfo);
+ WriteNumber(dataOffset);
+ WriteNumber(packSizes.Size());
+ WriteByte(NID::kSize);
+ for (int i = 0; i < packSizes.Size(); i++)
+ WriteNumber(packSizes[i]);
+
+ WriteHashDigests(packCRCsDefined, packCRCs);
+
+ WriteByte(NID::kEnd);
+}
+
+void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders)
+{
+ if (folders.IsEmpty())
+ return;
+
+ WriteByte(NID::kUnpackInfo);
+
+ WriteByte(NID::kFolder);
+ WriteNumber(folders.Size());
+ {
+ WriteByte(0);
+ for (int i = 0; i < folders.Size(); i++)
+ WriteFolder(folders[i]);
+ }
+
+ WriteByte(NID::kCodersUnpackSize);
+ int i;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ const CFolder &folder = folders[i];
+ for (int j = 0; j < folder.UnpackSizes.Size(); j++)
+ WriteNumber(folder.UnpackSizes[j]);
+ }
+
+ CRecordVector<bool> unpackCRCsDefined;
+ CRecordVector<UInt32> unpackCRCs;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ const CFolder &folder = folders[i];
+ unpackCRCsDefined.Add(folder.UnpackCRCDefined);
+ unpackCRCs.Add(folder.UnpackCRC);
+ }
+ WriteHashDigests(unpackCRCsDefined, unpackCRCs);
+
+ WriteByte(NID::kEnd);
+}
+
+void COutArchive::WriteSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ const CRecordVector<CNum> &numUnpackStreamsInFolders,
+ const CRecordVector<UInt64> &unpackSizes,
+ const CRecordVector<bool> &digestsDefined,
+ const CRecordVector<UInt32> &digests)
+{
+ WriteByte(NID::kSubStreamsInfo);
+
+ int i;
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ {
+ if (numUnpackStreamsInFolders[i] != 1)
+ {
+ WriteByte(NID::kNumUnpackStream);
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ WriteNumber(numUnpackStreamsInFolders[i]);
+ break;
+ }
+ }
+
+
+ bool needFlag = true;
+ CNum index = 0;
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ for (CNum j = 0; j < numUnpackStreamsInFolders[i]; j++)
+ {
+ if (j + 1 != numUnpackStreamsInFolders[i])
+ {
+ if (needFlag)
+ WriteByte(NID::kSize);
+ needFlag = false;
+ WriteNumber(unpackSizes[index]);
+ }
+ index++;
+ }
+
+ CRecordVector<bool> digestsDefined2;
+ CRecordVector<UInt32> digests2;
+
+ int digestIndex = 0;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ int numSubStreams = (int)numUnpackStreamsInFolders[i];
+ if (numSubStreams == 1 && folders[i].UnpackCRCDefined)
+ digestIndex++;
+ else
+ for (int j = 0; j < numSubStreams; j++, digestIndex++)
+ {
+ digestsDefined2.Add(digestsDefined[digestIndex]);
+ digests2.Add(digests[digestIndex]);
+ }
+ }
+ WriteHashDigests(digestsDefined2, digests2);
+ WriteByte(NID::kEnd);
+}
+
+void COutArchive::SkipAlign(unsigned /* pos */, unsigned /* alignSize */)
+{
+ return;
+}
+
+/*
+7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
+
+void COutArchive::SkipAlign(unsigned pos, unsigned alignSize)
+{
+ pos += (unsigned)GetPos();
+ pos &= (alignSize - 1);
+ if (pos == 0)
+ return;
+ unsigned skip = alignSize - pos;
+ if (skip < 2)
+ skip += alignSize;
+ skip -= 2;
+ WriteByte(NID::kDummy);
+ WriteByte((Byte)skip);
+ for (unsigned i = 0; i < skip; i++)
+ WriteByte(0);
+}
+*/
+
+static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
+
+void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize)
+{
+ const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
+ const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2;
+ SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize);
+
+ WriteByte(type);
+ WriteNumber(dataSize);
+ if (numDefined == v.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(v);
+ }
+ WriteByte(0);
+}
+
+void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
+{
+ int numDefined = 0;
+
+ int i;
+ for (i = 0; i < v.Defined.Size(); i++)
+ if (v.Defined[i])
+ numDefined++;
+
+ if (numDefined == 0)
+ return;
+
+ WriteAlignedBoolHeader(v.Defined, numDefined, type, 8);
+
+ for (i = 0; i < v.Defined.Size(); i++)
+ if (v.Defined[i])
+ WriteUInt64(v.Values[i]);
+}
+
+HRESULT COutArchive::EncodeStream(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CEncoder &encoder, const CByteBuffer &data,
+ CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
+{
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> stream = streamSpec;
+ streamSpec->Init(data, data.GetCapacity());
+ CFolder folderItem;
+ folderItem.UnpackCRCDefined = true;
+ folderItem.UnpackCRC = CrcCalc(data, data.GetCapacity());
+ UInt64 dataSize64 = data.GetCapacity();
+ RINOK(encoder.Encode(
+ EXTERNAL_CODECS_LOC_VARS
+ stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
+ folders.Add(folderItem);
+ return S_OK;
+}
+
+void COutArchive::WriteHeader(
+ const CArchiveDatabase &db,
+ const CHeaderOptions &headerOptions,
+ UInt64 &headerOffset)
+{
+ int i;
+
+ UInt64 packedSize = 0;
+ for (i = 0; i < db.PackSizes.Size(); i++)
+ packedSize += db.PackSizes[i];
+
+ headerOffset = packedSize;
+
+ WriteByte(NID::kHeader);
+
+ // Archive Properties
+
+ if (db.Folders.Size() > 0)
+ {
+ WriteByte(NID::kMainStreamsInfo);
+ WritePackInfo(0, db.PackSizes,
+ db.PackCRCsDefined,
+ db.PackCRCs);
+
+ WriteUnpackInfo(db.Folders);
+
+ CRecordVector<UInt64> unpackSizes;
+ CRecordVector<bool> digestsDefined;
+ CRecordVector<UInt32> digests;
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ if (!file.HasStream)
+ continue;
+ unpackSizes.Add(file.Size);
+ digestsDefined.Add(file.CrcDefined);
+ digests.Add(file.Crc);
+ }
+
+ WriteSubStreamsInfo(
+ db.Folders,
+ db.NumUnpackStreamsVector,
+ unpackSizes,
+ digestsDefined,
+ digests);
+ WriteByte(NID::kEnd);
+ }
+
+ if (db.Files.IsEmpty())
+ {
+ WriteByte(NID::kEnd);
+ return;
+ }
+
+ WriteByte(NID::kFilesInfo);
+ WriteNumber(db.Files.Size());
+
+ {
+ /* ---------- Empty Streams ---------- */
+ CBoolVector emptyStreamVector;
+ emptyStreamVector.Reserve(db.Files.Size());
+ int numEmptyStreams = 0;
+ for (i = 0; i < db.Files.Size(); i++)
+ if (db.Files[i].HasStream)
+ emptyStreamVector.Add(false);
+ else
+ {
+ emptyStreamVector.Add(true);
+ numEmptyStreams++;
+ }
+ if (numEmptyStreams > 0)
+ {
+ WriteByte(NID::kEmptyStream);
+ WriteNumber(Bv_GetSizeInBytes(emptyStreamVector));
+ WriteBoolVector(emptyStreamVector);
+
+ CBoolVector emptyFileVector, antiVector;
+ emptyFileVector.Reserve(numEmptyStreams);
+ antiVector.Reserve(numEmptyStreams);
+ CNum numEmptyFiles = 0, numAntiItems = 0;
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ if (!file.HasStream)
+ {
+ emptyFileVector.Add(!file.IsDir);
+ if (!file.IsDir)
+ numEmptyFiles++;
+ bool isAnti = db.IsItemAnti(i);
+ antiVector.Add(isAnti);
+ if (isAnti)
+ numAntiItems++;
+ }
+ }
+
+ if (numEmptyFiles > 0)
+ {
+ WriteByte(NID::kEmptyFile);
+ WriteNumber(Bv_GetSizeInBytes(emptyFileVector));
+ WriteBoolVector(emptyFileVector);
+ }
+
+ if (numAntiItems > 0)
+ {
+ WriteByte(NID::kAnti);
+ WriteNumber(Bv_GetSizeInBytes(antiVector));
+ WriteBoolVector(antiVector);
+ }
+ }
+ }
+
+
+ {
+ /* ---------- Names ---------- */
+
+ int numDefined = 0;
+ size_t namesDataSize = 0;
+ for (int i = 0; i < db.Files.Size(); i++)
+ {
+ const UString &name = db.Files[i].Name;
+ if (!name.IsEmpty())
+ numDefined++;
+ namesDataSize += (name.Length() + 1) * 2;
+ }
+
+ if (numDefined > 0)
+ {
+ namesDataSize++;
+ SkipAlign(2 + GetBigNumberSize(namesDataSize), 2);
+
+ WriteByte(NID::kName);
+ WriteNumber(namesDataSize);
+ WriteByte(0);
+ for (int i = 0; i < db.Files.Size(); i++)
+ {
+ const UString &name = db.Files[i].Name;
+ for (int t = 0; t <= name.Length(); t++)
+ {
+ wchar_t c = name[t];
+ WriteByte((Byte)c);
+ WriteByte((Byte)(c >> 8));
+ }
+ }
+ }
+ }
+
+ if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime);
+ if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime);
+ if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime);
+ WriteUInt64DefVector(db.StartPos, NID::kStartPos);
+
+ {
+ /* ---------- Write Attrib ---------- */
+ CBoolVector boolVector;
+ boolVector.Reserve(db.Files.Size());
+ int numDefined = 0;
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ bool defined = db.Files[i].AttribDefined;
+ boolVector.Add(defined);
+ if (defined)
+ numDefined++;
+ }
+ if (numDefined > 0)
+ {
+ WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4);
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ if (file.AttribDefined)
+ WriteUInt32(file.Attrib);
+ }
+ }
+ }
+
+ WriteByte(NID::kEnd); // for files
+ WriteByte(NID::kEnd); // for headers
+}
+
+HRESULT COutArchive::WriteDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CArchiveDatabase &db,
+ const CCompressionMethodMode *options,
+ const CHeaderOptions &headerOptions)
+{
+ if (!db.CheckNumFiles())
+ return E_FAIL;
+
+ UInt64 headerOffset;
+ UInt32 headerCRC;
+ UInt64 headerSize;
+ if (db.IsEmpty())
+ {
+ headerSize = 0;
+ headerOffset = 0;
+ headerCRC = CrcCalc(0, 0);
+ }
+ else
+ {
+ bool encodeHeaders = false;
+ if (options != 0)
+ if (options->IsEmpty())
+ options = 0;
+ if (options != 0)
+ if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
+ encodeHeaders = true;
+
+ _outByte.SetStream(SeqStream);
+ _outByte.Init();
+ _crc = CRC_INIT_VAL;
+ _countMode = encodeHeaders;
+ _writeToStream = true;
+ _countSize = 0;
+ WriteHeader(db, headerOptions, headerOffset);
+
+ if (encodeHeaders)
+ {
+ CByteBuffer buf;
+ buf.SetCapacity(_countSize);
+ _outByte2.Init((Byte *)buf, _countSize);
+
+ _countMode = false;
+ _writeToStream = false;
+ WriteHeader(db, headerOptions, headerOffset);
+
+ if (_countSize != _outByte2.GetPos())
+ return E_FAIL;
+
+ CCompressionMethodMode encryptOptions;
+ encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
+ encryptOptions.Password = options->Password;
+ CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
+ CRecordVector<UInt64> packSizes;
+ CObjectVector<CFolder> folders;
+ RINOK(EncodeStream(
+ EXTERNAL_CODECS_LOC_VARS
+ encoder, buf,
+ packSizes, folders));
+
+ _writeToStream = true;
+
+ if (folders.Size() == 0)
+ throw 1;
+
+ WriteID(NID::kEncodedHeader);
+ WritePackInfo(headerOffset, packSizes,
+ CRecordVector<bool>(), CRecordVector<UInt32>());
+ WriteUnpackInfo(folders);
+ WriteByte(NID::kEnd);
+ for (int i = 0; i < packSizes.Size(); i++)
+ headerOffset += packSizes[i];
+ }
+ RINOK(_outByte.Flush());
+ headerCRC = CRC_GET_DIGEST(_crc);
+ headerSize = _outByte.GetProcessedSize();
+ }
+ #ifdef _7Z_VOL
+ if (_endMarker)
+ {
+ CFinishHeader h;
+ h.NextHeaderSize = headerSize;
+ h.NextHeaderCRC = headerCRC;
+ h.NextHeaderOffset =
+ UInt64(0) - (headerSize +
+ 4 + kFinishHeaderSize);
+ h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
+ h.AdditionalStartBlockSize = 0;
+ RINOK(WriteFinishHeader(h));
+ return WriteFinishSignature();
+ }
+ else
+ #endif
+ {
+ CStartHeader h;
+ h.NextHeaderSize = headerSize;
+ h.NextHeaderCRC = headerCRC;
+ h.NextHeaderOffset = headerOffset;
+ RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
+ return WriteStartHeader(h);
+ }
+}
+
+void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const
+{
+ file = Files[index];
+ file2.CTimeDefined = CTime.GetItem(index, file2.CTime);
+ file2.ATimeDefined = ATime.GetItem(index, file2.ATime);
+ file2.MTimeDefined = MTime.GetItem(index, file2.MTime);
+ file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos);
+ file2.IsAnti = IsItemAnti(index);
+}
+
+void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2)
+{
+ int index = Files.Size();
+ CTime.SetItem(index, file2.CTimeDefined, file2.CTime);
+ ATime.SetItem(index, file2.ATimeDefined, file2.ATime);
+ MTime.SetItem(index, file2.MTimeDefined, file2.MTime);
+ StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos);
+ SetItemAnti(index, file2.IsAnti);
+ Files.Add(file);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.h
new file mode 100644
index 000000000..7b1b528e6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.h
@@ -0,0 +1,152 @@
+// 7zOut.h
+
+#ifndef __7Z_OUT_H
+#define __7Z_OUT_H
+
+#include "7zCompressionMode.h"
+#include "7zEncode.h"
+#include "7zHeader.h"
+#include "7zItem.h"
+
+#include "../../Common/OutBuffer.h"
+
+namespace NArchive {
+namespace N7z {
+
+class CWriteBufferLoc
+{
+ Byte *_data;
+ size_t _size;
+ size_t _pos;
+public:
+ CWriteBufferLoc(): _size(0), _pos(0) {}
+ void Init(Byte *data, size_t size)
+ {
+ _data = data;
+ _size = size;
+ _pos = 0;
+ }
+ void WriteBytes(const void *data, size_t size)
+ {
+ if (size > _size - _pos)
+ throw 1;
+ memcpy(_data + _pos, data, size);
+ _pos += size;
+ }
+ void WriteByte(Byte b)
+ {
+ if (_size == _pos)
+ throw 1;
+ _data[_pos++] = b;
+ }
+ size_t GetPos() const { return _pos; }
+};
+
+struct CHeaderOptions
+{
+ bool CompressMainHeader;
+ bool WriteCTime;
+ bool WriteATime;
+ bool WriteMTime;
+
+ CHeaderOptions():
+ CompressMainHeader(true),
+ WriteCTime(false),
+ WriteATime(false),
+ WriteMTime(true)
+ {}
+};
+
+class COutArchive
+{
+ UInt64 _prefixHeaderPos;
+
+ HRESULT WriteDirect(const void *data, UInt32 size);
+
+ UInt64 GetPos() const;
+ void WriteBytes(const void *data, size_t size);
+ void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.GetCapacity()); }
+ void WriteByte(Byte b);
+ void WriteUInt32(UInt32 value);
+ void WriteUInt64(UInt64 value);
+ void WriteNumber(UInt64 value);
+ void WriteID(UInt64 value) { WriteNumber(value); }
+
+ void WriteFolder(const CFolder &folder);
+ HRESULT WriteFileHeader(const CFileItem &itemInfo);
+ void WriteBoolVector(const CBoolVector &boolVector);
+ void WriteHashDigests(
+ const CRecordVector<bool> &digestsDefined,
+ const CRecordVector<UInt32> &hashDigests);
+
+ void WritePackInfo(
+ UInt64 dataOffset,
+ const CRecordVector<UInt64> &packSizes,
+ const CRecordVector<bool> &packCRCsDefined,
+ const CRecordVector<UInt32> &packCRCs);
+
+ void WriteUnpackInfo(const CObjectVector<CFolder> &folders);
+
+ void WriteSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ const CRecordVector<CNum> &numUnpackStreamsInFolders,
+ const CRecordVector<UInt64> &unpackSizes,
+ const CRecordVector<bool> &digestsDefined,
+ const CRecordVector<UInt32> &hashDigests);
+
+ void SkipAlign(unsigned pos, unsigned alignSize);
+ void WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize);
+ void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type);
+
+ HRESULT EncodeStream(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CEncoder &encoder, const CByteBuffer &data,
+ CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders);
+ void WriteHeader(
+ const CArchiveDatabase &db,
+ const CHeaderOptions &headerOptions,
+ UInt64 &headerOffset);
+
+ bool _countMode;
+ bool _writeToStream;
+ size_t _countSize;
+ UInt32 _crc;
+ COutBuffer _outByte;
+ CWriteBufferLoc _outByte2;
+
+ #ifdef _7Z_VOL
+ bool _endMarker;
+ #endif
+
+ HRESULT WriteSignature();
+ #ifdef _7Z_VOL
+ HRESULT WriteFinishSignature();
+ #endif
+ HRESULT WriteStartHeader(const CStartHeader &h);
+ #ifdef _7Z_VOL
+ HRESULT WriteFinishHeader(const CFinishHeader &h);
+ #endif
+ CMyComPtr<IOutStream> Stream;
+public:
+
+ COutArchive() { _outByte.Create(1 << 16); }
+ CMyComPtr<ISequentialOutStream> SeqStream;
+ HRESULT Create(ISequentialOutStream *stream, bool endMarker);
+ void Close();
+ HRESULT SkipPrefixArchiveHeader();
+ HRESULT WriteDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CArchiveDatabase &db,
+ const CCompressionMethodMode *options,
+ const CHeaderOptions &headerOptions);
+
+ #ifdef _7Z_VOL
+ static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false);
+ static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false);
+ #endif
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.cpp
new file mode 100644
index 000000000..fd4af49c7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.cpp
@@ -0,0 +1,164 @@
+// 7zProperties.cpp
+
+#include "StdAfx.h"
+
+#include "7zProperties.h"
+#include "7zHeader.h"
+#include "7zHandler.h"
+
+// #define _MULTI_PACK
+
+namespace NArchive {
+namespace N7z {
+
+struct CPropMap
+{
+ UInt64 FilePropID;
+ STATPROPSTG StatPROPSTG;
+};
+
+CPropMap kPropMap[] =
+{
+ { NID::kName, { NULL, kpidPath, VT_BSTR } },
+ { NID::kSize, { NULL, kpidSize, VT_UI8 } },
+ { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },
+
+ #ifdef _MULTI_PACK
+ { 100, { L"Pack0", kpidPackedSize0, VT_UI8 } },
+ { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } },
+ { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } },
+ { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } },
+ { 104, { L"Pack4", kpidPackedSize4, VT_UI8 } },
+ #endif
+
+ { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
+ { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },
+ { NID::kATime, { NULL, kpidATime, VT_FILETIME } },
+ { NID::kWinAttributes, { NULL, kpidAttrib, VT_UI4 } },
+ { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } },
+
+ { NID::kCRC, { NULL, kpidCRC, VT_UI4 } },
+
+ { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } }
+
+ #ifndef _SFX
+ ,
+ { 97, { NULL,kpidEncrypted, VT_BOOL } },
+ { 98, { NULL,kpidMethod, VT_BSTR } },
+ { 99, { NULL,kpidBlock, VT_UI4 } }
+ #endif
+};
+
+static const int kPropMapSize = sizeof(kPropMap) / sizeof(kPropMap[0]);
+
+static int FindPropInMap(UInt64 filePropID)
+{
+ for (int i = 0; i < kPropMapSize; i++)
+ if (kPropMap[i].FilePropID == filePropID)
+ return i;
+ return -1;
+}
+
+static void CopyOneItem(CRecordVector<UInt64> &src,
+ CRecordVector<UInt64> &dest, UInt32 item)
+{
+ for (int i = 0; i < src.Size(); i++)
+ if (src[i] == item)
+ {
+ dest.Add(item);
+ src.Delete(i);
+ return;
+ }
+}
+
+static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
+{
+ for (int i = 0; i < src.Size(); i++)
+ if (src[i] == item)
+ {
+ src.Delete(i);
+ return;
+ }
+}
+
+static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
+{
+ for (int i = 0; i < dest.Size(); i++)
+ if (dest[i] == item)
+ {
+ dest.Delete(i);
+ break;
+ }
+ dest.Insert(0, item);
+}
+
+void CHandler::FillPopIDs()
+{
+ _fileInfoPopIDs.Clear();
+
+ #ifdef _7Z_VOL
+ if(_volumes.Size() < 1)
+ return;
+ const CVolume &volume = _volumes.Front();
+ const CArchiveDatabaseEx &_db = volume.Database;
+ #endif
+
+ CRecordVector<UInt64> fileInfoPopIDs = _db.ArchiveInfo.FileInfoPopIDs;
+
+ RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
+ RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
+
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kName);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kAnti);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kSize);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kPackInfo);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCTime);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kMTime);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kATime);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kWinAttributes);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCRC);
+ CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kComment);
+ _fileInfoPopIDs += fileInfoPopIDs;
+
+ #ifndef _SFX
+ _fileInfoPopIDs.Add(97);
+ _fileInfoPopIDs.Add(98);
+ _fileInfoPopIDs.Add(99);
+ #endif
+ #ifdef _MULTI_PACK
+ _fileInfoPopIDs.Add(100);
+ _fileInfoPopIDs.Add(101);
+ _fileInfoPopIDs.Add(102);
+ _fileInfoPopIDs.Add(103);
+ _fileInfoPopIDs.Add(104);
+ #endif
+
+ #ifndef _SFX
+ InsertToHead(_fileInfoPopIDs, NID::kMTime);
+ InsertToHead(_fileInfoPopIDs, NID::kPackInfo);
+ InsertToHead(_fileInfoPopIDs, NID::kSize);
+ InsertToHead(_fileInfoPopIDs, NID::kName);
+ #endif
+}
+
+STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
+{
+ *numProperties = _fileInfoPopIDs.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)
+{
+ if ((int)index >= _fileInfoPopIDs.Size())
+ return E_INVALIDARG;
+ int indexInMap = FindPropInMap(_fileInfoPopIDs[index]);
+ if (indexInMap == -1)
+ return E_INVALIDARG;
+ const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG;
+ *propID = srcItem.propid;
+ *varType = srcItem.vt;
+ *name = 0;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.h
new file mode 100644
index 000000000..661817954
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.h
@@ -0,0 +1,22 @@
+// 7zProperties.h
+
+#ifndef __7Z_PROPERTIES_H
+#define __7Z_PROPERTIES_H
+
+#include "../../PropID.h"
+
+namespace NArchive {
+namespace N7z {
+
+enum
+{
+ kpidPackedSize0 = kpidUserDefined,
+ kpidPackedSize1,
+ kpidPackedSize2,
+ kpidPackedSize3,
+ kpidPackedSize4
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zRegister.cpp
new file mode 100644
index 000000000..6e9bf6b99
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zRegister.cpp
@@ -0,0 +1,18 @@
+// 7zRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "7zHandler.h"
+static IInArchive *CreateArc() { return new NArchive::N7z::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::N7z::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"7z", L"7z", 0, 7, {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}, 6, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(7z)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.cpp
new file mode 100644
index 000000000..06969636d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.cpp
@@ -0,0 +1,24 @@
+// 7zSpecStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zSpecStream.h"
+
+STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize != 0)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(
+ UInt64 subStream, UInt64 *value)
+{
+ if (_getSubStreamSize == NULL)
+ return E_NOTIMPL;
+ return _getSubStreamSize->GetSubStreamSize(subStream, value);
+}
+
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.h
new file mode 100644
index 000000000..2e26efd5c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.h
@@ -0,0 +1,35 @@
+// 7zSpecStream.h
+
+#ifndef __7Z_SPEC_STREAM_H
+#define __7Z_SPEC_STREAM_H
+
+#include "../../IStream.h"
+#include "../../ICoder.h"
+#include "../../../Common/MyCom.h"
+
+class CSequentialInStreamSizeCount2:
+ public ISequentialInStream,
+ public ICompressGetSubStreamSize,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
+ UInt64 _size;
+public:
+ void Init(ISequentialInStream *stream)
+ {
+ _stream = stream;
+ _getSubStreamSize = 0;
+ _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);
+ _size = 0;
+ }
+ UInt64 GetSize() const { return _size; }
+
+ MY_UNKNOWN_IMP1(ICompressGetSubStreamSize)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.cpp
new file mode 100644
index 000000000..ee7f55c04
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -0,0 +1,1177 @@
+// 7zUpdate.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "7zDecode.h"
+#include "7zEncode.h"
+#include "7zFolderInStream.h"
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+namespace NArchive {
+namespace N7z {
+
+static const UInt64 k_LZMA = 0x030101;
+static const UInt64 k_BCJ = 0x03030103;
+static const UInt64 k_BCJ2 = 0x0303011B;
+
+static const wchar_t *kMatchFinderForBCJ2_LZMA = L"BT2";
+static const UInt32 kDictionaryForBCJ2_LZMA = 1 << 20;
+static const UInt32 kAlgorithmForBCJ2_LZMA = 1;
+static const UInt32 kNumFastBytesForBCJ2_LZMA = 64;
+
+#ifdef MY_CPU_X86_OR_AMD64
+#define USE_86_FILTER
+#endif
+
+static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream,
+ UInt64 position, UInt64 size, ICompressProgressInfo *progress)
+{
+ RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0));
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(size);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
+ return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL);
+}
+
+static int GetReverseSlashPos(const UString &name)
+{
+ int slashPos = name.ReverseFind(L'/');
+ #ifdef _WIN32
+ int slash1Pos = name.ReverseFind(L'\\');
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+ return slashPos;
+}
+
+int CUpdateItem::GetExtensionPos() const
+{
+ int slashPos = GetReverseSlashPos(Name);
+ int dotPos = Name.ReverseFind(L'.');
+ if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+ return Name.Length();
+ return dotPos + 1;
+}
+
+UString CUpdateItem::GetExtension() const
+{
+ return Name.Mid(GetExtensionPos());
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+#define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b))
+
+static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2)
+{
+ size_t c1 = a1.GetCapacity();
+ size_t c2 = a2.GetCapacity();
+ RINOZ_COMP(c1, c2);
+ for (size_t i = 0; i < c1; i++)
+ RINOZ_COMP(a1[i], a2[i]);
+ return 0;
+}
+
+static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2)
+{
+ RINOZ_COMP(c1.NumInStreams, c2.NumInStreams);
+ RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams);
+ RINOZ_COMP(c1.MethodID, c2.MethodID);
+ return CompareBuffers(c1.Props, c2.Props);
+}
+
+static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2)
+{
+ RINOZ_COMP(b1.InIndex, b2.InIndex);
+ return MyCompare(b1.OutIndex, b2.OutIndex);
+}
+
+static int CompareFolders(const CFolder &f1, const CFolder &f2)
+{
+ int s1 = f1.Coders.Size();
+ int s2 = f2.Coders.Size();
+ RINOZ_COMP(s1, s2);
+ int i;
+ for (i = 0; i < s1; i++)
+ RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i]));
+ s1 = f1.BindPairs.Size();
+ s2 = f2.BindPairs.Size();
+ RINOZ_COMP(s1, s2);
+ for (i = 0; i < s1; i++)
+ RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i]));
+ return 0;
+}
+
+/*
+static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
+{
+ return MyStringCompareNoCase(f1.Name, f2.Name);
+}
+*/
+
+struct CFolderRepack
+{
+ int FolderIndex;
+ int Group;
+ CNum NumCopyFiles;
+};
+
+static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *param)
+{
+ RINOZ_COMP(p1->Group, p2->Group);
+ int i1 = p1->FolderIndex;
+ int i2 = p2->FolderIndex;
+ const CArchiveDatabaseEx &db = *(const CArchiveDatabaseEx *)param;
+ RINOZ(CompareFolders(
+ db.Folders[i1],
+ db.Folders[i2]));
+ return MyCompare(i1, i2);
+ /*
+ RINOZ_COMP(
+ db.NumUnpackStreamsVector[i1],
+ db.NumUnpackStreamsVector[i2]);
+ if (db.NumUnpackStreamsVector[i1] == 0)
+ return 0;
+ return CompareFiles(
+ db.Files[db.FolderStartFileIndex[i1]],
+ db.Files[db.FolderStartFileIndex[i2]]);
+ */
+}
+
+////////////////////////////////////////////////////////////
+
+static int CompareEmptyItems(const int *p1, const int *p2, void *param)
+{
+ const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
+ const CUpdateItem &u1 = updateItems[*p1];
+ const CUpdateItem &u2 = updateItems[*p2];
+ if (u1.IsDir != u2.IsDir)
+ return (u1.IsDir) ? 1 : -1;
+ if (u1.IsDir)
+ {
+ if (u1.IsAnti != u2.IsAnti)
+ return (u1.IsAnti ? 1 : -1);
+ int n = MyStringCompareNoCase(u1.Name, u2.Name);
+ return -n;
+ }
+ if (u1.IsAnti != u2.IsAnti)
+ return (u1.IsAnti ? 1 : -1);
+ return MyStringCompareNoCase(u1.Name, u2.Name);
+}
+
+static const char *g_Exts =
+ " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo"
+ " zip jar ear war msi"
+ " 3gp avi mov mpeg mpg mpe wmv"
+ " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav"
+ " swf "
+ " chm hxi hxs"
+ " gif jpeg jpg jp2 png tiff bmp ico psd psp"
+ " awg ps eps cgm dxf svg vrml wmf emf ai md"
+ " cad dwg pps key sxi"
+ " max 3ds"
+ " iso bin nrg mdf img pdi tar cpio xpi"
+ " vfd vhd vud vmc vsv"
+ " vmdk dsk nvram vmem vmsd vmsn vmss vmtm"
+ " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def"
+ " f77 f f90 f95"
+ " asm sql manifest dep "
+ " mak clw csproj vcproj sln dsp dsw "
+ " class "
+ " bat cmd"
+ " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
+ " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs"
+ " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf"
+ " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf"
+ " abw afp cwk lwp wpd wps wpt wrf wri"
+ " abf afm bdf fon mgf otf pcf pfa snf ttf"
+ " dbf mdb nsf ntf wdb db fdb gdb"
+ " exe dll ocx vbx sfx sys tlb awx com obj lib out o so "
+ " pdb pch idb ncb opt";
+
+int GetExtIndex(const char *ext)
+{
+ int extIndex = 1;
+ const char *p = g_Exts;
+ for (;;)
+ {
+ char c = *p++;
+ if (c == 0)
+ return extIndex;
+ if (c == ' ')
+ continue;
+ int pos = 0;
+ for (;;)
+ {
+ char c2 = ext[pos++];
+ if (c2 == 0 && (c == 0 || c == ' '))
+ return extIndex;
+ if (c != c2)
+ break;
+ c = *p++;
+ }
+ extIndex++;
+ for (;;)
+ {
+ if (c == 0)
+ return extIndex;
+ if (c == ' ')
+ break;
+ c = *p++;
+ }
+ }
+}
+
+struct CRefItem
+{
+ const CUpdateItem *UpdateItem;
+ UInt32 Index;
+ UInt32 ExtensionPos;
+ UInt32 NamePos;
+ int ExtensionIndex;
+ CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType):
+ UpdateItem(&ui),
+ Index(index),
+ ExtensionPos(0),
+ NamePos(0),
+ ExtensionIndex(0)
+ {
+ if (sortByType)
+ {
+ int slashPos = GetReverseSlashPos(ui.Name);
+ NamePos = ((slashPos >= 0) ? (slashPos + 1) : 0);
+ int dotPos = ui.Name.ReverseFind(L'.');
+ if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0))
+ ExtensionPos = ui.Name.Length();
+ else
+ {
+ ExtensionPos = dotPos + 1;
+ UString us = ui.Name.Mid(ExtensionPos);
+ if (!us.IsEmpty())
+ {
+ us.MakeLower();
+ int i;
+ AString s;
+ for (i = 0; i < us.Length(); i++)
+ {
+ wchar_t c = us[i];
+ if (c >= 0x80)
+ break;
+ s += (char)c;
+ }
+ if (i == us.Length())
+ ExtensionIndex = GetExtIndex(s);
+ else
+ ExtensionIndex = 0;
+ }
+ }
+ }
+ }
+};
+
+static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param)
+{
+ const CRefItem &a1 = *p1;
+ const CRefItem &a2 = *p2;
+ const CUpdateItem &u1 = *a1.UpdateItem;
+ const CUpdateItem &u2 = *a2.UpdateItem;
+ int n;
+ if (u1.IsDir != u2.IsDir)
+ return (u1.IsDir) ? 1 : -1;
+ if (u1.IsDir)
+ {
+ if (u1.IsAnti != u2.IsAnti)
+ return (u1.IsAnti ? 1 : -1);
+ n = MyStringCompareNoCase(u1.Name, u2.Name);
+ return -n;
+ }
+ bool sortByType = *(bool *)param;
+ if (sortByType)
+ {
+ RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex);
+ RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos));
+ RINOZ(MyStringCompareNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos));
+ if (!u1.MTimeDefined && u2.MTimeDefined) return 1;
+ if (u1.MTimeDefined && !u2.MTimeDefined) return -1;
+ if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime);
+ RINOZ_COMP(u1.Size, u2.Size);
+ }
+ return MyStringCompareNoCase(u1.Name, u2.Name);
+}
+
+struct CSolidGroup
+{
+ CRecordVector<UInt32> Indices;
+};
+
+static wchar_t *g_ExeExts[] =
+{
+ L"dll",
+ L"exe",
+ L"ocx",
+ L"sfx",
+ L"sys"
+};
+
+static bool IsExeExt(const UString &ext)
+{
+ for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++)
+ if (ext.CompareNoCase(g_ExeExts[i]) == 0)
+ return true;
+ return false;
+}
+
+#ifdef USE_86_FILTER
+
+static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &methodResult)
+{
+ methodResult.Id = methodID;
+ methodResult.NumInStreams = numInStreams;
+ methodResult.NumOutStreams = 1;
+}
+
+static void MakeExeMethod(const CCompressionMethodMode &method,
+ bool bcj2Filter, CCompressionMethodMode &exeMethod)
+{
+ exeMethod = method;
+ if (bcj2Filter)
+ {
+ CMethodFull methodFull;
+ GetMethodFull(k_BCJ2, 4, methodFull);
+ exeMethod.Methods.Insert(0, methodFull);
+ GetMethodFull(k_LZMA, 1, methodFull);
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kAlgorithm;
+ prop.Value = kAlgorithmForBCJ2_LZMA;
+ methodFull.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kMatchFinder;
+ prop.Value = kMatchFinderForBCJ2_LZMA;
+ methodFull.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kDictionarySize;
+ prop.Value = kDictionaryForBCJ2_LZMA;
+ methodFull.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kNumFastBytes;
+ prop.Value = kNumFastBytesForBCJ2_LZMA;
+ methodFull.Props.Add(prop);
+ }
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kNumThreads;
+ prop.Value = (UInt32)1;
+ methodFull.Props.Add(prop);
+ }
+
+ exeMethod.Methods.Add(methodFull);
+ exeMethod.Methods.Add(methodFull);
+ CBind bind;
+
+ bind.OutCoder = 0;
+ bind.InStream = 0;
+
+ bind.InCoder = 1;
+ bind.OutStream = 0;
+ exeMethod.Binds.Add(bind);
+
+ bind.InCoder = 2;
+ bind.OutStream = 1;
+ exeMethod.Binds.Add(bind);
+
+ bind.InCoder = 3;
+ bind.OutStream = 2;
+ exeMethod.Binds.Add(bind);
+ }
+ else
+ {
+ CMethodFull methodFull;
+ GetMethodFull(k_BCJ, 1, methodFull);
+ exeMethod.Methods.Insert(0, methodFull);
+ CBind bind;
+ bind.OutCoder = 0;
+ bind.InStream = 0;
+ bind.InCoder = 1;
+ bind.OutStream = 0;
+ exeMethod.Binds.Add(bind);
+ }
+}
+
+#endif
+
+static void FromUpdateItemToFileItem(const CUpdateItem &ui,
+ CFileItem &file, CFileItem2 &file2)
+{
+ file.Name = NItemName::MakeLegalName(ui.Name);
+ if (ui.AttribDefined)
+ file.SetAttrib(ui.Attrib);
+
+ file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined;
+ file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined;
+ file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined;
+ file2.IsAnti = ui.IsAnti;
+ file2.StartPosDefined = false;
+
+ file.Size = ui.Size;
+ file.IsDir = ui.IsDir;
+ file.HasStream = ui.HasStream();
+}
+
+class CFolderOutStream2:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ COutStreamWithCRC *_crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> _crcStream;
+ const CArchiveDatabaseEx *_db;
+ const CBoolVector *_extractStatuses;
+ CMyComPtr<ISequentialOutStream> _outStream;
+ UInt32 _startIndex;
+ int _currentIndex;
+ bool _fileIsOpen;
+ UInt64 _rem;
+
+ void OpenFile();
+ void CloseFile();
+ HRESULT CloseFileAndSetResult();
+ HRESULT ProcessEmptyFiles();
+public:
+ MY_UNKNOWN_IMP
+
+ CFolderOutStream2()
+ {
+ _crcStreamSpec = new COutStreamWithCRC;
+ _crcStream = _crcStreamSpec;
+ }
+
+ HRESULT Init(const CArchiveDatabaseEx *db, UInt32 startIndex,
+ const CBoolVector *extractStatuses, ISequentialOutStream *outStream);
+ void ReleaseOutStream();
+ HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+HRESULT CFolderOutStream2::Init(const CArchiveDatabaseEx *db, UInt32 startIndex,
+ const CBoolVector *extractStatuses, ISequentialOutStream *outStream)
+{
+ _db = db;
+ _startIndex = startIndex;
+ _extractStatuses = extractStatuses;
+ _outStream = outStream;
+
+ _currentIndex = 0;
+ _fileIsOpen = false;
+ return ProcessEmptyFiles();
+}
+
+void CFolderOutStream2::ReleaseOutStream()
+{
+ _outStream.Release();
+ _crcStreamSpec->ReleaseStream();
+}
+
+void CFolderOutStream2::OpenFile()
+{
+ _crcStreamSpec->SetStream((*_extractStatuses)[_currentIndex] ? _outStream : NULL);
+ _crcStreamSpec->Init(true);
+ _fileIsOpen = true;
+ _rem = _db->Files[_startIndex + _currentIndex].Size;
+}
+
+void CFolderOutStream2::CloseFile()
+{
+ _crcStreamSpec->ReleaseStream();
+ _fileIsOpen = false;
+ _currentIndex++;
+}
+
+HRESULT CFolderOutStream2::CloseFileAndSetResult()
+{
+ const CFileItem &file = _db->Files[_startIndex + _currentIndex];
+ CloseFile();
+ return (file.IsDir || !file.CrcDefined || file.Crc == _crcStreamSpec->GetCRC()) ? S_OK: S_FALSE;
+}
+
+HRESULT CFolderOutStream2::ProcessEmptyFiles()
+{
+ while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
+ {
+ OpenFile();
+ RINOK(CloseFileAndSetResult());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = size < _rem ? size : (UInt32)_rem;
+ RINOK(_crcStream->Write(data, cur, &cur));
+ if (cur == 0)
+ break;
+ data = (const Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (processedSize != NULL)
+ *processedSize += cur;
+ if (_rem == 0)
+ {
+ RINOK(CloseFileAndSetResult());
+ RINOK(ProcessEmptyFiles());
+ continue;
+ }
+ }
+ else
+ {
+ RINOK(ProcessEmptyFiles());
+ if (_currentIndex == _extractStatuses->Size())
+ {
+ // we don't support partial extracting
+ return E_FAIL;
+ }
+ OpenFile();
+ }
+ }
+ return S_OK;
+}
+
+class CThreadDecoder: public CVirtThread
+{
+public:
+ HRESULT Result;
+ CMyComPtr<IInStream> InStream;
+
+ CFolderOutStream2 *FosSpec;
+ CMyComPtr<ISequentialOutStream> Fos;
+
+ UInt64 StartPos;
+ const UInt64 *PackSizes;
+ const CFolder *Folder;
+ #ifndef _NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> GetTextPassword;
+ #endif
+
+ DECL_EXTERNAL_CODECS_VARS
+ CDecoder Decoder;
+
+ #ifndef _7ZIP_ST
+ bool MtMode;
+ UInt32 NumThreads;
+ #endif
+
+ CThreadDecoder():
+ Decoder(true)
+ {
+ #ifndef _7ZIP_ST
+ MtMode = false;
+ NumThreads = 1;
+ #endif
+ FosSpec = new CFolderOutStream2;
+ Fos = FosSpec;
+ Result = E_FAIL;
+ }
+ virtual void Execute();
+};
+
+void CThreadDecoder::Execute()
+{
+ try
+ {
+ #ifndef _NO_CRYPTO
+ bool passwordIsDefined;
+ #endif
+ Result = Decoder.Decode(
+ EXTERNAL_CODECS_VARS
+ InStream,
+ StartPos,
+ PackSizes,
+ *Folder,
+ Fos,
+ NULL
+ #ifndef _NO_CRYPTO
+ , GetTextPassword, passwordIsDefined
+ #endif
+ #ifndef _7ZIP_ST
+ , MtMode, NumThreads
+ #endif
+ );
+ }
+ catch(...)
+ {
+ Result = E_FAIL;
+ }
+ if (Result == S_OK)
+ Result = FosSpec->CheckFinishedState();
+ FosSpec->ReleaseOutStream();
+}
+
+bool static Is86FilteredFolder(const CFolder &f)
+{
+ for (int i = 0; i < f.Coders.Size(); i++)
+ {
+ CMethodId m = f.Coders[i].MethodID;
+ if (m == k_BCJ || m == k_BCJ2)
+ return true;
+ }
+ return false;
+}
+
+#ifndef _NO_CRYPTO
+
+class CCryptoGetTextPassword:
+ public ICryptoGetTextPassword,
+ public CMyUnknownImp
+{
+public:
+ UString Password;
+
+ MY_UNKNOWN_IMP
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+};
+
+STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password)
+{
+ return StringToBstr(Password, password);
+}
+
+#endif
+
+static const int kNumGroupsMax = 4;
+
+#ifdef USE_86_FILTER
+static bool Is86Group(int group) { return (group & 1) != 0; }
+#endif
+static bool IsEncryptedGroup(int group) { return (group & 2) != 0; }
+static int GetGroupIndex(bool encrypted, int bcjFiltered)
+ { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); }
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ const CArchiveDatabaseEx *db,
+ const CObjectVector<CUpdateItem> &updateItems,
+ COutArchive &archive,
+ CArchiveDatabase &newDatabase,
+ ISequentialOutStream *seqOutStream,
+ IArchiveUpdateCallback *updateCallback,
+ const CUpdateOptions &options
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getDecoderPassword
+ #endif
+ )
+{
+ UInt64 numSolidFiles = options.NumSolidFiles;
+ if (numSolidFiles == 0)
+ numSolidFiles = 1;
+ /*
+ CMyComPtr<IOutStream> outStream;
+ RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
+ if (!outStream)
+ return E_NOTIMPL;
+ */
+
+ UInt64 startBlockSize = db != 0 ? db->ArchiveInfo.StartPosition: 0;
+ if (startBlockSize > 0 && !options.RemoveSfxBlock)
+ {
+ RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
+ }
+
+ CRecordVector<int> fileIndexToUpdateIndexMap;
+ CRecordVector<CFolderRepack> folderRefs;
+ UInt64 complexity = 0;
+ UInt64 inSizeForReduce2 = 0;
+ bool needEncryptedRepack = false;
+ if (db != 0)
+ {
+ fileIndexToUpdateIndexMap.Reserve(db->Files.Size());
+ int i;
+ for (i = 0; i < db->Files.Size(); i++)
+ fileIndexToUpdateIndexMap.Add(-1);
+
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ int index = updateItems[i].IndexInArchive;
+ if (index != -1)
+ fileIndexToUpdateIndexMap[index] = i;
+ }
+
+ for (i = 0; i < db->Folders.Size(); i++)
+ {
+ CNum indexInFolder = 0;
+ CNum numCopyItems = 0;
+ CNum numUnpackStreams = db->NumUnpackStreamsVector[i];
+ UInt64 repackSize = 0;
+ for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++)
+ {
+ const CFileItem &file = db->Files[fi];
+ if (file.HasStream)
+ {
+ indexInFolder++;
+ int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0 && !updateItems[updateIndex].NewData)
+ {
+ numCopyItems++;
+ repackSize += file.Size;
+ }
+ }
+ }
+
+ if (numCopyItems == 0)
+ continue;
+
+ CFolderRepack rep;
+ rep.FolderIndex = i;
+ rep.NumCopyFiles = numCopyItems;
+ const CFolder &f = db->Folders[i];
+ bool isEncrypted = f.IsEncrypted();
+ rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f));
+ folderRefs.Add(rep);
+ if (numCopyItems == numUnpackStreams)
+ complexity += db->GetFolderFullPackSize(i);
+ else
+ {
+ complexity += repackSize;
+ if (repackSize > inSizeForReduce2)
+ inSizeForReduce2 = repackSize;
+ if (isEncrypted)
+ needEncryptedRepack = true;
+ }
+ }
+ folderRefs.Sort(CompareFolderRepacks, (void *)db);
+ }
+
+ UInt64 inSizeForReduce = 0;
+ int i;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ complexity += ui.Size;
+ if (numSolidFiles != 1)
+ inSizeForReduce += ui.Size;
+ else if (ui.Size > inSizeForReduce)
+ inSizeForReduce = ui.Size;
+ }
+ }
+
+ if (inSizeForReduce2 > inSizeForReduce)
+ inSizeForReduce = inSizeForReduce2;
+
+ const UInt32 kMinReduceSize = (1 << 16);
+ if (inSizeForReduce < kMinReduceSize)
+ inSizeForReduce = kMinReduceSize;
+
+ RINOK(updateCallback->SetTotal(complexity));
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CThreadDecoder threadDecoder;
+ if (!folderRefs.IsEmpty())
+ {
+ #ifdef EXTERNAL_CODECS
+ threadDecoder._codecsInfo = codecsInfo;
+ threadDecoder._externalCodecs = *externalCodecs;
+ #endif
+ RINOK(threadDecoder.Create());
+ }
+
+ CObjectVector<CSolidGroup> groups;
+ for (i = 0; i < kNumGroupsMax; i++)
+ groups.Add(CSolidGroup());
+
+ {
+ // ---------- Split files to 2 groups ----------
+
+ bool useFilters = options.UseFilters;
+ const CCompressionMethodMode &method = *options.Method;
+ if (method.Methods.Size() != 1 || method.Binds.Size() != 0)
+ useFilters = false;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (!ui.NewData || !ui.HasStream())
+ continue;
+ bool filteredGroup = false;
+ if (useFilters)
+ {
+ int dotPos = ui.Name.ReverseFind(L'.');
+ if (dotPos >= 0)
+ filteredGroup = IsExeExt(ui.Name.Mid(dotPos + 1));
+ }
+ groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i);
+ }
+ }
+
+ #ifndef _NO_CRYPTO
+
+ CCryptoGetTextPassword *getPasswordSpec = NULL;
+ if (needEncryptedRepack)
+ {
+ getPasswordSpec = new CCryptoGetTextPassword;
+ threadDecoder.GetTextPassword = getPasswordSpec;
+
+ if (options.Method->PasswordIsDefined)
+ getPasswordSpec->Password = options.Method->Password;
+ else
+ {
+ if (!getDecoderPassword)
+ return E_NOTIMPL;
+ CMyComBSTR password;
+ RINOK(getDecoderPassword->CryptoGetTextPassword(&password));
+ getPasswordSpec->Password = password;
+ }
+ }
+
+ #endif
+
+ // ---------- Compress ----------
+
+ RINOK(archive.Create(seqOutStream, false));
+ RINOK(archive.SkipPrefixArchiveHeader());
+
+ int folderRefIndex = 0;
+ lps->ProgressOffset = 0;
+
+ for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++)
+ {
+ const CSolidGroup &group = groups[groupIndex];
+
+ CCompressionMethodMode method;
+ #ifdef USE_86_FILTER
+ if (Is86Group(groupIndex))
+ MakeExeMethod(*options.Method, options.MaxFilter, method);
+ else
+ #endif
+ method = *options.Method;
+
+ if (IsEncryptedGroup(groupIndex))
+ {
+ if (!method.PasswordIsDefined)
+ {
+ #ifndef _NO_CRYPTO
+ if (getPasswordSpec)
+ method.Password = getPasswordSpec->Password;
+ #endif
+ method.PasswordIsDefined = true;
+ }
+ }
+ else
+ {
+ method.PasswordIsDefined = false;
+ method.Password.Empty();
+ }
+
+ CEncoder encoder(method);
+
+ for (; folderRefIndex < folderRefs.Size(); folderRefIndex++)
+ {
+ const CFolderRepack &rep = folderRefs[folderRefIndex];
+ if (rep.Group != groupIndex)
+ break;
+ int folderIndex = rep.FolderIndex;
+
+ if (rep.NumCopyFiles == db->NumUnpackStreamsVector[folderIndex])
+ {
+ UInt64 packSize = db->GetFolderFullPackSize(folderIndex);
+ RINOK(WriteRange(inStream, archive.SeqStream,
+ db->GetFolderStreamPos(folderIndex, 0), packSize, progress));
+ lps->ProgressOffset += packSize;
+
+ const CFolder &folder = db->Folders[folderIndex];
+ CNum startIndex = db->FolderStartPackStreamIndex[folderIndex];
+ for (int j = 0; j < folder.PackStreams.Size(); j++)
+ {
+ newDatabase.PackSizes.Add(db->PackSizes[startIndex + j]);
+ // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);
+ // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);
+ }
+ newDatabase.Folders.Add(folder);
+ }
+ else
+ {
+ CStreamBinder sb;
+ RINOK(sb.CreateEvents());
+ CMyComPtr<ISequentialOutStream> sbOutStream;
+ CMyComPtr<ISequentialInStream> sbInStream;
+ sb.CreateStreams(&sbInStream, &sbOutStream);
+ CBoolVector extractStatuses;
+
+ CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
+ CNum indexInFolder = 0;
+
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ bool needExtract = false;
+ if (db->Files[fi].HasStream)
+ {
+ indexInFolder++;
+ int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0 && !updateItems[updateIndex].NewData)
+ needExtract = true;
+ }
+ extractStatuses.Add(needExtract);
+ }
+
+ RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream));
+ sbOutStream.Release();
+
+ threadDecoder.InStream = inStream;
+ threadDecoder.Folder = &db->Folders[folderIndex];
+ threadDecoder.StartPos = db->GetFolderStreamPos(folderIndex, 0);
+ threadDecoder.PackSizes = &db->PackSizes[db->FolderStartPackStreamIndex[folderIndex]];
+
+ threadDecoder.Start();
+
+ int startPackIndex = newDatabase.PackSizes.Size();
+ CFolder newFolder;
+ RINOK(encoder.Encode(
+ EXTERNAL_CODECS_LOC_VARS
+ sbInStream, NULL, &inSizeForReduce, newFolder,
+ archive.SeqStream, newDatabase.PackSizes, progress));
+
+ threadDecoder.WaitFinish();
+
+ RINOK(threadDecoder.Result);
+
+ for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+ lps->OutSize += newDatabase.PackSizes[startPackIndex];
+ lps->InSize += newFolder.GetUnpackSize();
+
+ newDatabase.Folders.Add(newFolder);
+ }
+
+ newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles);
+
+ CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
+
+ CNum indexInFolder = 0;
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ CFileItem file;
+ CFileItem2 file2;
+ db->GetFile(fi, file, file2);
+ if (file.HasStream)
+ {
+ indexInFolder++;
+ int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0)
+ {
+ const CUpdateItem &ui = updateItems[updateIndex];
+ if (ui.NewData)
+ continue;
+ if (ui.NewProps)
+ {
+ CFileItem uf;
+ FromUpdateItemToFileItem(ui, uf, file2);
+ uf.Size = file.Size;
+ uf.Crc = file.Crc;
+ uf.CrcDefined = file.CrcDefined;
+ uf.HasStream = file.HasStream;
+ file = uf;
+ }
+ newDatabase.AddFile(file, file2);
+ }
+ }
+ }
+ }
+
+ int numFiles = group.Indices.Size();
+ if (numFiles == 0)
+ continue;
+ CRecordVector<CRefItem> refItems;
+ refItems.Reserve(numFiles);
+ bool sortByType = (numSolidFiles > 1);
+ for (i = 0; i < numFiles; i++)
+ refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType));
+ refItems.Sort(CompareUpdateItems, (void *)&sortByType);
+
+ CRecordVector<UInt32> indices;
+ indices.Reserve(numFiles);
+
+ for (i = 0; i < numFiles; i++)
+ {
+ UInt32 index = refItems[i].Index;
+ indices.Add(index);
+ /*
+ const CUpdateItem &ui = updateItems[index];
+ CFileItem file;
+ if (ui.NewProps)
+ FromUpdateItemToFileItem(ui, file);
+ else
+ file = db.Files[ui.IndexInArchive];
+ if (file.IsAnti || file.IsDir)
+ return E_FAIL;
+ newDatabase.Files.Add(file);
+ */
+ }
+
+ for (i = 0; i < numFiles;)
+ {
+ UInt64 totalSize = 0;
+ int numSubFiles;
+ UString prevExtension;
+ for (numSubFiles = 0; i + numSubFiles < numFiles &&
+ numSubFiles < numSolidFiles; numSubFiles++)
+ {
+ const CUpdateItem &ui = updateItems[indices[i + numSubFiles]];
+ totalSize += ui.Size;
+ if (totalSize > options.NumSolidBytes)
+ break;
+ if (options.SolidExtension)
+ {
+ UString ext = ui.GetExtension();
+ if (numSubFiles == 0)
+ prevExtension = ext;
+ else
+ if (ext.CompareNoCase(prevExtension) != 0)
+ break;
+ }
+ }
+ if (numSubFiles < 1)
+ numSubFiles = 1;
+
+ CFolderInStream *inStreamSpec = new CFolderInStream;
+ CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
+ inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
+
+ CFolder folderItem;
+
+ int startPackIndex = newDatabase.PackSizes.Size();
+ RINOK(encoder.Encode(
+ EXTERNAL_CODECS_LOC_VARS
+ solidInStream, NULL, &inSizeForReduce, folderItem,
+ archive.SeqStream, newDatabase.PackSizes, progress));
+
+ for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+ lps->OutSize += newDatabase.PackSizes[startPackIndex];
+
+ lps->InSize += folderItem.GetUnpackSize();
+ // for ()
+ // newDatabase.PackCRCsDefined.Add(false);
+ // newDatabase.PackCRCs.Add(0);
+
+ newDatabase.Folders.Add(folderItem);
+
+ CNum numUnpackStreams = 0;
+ for (int subIndex = 0; subIndex < numSubFiles; subIndex++)
+ {
+ const CUpdateItem &ui = updateItems[indices[i + subIndex]];
+ CFileItem file;
+ CFileItem2 file2;
+ if (ui.NewProps)
+ FromUpdateItemToFileItem(ui, file, file2);
+ else
+ db->GetFile(ui.IndexInArchive, file, file2);
+ if (file2.IsAnti || file.IsDir)
+ return E_FAIL;
+
+ /*
+ CFileItem &file = newDatabase.Files[
+ startFileIndexInDatabase + i + subIndex];
+ */
+ if (!inStreamSpec->Processed[subIndex])
+ {
+ continue;
+ // file.Name += L".locked";
+ }
+
+ file.Crc = inStreamSpec->CRCs[subIndex];
+ file.Size = inStreamSpec->Sizes[subIndex];
+ if (file.Size != 0)
+ {
+ file.CrcDefined = true;
+ file.HasStream = true;
+ numUnpackStreams++;
+ }
+ else
+ {
+ file.CrcDefined = false;
+ file.HasStream = false;
+ }
+ newDatabase.AddFile(file, file2);
+ }
+ // numUnpackStreams = 0 is very bad case for locked files
+ // v3.13 doesn't understand it.
+ newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
+ i += numSubFiles;
+ }
+ }
+
+ if (folderRefIndex != folderRefs.Size())
+ return E_FAIL;
+
+ /*
+ folderRefs.ClearAndFree();
+ fileIndexToUpdateIndexMap.ClearAndFree();
+ groups.ClearAndFree();
+ */
+
+ {
+ // ---------- Write Folders & Empty Files ----------
+
+ CRecordVector<int> emptyRefs;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ if (ui.HasStream())
+ continue;
+ }
+ else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream)
+ continue;
+ emptyRefs.Add(i);
+ }
+ emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems);
+ for (i = 0; i < emptyRefs.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[emptyRefs[i]];
+ CFileItem file;
+ CFileItem2 file2;
+ if (ui.NewProps)
+ FromUpdateItemToFileItem(ui, file, file2);
+ else
+ db->GetFile(ui.IndexInArchive, file, file2);
+ newDatabase.AddFile(file, file2);
+ }
+ }
+
+ newDatabase.ReserveDown();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.h
new file mode 100644
index 000000000..31e362246
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.h
@@ -0,0 +1,88 @@
+// 7zUpdate.h
+
+#ifndef __7Z_UPDATE_H
+#define __7Z_UPDATE_H
+
+#include "7zCompressionMode.h"
+#include "7zIn.h"
+#include "7zOut.h"
+
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CUpdateItem
+{
+ int IndexInArchive;
+ int IndexInClient;
+
+ UInt64 CTime;
+ UInt64 ATime;
+ UInt64 MTime;
+
+ UInt64 Size;
+ UString Name;
+
+ UInt32 Attrib;
+
+ bool NewData;
+ bool NewProps;
+
+ bool IsAnti;
+ bool IsDir;
+
+ bool AttribDefined;
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+
+ bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
+
+ CUpdateItem():
+ IsAnti(false),
+ IsDir(false),
+ AttribDefined(false),
+ CTimeDefined(false),
+ ATimeDefined(false),
+ MTimeDefined(false)
+ {}
+ void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); };
+
+ int GetExtensionPos() const;
+ UString GetExtension() const;
+};
+
+struct CUpdateOptions
+{
+ const CCompressionMethodMode *Method;
+ const CCompressionMethodMode *HeaderMethod;
+ bool UseFilters;
+ bool MaxFilter;
+
+ CHeaderOptions HeaderOptions;
+
+ UInt64 NumSolidFiles;
+ UInt64 NumSolidBytes;
+ bool SolidExtension;
+ bool RemoveSfxBlock;
+ bool VolumeMode;
+};
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ const CArchiveDatabaseEx *db,
+ const CObjectVector<CUpdateItem> &updateItems,
+ COutArchive &archive,
+ CArchiveDatabase &newDatabase,
+ ISequentialOutStream *seqOutStream,
+ IArchiveUpdateCallback *updateCallback,
+ const CUpdateOptions &options
+ #ifndef _NO_CRYPTO
+ , ICryptoGetTextPassword *getDecoderPassword
+ #endif
+ );
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.cpp
new file mode 100644
index 000000000..d0feea85c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.h
new file mode 100644
index 000000000..2e4be10b2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ApmHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ApmHandler.cpp
new file mode 100644
index 000000000..a3b5e19b9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/ApmHandler.cpp
@@ -0,0 +1,356 @@
+// ApmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NApm {
+
+struct CItem
+{
+ UInt32 StartBlock;
+ UInt32 NumBlocks;
+ char Name[32];
+ char Type[32];
+ /*
+ UInt32 DataStartBlock;
+ UInt32 NumDataBlocks;
+ UInt32 Status;
+ UInt32 BootStartBlock;
+ UInt32 BootSize;
+ UInt32 BootAddr;
+ UInt32 BootEntry;
+ UInt32 BootChecksum;
+ char Processor[16];
+ */
+
+ bool Parse(const Byte *p, UInt32 &numBlocksInMap)
+ {
+ if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0)
+ return false;
+ numBlocksInMap = Get32(p + 4);
+ StartBlock = Get32(p + 8);
+ NumBlocks = Get32(p + 0xC);
+ memcpy(Name, p + 0x10, 32);
+ memcpy(Type, p + 0x30, 32);
+ /*
+ DataStartBlock = Get32(p + 0x50);
+ NumDataBlocks = Get32(p + 0x54);
+ Status = Get32(p + 0x58);
+ BootStartBlock = Get32(p + 0x5C);
+ BootSize = Get32(p + 0x60);
+ BootAddr = Get32(p + 0x64);
+ if (Get32(p + 0x68) != 0)
+ return false;
+ BootEntry = Get32(p + 0x6C);
+ if (Get32(p + 0x70) != 0)
+ return false;
+ BootChecksum = Get32(p + 0x74);
+ memcpy(Processor, p + 0x78, 16);
+ */
+ return true;
+ }
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CRecordVector<CItem> _items;
+
+ int _blockSizeLog;
+ UInt32 _numBlocks;
+
+ HRESULT ReadTables(IInStream *stream);
+ UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; }
+ UInt64 GetItemSize(const CItem &item) { return BlocksToBytes(item.NumBlocks); }
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+static inline int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+HRESULT CHandler::ReadTables(IInStream *stream)
+{
+ const UInt32 kSectorSize = 512;
+ Byte buf[kSectorSize];
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+ if (buf[0] != 0x45 || buf[1] != 0x52)
+ return S_FALSE;
+ _blockSizeLog = GetLog(Get16(buf + 2));
+ if (_blockSizeLog < 9 || _blockSizeLog > 14)
+ return S_FALSE;
+ _numBlocks = Get32(buf + 4);
+ for (int i = 8; i < 16; i++)
+ if (buf[i] != 0)
+ return S_FALSE;
+ }
+
+ unsigned numSkips = (unsigned)1 << (_blockSizeLog - 9);
+ for (unsigned j = 1; j < numSkips; j++)
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+ }
+
+ UInt32 numBlocksInMap = 0;
+ for (unsigned i = 0;;)
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+
+ CItem item;
+
+ UInt32 numBlocksInMap2;
+ if (!item.Parse(buf, numBlocksInMap2))
+ return S_FALSE;
+ if (i == 0)
+ {
+ numBlocksInMap = numBlocksInMap2;
+ if (numBlocksInMap > (1 << 8))
+ return S_FALSE;
+ }
+ else if (numBlocksInMap2 != numBlocksInMap)
+ return S_FALSE;
+
+ UInt32 finish = item.StartBlock + item.NumBlocks;
+ if (finish < item.StartBlock)
+ return S_FALSE;
+ _numBlocks = MyMax(_numBlocks, finish);
+
+ _items.Add(item);
+ for (unsigned j = 1; j < numSkips; j++)
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+ }
+ if (++i == numBlocksInMap)
+ break;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(ReadTables(stream));
+ _stream = stream;
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static AString GetString(const char *s)
+{
+ AString res;
+ for (int i = 0; i < 32 && s[i] != 0; i++)
+ res += s[i];
+ return res;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMainSubfile:
+ {
+ int mainIndex = -1;
+ for (int i = 0; i < _items.Size(); i++)
+ {
+ AString s = GetString(_items[i].Type);
+ if (s != "Apple_Free" &&
+ s != "Apple_partition_map")
+ {
+ if (mainIndex >= 0)
+ {
+ mainIndex = -1;
+ break;
+ }
+ mainIndex = i;
+ }
+ }
+ if (mainIndex >= 0)
+ prop = (UInt32)mainIndex;
+ break;
+ }
+ case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
+ case kpidPhySize: prop = BlocksToBytes(_numBlocks); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ AString s = GetString(item.Name);
+ if (s.IsEmpty())
+ {
+ char s2[32];
+ ConvertUInt32ToString(index, s2);
+ s = s2;
+ }
+ AString type = GetString(item.Type);
+ if (type == "Apple_HFS")
+ type = "hfs";
+ if (!type.IsEmpty())
+ {
+ s += '.';
+ s += type;
+ }
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = GetItemSize(item);
+ break;
+ case kpidOffset: prop = BlocksToBytes(item.StartBlock); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += GetItemSize(_items[allFilesMode ? i : indices[i]]);
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ UInt64 size = GetItemSize(item);
+ totalSize += size;
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ RINOK(_stream->Seek(BlocksToBytes(item.StartBlock), STREAM_SEEK_SET, NULL));
+ streamSpec->Init(size);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == size ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ return CreateLimitedInStream(_stream, BlocksToBytes(item.StartBlock), GetItemSize(item), stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"APM", L"", 0, 0xD4, { 0x50, 0x4D, 0, 0, 0, 0, 0 }, 7, false, CreateArc, 0 };
+
+REGISTER_ARC(Apm)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ArchiveExports.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ArchiveExports.cpp
new file mode 100644
index 000000000..c7908b591
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/ArchiveExports.cpp
@@ -0,0 +1,135 @@
+// ArchiveExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+
+static const unsigned int kNumArcsMax = 48;
+static unsigned int g_NumArcs = 0;
+static unsigned int g_DefaultArcIndex = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax];
+void RegisterArc(const CArcInfo *arcInfo)
+{
+ if (g_NumArcs < kNumArcsMax)
+ {
+ const wchar_t *p = arcInfo->Name;
+ if (p[0] == '7' && p[1] == 'z' && p[2] == 0)
+ g_DefaultArcIndex = g_NumArcs;
+ g_Arcs[g_NumArcs++] = arcInfo;
+ }
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler,
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
+
+static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value)
+{
+ if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
+ value->vt = VT_BSTR;
+ return S_OK;
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
+{
+ return SetPropString((const char *)&guid, sizeof(GUID), value);
+}
+
+int FindFormatCalssId(const GUID *clsID)
+{
+ GUID cls = *clsID;
+ CLS_ARC_ID_ITEM(cls) = 0;
+ if (cls != CLSID_CArchiveHandler)
+ return -1;
+ Byte id = CLS_ARC_ID_ITEM(*clsID);
+ for (unsigned i = 0; i < g_NumArcs; i++)
+ if (g_Arcs[i]->ClassId == id)
+ return (int)i;
+ return -1;
+}
+
+STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ COM_TRY_BEGIN
+ {
+ int needIn = (*iid == IID_IInArchive);
+ int needOut = (*iid == IID_IOutArchive);
+ if (!needIn && !needOut)
+ return E_NOINTERFACE;
+ int formatIndex = FindFormatCalssId(clsid);
+ if (formatIndex < 0)
+ return CLASS_E_CLASSNOTAVAILABLE;
+
+ const CArcInfo &arc = *g_Arcs[formatIndex];
+ if (needIn)
+ {
+ *outObject = arc.CreateInArchive();
+ ((IInArchive *)*outObject)->AddRef();
+ }
+ else
+ {
+ if (!arc.CreateOutArchive)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ *outObject = arc.CreateOutArchive();
+ ((IOutArchive *)*outObject)->AddRef();
+ }
+ }
+ COM_TRY_END
+ return S_OK;
+}
+
+STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ if (formatIndex >= g_NumArcs)
+ return E_INVALIDARG;
+ const CArcInfo &arc = *g_Arcs[formatIndex];
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case NArchive::kName:
+ prop = arc.Name;
+ break;
+ case NArchive::kClassID:
+ {
+ GUID clsId = CLSID_CArchiveHandler;
+ CLS_ARC_ID_ITEM(clsId) = arc.ClassId;
+ return SetPropGUID(clsId, value);
+ }
+ case NArchive::kExtension:
+ if (arc.Ext != 0)
+ prop = arc.Ext;
+ break;
+ case NArchive::kAddExtension:
+ if (arc.AddExt != 0)
+ prop = arc.AddExt;
+ break;
+ case NArchive::kUpdate:
+ prop = (bool)(arc.CreateOutArchive != 0);
+ break;
+ case NArchive::kKeepName:
+ prop = arc.KeepName;
+ break;
+ case NArchive::kStartSignature:
+ return SetPropString((const char *)arc.Signature, arc.SignatureSize, value);
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
+{
+ return GetHandlerProperty2(g_DefaultArcIndex, propID, value);
+}
+
+STDAPI GetNumberOfFormats(UINT32 *numFormats)
+{
+ *numFormats = g_NumArcs;
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp
new file mode 100644
index 000000000..4dd686ec0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp
@@ -0,0 +1,798 @@
+// ArjHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/ArjDecoder1.h"
+#include "../Compress/ArjDecoder2.h"
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+#include "Common/OutStreamWithCRC.h"
+
+using namespace NWindows;
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NArj {
+
+const int kBlockSizeMin = 30;
+const int kBlockSizeMax = 2600;
+
+namespace NSignature
+{
+ const Byte kSig0 = 0x60;
+ const Byte kSig1 = 0xEA;
+}
+
+namespace NFileHeader
+{
+ namespace NCompressionMethod
+ {
+ enum
+ {
+ kStored = 0,
+ kCompressed1a = 1,
+ kCompressed1b = 2,
+ kCompressed1c = 3,
+ kCompressed2 = 4,
+ kNoDataNoCRC = 8,
+ kNoData = 9
+ };
+ }
+
+ namespace NFileType
+ {
+ enum
+ {
+ kBinary = 0,
+ k7BitText = 1,
+ kArchiveHeader = 2,
+ kDirectory = 3,
+ kVolumeLablel = 4,
+ kChapterLabel = 5
+ };
+ }
+
+ namespace NFlags
+ {
+ const Byte kGarbled = 1;
+ const Byte kVolume = 4;
+ const Byte kExtFile = 8;
+ const Byte kPathSym = 0x10;
+ const Byte kBackup = 0x20;
+ }
+
+ namespace NHostOS
+ {
+ enum EEnum
+ {
+ kMSDOS = 0, // filesystem used by MS-DOS, OS/2, Win32
+ // pkarj 2.50 (FAT / VFAT / FAT32 file systems)
+ kPRIMOS,
+ kUnix,
+ kAMIGA,
+ kMac,
+ kOS_2,
+ kAPPLE_GS,
+ kAtari_ST,
+ kNext,
+ kVAX_VMS,
+ kWIN95
+ };
+ }
+}
+
+struct CArchiveHeader
+{
+ // Byte ArchiverVersion;
+ // Byte ExtractVersion;
+ Byte HostOS;
+ // Byte Flags;
+ // Byte SecuryVersion;
+ // Byte FileType;
+ // Byte Reserved;
+ UInt32 CTime;
+ UInt32 MTime;
+ UInt32 ArchiveSize;
+ // UInt32 SecurityEnvelopeFilePosition;
+ // UInt16 FilespecPositionInFilename;
+ // UInt16 LengthOfSecurityEnvelopeSata;
+ // Byte EncryptionVersion;
+ // Byte LastChapter;
+ AString Name;
+ AString Comment;
+
+ HRESULT Parse(const Byte *p, unsigned size);
+};
+
+static HRESULT ReadString(const Byte *p, unsigned &size, AString &res)
+{
+ AString s;
+ for (unsigned i = 0; i < size;)
+ {
+ char c = (char)p[i++];
+ if (c == 0)
+ {
+ size = i;
+ res = s;
+ return S_OK;
+ }
+ s += c;
+ }
+ return S_FALSE;
+}
+
+HRESULT CArchiveHeader::Parse(const Byte *p, unsigned size)
+{
+ if (size < kBlockSizeMin)
+ return S_FALSE;
+ Byte firstHeaderSize = p[0];
+ if (firstHeaderSize > size)
+ return S_FALSE;
+ // ArchiverVersion = p[1];
+ // ExtractVersion = p[2];
+ HostOS = p[3];
+ // Flags = p[4];
+ // SecuryVersion = p[5];
+ if (p[6] != NFileHeader::NFileType::kArchiveHeader)
+ return S_FALSE;
+ // Reserved = p[7];
+ CTime = Get32(p + 8);
+ MTime = Get32(p + 12);
+ ArchiveSize = Get32(p + 16);
+ // SecurityEnvelopeFilePosition = Get32(p + 20);
+ // UInt16 filespecPositionInFilename = Get16(p + 24);
+ // LengthOfSecurityEnvelopeSata = Get16(p + 26);
+ // EncryptionVersion = p[28];
+ // LastChapter = p[29];
+ unsigned pos = firstHeaderSize;
+ unsigned size1 = size - pos;
+ RINOK(ReadString(p + pos, size1, Name));
+ pos += size1;
+ size1 = size - pos;
+ RINOK(ReadString(p + pos, size1, Comment));
+ pos += size1;
+ return S_OK;
+}
+
+struct CItem
+{
+ AString Name;
+ AString Comment;
+
+ UInt32 MTime;
+ UInt32 PackSize;
+ UInt32 Size;
+ UInt32 FileCRC;
+ UInt32 SplitPos;
+
+ Byte Version;
+ Byte ExtractVersion;
+ Byte HostOS;
+ Byte Flags;
+ Byte Method;
+ Byte FileType;
+
+ // UInt16 FilespecPositionInFilename;
+ UInt16 FileAccessMode;
+ // Byte FirstChapter;
+ // Byte LastChapter;
+
+ UInt64 DataPosition;
+
+ bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kGarbled) != 0; }
+ bool IsDir() const { return (FileType == NFileHeader::NFileType::kDirectory); }
+ bool IsSplitAfter() const { return (Flags & NFileHeader::NFlags::kVolume) != 0; }
+ bool IsSplitBefore() const { return (Flags & NFileHeader::NFlags::kExtFile) != 0; }
+ UInt32 GetWinAttributes() const
+ {
+ UInt32 winAtrributes;
+ switch(HostOS)
+ {
+ case NFileHeader::NHostOS::kMSDOS:
+ case NFileHeader::NHostOS::kWIN95:
+ winAtrributes = FileAccessMode;
+ break;
+ default:
+ winAtrributes = 0;
+ }
+ if (IsDir())
+ winAtrributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAtrributes;
+ }
+
+ HRESULT Parse(const Byte *p, unsigned size);
+};
+
+HRESULT CItem::Parse(const Byte *p, unsigned size)
+{
+ if (size < kBlockSizeMin)
+ return S_FALSE;
+
+ Byte firstHeaderSize = p[0];
+
+ Version = p[1];
+ ExtractVersion = p[2];
+ HostOS = p[3];
+ Flags = p[4];
+ Method = p[5];
+ FileType = p[6];
+ // Reserved = p[7];
+ MTime = Get32(p + 8);
+ PackSize = Get32(p + 12);
+ Size = Get32(p + 16);
+ FileCRC = Get32(p + 20);
+ // FilespecPositionInFilename = Get16(p + 24);
+ FileAccessMode = Get16(p + 26);
+ // FirstChapter = p[28];
+ // FirstChapter = p[29];
+
+ SplitPos = 0;
+ if (IsSplitBefore() && firstHeaderSize >= 34)
+ SplitPos = Get32(p + 30);
+
+ unsigned pos = firstHeaderSize;
+ unsigned size1 = size - pos;
+ RINOK(ReadString(p + pos, size1, Name));
+ pos += size1;
+ size1 = size - pos;
+ RINOK(ReadString(p + pos, size1, Comment));
+ pos += size1;
+
+ return S_OK;
+}
+
+struct CInArchiveException
+{
+ enum CCauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kCRCError,
+ kIncorrectArchive
+ }
+ Cause;
+ CInArchiveException(CCauseType cause): Cause(cause) {};
+};
+
+class CInArchive
+{
+ UInt32 _blockSize;
+ Byte _block[kBlockSizeMax + 4];
+
+ HRESULT ReadBlock(bool &filled);
+ HRESULT ReadSignatureAndBlock(bool &filled);
+ HRESULT SkipExtendedHeaders();
+
+ HRESULT SafeReadBytes(void *data, UInt32 size);
+
+public:
+ CArchiveHeader Header;
+
+ IInStream *Stream;
+ IArchiveOpenCallback *Callback;
+ UInt64 NumFiles;
+ UInt64 NumBytes;
+
+ HRESULT Open(const UInt64 *searchHeaderSizeLimit);
+ HRESULT GetNextItem(bool &filled, CItem &item);
+};
+
+static inline bool TestMarkerCandidate(const Byte *p, unsigned maxSize)
+{
+ if (p[0] != NSignature::kSig0 || p[1] != NSignature::kSig1)
+ return false;
+ UInt32 blockSize = Get16(p + 2);
+ p += 4;
+ if (p[6] != NFileHeader::NFileType::kArchiveHeader ||
+ p[0] > blockSize ||
+ maxSize < 2 + 2 + blockSize + 4 ||
+ blockSize < kBlockSizeMin || blockSize > kBlockSizeMax ||
+ p[28] > 8) // EncryptionVersion
+ return false;
+ // return (Get32(p + blockSize) == CrcCalc(p, blockSize));
+ return true;
+}
+
+static HRESULT FindAndReadMarker(ISequentialInStream *stream, const UInt64 *searchHeaderSizeLimit, UInt64 &position)
+{
+ position = 0;
+
+ const int kMarkerSizeMin = 2 + 2 + kBlockSizeMin + 4;
+ const int kMarkerSizeMax = 2 + 2 + kBlockSizeMax + 4;
+
+ CByteBuffer byteBuffer;
+ const UInt32 kBufSize = 1 << 16;
+ byteBuffer.SetCapacity(kBufSize);
+ Byte *buf = byteBuffer;
+
+ size_t processedSize = kMarkerSizeMax;
+ RINOK(ReadStream(stream, buf, &processedSize));
+ if (processedSize < kMarkerSizeMin)
+ return S_FALSE;
+ if (TestMarkerCandidate(buf, (unsigned)processedSize))
+ return S_OK;
+
+ UInt32 numBytesPrev = (UInt32)processedSize - 1;
+ memmove(buf, buf + 1, numBytesPrev);
+ UInt64 curTestPos = 1;
+ for (;;)
+ {
+ if (searchHeaderSizeLimit != NULL)
+ if (curTestPos > *searchHeaderSizeLimit)
+ return S_FALSE;
+ processedSize = kBufSize - numBytesPrev;
+ RINOK(ReadStream(stream, buf + numBytesPrev, &processedSize));
+ UInt32 numBytesInBuffer = numBytesPrev + (UInt32)processedSize;
+ if (numBytesInBuffer < kMarkerSizeMin)
+ return S_FALSE;
+ UInt32 numTests = numBytesInBuffer - kMarkerSizeMin + 1;
+ UInt32 pos;
+ for (pos = 0; pos < numTests; pos++)
+ {
+ for (; buf[pos] != NSignature::kSig0 && pos < numTests; pos++);
+ if (pos == numTests)
+ break;
+ if (TestMarkerCandidate(buf + pos, numBytesInBuffer - pos))
+ {
+ position = curTestPos + pos;
+ return S_OK;
+ }
+ }
+ curTestPos += pos;
+ numBytesPrev = numBytesInBuffer - numTests;
+ memmove(buf, buf + numTests, numBytesPrev);
+ }
+}
+
+HRESULT CInArchive::SafeReadBytes(void *data, UInt32 size)
+{
+ size_t processed = size;
+ RINOK(ReadStream(Stream, data, &processed));
+ if (processed != size)
+ throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadBlock(bool &filled)
+{
+ filled = false;
+ Byte buf[2];
+ RINOK(SafeReadBytes(buf, 2));
+ _blockSize = Get16(buf);
+ if (_blockSize == 0)
+ return S_OK;
+ if (_blockSize > kBlockSizeMax)
+ throw CInArchiveException(CInArchiveException::kIncorrectArchive);
+ RINOK(SafeReadBytes(_block, _blockSize + 4));
+ NumBytes += _blockSize + 6;
+ if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize))
+ throw CInArchiveException(CInArchiveException::kCRCError);
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadSignatureAndBlock(bool &filled)
+{
+ Byte id[2];
+ RINOK(SafeReadBytes(id, 2));
+ if (id[0] != NSignature::kSig0 || id[1] != NSignature::kSig1)
+ throw CInArchiveException(CInArchiveException::kIncorrectArchive);
+ return ReadBlock(filled);
+}
+
+HRESULT CInArchive::SkipExtendedHeaders()
+{
+ for (UInt32 i = 0;; i++)
+ {
+ bool filled;
+ RINOK(ReadBlock(filled));
+ if (!filled)
+ return S_OK;
+ if (Callback && (i & 0xFF) == 0)
+ RINOK(Callback->SetCompleted(&NumFiles, &NumBytes));
+ }
+}
+
+HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit)
+{
+ UInt64 position = 0;
+ RINOK(FindAndReadMarker(Stream, searchHeaderSizeLimit, position));
+ RINOK(Stream->Seek(position, STREAM_SEEK_SET, NULL));
+ bool filled;
+ RINOK(ReadSignatureAndBlock(filled));
+ if (!filled)
+ return S_FALSE;
+ RINOK(Header.Parse(_block, _blockSize));
+ return SkipExtendedHeaders();
+}
+
+HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
+{
+ RINOK(ReadSignatureAndBlock(filled));
+ if (!filled)
+ return S_OK;
+ filled = false;
+ RINOK(item.Parse(_block, _blockSize));
+ /*
+ UInt32 extraData;
+ if ((header.Flags & NFileHeader::NFlags::kExtFile) != 0)
+ extraData = GetUi32(_block + pos);
+ */
+
+ RINOK(SkipExtendedHeaders());
+ filled = true;
+ return S_OK;
+}
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+
+ INTERFACE_IInArchive(;)
+
+ HRESULT Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *callback);
+private:
+ CInArchive _archive;
+ CObjectVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+};
+
+const wchar_t *kHostOS[] =
+{
+ L"MSDOS",
+ L"PRIMOS",
+ L"UNIX",
+ L"AMIGA",
+ L"MAC",
+ L"OS/2",
+ L"APPLE GS",
+ L"ATARI ST",
+ L"NEXT",
+ L"VAX VMS",
+ L"WIN95"
+};
+
+const wchar_t *kUnknownOS = L"Unknown";
+
+const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidName, VT_BSTR},
+ { NULL, kpidCTime, VT_BSTR},
+ { NULL, kpidMTime, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidComment, VT_BSTR}
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI4},
+ { NULL, kpidPosition, VT_UI8},
+ { NULL, kpidPackSize, VT_UI4},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidMethod, VT_UI1},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidComment, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop)
+{
+ if (dosTime == 0)
+ return;
+ FILETIME localFileTime, utc;
+ if (NTime::DosTimeToFileTime(dosTime, localFileTime))
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utc))
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ else
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ prop = utc;
+}
+
+static void SetHostOS(Byte hostOS, NWindows::NCOM::CPropVariant &prop)
+{
+ prop = hostOS < kNumHostOSes ? kHostOS[hostOS] : kUnknownOS;
+}
+
+static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &prop)
+{
+ if (!s.IsEmpty())
+ prop = MultiByteToUnicodeString(s, CP_OEMCP);
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidName: SetUnicodeString(_archive.Header.Name, prop); break;
+ case kpidCTime: SetTime(_archive.Header.CTime, prop); break;
+ case kpidMTime: SetTime(_archive.Header.MTime, prop); break;
+ case kpidHostOS: SetHostOS(_archive.Header.HostOS, prop); break;
+ case kpidComment: SetUnicodeString(_archive.Header.Comment, prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break;
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidCRC: prop = item.FileCRC; break;
+ case kpidMethod: prop = item.Method; break;
+ case kpidHostOS: SetHostOS(item.HostOS, prop); break;
+ case kpidMTime: SetTime(item.MTime, prop); break;
+ case kpidComment: SetUnicodeString(item.Comment, prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *callback)
+{
+ Close();
+
+ UInt64 endPos = 0;
+ if (callback != NULL)
+ {
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+
+ _archive.Stream = inStream;
+ _archive.Callback = callback;
+ _archive.NumFiles = _archive.NumBytes = 0;
+
+ RINOK(_archive.Open(maxCheckStartPosition));
+ if (callback != NULL)
+ RINOK(callback->SetTotal(NULL, &endPos));
+ for (;;)
+ {
+ CItem item;
+ bool filled;
+
+
+ RINOK(_archive.GetNextItem(filled, item));
+
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition));
+
+ if (!filled)
+ break;
+ _items.Add(item);
+
+ if (inStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL) != S_OK)
+ throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+
+ _archive.NumFiles = _items.Size();
+ _archive.NumBytes = item.DataPosition;
+
+ if (callback != NULL && _items.Size() % 100 == 0)
+ {
+ RINOK(callback->SetCompleted(&_archive.NumFiles, &_archive.NumBytes));
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ res = Open2(inStream, maxCheckStartPosition, callback);
+ if (res == S_OK)
+ {
+ _stream = inStream;
+ return S_OK;
+ }
+ }
+ catch(const CInArchiveException &) { res = S_FALSE; }
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ UInt64 totalUnpacked = 0, totalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _items[allFilesMode ? i : indices[i]];
+ totalUnpacked += item.Size;
+ totalPacked += item.PackSize;
+ }
+ extractCallback->SetTotal(totalUnpacked);
+
+ totalUnpacked = totalPacked = 0;
+ UInt64 curUnpacked, curPacked;
+
+ CMyComPtr<ICompressCoder> arj1Decoder;
+ CMyComPtr<ICompressCoder> arj2Decoder;
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
+ inStreamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, totalUnpacked += curUnpacked, totalPacked += curPacked)
+ {
+ lps->InSize = totalPacked;
+ lps->OutSize = totalUnpacked;
+ RINOK(lps->SetCur());
+
+ curUnpacked = curPacked = 0;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ continue;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ curUnpacked = item.Size;
+ curPacked = item.PackSize;
+
+ {
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init();
+
+ inStreamSpec->Init(item.PackSize);
+
+ UInt64 pos;
+ _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
+
+ HRESULT result = S_OK;
+ Int32 opRes = NExtract::NOperationResult::kOK;
+
+ if (item.IsEncrypted())
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ switch(item.Method)
+ {
+ case NFileHeader::NCompressionMethod::kStored:
+ {
+ result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
+ result = S_FALSE;
+ break;
+ }
+ case NFileHeader::NCompressionMethod::kCompressed1a:
+ case NFileHeader::NCompressionMethod::kCompressed1b:
+ case NFileHeader::NCompressionMethod::kCompressed1c:
+ {
+ if (!arj1Decoder)
+ arj1Decoder = new NCompress::NArj::NDecoder1::CCoder;
+ result = arj1Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
+ break;
+ }
+ case NFileHeader::NCompressionMethod::kCompressed2:
+ {
+ if (!arj2Decoder)
+ arj2Decoder = new NCompress::NArj::NDecoder2::CCoder;
+ result = arj2Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
+ break;
+ }
+ default:
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ }
+ }
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ if (result == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(result);
+ opRes = (outStreamSpec->GetCRC() == item.FileCRC) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Arj", L"arj", 0, 4, { 0x60, 0xEA }, 2, false, CreateArc, 0 };
+
+REGISTER_ARC(Arj)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Bz2Handler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Bz2Handler.cpp
new file mode 100644
index 000000000..98cbcc182
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Bz2Handler.cpp
@@ -0,0 +1,423 @@
+// Bz2Handler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#ifndef _7ZIP_ST
+#include "../../Windows/System.h"
+#endif
+
+#include "../Common/CreateCoder.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BZip2Decoder.h"
+#include "../Compress/BZip2Encoder.h"
+#include "../Compress/CopyCoder.h"
+
+#include "Common/DummyOutStream.h"
+#include "Common/ParseProperties.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NBz2 {
+
+static const UInt32 kNumPassesX1 = 1;
+static const UInt32 kNumPassesX7 = 2;
+static const UInt32 kNumPassesX9 = 7;
+
+static const UInt32 kDicSizeX1 = 100000;
+static const UInt32 kDicSizeX3 = 500000;
+static const UInt32 kDicSizeX5 = 900000;
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IOutArchive,
+ public ISetProperties,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+ UInt64 _packSize;
+ UInt64 _startPosition;
+ bool _packSizeDefined;
+
+ UInt32 _level;
+ UInt32 _dicSize;
+ UInt32 _numPasses;
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ #endif
+
+ void InitMethodProperties()
+ {
+ _level = 5;
+ _dicSize =
+ _numPasses = 0xFFFFFFFF;
+ #ifndef _7ZIP_ST
+ _numThreads = NWindows::NSystem::GetNumberOfProcessors();;
+ #endif
+ }
+
+public:
+ MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
+
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+
+ CHandler() { InitMethodProperties(); }
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPackSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+ const int kSignatureSize = 3;
+ Byte buf[kSignatureSize];
+ RINOK(ReadStream_FALSE(stream, buf, kSignatureSize));
+ if (buf[0] != 'B' || buf[1] != 'Z' || buf[2] != 'h')
+ return S_FALSE;
+
+ UInt64 endPosition;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition));
+ _packSize = endPosition - _startPosition;
+ _packSizeDefined = true;
+ _stream = stream;
+ _seqStream = stream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_stream)
+ extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ }
+
+ decoderSpec->SetInStream(_seqStream);
+
+ #ifndef _7ZIP_ST
+ RINOK(decoderSpec->SetNumberOfThreads(_numThreads));
+ #endif
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ HRESULT result = S_OK;
+
+ bool firstItem = true;
+ for (;;)
+ {
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = outStreamSpec->GetSize();
+
+ RINOK(lps->SetCur());
+
+ bool isBz2;
+ result = decoderSpec->CodeResume(outStream, isBz2, progress);
+
+ if (result != S_OK)
+ break;
+ if (!isBz2)
+ {
+ if (firstItem)
+ result = S_FALSE;
+ break;
+ }
+ firstItem = false;
+
+ _packSize = currentTotalPacked = decoderSpec->GetInputProcessedSize();
+ _packSizeDefined = true;
+ }
+ decoderSpec->ReleaseInStream();
+ outStream.Release();
+
+ Int32 retResult;
+ if (result == S_OK)
+ retResult = NExtract::NOperationResult::kOK;
+ else if (result == S_FALSE)
+ retResult = NExtract::NOperationResult::kDataError;
+ else
+ return result;
+ return extractCallback->SetOperationResult(retResult);
+
+ COM_TRY_END
+}
+
+static HRESULT UpdateArchive(
+ UInt64 unpackSize,
+ ISequentialOutStream *outStream,
+ int indexInClient,
+ UInt32 dictionary,
+ UInt32 numPasses,
+ #ifndef _7ZIP_ST
+ UInt32 numThreads,
+ #endif
+ IArchiveUpdateCallback *updateCallback)
+{
+ RINOK(updateCallback->SetTotal(unpackSize));
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetCompleted(&complexity));
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+
+ RINOK(updateCallback->GetStream(indexInClient, &fileInStream));
+
+ CLocalProgress *localProgressSpec = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
+ localProgressSpec->Init(updateCallback, true);
+
+ NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+ {
+ NWindows::NCOM::CPropVariant properties[] =
+ {
+ dictionary,
+ numPasses
+ #ifndef _7ZIP_ST
+ , numThreads
+ #endif
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumPasses
+ #ifndef _7ZIP_ST
+ , NCoderPropID::kNumThreads
+ #endif
+ };
+ RINOK(encoderSpec->SetCoderProperties(propIDs, properties, sizeof(propIDs) / sizeof(propIDs[0])));
+ }
+
+ RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
+
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+}
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+{
+ *type = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
+ if (prop.vt == VT_BOOL)
+ {
+ if (prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+
+ UInt32 dicSize = _dicSize;
+ if (dicSize == 0xFFFFFFFF)
+ dicSize = (_level >= 5 ? kDicSizeX5 :
+ (_level >= 3 ? kDicSizeX3 :
+ kDicSizeX1));
+
+ UInt32 numPasses = _numPasses;
+ if (numPasses == 0xFFFFFFFF)
+ numPasses = (_level >= 9 ? kNumPassesX9 :
+ (_level >= 7 ? kNumPassesX7 :
+ kNumPassesX1));
+
+ return UpdateArchive(
+ size, outStream, 0, dicSize, numPasses,
+ #ifndef _7ZIP_ST
+ _numThreads,
+ #endif
+ updateCallback);
+ }
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+ if (_stream)
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ return NCompress::CopyStream(_stream, outStream, NULL);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ InitMethodProperties();
+ #ifndef _7ZIP_ST
+ const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+ _numThreads = numProcessors;
+ #endif
+
+ for (int i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &prop = values[i];
+ if (name[0] == L'X')
+ {
+ UInt32 level = 9;
+ RINOK(ParsePropValue(name.Mid(1), prop, level));
+ _level = level;
+ }
+ else if (name[0] == L'D')
+ {
+ UInt32 dicSize = kDicSizeX5;
+ RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
+ _dicSize = dicSize;
+ }
+ else if (name.Left(4) == L"PASS")
+ {
+ UInt32 num = kNumPassesX9;
+ RINOK(ParsePropValue(name.Mid(4), prop, num));
+ _numPasses = num;
+ }
+ else if (name.Left(2) == L"MT")
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
+ #endif
+ }
+ else
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"bzip2", L"bz2 bzip2 tbz2 tbz", L"* * .tar .tar", 2, { 'B', 'Z', 'h' }, 3, true, CreateArc, CreateArcOut };
+
+REGISTER_ARC(BZip2)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
new file mode 100644
index 000000000..12c73eb5f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
@@ -0,0 +1,189 @@
+// CabBlockInStream.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+
+#include "Common/Defs.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "CabBlockInStream.h"
+
+namespace NArchive {
+namespace NCab {
+
+static const UInt32 kBlockSize = (1 << 16);
+
+bool CCabBlockInStream::Create()
+{
+ if (!_buffer)
+ _buffer = (Byte *)::MyAlloc(kBlockSize);
+ return (_buffer != 0);
+}
+
+CCabBlockInStream::~CCabBlockInStream()
+{
+ MyFree(_buffer);
+}
+
+class CCheckSum2
+{
+ UInt32 m_Value;
+ int m_Pos;
+ Byte m_Hist[4];
+public:
+ CCheckSum2(): m_Value(0){};
+ void Init() { m_Value = 0; m_Pos = 0; }
+ void Update(const void *data, UInt32 size);
+ void FinishDataUpdate()
+ {
+ for (int i = 0; i < m_Pos; i++)
+ m_Value ^= ((UInt32)(m_Hist[i])) << (8 * (m_Pos - i - 1));
+ }
+ void UpdateUInt32(UInt32 v) { m_Value ^= v; }
+ UInt32 GetResult() const { return m_Value; }
+};
+
+void CCheckSum2::Update(const void *data, UInt32 size)
+{
+ UInt32 checkSum = m_Value;
+ const Byte *dataPointer = (const Byte *)data;
+
+ while (size != 0 && m_Pos != 0)
+ {
+ m_Hist[m_Pos] = *dataPointer++;
+ m_Pos = (m_Pos + 1) & 3;
+ size--;
+ if (m_Pos == 0)
+ for (int i = 0; i < 4; i++)
+ checkSum ^= ((UInt32)m_Hist[i]) << (8 * i);
+ }
+
+ int numWords = size / 4;
+
+ while (numWords-- != 0)
+ {
+ UInt32 temp = *dataPointer++;
+ temp |= ((UInt32)(*dataPointer++)) << 8;
+ temp |= ((UInt32)(*dataPointer++)) << 16;
+ temp |= ((UInt32)(*dataPointer++)) << 24;
+ checkSum ^= temp;
+ }
+ m_Value = checkSum;
+
+ size &= 3;
+
+ while (size != 0)
+ {
+ m_Hist[m_Pos] = *dataPointer++;
+ m_Pos = (m_Pos + 1) & 3;
+ size--;
+ }
+}
+
+static const UInt32 kDataBlockHeaderSize = 8;
+
+class CTempCabInBuffer2
+{
+public:
+ Byte Buffer[kDataBlockHeaderSize];
+ UInt32 Pos;
+ Byte ReadByte()
+ {
+ return Buffer[Pos++];
+ }
+ UInt32 ReadUInt32()
+ {
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ value |= (((UInt32)ReadByte()) << (8 * i));
+ return value;
+ }
+ UInt16 ReadUInt16()
+ {
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ value |= (((UInt16)ReadByte()) << (8 * i));
+ return value;
+ }
+};
+
+HRESULT CCabBlockInStream::PreRead(UInt32 &packSize, UInt32 &unpackSize)
+{
+ CTempCabInBuffer2 inBuffer;
+ inBuffer.Pos = 0;
+ RINOK(ReadStream_FALSE(_stream, inBuffer.Buffer, kDataBlockHeaderSize))
+
+ UInt32 checkSum = inBuffer.ReadUInt32();
+ packSize = inBuffer.ReadUInt16();
+ unpackSize = inBuffer.ReadUInt16();
+ if (ReservedSize != 0)
+ {
+ RINOK(ReadStream_FALSE(_stream, _buffer, ReservedSize));
+ }
+ _pos = 0;
+ CCheckSum2 checkSumCalc;
+ checkSumCalc.Init();
+ UInt32 packSize2 = packSize;
+ if (MsZip && _size == 0)
+ {
+ if (packSize < 2)
+ return S_FALSE; // bad block;
+ Byte sig[2];
+ RINOK(ReadStream_FALSE(_stream, sig, 2));
+ if (sig[0] != 0x43 || sig[1] != 0x4B)
+ return S_FALSE;
+ packSize2 -= 2;
+ checkSumCalc.Update(sig, 2);
+ }
+
+ if (kBlockSize - _size < packSize2)
+ return S_FALSE;
+
+ UInt32 curSize = packSize2;
+ if (curSize != 0)
+ {
+ size_t processedSizeLoc = curSize;
+ RINOK(ReadStream(_stream, _buffer + _size, &processedSizeLoc));
+ checkSumCalc.Update(_buffer + _size, (UInt32)processedSizeLoc);
+ _size += (UInt32)processedSizeLoc;
+ if (processedSizeLoc != curSize)
+ return S_FALSE;
+ }
+ TotalPackSize = _size;
+
+ checkSumCalc.FinishDataUpdate();
+
+ bool dataError;
+ if (checkSum == 0)
+ dataError = false;
+ else
+ {
+ checkSumCalc.UpdateUInt32(packSize | (((UInt32)unpackSize) << 16));
+ dataError = (checkSumCalc.GetResult() != checkSum);
+ }
+ DataError |= dataError;
+ return dataError ? S_FALSE : S_OK;
+}
+
+STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != 0)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_size != 0)
+ {
+ size = MyMin(_size, size);
+ memmove(data, _buffer + _pos, size);
+ _pos += size;
+ _size -= size;
+ if (processedSize != 0)
+ *processedSize = size;
+ return S_OK;
+ }
+ return S_OK; // no blocks data
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.h
new file mode 100644
index 000000000..1db3835b4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.h
@@ -0,0 +1,44 @@
+// CabBlockInStream.cpp
+
+#ifndef __CABBLOCKINSTREAM_H
+#define __CABBLOCKINSTREAM_H
+
+#include "Common/MyCom.h"
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NCab {
+
+class CCabBlockInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ Byte *_buffer;
+ UInt32 _pos;
+ UInt32 _size;
+
+public:
+ UInt32 TotalPackSize;
+ UInt32 ReservedSize;
+ bool DataError;
+ bool MsZip;
+
+ CCabBlockInStream(): _buffer(0), ReservedSize(0), MsZip(false), DataError(false), TotalPackSize(0) {}
+ ~CCabBlockInStream();
+ bool Create();
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+
+ void InitForNewFolder() { TotalPackSize = 0; }
+ void InitForNewBlock() { _size = 0; }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ HRESULT PreRead(UInt32 &packSize, UInt32 &unpackSize);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.cpp
new file mode 100644
index 000000000..20f670d35
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.cpp
@@ -0,0 +1,929 @@
+// CabHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/Defs.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/DeflateDecoder.h"
+#include "../../Compress/LzxDecoder.h"
+#include "../../Compress/QuantumDecoder.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "CabBlockInStream.h"
+#include "CabHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NCab {
+
+// #define _CAB_DETAILS
+
+#ifdef _CAB_DETAILS
+enum
+{
+ kpidBlockReal = kpidUserDefined
+};
+#endif
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidBlock, VT_I4}
+ #ifdef _CAB_DETAILS
+ ,
+ { L"BlockReal", kpidBlockReal, VT_UI4},
+ { NULL, kpidOffset, VT_UI4},
+ { NULL, kpidVolume, VT_UI4}
+ #endif
+};
+
+static const char *kMethods[] =
+{
+ "None",
+ "MSZip",
+ "Quantum",
+ "LZX"
+};
+
+static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
+static const char *kUnknownMethod = "Unknown";
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ // { NULL, kpidSolid, VT_BOOL},
+ { NULL, kpidNumBlocks, VT_UI4},
+ { NULL, kpidNumVolumes, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ AString resString;
+ CRecordVector<Byte> ids;
+ int i;
+ for (int v = 0; v < m_Database.Volumes.Size(); v++)
+ {
+ const CDatabaseEx &de = m_Database.Volumes[v];
+ for (i = 0; i < de.Folders.Size(); i++)
+ ids.AddToUniqueSorted(de.Folders[i].GetCompressionMethod());
+ }
+ for (i = 0; i < ids.Size(); i++)
+ {
+ Byte id = ids[i];
+ AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod;
+ if (!resString.IsEmpty())
+ resString += ' ';
+ resString += method;
+ }
+ prop = resString;
+ break;
+ }
+ // case kpidSolid: prop = _database.IsSolid(); break;
+ case kpidNumBlocks:
+ {
+ UInt32 numFolders = 0;
+ for (int v = 0; v < m_Database.Volumes.Size(); v++)
+ numFolders += m_Database.Volumes[v].Folders.Size();
+ prop = numFolders;
+ break;
+ }
+ case kpidNumVolumes:
+ {
+ prop = (UInt32)m_Database.Volumes.Size();
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CMvItem &mvItem = m_Database.Items[index];
+ const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
+ int itemIndex = mvItem.ItemIndex;
+ const CItem &item = db.Items[itemIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString unicodeName;
+ if (item.IsNameUTF())
+ ConvertUTF8ToUnicode(item.Name, unicodeName);
+ else
+ unicodeName = MultiByteToUnicodeString(item.Name, CP_ACP);
+ prop = (const wchar_t *)NItemName::WinNameToOSName(unicodeName);
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+
+ case kpidMTime:
+ {
+ FILETIME localFileTime, utcFileTime;
+ if (NTime::DosTimeToFileTime(item.Time, localFileTime))
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ }
+ else
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ prop = utcFileTime;
+ break;
+ }
+
+ case kpidMethod:
+ {
+ UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size());
+ const CFolder &folder = db.Folders[realFolderIndex];
+ int methodIndex = folder.GetCompressionMethod();
+ AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
+ if (methodIndex == NHeader::NCompressionMethodMajor::kLZX ||
+ methodIndex == NHeader::NCompressionMethodMajor::kQuantum)
+ {
+ method += ':';
+ char temp[32];
+ ConvertUInt64ToString(folder.CompressionTypeMinor, temp);
+ method += temp;
+ }
+ prop = method;
+ break;
+ }
+ case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break;
+
+ #ifdef _CAB_DETAILS
+
+ case kpidBlockReal: prop = (UInt32)item.FolderIndex; break;
+ case kpidOffset: prop = (UInt32)item.Offset; break;
+ case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break;
+
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+/*
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback;
+public:
+ STDMETHOD(SetTotal)(const UInt64 *numFiles);
+ STDMETHOD(SetCompleted)(const UInt64 *numFiles);
+ void Init(IArchiveOpenCallback *openArchiveCallback)
+ { m_OpenArchiveCallback = openArchiveCallback; }
+};
+
+STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles)
+{
+ if (m_OpenArchiveCallback)
+ return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
+{
+ if (m_OpenArchiveCallback)
+ return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
+ return S_OK;
+}
+*/
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ HRESULT res = S_FALSE;
+ CInArchive archive;
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+
+ CMyComPtr<IInStream> nextStream = inStream;
+ bool prevChecked = false;
+ UInt64 numItems = 0;
+ try
+ {
+ while (nextStream != 0)
+ {
+ CDatabaseEx db;
+ db.Stream = nextStream;
+ res = archive.Open(maxCheckStartPosition, db);
+ if (res == S_OK)
+ {
+ if (!m_Database.Volumes.IsEmpty())
+ {
+ const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0];
+ if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID ||
+ dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) !=
+ db.ArchiveInfo.CabinetNumber)
+ res = S_FALSE;
+ }
+ }
+ if (res == S_OK)
+ m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db);
+ else if (res != S_FALSE)
+ return res;
+ else
+ {
+ if (m_Database.Volumes.IsEmpty())
+ return S_FALSE;
+ if (prevChecked)
+ break;
+ prevChecked = true;
+ }
+
+ numItems += db.Items.Size();
+ RINOK(callback->SetCompleted(&numItems, NULL));
+
+ nextStream = 0;
+ for (;;)
+ {
+ const COtherArchive *otherArchive = 0;
+ if (!prevChecked)
+ {
+ const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo;
+ if (ai.IsTherePrev())
+ otherArchive = &ai.PrevArc;
+ else
+ prevChecked = true;
+ }
+ if (otherArchive == 0)
+ {
+ const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo;
+ if (ai.IsThereNext())
+ otherArchive = &ai.NextArc;
+ }
+ if (!otherArchive)
+ break;
+ const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP);
+ if (!openVolumeCallback)
+ break;
+
+ HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
+ if (result == S_OK)
+ break;
+ if (result != S_FALSE)
+ return result;
+ if (prevChecked)
+ break;
+ prevChecked = true;
+ }
+ }
+ if (res == S_OK)
+ {
+ m_Database.FillSortAndShrink();
+ if (!m_Database.Check())
+ res = S_FALSE;
+ }
+ }
+ catch(...)
+ {
+ res = S_FALSE;
+ }
+ if (res != S_OK)
+ {
+ Close();
+ return res;
+ }
+ COM_TRY_END
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ m_Database.Clear();
+ return S_OK;
+}
+
+class CFolderOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+private:
+ const CMvDatabaseEx *m_Database;
+ const CRecordVector<bool> *m_ExtractStatuses;
+
+ Byte *TempBuf;
+ UInt32 TempBufSize;
+ int NumIdenticalFiles;
+ bool TempBufMode;
+ UInt32 m_BufStartFolderOffset;
+
+ int m_StartIndex;
+ int m_CurrentIndex;
+ CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
+ bool m_TestMode;
+
+ CMyComPtr<ISequentialOutStream> m_RealOutStream;
+
+ bool m_IsOk;
+ bool m_FileIsOpen;
+ UInt32 m_RemainFileSize;
+ UInt64 m_FolderSize;
+ UInt64 m_PosInFolder;
+
+ void FreeTempBuf()
+ {
+ ::MyFree(TempBuf);
+ TempBuf = NULL;
+ }
+
+ HRESULT OpenFile();
+ HRESULT CloseFileWithResOp(Int32 resOp);
+ HRESULT CloseFile();
+ HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
+public:
+ HRESULT WriteEmptyFiles();
+
+ CFolderOutStream(): TempBuf(NULL) {}
+ ~CFolderOutStream() { FreeTempBuf(); }
+ void Init(
+ const CMvDatabaseEx *database,
+ const CRecordVector<bool> *extractStatuses,
+ int startIndex,
+ UInt64 folderSize,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode);
+ HRESULT FlushCorrupted();
+ HRESULT Unsupported();
+
+ UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; }
+ UInt64 GetPosInFolder() const { return m_PosInFolder; }
+};
+
+void CFolderOutStream::Init(
+ const CMvDatabaseEx *database,
+ const CRecordVector<bool> *extractStatuses,
+ int startIndex,
+ UInt64 folderSize,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode)
+{
+ m_Database = database;
+ m_ExtractStatuses = extractStatuses;
+ m_StartIndex = startIndex;
+ m_FolderSize = folderSize;
+
+ m_ExtractCallback = extractCallback;
+ m_TestMode = testMode;
+
+ m_CurrentIndex = 0;
+ m_PosInFolder = 0;
+ m_FileIsOpen = false;
+ m_IsOk = true;
+ TempBufMode = false;
+ NumIdenticalFiles = 0;
+}
+
+HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp)
+{
+ m_RealOutStream.Release();
+ m_FileIsOpen = false;
+ NumIdenticalFiles--;
+ return m_ExtractCallback->SetOperationResult(resOp);
+}
+
+HRESULT CFolderOutStream::CloseFile()
+{
+ return CloseFileWithResOp(m_IsOk ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError);
+}
+
+HRESULT CFolderOutStream::OpenFile()
+{
+ if (NumIdenticalFiles == 0)
+ {
+ const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
+ const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ int numExtractItems = 0;
+ int curIndex;
+ for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++)
+ {
+ const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex];
+ const CItem &item2 = m_Database->Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex];
+ if (item.Offset != item2.Offset ||
+ item.Size != item2.Size ||
+ item.Size == 0)
+ break;
+ if (!m_TestMode && (*m_ExtractStatuses)[curIndex])
+ numExtractItems++;
+ }
+ NumIdenticalFiles = (curIndex - m_CurrentIndex);
+ if (NumIdenticalFiles == 0)
+ NumIdenticalFiles = 1;
+ TempBufMode = false;
+ if (numExtractItems > 1)
+ {
+ if (!TempBuf || item.Size > TempBufSize)
+ {
+ FreeTempBuf();
+ TempBuf = (Byte *)MyAlloc(item.Size);
+ TempBufSize = item.Size;
+ if (TempBuf == NULL)
+ return E_OUTOFMEMORY;
+ }
+ TempBufMode = true;
+ m_BufStartFolderOffset = item.Offset;
+ }
+ else if (numExtractItems == 1)
+ {
+ while (NumIdenticalFiles && !(*m_ExtractStatuses)[m_CurrentIndex])
+ {
+ CMyComPtr<ISequentialOutStream> stream;
+ RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &stream, NExtract::NAskMode::kSkip));
+ if (stream)
+ return E_FAIL;
+ RINOK(m_ExtractCallback->PrepareOperation(NExtract::NAskMode::kSkip));
+ m_CurrentIndex++;
+ m_FileIsOpen = true;
+ CloseFile();
+ }
+ }
+ }
+
+ Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract) :
+ NExtract::NAskMode::kSkip;
+ RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));
+ if (!m_RealOutStream && !m_TestMode)
+ askMode = NExtract::NAskMode::kSkip;
+ return m_ExtractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CFolderOutStream::WriteEmptyFiles()
+{
+ if (m_FileIsOpen)
+ return S_OK;
+ for (; m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++)
+ {
+ const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
+ const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ UInt64 fileSize = item.Size;
+ if (fileSize != 0)
+ return S_OK;
+ HRESULT result = OpenFile();
+ m_RealOutStream.Release();
+ RINOK(result);
+ RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+}
+
+// This is Write function
+HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
+{
+ COM_TRY_BEGIN
+ UInt32 realProcessed = 0;
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (m_FileIsOpen)
+ {
+ UInt32 numBytesToWrite = MyMin(m_RemainFileSize, size);
+ HRESULT res = S_OK;
+ if (numBytesToWrite > 0)
+ {
+ if (!isOK)
+ m_IsOk = false;
+ if (m_RealOutStream)
+ {
+ UInt32 processedSizeLocal = 0;
+ res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
+ numBytesToWrite = processedSizeLocal;
+ }
+ if (TempBufMode && TempBuf)
+ memcpy(TempBuf + (m_PosInFolder - m_BufStartFolderOffset), data, numBytesToWrite);
+ }
+ realProcessed += numBytesToWrite;
+ if (processedSize != NULL)
+ *processedSize = realProcessed;
+ data = (const void *)((const Byte *)data + numBytesToWrite);
+ size -= numBytesToWrite;
+ m_RemainFileSize -= numBytesToWrite;
+ m_PosInFolder += numBytesToWrite;
+ if (res != S_OK)
+ return res;
+ if (m_RemainFileSize == 0)
+ {
+ RINOK(CloseFile());
+
+ while (NumIdenticalFiles)
+ {
+ HRESULT result = OpenFile();
+ m_FileIsOpen = true;
+ m_CurrentIndex++;
+ if (result == S_OK && m_RealOutStream && TempBuf)
+ result = WriteStream(m_RealOutStream, TempBuf, (size_t)(m_PosInFolder - m_BufStartFolderOffset));
+
+ if (!TempBuf && TempBufMode && m_RealOutStream)
+ {
+ RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnSupportedMethod));
+ }
+ else
+ {
+ RINOK(CloseFile());
+ }
+ RINOK(result);
+ }
+ TempBufMode = false;
+ }
+ if (realProcessed > 0)
+ break; // with this break this function works as Write-Part
+ }
+ else
+ {
+ if (m_CurrentIndex >= m_ExtractStatuses->Size())
+ return E_FAIL;
+
+ const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
+ const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+
+ m_RemainFileSize = item.Size;
+
+ UInt32 fileOffset = item.Offset;
+ if (fileOffset < m_PosInFolder)
+ return E_FAIL;
+ if (fileOffset > m_PosInFolder)
+ {
+ UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size);
+ realProcessed += numBytesToWrite;
+ if (processedSize != NULL)
+ *processedSize = realProcessed;
+ data = (const void *)((const Byte *)data + numBytesToWrite);
+ size -= numBytesToWrite;
+ m_PosInFolder += numBytesToWrite;
+ }
+ if (fileOffset == m_PosInFolder)
+ {
+ RINOK(OpenFile());
+ m_FileIsOpen = true;
+ m_CurrentIndex++;
+ m_IsOk = true;
+ }
+ }
+ }
+ return WriteEmptyFiles();
+ COM_TRY_END
+}
+
+STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ return Write2(data, size, processedSize, true);
+}
+
+HRESULT CFolderOutStream::FlushCorrupted()
+{
+ const UInt32 kBufferSize = (1 << 10);
+ Byte buffer[kBufferSize];
+ for (int i = 0; i < kBufferSize; i++)
+ buffer[i] = 0;
+ for (;;)
+ {
+ UInt64 remain = GetRemain();
+ if (remain == 0)
+ return S_OK;
+ UInt32 size = (UInt32)MyMin(remain, (UInt64)kBufferSize);
+ UInt32 processedSizeLocal = 0;
+ RINOK(Write2(buffer, size, &processedSizeLocal, false));
+ }
+}
+
+HRESULT CFolderOutStream::Unsupported()
+{
+ while(m_CurrentIndex < m_ExtractStatuses->Size())
+ {
+ HRESULT result = OpenFile();
+ if (result != S_FALSE && result != S_OK)
+ return result;
+ m_RealOutStream.Release();
+ RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ m_CurrentIndex++;
+ }
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = m_Database.Items.Size();
+ if(numItems == 0)
+ return S_OK;
+ bool testMode = (testModeSpec != 0);
+ UInt64 totalUnPacked = 0;
+
+ UInt32 i;
+ int lastFolder = -2;
+ UInt64 lastFolderSize = 0;
+ for(i = 0; i < numItems; i++)
+ {
+ int index = allFilesMode ? i : indices[i];
+ const CMvItem &mvItem = m_Database.Items[index];
+ const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ if (item.IsDir())
+ continue;
+ int folderIndex = m_Database.GetFolderIndex(&mvItem);
+ if (folderIndex != lastFolder)
+ totalUnPacked += lastFolderSize;
+ lastFolder = folderIndex;
+ lastFolderSize = item.GetEndOffset();
+ }
+ totalUnPacked += lastFolderSize;
+
+ extractCallback->SetTotal(totalUnPacked);
+
+ totalUnPacked = 0;
+
+ UInt64 totalPacked = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> deflateDecoder;
+
+ NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> lzxDecoder;
+
+ NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> quantumDecoder;
+
+ CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
+ CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
+ if (!cabBlockInStreamSpec->Create())
+ return E_OUTOFMEMORY;
+
+ CRecordVector<bool> extractStatuses;
+ for(i = 0; i < numItems;)
+ {
+ int index = allFilesMode ? i : indices[i];
+
+ const CMvItem &mvItem = m_Database.Items[index];
+ const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
+ int itemIndex = mvItem.ItemIndex;
+ const CItem &item = db.Items[itemIndex];
+
+ i++;
+ if (item.IsDir())
+ {
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ int folderIndex = m_Database.GetFolderIndex(&mvItem);
+ if (folderIndex < 0)
+ {
+ // If we need previous archive
+ Int32 askMode= testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ int startIndex2 = m_Database.FolderStartFileIndex[folderIndex];
+ int startIndex = startIndex2;
+ extractStatuses.Clear();
+ for (; startIndex < index; startIndex++)
+ extractStatuses.Add(false);
+ extractStatuses.Add(true);
+ startIndex++;
+ UInt64 curUnpack = item.GetEndOffset();
+ for(;i < numItems; i++)
+ {
+ int indexNext = allFilesMode ? i : indices[i];
+ const CMvItem &mvItem = m_Database.Items[indexNext];
+ const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ if (item.IsDir())
+ continue;
+ int newFolderIndex = m_Database.GetFolderIndex(&mvItem);
+
+ if (newFolderIndex != folderIndex)
+ break;
+ for (; startIndex < indexNext; startIndex++)
+ extractStatuses.Add(false);
+ extractStatuses.Add(true);
+ startIndex++;
+ curUnpack = item.GetEndOffset();
+ }
+
+ lps->OutSize = totalUnPacked;
+ lps->InSize = totalPacked;
+ RINOK(lps->SetCur());
+
+ CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);
+
+ const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())];
+
+ cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2,
+ curUnpack, extractCallback, testMode);
+
+ cabBlockInStreamSpec->MsZip = false;
+ switch(folder.GetCompressionMethod())
+ {
+ case NHeader::NCompressionMethodMajor::kNone:
+ break;
+ case NHeader::NCompressionMethodMajor::kMSZip:
+ if(deflateDecoderSpec == NULL)
+ {
+ deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
+ deflateDecoder = deflateDecoderSpec;
+ }
+ cabBlockInStreamSpec->MsZip = true;
+ break;
+ case NHeader::NCompressionMethodMajor::kLZX:
+ if(lzxDecoderSpec == NULL)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder;
+ lzxDecoder = lzxDecoderSpec;
+ }
+ RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor));
+ break;
+ case NHeader::NCompressionMethodMajor::kQuantum:
+ if(quantumDecoderSpec == NULL)
+ {
+ quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
+ quantumDecoder = quantumDecoderSpec;
+ }
+ quantumDecoderSpec->SetParams(folder.CompressionTypeMinor);
+ break;
+ default:
+ {
+ RINOK(cabFolderOutStream->Unsupported());
+ totalUnPacked += curUnpack;
+ continue;
+ }
+ }
+
+ cabBlockInStreamSpec->InitForNewFolder();
+
+ HRESULT res = S_OK;
+
+ {
+ int volIndex = mvItem.VolumeIndex;
+ int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
+ bool keepHistory = false;
+ bool keepInputBuffer = false;
+ for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;)
+ {
+ if (volIndex >= m_Database.Volumes.Size())
+ {
+ res = S_FALSE;
+ break;
+ }
+
+ const CDatabaseEx &db = m_Database.Volumes[volIndex];
+ const CFolder &folder = db.Folders[locFolderIndex];
+ if (f == 0)
+ {
+ cabBlockInStreamSpec->SetStream(db.Stream);
+ cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize();
+ RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL));
+ }
+ if (f == folder.NumDataBlocks)
+ {
+ volIndex++;
+ locFolderIndex = 0;
+ f = 0;
+ continue;
+ }
+ f++;
+
+ cabBlockInStreamSpec->DataError = false;
+
+ if (!keepInputBuffer)
+ cabBlockInStreamSpec->InitForNewBlock();
+
+ UInt32 packSize, unpackSize;
+ res = cabBlockInStreamSpec->PreRead(packSize, unpackSize);
+ if (res == S_FALSE)
+ break;
+ RINOK(res);
+ keepInputBuffer = (unpackSize == 0);
+ if (keepInputBuffer)
+ continue;
+
+ UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder();
+ totalPacked += packSize;
+
+ lps->OutSize = totalUnPacked2;
+ lps->InSize = totalPacked;
+ RINOK(lps->SetCur());
+
+ UInt64 unpackRemain = cabFolderOutStream->GetRemain();
+
+ const UInt32 kBlockSizeMax = (1 << 15);
+ if (unpackRemain > kBlockSizeMax)
+ unpackRemain = kBlockSizeMax;
+ if (unpackRemain > unpackSize)
+ unpackRemain = unpackSize;
+
+ switch(folder.GetCompressionMethod())
+ {
+ case NHeader::NCompressionMethodMajor::kNone:
+ res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
+ break;
+ case NHeader::NCompressionMethodMajor::kMSZip:
+ deflateDecoderSpec->SetKeepHistory(keepHistory);
+ res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
+ break;
+ case NHeader::NCompressionMethodMajor::kLZX:
+ lzxDecoderSpec->SetKeepHistory(keepHistory);
+ res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
+ break;
+ case NHeader::NCompressionMethodMajor::kQuantum:
+ quantumDecoderSpec->SetKeepHistory(keepHistory);
+ res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
+ break;
+ }
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ RINOK(res);
+ break;
+ }
+ keepHistory = true;
+ }
+ if (res == S_OK)
+ {
+ RINOK(cabFolderOutStream->WriteEmptyFiles());
+ }
+ }
+ if (res != S_OK || cabFolderOutStream->GetRemain() != 0)
+ {
+ RINOK(cabFolderOutStream->FlushCorrupted());
+ }
+ totalUnPacked += curUnpack;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = m_Database.Items.Size();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.h
new file mode 100644
index 000000000..1edcd11e2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.h
@@ -0,0 +1,28 @@
+// CabHandler.h
+
+#ifndef __CAB_HANDLER_H
+#define __CAB_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "CabIn.h"
+
+namespace NArchive {
+namespace NCab {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+
+ INTERFACE_IInArchive(;)
+
+private:
+ CMvDatabaseEx m_Database;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.cpp
new file mode 100644
index 000000000..0cba1b0b7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.cpp
@@ -0,0 +1,15 @@
+// CabHeader.cpp
+
+#include "StdAfx.h"
+
+#include "CabHeader.h"
+
+namespace NArchive {
+namespace NCab {
+namespace NHeader {
+
+Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 };
+
+// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; }; } g_SignatureInitializer;
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.h
new file mode 100644
index 000000000..0f0d2af35
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.h
@@ -0,0 +1,44 @@
+// Archive/Cab/Header.h
+
+#ifndef __ARCHIVE_CAB_HEADER_H
+#define __ARCHIVE_CAB_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NCab {
+namespace NHeader {
+
+const unsigned kMarkerSize = 8;
+extern Byte kMarker[kMarkerSize];
+
+namespace NArchive
+{
+ namespace NFlags
+ {
+ const int kPrevCabinet = 0x0001;
+ const int kNextCabinet = 0x0002;
+ const int kReservePresent = 0x0004;
+ }
+}
+
+namespace NCompressionMethodMajor
+{
+ const Byte kNone = 0;
+ const Byte kMSZip = 1;
+ const Byte kQuantum = 2;
+ const Byte kLZX = 3;
+}
+
+const int kFileNameIsUTFAttributeMask = 0x80;
+
+namespace NFolderIndex
+{
+ const int kContinuedFromPrev = 0xFFFD;
+ const int kContinuedToNext = 0xFFFE;
+ const int kContinuedPrevAndNext = 0xFFFF;
+}
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp
new file mode 100644
index 000000000..c0bffa2d2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp
@@ -0,0 +1,272 @@
+// Archive/CabIn.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/FindSignature.h"
+
+#include "CabIn.h"
+
+namespace NArchive {
+namespace NCab {
+
+Byte CInArchive::Read8()
+{
+ Byte b;
+ if (!inBuffer.ReadByte(b))
+ throw CInArchiveException(CInArchiveException::kUnsupported);
+ return b;
+}
+
+UInt16 CInArchive::Read16()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = Read8();
+ value |= (UInt16(b) << (8 * i));
+ }
+ return value;
+}
+
+UInt32 CInArchive::Read32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b = Read8();
+ value |= (UInt32(b) << (8 * i));
+ }
+ return value;
+}
+
+AString CInArchive::SafeReadName()
+{
+ AString name;
+ for (;;)
+ {
+ Byte b = Read8();
+ if (b == 0)
+ return name;
+ name += (char)b;
+ }
+}
+
+void CInArchive::ReadOtherArchive(COtherArchive &oa)
+{
+ oa.FileName = SafeReadName();
+ oa.DiskName = SafeReadName();
+}
+
+void CInArchive::Skip(UInt32 size)
+{
+ while (size-- != 0)
+ Read8();
+}
+
+HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db)
+{
+ IInStream *stream = db.Stream;
+ db.Clear();
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, &db.StartPosition));
+
+ RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
+ searchHeaderSizeLimit, db.StartPosition));
+
+ RINOK(stream->Seek(db.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL));
+ if (!inBuffer.Create(1 << 17))
+ return E_OUTOFMEMORY;
+ inBuffer.SetStream(stream);
+ inBuffer.Init();
+
+ CInArchiveInfo &ai = db.ArchiveInfo;
+
+ ai.Size = Read32();
+ if (Read32() != 0)
+ return S_FALSE;
+ ai.FileHeadersOffset = Read32();
+ if (Read32() != 0)
+ return S_FALSE;
+
+ ai.VersionMinor = Read8();
+ ai.VersionMajor = Read8();
+ ai.NumFolders = Read16();
+ ai.NumFiles = Read16();
+ ai.Flags = Read16();
+ if (ai.Flags > 7)
+ return S_FALSE;
+ ai.SetID = Read16();
+ ai.CabinetNumber = Read16();
+
+ if (ai.ReserveBlockPresent())
+ {
+ ai.PerCabinetAreaSize = Read16();
+ ai.PerFolderAreaSize = Read8();
+ ai.PerDataBlockAreaSize = Read8();
+
+ Skip(ai.PerCabinetAreaSize);
+ }
+
+ {
+ if (ai.IsTherePrev())
+ ReadOtherArchive(ai.PrevArc);
+ if (ai.IsThereNext())
+ ReadOtherArchive(ai.NextArc);
+ }
+
+ int i;
+ for (i = 0; i < ai.NumFolders; i++)
+ {
+ CFolder folder;
+
+ folder.DataStart = Read32();
+ folder.NumDataBlocks = Read16();
+ folder.CompressionTypeMajor = Read8();
+ folder.CompressionTypeMinor = Read8();
+
+ Skip(ai.PerFolderAreaSize);
+ db.Folders.Add(folder);
+ }
+
+ RINOK(stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL));
+
+ inBuffer.SetStream(stream);
+ inBuffer.Init();
+ for (i = 0; i < ai.NumFiles; i++)
+ {
+ CItem item;
+ item.Size = Read32();
+ item.Offset = Read32();
+ item.FolderIndex = Read16();
+ UInt16 pureDate = Read16();
+ UInt16 pureTime = Read16();
+ item.Time = ((UInt32(pureDate) << 16)) | pureTime;
+ item.Attributes = Read16();
+ item.Name = SafeReadName();
+ int folderIndex = item.GetFolderIndex(db.Folders.Size());
+ if (folderIndex >= db.Folders.Size())
+ return S_FALSE;
+ db.Items.Add(item);
+ }
+ return S_OK;
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param)
+{
+ const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param;
+ const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex];
+ const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex];
+ const CItem &item1 = db1.Items[p1->ItemIndex];
+ const CItem &item2 = db2.Items[p2->ItemIndex];;
+ bool isDir1 = item1.IsDir();
+ bool isDir2 = item2.IsDir();
+ if (isDir1 && !isDir2)
+ return -1;
+ if (isDir2 && !isDir1)
+ return 1;
+ int f1 = mvDb.GetFolderIndex(p1);
+ int f2 = mvDb.GetFolderIndex(p2);
+ RINOZ(MyCompare(f1, f2));
+ RINOZ(MyCompare(item1.Offset, item2.Offset));
+ RINOZ(MyCompare(item1.Size, item2.Size));
+ RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex));
+ return MyCompare(p1->ItemIndex, p2->ItemIndex);
+}
+
+bool CMvDatabaseEx::AreItemsEqual(int i1, int i2)
+{
+ const CMvItem *p1 = &Items[i1];
+ const CMvItem *p2 = &Items[i2];
+ const CDatabaseEx &db1 = Volumes[p1->VolumeIndex];
+ const CDatabaseEx &db2 = Volumes[p2->VolumeIndex];
+ const CItem &item1 = db1.Items[p1->ItemIndex];
+ const CItem &item2 = db2.Items[p2->ItemIndex];;
+ return GetFolderIndex(p1) == GetFolderIndex(p2) &&
+ item1.Offset == item2.Offset &&
+ item1.Size == item2.Size &&
+ item1.Name == item2.Name;
+}
+
+void CMvDatabaseEx::FillSortAndShrink()
+{
+ Items.Clear();
+ StartFolderOfVol.Clear();
+ FolderStartFileIndex.Clear();
+ int offset = 0;
+ for (int v = 0; v < Volumes.Size(); v++)
+ {
+ const CDatabaseEx &db = Volumes[v];
+ int curOffset = offset;
+ if (db.IsTherePrevFolder())
+ curOffset--;
+ StartFolderOfVol.Add(curOffset);
+ offset += db.GetNumberOfNewFolders();
+
+ CMvItem mvItem;
+ mvItem.VolumeIndex = v;
+ for (int i = 0 ; i < db.Items.Size(); i++)
+ {
+ mvItem.ItemIndex = i;
+ Items.Add(mvItem);
+ }
+ }
+
+ Items.Sort(CompareMvItems, (void *)this);
+ int j = 1;
+ int i;
+ for (i = 1; i < Items.Size(); i++)
+ if (!AreItemsEqual(i, i -1))
+ Items[j++] = Items[i];
+ Items.DeleteFrom(j);
+
+ for (i = 0; i < Items.Size(); i++)
+ {
+ int folderIndex = GetFolderIndex(&Items[i]);
+ if (folderIndex >= FolderStartFileIndex.Size())
+ FolderStartFileIndex.Add(i);
+ }
+}
+
+bool CMvDatabaseEx::Check()
+{
+ for (int v = 1; v < Volumes.Size(); v++)
+ {
+ const CDatabaseEx &db1 = Volumes[v];
+ if (db1.IsTherePrevFolder())
+ {
+ const CDatabaseEx &db0 = Volumes[v - 1];
+ if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty())
+ return false;
+ const CFolder &f0 = db0.Folders.Back();
+ const CFolder &f1 = db1.Folders.Front();
+ if (f0.CompressionTypeMajor != f1.CompressionTypeMajor ||
+ f0.CompressionTypeMinor != f1.CompressionTypeMinor)
+ return false;
+ }
+ }
+ UInt32 beginPos = 0;
+ UInt64 endPos = 0;
+ int prevFolder = -2;
+ for (int i = 0; i < Items.Size(); i++)
+ {
+ const CMvItem &mvItem = Items[i];
+ int fIndex = GetFolderIndex(&mvItem);
+ if (fIndex >= FolderStartFileIndex.Size())
+ return false;
+ const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
+ if (item.IsDir())
+ continue;
+ int folderIndex = GetFolderIndex(&mvItem);
+ if (folderIndex != prevFolder)
+ prevFolder = folderIndex;
+ else if (item.Offset < endPos &&
+ (item.Offset != beginPos || item.GetEndOffset() != endPos))
+ return false;
+ beginPos = item.Offset;
+ endPos = item.GetEndOffset();
+ }
+ return true;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.h
new file mode 100644
index 000000000..1e9b188b5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.h
@@ -0,0 +1,161 @@
+// Archive/CabIn.h
+
+#ifndef __ARCHIVE_CAB_IN_H
+#define __ARCHIVE_CAB_IN_H
+
+#include "../../IStream.h"
+#include "../../Common/InBuffer.h"
+#include "CabHeader.h"
+#include "CabItem.h"
+
+namespace NArchive {
+namespace NCab {
+
+class CInArchiveException
+{
+public:
+ enum CCauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kIncorrectArchive,
+ kUnsupported
+ } Cause;
+ CInArchiveException(CCauseType cause) : Cause(cause) {}
+};
+
+struct COtherArchive
+{
+ AString FileName;
+ AString DiskName;
+};
+
+struct CArchiveInfo
+{
+ Byte VersionMinor; /* cabinet file format version, minor */
+ Byte VersionMajor; /* cabinet file format version, major */
+ UInt16 NumFolders; /* number of CFFOLDER entries in this cabinet */
+ UInt16 NumFiles; /* number of CFFILE entries in this cabinet */
+ UInt16 Flags; /* cabinet file option indicators */
+ UInt16 SetID; /* must be the same for all cabinets in a set */
+ UInt16 CabinetNumber; /* number of this cabinet file in a set */
+
+ bool ReserveBlockPresent() const { return (Flags & NHeader::NArchive::NFlags::kReservePresent) != 0; }
+
+ bool IsTherePrev() const { return (Flags & NHeader::NArchive::NFlags::kPrevCabinet) != 0; }
+ bool IsThereNext() const { return (Flags & NHeader::NArchive::NFlags::kNextCabinet) != 0; }
+
+ UInt16 PerCabinetAreaSize; // (optional) size of per-cabinet reserved area
+ Byte PerFolderAreaSize; // (optional) size of per-folder reserved area
+ Byte PerDataBlockAreaSize; // (optional) size of per-datablock reserved area
+
+ Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlockAreaSize : 0); }
+
+ COtherArchive PrevArc;
+ COtherArchive NextArc;
+
+ CArchiveInfo()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ PerCabinetAreaSize = 0;
+ PerFolderAreaSize = 0;
+ PerDataBlockAreaSize = 0;
+ }
+};
+
+struct CInArchiveInfo: public CArchiveInfo
+{
+ UInt32 Size; /* size of this cabinet file in bytes */
+ UInt32 FileHeadersOffset; // offset of the first CFFILE entry
+};
+
+
+struct CDatabase
+{
+ UInt64 StartPosition;
+ CInArchiveInfo ArchiveInfo;
+ CObjectVector<CFolder> Folders;
+ CObjectVector<CItem> Items;
+
+ void Clear()
+ {
+ ArchiveInfo.Clear();
+ Folders.Clear();
+ Items.Clear();
+ }
+ bool IsTherePrevFolder() const
+ {
+ for (int i = 0; i < Items.Size(); i++)
+ if (Items[i].ContinuedFromPrev())
+ return true;
+ return false;
+ }
+ int GetNumberOfNewFolders() const
+ {
+ int res = Folders.Size();
+ if (IsTherePrevFolder())
+ res--;
+ return res;
+ }
+ UInt32 GetFileOffset(int index) const { return Items[index].Offset; }
+ UInt32 GetFileSize(int index) const { return Items[index].Size; }
+};
+
+struct CDatabaseEx: public CDatabase
+{
+ CMyComPtr<IInStream> Stream;
+};
+
+struct CMvItem
+{
+ int VolumeIndex;
+ int ItemIndex;
+};
+
+class CMvDatabaseEx
+{
+ bool AreItemsEqual(int i1, int i2);
+public:
+ CObjectVector<CDatabaseEx> Volumes;
+ CRecordVector<CMvItem> Items;
+ CRecordVector<int> StartFolderOfVol;
+ CRecordVector<int> FolderStartFileIndex;
+
+ int GetFolderIndex(const CMvItem *mvi) const
+ {
+ const CDatabaseEx &db = Volumes[mvi->VolumeIndex];
+ return StartFolderOfVol[mvi->VolumeIndex] +
+ db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size());
+ }
+ void Clear()
+ {
+ Volumes.Clear();
+ Items.Clear();
+ StartFolderOfVol.Clear();
+ FolderStartFileIndex.Clear();
+ }
+ void FillSortAndShrink();
+ bool Check();
+};
+
+class CInArchive
+{
+ CInBuffer inBuffer;
+
+ Byte Read8();
+ UInt16 Read16();
+ UInt32 Read32();
+ AString SafeReadName();
+ void Skip(UInt32 size);
+ void ReadOtherArchive(COtherArchive &oa);
+
+public:
+ HRESULT Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabItem.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabItem.h
new file mode 100644
index 000000000..63a1e856c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabItem.h
@@ -0,0 +1,63 @@
+// Archive/CabItem.h
+
+#ifndef __ARCHIVE_CAB_ITEM_H
+#define __ARCHIVE_CAB_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+#include "CabHeader.h"
+
+namespace NArchive {
+namespace NCab {
+
+struct CFolder
+{
+ UInt32 DataStart; // offset of the first CFDATA block in this folder
+ UInt16 NumDataBlocks; // number of CFDATA blocks in this folder
+ Byte CompressionTypeMajor;
+ Byte CompressionTypeMinor;
+ Byte GetCompressionMethod() const { return (Byte)(CompressionTypeMajor & 0xF); }
+};
+
+struct CItem
+{
+ AString Name;
+ UInt32 Offset;
+ UInt32 Size;
+ UInt32 Time;
+ UInt16 FolderIndex;
+ UInt16 Flags;
+ UInt16 Attributes;
+
+ UInt64 GetEndOffset() const { return (UInt64)Offset + Size; }
+ UInt32 GetWinAttributes() const { return (Attributes & ~NHeader::kFileNameIsUTFAttributeMask); }
+ bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUTFAttributeMask) != 0; }
+ bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; }
+
+ bool ContinuedFromPrev() const
+ {
+ return
+ (FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev) ||
+ (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext);
+ }
+
+ bool ContinuedToNext() const
+ {
+ return
+ (FolderIndex == NHeader::NFolderIndex::kContinuedToNext) ||
+ (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext);
+ }
+
+ int GetFolderIndex(int numFolders) const
+ {
+ if (ContinuedFromPrev())
+ return 0;
+ if (ContinuedToNext())
+ return (numFolders - 1);
+ return FolderIndex;
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabRegister.cpp
new file mode 100644
index 000000000..15fe4099f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabRegister.cpp
@@ -0,0 +1,13 @@
+// CabRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "CabHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NCab::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Cab", L"cab", 0, 8, { 0x4D, 0x53, 0x43, 0x46 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Cab)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/StdAfx.h
new file mode 100644
index 000000000..e7fb6986d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.cpp
new file mode 100644
index 000000000..a9e334b03
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.cpp
@@ -0,0 +1,721 @@
+// ChmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/Defs.h"
+#include "Common/StringConvert.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/LzxDecoder.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "ChmHandler.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NChm {
+
+// #define _CHM_DETAILS
+
+#ifdef _CHM_DETAILS
+
+enum
+{
+ kpidSection = kpidUserDefined
+};
+
+#endif
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidBlock, VT_UI4}
+
+ #ifdef _CHM_DETAILS
+ ,
+ { L"Section", kpidSection, VT_UI4},
+ { NULL, kpidOffset, VT_UI4}
+ #endif
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidNumBlocks, VT_UI8}
+};
+
+IMP_IInArchive_Props
+
+IMP_IInArchive_ArcProps_NO
+/*
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidNumBlocks:
+ {
+ UInt64 numBlocks = 0;
+ for (int i = 0; i < m_Database.Sections.Size(); i++)
+ {
+ const CSectionInfo &s = m_Database.Sections[i];
+ for (int j = 0; j < s.Methods.Size(); j++)
+ {
+ const CMethodInfo &m = s.Methods[j];
+ if (m.IsLzx())
+ numBlocks += m.LzxInfo.ResetTable.GetNumBlocks();
+ }
+ }
+ prop = numBlocks;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+*/
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ if (m_Database.NewFormat)
+ {
+ switch(propID)
+ {
+ case kpidSize:
+ prop = (UInt64)m_Database.NewFormatString.Length();
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ }
+ int entryIndex;
+ if (m_Database.LowLevel)
+ entryIndex = index;
+ else
+ entryIndex = m_Database.Indices[index];
+ const CItem &item = m_Database.Items[entryIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString us;
+ if (ConvertUTF8ToUnicode(item.Name, us))
+ {
+ if (!m_Database.LowLevel)
+ {
+ if (us.Length() > 1)
+ if (us[0] == L'/')
+ us.Delete(0);
+ }
+ prop = NItemName::GetOSName2(us);
+ }
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidMethod:
+ {
+ if (!item.IsDir())
+ if (item.Section == 0)
+ prop = L"Copy";
+ else if (item.Section < m_Database.Sections.Size())
+ prop = m_Database.Sections[(int)item.Section].GetMethodName();
+ break;
+ }
+ case kpidBlock:
+ if (m_Database.LowLevel)
+ prop = item.Section;
+ else if (item.Section != 0)
+ prop = m_Database.GetFolder(index);
+ break;
+
+ #ifdef _CHM_DETAILS
+
+ case kpidSection: prop = (UInt32)item.Section; break;
+ case kpidOffset: prop = (UInt32)item.Offset; break;
+
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+public:
+ STDMETHOD(SetTotal)(const UInt64 *numFiles);
+ STDMETHOD(SetCompleted)(const UInt64 *numFiles);
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {};
+};
+
+STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ m_Stream.Release();
+ try
+ {
+ CInArchive archive;
+ // CProgressImp progressImp(openArchiveCallback);
+ RINOK(archive.Open(inStream, maxCheckStartPosition, m_Database));
+ /*
+ if (m_Database.LowLevel)
+ return S_FALSE;
+ */
+ m_Stream = inStream;
+ }
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ m_Database.Clear();
+ m_Stream.Release();
+ return S_OK;
+}
+
+class CChmFolderOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+
+ UInt64 m_FolderSize;
+ UInt64 m_PosInFolder;
+ UInt64 m_PosInSection;
+ const CRecordVector<bool> *m_ExtractStatuses;
+ int m_StartIndex;
+ int m_CurrentIndex;
+ int m_NumFiles;
+
+private:
+ const CFilesDatabase *m_Database;
+ CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
+ bool m_TestMode;
+
+ bool m_IsOk;
+ bool m_FileIsOpen;
+ UInt64 m_RemainFileSize;
+ CMyComPtr<ISequentialOutStream> m_RealOutStream;
+
+ HRESULT OpenFile();
+ HRESULT WriteEmptyFiles();
+public:
+ void Init(
+ const CFilesDatabase *database,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode);
+ HRESULT FlushCorrupted(UInt64 maxSize);
+};
+
+void CChmFolderOutStream::Init(
+ const CFilesDatabase *database,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode)
+{
+ m_Database = database;
+ m_ExtractCallback = extractCallback;
+ m_TestMode = testMode;
+
+ m_CurrentIndex = 0;
+ m_FileIsOpen = false;
+}
+
+HRESULT CChmFolderOutStream::OpenFile()
+{
+ Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract) :
+ NExtract::NAskMode::kSkip;
+ m_RealOutStream.Release();
+ RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));
+ if (!m_RealOutStream && !m_TestMode)
+ askMode = NExtract::NAskMode::kSkip;
+ return m_ExtractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CChmFolderOutStream::WriteEmptyFiles()
+{
+ if (m_FileIsOpen)
+ return S_OK;
+ for (;m_CurrentIndex < m_NumFiles; m_CurrentIndex++)
+ {
+ UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex);
+ if (fileSize != 0)
+ return S_OK;
+ HRESULT result = OpenFile();
+ m_RealOutStream.Release();
+ RINOK(result);
+ RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+}
+
+// This is WritePart function
+HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
+{
+ UInt32 realProcessed = 0;
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while(size != 0)
+ {
+ if (m_FileIsOpen)
+ {
+ UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size));
+ HRESULT res = S_OK;
+ if (numBytesToWrite > 0)
+ {
+ if (!isOK)
+ m_IsOk = false;
+ if (m_RealOutStream)
+ {
+ UInt32 processedSizeLocal = 0;
+ res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
+ numBytesToWrite = processedSizeLocal;
+ }
+ }
+ realProcessed += numBytesToWrite;
+ if (processedSize != NULL)
+ *processedSize = realProcessed;
+ data = (const void *)((const Byte *)data + numBytesToWrite);
+ size -= numBytesToWrite;
+ m_RemainFileSize -= numBytesToWrite;
+ m_PosInSection += numBytesToWrite;
+ m_PosInFolder += numBytesToWrite;
+ if (res != S_OK)
+ return res;
+ if (m_RemainFileSize == 0)
+ {
+ m_RealOutStream.Release();
+ RINOK(m_ExtractCallback->SetOperationResult(
+ m_IsOk ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ m_FileIsOpen = false;
+ }
+ if (realProcessed > 0)
+ break; // with this break this function works as write part
+ }
+ else
+ {
+ if (m_CurrentIndex >= m_NumFiles)
+ return E_FAIL;
+ int fullIndex = m_StartIndex + m_CurrentIndex;
+ m_RemainFileSize = m_Database->GetFileSize(fullIndex);
+ UInt64 fileOffset = m_Database->GetFileOffset(fullIndex);
+ if (fileOffset < m_PosInSection)
+ return E_FAIL;
+ if (fileOffset > m_PosInSection)
+ {
+ UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size));
+ realProcessed += numBytesToWrite;
+ if (processedSize != NULL)
+ *processedSize = realProcessed;
+ data = (const void *)((const Byte *)data + numBytesToWrite);
+ size -= numBytesToWrite;
+ m_PosInSection += numBytesToWrite;
+ m_PosInFolder += numBytesToWrite;
+ }
+ if (fileOffset == m_PosInSection)
+ {
+ RINOK(OpenFile());
+ m_FileIsOpen = true;
+ m_CurrentIndex++;
+ m_IsOk = true;
+ }
+ }
+ }
+ return WriteEmptyFiles();
+}
+
+STDMETHODIMP CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ return Write2(data, size, processedSize, true);
+}
+
+HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize)
+{
+ const UInt32 kBufferSize = (1 << 10);
+ Byte buffer[kBufferSize];
+ for (int i = 0; i < kBufferSize; i++)
+ buffer[i] = 0;
+ if (maxSize > m_FolderSize)
+ maxSize = m_FolderSize;
+ while (m_PosInFolder < maxSize)
+ {
+ UInt32 size = (UInt32)MyMin(maxSize - m_PosInFolder, (UInt64)kBufferSize);
+ UInt32 processedSizeLocal = 0;
+ RINOK(Write2(buffer, size, &processedSizeLocal, false));
+ if (processedSizeLocal == 0)
+ return S_OK;
+ }
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+
+ if (allFilesMode)
+ numItems = m_Database.NewFormat ? 1:
+ (m_Database.LowLevel ?
+ m_Database.Items.Size():
+ m_Database.Indices.Size());
+ if (numItems == 0)
+ return S_OK;
+ bool testMode = (testModeSpec != 0);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+ UInt32 i;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(m_Stream);
+
+ if (m_Database.LowLevel)
+ {
+ UInt64 currentItemSize = 0;
+ UInt64 totalSize = 0;
+ if (m_Database.NewFormat)
+ totalSize = m_Database.NewFormatString.Length();
+ else
+ for (i = 0; i < numItems; i++)
+ totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ currentItemSize = 0;
+ lps->InSize = currentTotalSize; // Change it
+ lps->OutSize = currentTotalSize;
+
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode= testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (m_Database.NewFormat)
+ {
+ if (index != 0)
+ return E_FAIL;
+ if (!testMode && !realOutStream)
+ continue;
+ if (!testMode)
+ {
+ UInt32 size = m_Database.NewFormatString.Length();
+ RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size));
+ }
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ const CItem &item = m_Database.Items[index];
+
+ currentItemSize = item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (item.Section != 0)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ }
+
+ UInt64 lastFolderIndex = ((UInt64)0 - 1);
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = allFilesMode ? i : indices[i];
+ int entryIndex = m_Database.Indices[index];
+ const CItem &item = m_Database.Items[entryIndex];
+ UInt64 sectionIndex = item.Section;
+ if (item.IsDir() || item.Size == 0)
+ continue;
+ if (sectionIndex == 0)
+ {
+ currentTotalSize += item.Size;
+ continue;
+ }
+ const CSectionInfo &section = m_Database.Sections[(int)item.Section];
+ if (section.IsLzx())
+ {
+ const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
+ UInt64 folderIndex = m_Database.GetFolder(index);
+ if (lastFolderIndex == folderIndex)
+ folderIndex++;
+ lastFolderIndex = m_Database.GetLastFolder(index);
+ for (; folderIndex <= lastFolderIndex; folderIndex++)
+ currentTotalSize += lzxInfo.GetFolderSize();
+ }
+ }
+
+ RINOK(extractCallback->SetTotal(currentTotalSize));
+
+ NCompress::NLzx::CDecoder *lzxDecoderSpec = 0;
+ CMyComPtr<ICompressCoder> lzxDecoder;
+ CChmFolderOutStream *chmFolderOutStream = 0;
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ currentTotalSize = 0;
+
+ CRecordVector<bool> extractStatuses;
+ for (i = 0; i < numItems;)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ UInt32 index = allFilesMode ? i : indices[i];
+ i++;
+ int entryIndex = m_Database.Indices[index];
+ const CItem &item = m_Database.Items[entryIndex];
+ UInt64 sectionIndex = item.Section;
+ Int32 askMode= testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ if (item.IsDir())
+ {
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ lps->InSize = currentTotalSize; // Change it
+ lps->OutSize = currentTotalSize;
+
+ if (item.Size == 0 || sectionIndex == 0)
+ {
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ if (!testMode && item.Size != 0)
+ {
+ RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != item.Size)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ currentTotalSize += item.Size;
+ continue;
+ }
+
+ const CSectionInfo &section = m_Database.Sections[(int)sectionIndex];
+
+ if (!section.IsLzx())
+ {
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+
+ const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo;
+
+ if (chmFolderOutStream == 0)
+ {
+ chmFolderOutStream = new CChmFolderOutStream;
+ outStream = chmFolderOutStream;
+ }
+
+ chmFolderOutStream->Init(&m_Database, extractCallback, testMode);
+
+ if (lzxDecoderSpec == NULL)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder;
+ lzxDecoder = lzxDecoderSpec;
+ }
+
+ UInt64 folderIndex = m_Database.GetFolder(index);
+
+ UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
+ UInt32 numDictBits = lzxInfo.GetNumDictBits();
+ RINOK(lzxDecoderSpec->SetParams(numDictBits));
+
+ const CItem *lastItem = &item;
+ extractStatuses.Clear();
+ extractStatuses.Add(true);
+
+ for (;; folderIndex++)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+
+ UInt64 startPos = lzxInfo.GetFolderPos(folderIndex);
+ UInt64 finishPos = lastItem->Offset + lastItem->Size;
+ UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos);
+
+ lastFolderIndex = m_Database.GetLastFolder(index);
+ UInt64 folderSize = lzxInfo.GetFolderSize();
+ UInt64 unPackSize = folderSize;
+ if (extractStatuses.IsEmpty())
+ chmFolderOutStream->m_StartIndex = index + 1;
+ else
+ chmFolderOutStream->m_StartIndex = index;
+ if (limitFolderIndex == folderIndex)
+ {
+ for (; i < numItems; i++)
+ {
+ UInt32 nextIndex = allFilesMode ? i : indices[i];
+ int entryIndex = m_Database.Indices[nextIndex];
+ const CItem &nextItem = m_Database.Items[entryIndex];
+ if (nextItem.Section != sectionIndex)
+ break;
+ UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex);
+ if (nextFolderIndex != folderIndex)
+ break;
+ for (index++; index < nextIndex; index++)
+ extractStatuses.Add(false);
+ extractStatuses.Add(true);
+ index = nextIndex;
+ lastItem = &nextItem;
+ if (nextItem.Size != 0)
+ finishPos = nextItem.Offset + nextItem.Size;
+ lastFolderIndex = m_Database.GetLastFolder(index);
+ }
+ }
+ unPackSize = MyMin(finishPos - startPos, unPackSize);
+
+ chmFolderOutStream->m_FolderSize = folderSize;
+ chmFolderOutStream->m_PosInFolder = 0;
+ chmFolderOutStream->m_PosInSection = startPos;
+ chmFolderOutStream->m_ExtractStatuses = &extractStatuses;
+ chmFolderOutStream->m_NumFiles = extractStatuses.Size();
+ chmFolderOutStream->m_CurrentIndex = 0;
+ try
+ {
+ UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex);
+ const CResetTable &rt = lzxInfo.ResetTable;
+ UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize);
+ for (UInt32 b = 0; b < numBlocks; b++)
+ {
+ UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos;
+ RINOK(extractCallback->SetCompleted(&completedSize));
+ UInt64 bCur = startBlock + b;
+ if (bCur >= rt.ResetOffsets.Size())
+ return E_FAIL;
+ UInt64 offset = rt.ResetOffsets[(int)bCur];
+ UInt64 compressedSize;
+ rt.GetCompressedSizeOfBlock(bCur, compressedSize);
+ UInt64 rem = finishPos - chmFolderOutStream->m_PosInSection;
+ if (rem > rt.BlockSize)
+ rem = rt.BlockSize;
+ RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL));
+ streamSpec->SetStream(m_Stream);
+ streamSpec->Init(compressedSize);
+ lzxDecoderSpec->SetKeepHistory(b > 0);
+ HRESULT res = lzxDecoder->Code(inStream, outStream, NULL, &rem, NULL);
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ throw 1;
+ }
+ }
+ }
+ catch(...)
+ {
+ RINOK(chmFolderOutStream->FlushCorrupted(unPackSize));
+ }
+ currentTotalSize += folderSize;
+ if (folderIndex == lastFolderIndex)
+ break;
+ extractStatuses.Clear();
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = m_Database.NewFormat ? 1:
+ (m_Database.LowLevel ?
+ m_Database.Items.Size():
+ m_Database.Indices.Size());
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.h
new file mode 100644
index 000000000..440c50f11
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.h
@@ -0,0 +1,29 @@
+// ChmHandler.h
+
+#ifndef __ARCHIVE_CHM_HANDLER_H
+#define __ARCHIVE_CHM_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "ChmIn.h"
+
+namespace NArchive {
+namespace NChm {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+
+ INTERFACE_IInArchive(;)
+
+private:
+ CFilesDatabase m_Database;
+ CMyComPtr<IInStream> m_Stream;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.cpp
new file mode 100644
index 000000000..e8dc9f3e8
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.cpp
@@ -0,0 +1,24 @@
+// Archive/Chm/Header.h
+
+#include "StdAfx.h"
+
+#include "ChmHeader.h"
+
+namespace NArchive{
+namespace NChm{
+namespace NHeader{
+
+UInt32 kItsfSignature = 0x46535449 + 1;
+UInt32 kItolSignature = 0x4C4F5449 + 1;
+static class CSignatureInitializer
+{
+public:
+ CSignatureInitializer()
+ {
+ kItsfSignature--;
+ kItolSignature--;
+ }
+}g_SignatureInitializer;
+
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.h
new file mode 100644
index 000000000..9f1bd42b6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.h
@@ -0,0 +1,28 @@
+// Archive/Chm/Header.h
+
+#ifndef __ARCHIVE_CHM_HEADER_H
+#define __ARCHIVE_CHM_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NChm {
+namespace NHeader{
+
+const UInt32 kItspSignature = 0x50535449;
+const UInt32 kPmglSignature = 0x4C474D50;
+const UInt32 kLzxcSignature = 0x43585A4C;
+
+const UInt32 kIfcmSignature = 0x4D434649;
+const UInt32 kAollSignature = 0x4C4C4F41;
+const UInt32 kCaolSignature = 0x4C4F4143;
+
+extern UInt32 kItsfSignature;
+
+extern UInt32 kItolSignature;
+const UInt32 kItlsSignature = 0x534C5449;
+UInt64 inline GetHxsSignature() { return ((UInt64)kItlsSignature << 32) | kItolSignature; }
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.cpp
new file mode 100644
index 000000000..d52b9ba6c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.cpp
@@ -0,0 +1,937 @@
+// Archive/ChmIn.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/UTFConvert.h"
+
+#include "../../Common/LimitedStreams.h"
+
+#include "ChmIn.h"
+
+namespace NArchive {
+namespace NChm {
+
+// define CHM_LOW, if you want to see low level items
+// #define CHM_LOW
+
+static const GUID kChmLzxGuid = { 0x7FC28940, 0x9D31, 0x11D0, { 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C } };
+static const GUID kHelp2LzxGuid = { 0x0A9007C6, 0x4076, 0x11D3, { 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 } };
+static const GUID kDesGuid = { 0x67F6E4A2, 0x60BF, 0x11D3, { 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF } };
+
+static bool AreGuidsEqual(REFGUID g1, REFGUID g2)
+{
+ if (g1.Data1 != g2.Data1 ||
+ g1.Data2 != g2.Data2 ||
+ g1.Data3 != g2.Data3)
+ return false;
+ for (int i = 0; i < 8; i++)
+ if (g1.Data4[i] != g2.Data4[i])
+ return false;
+ return true;
+}
+
+static char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+static void PrintByte(Byte b, AString &s)
+{
+ s += GetHex(b >> 4);
+ s += GetHex(b & 0xF);
+}
+
+static void PrintUInt16(UInt16 v, AString &s)
+{
+ PrintByte((Byte)(v >> 8), s);
+ PrintByte((Byte)v, s);
+}
+
+static void PrintUInt32(UInt32 v, AString &s)
+{
+ PrintUInt16((UInt16)(v >> 16), s);
+ PrintUInt16((UInt16)v, s);
+}
+
+AString CMethodInfo::GetGuidString() const
+{
+ AString s;
+ s += '{';
+ PrintUInt32(Guid.Data1, s);
+ s += '-';
+ PrintUInt16(Guid.Data2, s);
+ s += '-';
+ PrintUInt16(Guid.Data3, s);
+ s += '-';
+ PrintByte(Guid.Data4[0], s);
+ PrintByte(Guid.Data4[1], s);
+ s += '-';
+ for (int i = 2; i < 8; i++)
+ PrintByte(Guid.Data4[i], s);
+ s += '}';
+ return s;
+}
+
+bool CMethodInfo::IsLzx() const
+{
+ if (AreGuidsEqual(Guid, kChmLzxGuid))
+ return true;
+ return AreGuidsEqual(Guid, kHelp2LzxGuid);
+}
+
+bool CMethodInfo::IsDes() const
+{
+ return AreGuidsEqual(Guid, kDesGuid);
+}
+
+UString CMethodInfo::GetName() const
+{
+ UString s;
+ if (IsLzx())
+ {
+ s = L"LZX:";
+ wchar_t temp[16];
+ ConvertUInt32ToString(LzxInfo.GetNumDictBits(), temp);
+ s += temp;
+ }
+ else
+ {
+ AString s2;
+ if (IsDes())
+ s2 = "DES";
+ else
+ {
+ s2 = GetGuidString();
+ if (ControlData.GetCapacity() > 0)
+ {
+ s2 += ':';
+ for (size_t i = 0; i < ControlData.GetCapacity(); i++)
+ PrintByte(ControlData[i], s2);
+ }
+ }
+ ConvertUTF8ToUnicode(s2, s);
+ }
+ return s;
+}
+
+bool CSectionInfo::IsLzx() const
+{
+ if (Methods.Size() != 1)
+ return false;
+ return Methods[0].IsLzx();
+}
+
+UString CSectionInfo::GetMethodName() const
+{
+ UString s;
+ if (!IsLzx())
+ {
+ UString temp;
+ if (ConvertUTF8ToUnicode(Name, temp))
+ s += temp;
+ s += L": ";
+ }
+ for (int i = 0; i < Methods.Size(); i++)
+ {
+ if (i != 0)
+ s += L' ';
+ s += Methods[i].GetName();
+ }
+ return s;
+}
+
+Byte CInArchive::ReadByte()
+{
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ throw 1;
+ return b;
+}
+
+void CInArchive::Skip(size_t size)
+{
+ while (size-- != 0)
+ ReadByte();
+}
+
+void CInArchive::ReadBytes(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ data[i] = ReadByte();
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ value |= ((UInt16)(ReadByte()) << (8 * i));
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ value |= ((UInt32)(ReadByte()) << (8 * i));
+ return value;
+}
+
+UInt64 CInArchive::ReadUInt64()
+{
+ UInt64 value = 0;
+ for (int i = 0; i < 8; i++)
+ value |= ((UInt64)(ReadByte()) << (8 * i));
+ return value;
+}
+
+UInt64 CInArchive::ReadEncInt()
+{
+ UInt64 val = 0;;
+ for (int i = 0; i < 10; i++)
+ {
+ Byte b = ReadByte();
+ val |= (b & 0x7F);
+ if (b < 0x80)
+ return val;
+ val <<= 7;
+ }
+ throw 1;
+}
+
+void CInArchive::ReadGUID(GUID &g)
+{
+ g.Data1 = ReadUInt32();
+ g.Data2 = ReadUInt16();
+ g.Data3 = ReadUInt16();
+ ReadBytes(g.Data4, 8);
+}
+
+void CInArchive::ReadString(int size, AString &s)
+{
+ s.Empty();
+ while(size-- != 0)
+ {
+ char c = (char)ReadByte();
+ if (c == 0)
+ {
+ Skip(size);
+ return;
+ }
+ s += c;
+ }
+}
+
+void CInArchive::ReadUString(int size, UString &s)
+{
+ s.Empty();
+ while(size-- != 0)
+ {
+ wchar_t c = ReadUInt16();
+ if (c == 0)
+ {
+ Skip(2 * size);
+ return;
+ }
+ s += c;
+ }
+}
+
+HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size)
+{
+ RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL));
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> limitedStream(streamSpec);
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(size);
+ _inBuffer.SetStream(limitedStream);
+ _inBuffer.Init();
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadDirEntry(CDatabase &database)
+{
+ CItem item;
+ UInt64 nameLength = ReadEncInt();
+ if (nameLength == 0 || nameLength >= 0x10000000)
+ return S_FALSE;
+ ReadString((int)nameLength, item.Name);
+ item.Section = ReadEncInt();
+ item.Offset = ReadEncInt();
+ item.Size = ReadEncInt();
+ database.Items.Add(item);
+ return S_OK;
+}
+
+HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
+{
+ UInt32 headerSize = ReadUInt32();
+ if (headerSize != 0x60)
+ return S_FALSE;
+ UInt32 unknown1 = ReadUInt32();
+ if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file
+ return S_FALSE;
+ /* UInt32 timeStamp = */ ReadUInt32();
+ // Considered as a big-endian DWORD, it appears to contain seconds (MSB) and
+ // fractional seconds (second byte).
+ // The third and fourth bytes may contain even more fractional bits.
+ // The 4 least significant bits in the last byte are constant.
+ /* UInt32 lang = */ ReadUInt32();
+ GUID g;
+ ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}
+ ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}
+ const int kNumSections = 2;
+ UInt64 sectionOffsets[kNumSections];
+ UInt64 sectionSizes[kNumSections];
+ int i;
+ for (i = 0; i < kNumSections; i++)
+ {
+ sectionOffsets[i] = ReadUInt64();
+ sectionSizes[i] = ReadUInt64();
+ }
+ // if (chmVersion == 3)
+ database.ContentOffset = ReadUInt64();
+ /*
+ else
+ database.ContentOffset = _startPosition + 0x58
+ */
+
+ /*
+ // Section 0
+ ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]);
+ if (sectionSizes[0] != 0x18)
+ return S_FALSE;
+ ReadUInt32(); // unknown: 01FE
+ ReadUInt32(); // unknown: 0
+ UInt64 fileSize = ReadUInt64();
+ ReadUInt32(); // unknown: 0
+ ReadUInt32(); // unknown: 0
+ */
+
+ // Section 1: The Directory Listing
+ ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]);
+ if (ReadUInt32() != NHeader::kItspSignature)
+ return S_FALSE;
+ if (ReadUInt32() != 1) // version
+ return S_FALSE;
+ /* UInt32 dirHeaderSize = */ ReadUInt32();
+ ReadUInt32(); // 0x0A (unknown)
+ UInt32 dirChunkSize = ReadUInt32(); // $1000
+ if (dirChunkSize < 32)
+ return S_FALSE;
+ /* UInt32 density = */ ReadUInt32(); // "Density" of quickref section, usually 2.
+ /* UInt32 depth = */ ReadUInt32(); // Depth of the index tree: 1 there is no index,
+ // 2 if there is one level of PMGI chunks.
+
+ /* UInt32 chunkNumber = */ ReadUInt32(); // Chunk number of root index chunk, -1 if there is none
+ // (though at least one file has 0 despite there being no
+ // index chunk, probably a bug.)
+ /* UInt32 firstPmglChunkNumber = */ ReadUInt32(); // Chunk number of first PMGL (listing) chunk
+ /* UInt32 lastPmglChunkNumber = */ ReadUInt32(); // Chunk number of last PMGL (listing) chunk
+ ReadUInt32(); // -1 (unknown)
+ UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total)
+ /* UInt32 windowsLangId = */ ReadUInt32();
+ ReadGUID(g); // {5D02926A-212E-11D0-9DF9-00A0C922E6EC}
+ ReadUInt32(); // 0x54 (This is the length again)
+ ReadUInt32(); // -1 (unknown)
+ ReadUInt32(); // -1 (unknown)
+ ReadUInt32(); // -1 (unknown)
+
+ for (UInt32 ci = 0; ci < numDirChunks; ci++)
+ {
+ UInt64 chunkPos = _inBuffer.GetProcessedSize();
+ if (ReadUInt32() == NHeader::kPmglSignature)
+ {
+ // The quickref area is written backwards from the end of the chunk.
+ // One quickref entry exists for every n entries in the file, where n
+ // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5.
+
+ UInt32 quickrefLength = ReadUInt32(); // Length of free space and/or quickref area at end of directory chunk
+ if (quickrefLength > dirChunkSize || quickrefLength < 2)
+ return S_FALSE;
+ ReadUInt32(); // Always 0
+ ReadUInt32(); // Chunk number of previous listing chunk when reading
+ // directory in sequence (-1 if this is the first listing chunk)
+ ReadUInt32(); // Chunk number of next listing chunk when reading
+ // directory in sequence (-1 if this is the last listing chunk)
+ int numItems = 0;
+ for (;;)
+ {
+ UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
+ UInt32 offsetLimit = dirChunkSize - quickrefLength;
+ if (offset > offsetLimit)
+ return S_FALSE;
+ if (offset == offsetLimit)
+ break;
+ RINOK(ReadDirEntry(database));
+ numItems++;
+ }
+ Skip(quickrefLength - 2);
+ if (ReadUInt16() != numItems)
+ return S_FALSE;
+ }
+ else
+ Skip(dirChunkSize - 4);
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
+{
+ if (ReadUInt32() != 1) // version
+ return S_FALSE;
+ if (ReadUInt32() != 0x28) // Location of header section table
+ return S_FALSE;
+ UInt32 numHeaderSections = ReadUInt32();
+ const int kNumHeaderSectionsMax = 5;
+ if (numHeaderSections != kNumHeaderSectionsMax)
+ return S_FALSE;
+ ReadUInt32(); // Length of post-header table
+ GUID g;
+ ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754}
+
+ // header section table
+ UInt64 sectionOffsets[kNumHeaderSectionsMax];
+ UInt64 sectionSizes[kNumHeaderSectionsMax];
+ UInt32 i;
+ for (i = 0; i < numHeaderSections; i++)
+ {
+ sectionOffsets[i] = ReadUInt64();
+ sectionSizes[i] = ReadUInt64();
+ }
+
+ // Post-Header
+ ReadUInt32(); // 2
+ ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header)
+ // ----- Directory information
+ ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1
+ ReadUInt64(); // Chunk number of first AOLL chunk in directory
+ ReadUInt64(); // Chunk number of last AOLL chunk in directory
+ ReadUInt64(); // 0 (unknown)
+ ReadUInt32(); // $2000 (Directory chunk size of directory)
+ ReadUInt32(); // Quickref density for main directory, usually 2
+ ReadUInt32(); // 0 (unknown)
+ ReadUInt32(); // Depth of main directory index tree
+ // 1 there is no index, 2 if there is one level of AOLI chunks.
+ ReadUInt64(); // 0 (unknown)
+ UInt64 numDirEntries = ReadUInt64(); // Number of directory entries
+ // ----- Directory Index Information
+ ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index)
+ ReadUInt64(); // Chunk number of first AOLL chunk in directory index
+ ReadUInt64(); // Chunk number of last AOLL chunk in directory index
+ ReadUInt64(); // 0 (unknown)
+ ReadUInt32(); // $200 (Directory chunk size of directory index)
+ ReadUInt32(); // Quickref density for directory index, usually 2
+ ReadUInt32(); // 0 (unknown)
+ ReadUInt32(); // Depth of directory index index tree.
+ ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0.
+ ReadUInt64(); // Number of directory index entries (same as number of AOLL
+ // chunks in main directory)
+
+ // (The obvious guess for the following two fields, which recur in a number
+ // of places, is they are maximum sizes for the directory and directory index.
+ // However, I have seen no direct evidence that this is the case.)
+
+ ReadUInt32(); // $100000 (Same as field following chunk size in directory)
+ ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
+
+ ReadUInt64(); // 0 (unknown)
+ if (ReadUInt32() != NHeader::kCaolSignature)
+ return S_FALSE;
+ if (ReadUInt32() != 2) // (Most likely a version number)
+ return S_FALSE;
+ UInt32 caolLength = ReadUInt32(); // $50 (Length of the CAOL section, which includes the ITSF section)
+ if (caolLength >= 0x2C)
+ {
+ /* UInt32 c7 = */ ReadUInt16(); // Unknown. Remains the same when identical files are built.
+ // Does not appear to be a checksum. Many files have
+ // 'HH' (HTML Help?) here, indicating this may be a compiler ID
+ // field. But at least one ITOL/ITLS compiler does not set this
+ // field to a constant value.
+ ReadUInt16(); // 0 (Unknown. Possibly part of 00A4 field)
+ ReadUInt32(); // Unknown. Two values have been seen -- $43ED, and 0.
+ ReadUInt32(); // $2000 (Directory chunk size of directory)
+ ReadUInt32(); // $200 (Directory chunk size of directory index)
+ ReadUInt32(); // $100000 (Same as field following chunk size in directory)
+ ReadUInt32(); // $20000 (Same as field following chunk size in directory index)
+ ReadUInt32(); // 0 (unknown)
+ ReadUInt32(); // 0 (Unknown)
+ if (caolLength == 0x2C)
+ {
+ database.ContentOffset = 0;
+ database.NewFormat = true;
+ }
+ else if (caolLength == 0x50)
+ {
+ ReadUInt32(); // 0 (Unknown)
+ if (ReadUInt32() != NHeader::kItsfSignature)
+ return S_FALSE;
+ if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3)
+ return S_FALSE;
+ if (ReadUInt32() != 0x20) // $20 (length of ITSF)
+ return S_FALSE;
+ UInt32 unknown = ReadUInt32();
+ if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases;
+ return S_FALSE;
+ database.ContentOffset = _startPosition + ReadUInt64();
+ /* UInt32 timeStamp = */ ReadUInt32();
+ // A timestamp of some sort.
+ // Considered as a big-endian DWORD, it appears to contain
+ // seconds (MSB) and fractional seconds (second byte).
+ // The third and fourth bytes may contain even more fractional
+ // bits. The 4 least significant bits in the last byte are constant.
+ /* UInt32 lang = */ ReadUInt32(); // BE?
+ }
+ else
+ return S_FALSE;
+ }
+
+ /*
+ // Section 0
+ ReadChunk(inStream, _startPosition + sectionOffsets[0], sectionSizes[0]);
+ if (sectionSizes[0] != 0x18)
+ return S_FALSE;
+ ReadUInt32(); // unknown: 01FE
+ ReadUInt32(); // unknown: 0
+ UInt64 fileSize = ReadUInt64();
+ ReadUInt32(); // unknown: 0
+ ReadUInt32(); // unknown: 0
+ */
+
+ // Section 1: The Directory Listing
+ ReadChunk(inStream, _startPosition + sectionOffsets[1], sectionSizes[1]);
+ if (ReadUInt32() != NHeader::kIfcmSignature)
+ return S_FALSE;
+ if (ReadUInt32() != 1) // (probably a version number)
+ return S_FALSE;
+ UInt32 dirChunkSize = ReadUInt32(); // $2000
+ if (dirChunkSize < 64)
+ return S_FALSE;
+ ReadUInt32(); // $100000 (unknown)
+ ReadUInt32(); // -1 (unknown)
+ ReadUInt32(); // -1 (unknown)
+ UInt32 numDirChunks = ReadUInt32();
+ ReadUInt32(); // 0 (unknown, probably high word of above)
+
+ for (UInt32 ci = 0; ci < numDirChunks; ci++)
+ {
+ UInt64 chunkPos = _inBuffer.GetProcessedSize();
+ if (ReadUInt32() == NHeader::kAollSignature)
+ {
+ UInt32 quickrefLength = ReadUInt32(); // Length of quickref area at end of directory chunk
+ if (quickrefLength > dirChunkSize || quickrefLength < 2)
+ return S_FALSE;
+ ReadUInt64(); // Directory chunk number
+ // This must match physical position in file, that is
+ // the chunk size times the chunk number must be the
+ // offset from the end of the directory header.
+ ReadUInt64(); // Chunk number of previous listing chunk when reading
+ // directory in sequence (-1 if first listing chunk)
+ ReadUInt64(); // Chunk number of next listing chunk when reading
+ // directory in sequence (-1 if last listing chunk)
+ ReadUInt64(); // Number of first listing entry in this chunk
+ ReadUInt32(); // 1 (unknown -- other values have also been seen here)
+ ReadUInt32(); // 0 (unknown)
+
+ int numItems = 0;
+ for (;;)
+ {
+ UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos;
+ UInt32 offsetLimit = dirChunkSize - quickrefLength;
+ if (offset > offsetLimit)
+ return S_FALSE;
+ if (offset == offsetLimit)
+ break;
+ if (database.NewFormat)
+ {
+ UInt16 nameLength = ReadUInt16();
+ if (nameLength == 0)
+ return S_FALSE;
+ UString name;
+ ReadUString((int)nameLength, name);
+ AString s;
+ ConvertUnicodeToUTF8(name, s);
+ Byte b = ReadByte();
+ s += ' ';
+ PrintByte(b, s);
+ s += ' ';
+ UInt64 len = ReadEncInt();
+ // then number of items ?
+ // then length ?
+ // then some data (binary encoding?)
+ while (len-- != 0)
+ {
+ b = ReadByte();
+ PrintByte(b, s);
+ }
+ database.NewFormatString += s;
+ database.NewFormatString += "\r\n";
+ }
+ else
+ {
+ RINOK(ReadDirEntry(database));
+ }
+ numItems++;
+ }
+ Skip(quickrefLength - 2);
+ if (ReadUInt16() != numItems)
+ return S_FALSE;
+ if (numItems > numDirEntries)
+ return S_FALSE;
+ numDirEntries -= numItems;
+ }
+ else
+ Skip(dirChunkSize - 4);
+ }
+ return numDirEntries == 0 ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name)
+{
+ int index = database.FindItem(name);
+ if (index < 0)
+ return S_FALSE;
+ const CItem &item = database.Items[index];
+ _chunkSize = item.Size;
+ return ReadChunk(inStream, database.ContentOffset + item.Offset, item.Size);
+}
+
+
+#define DATA_SPACE "::DataSpace/"
+static const char *kNameList = DATA_SPACE "NameList";
+static const char *kStorage = DATA_SPACE "Storage/";
+static const char *kContent = "Content";
+static const char *kControlData = "ControlData";
+static const char *kSpanInfo = "SpanInfo";
+static const char *kTransform = "Transform/";
+static const char *kResetTable = "/InstanceData/ResetTable";
+static const char *kTransformList = "List";
+
+static AString GetSectionPrefix(const AString &name)
+{
+ return AString(kStorage) + name + AString("/");
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareFiles(const int *p1, const int *p2, void *param)
+{
+ const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
+ const CItem &item1 = items[*p1];
+ const CItem &item2 = items[*p2];
+ bool isDir1 = item1.IsDir();
+ bool isDir2 = item2.IsDir();
+ if (isDir1 && !isDir2)
+ return -1;
+ if (isDir2)
+ {
+ if (isDir1)
+ return MyCompare(*p1, *p2);
+ return 1;
+ }
+ RINOZ(MyCompare(item1.Section, item2.Section));
+ RINOZ(MyCompare(item1.Offset, item2.Offset));
+ RINOZ(MyCompare(item1.Size, item2.Size));
+ return MyCompare(*p1, *p2);
+}
+
+void CFilesDatabase::SetIndices()
+{
+ for (int i = 0; i < Items.Size(); i++)
+ {
+ const CItem &item = Items[i];
+ if (item.IsUserItem() && item.Name.Length() != 1)
+ Indices.Add(i);
+ }
+}
+
+void CFilesDatabase::Sort()
+{
+ Indices.Sort(CompareFiles, (void *)&Items);
+}
+
+bool CFilesDatabase::Check()
+{
+ UInt64 maxPos = 0;
+ UInt64 prevSection = 0;
+ for(int i = 0; i < Indices.Size(); i++)
+ {
+ const CItem &item = Items[Indices[i]];
+ if (item.Section == 0 || item.IsDir())
+ continue;
+ if (item.Section != prevSection)
+ {
+ prevSection = item.Section;
+ maxPos = 0;
+ continue;
+ }
+ if (item.Offset < maxPos)
+ return false;
+ maxPos = item.Offset + item.Size;
+ if (maxPos < item.Offset)
+ return false;
+ }
+ return true;
+}
+
+HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
+{
+ {
+ // The NameList file
+ RINOK(DecompressStream(inStream, database, kNameList));
+ /* UInt16 length = */ ReadUInt16();
+ UInt16 numSections = ReadUInt16();
+ for (int i = 0; i < numSections; i++)
+ {
+ CSectionInfo section;
+ UInt16 nameLength = ReadUInt16();
+ UString name;
+ ReadUString(nameLength, name);
+ if (ReadUInt16() != 0)
+ return S_FALSE;
+ if (!ConvertUnicodeToUTF8(name, section.Name))
+ return S_FALSE;
+ database.Sections.Add(section);
+ }
+ }
+
+ int i;
+ for (i = 1; i < database.Sections.Size(); i++)
+ {
+ CSectionInfo &section = database.Sections[i];
+ AString sectionPrefix = GetSectionPrefix(section.Name);
+ {
+ // Content
+ int index = database.FindItem(sectionPrefix + kContent);
+ if (index < 0)
+ return S_FALSE;
+ const CItem &item = database.Items[index];
+ section.Offset = item.Offset;
+ section.CompressedSize = item.Size;
+ }
+ AString transformPrefix = sectionPrefix + kTransform;
+ if (database.Help2Format)
+ {
+ // Transform List
+ RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList));
+ if ((_chunkSize & 0xF) != 0)
+ return S_FALSE;
+ int numGuids = (int)(_chunkSize / 0x10);
+ if (numGuids < 1)
+ return S_FALSE;
+ for (int i = 0; i < numGuids; i++)
+ {
+ CMethodInfo method;
+ ReadGUID(method.Guid);
+ section.Methods.Add(method);
+ }
+ }
+ else
+ {
+ CMethodInfo method;
+ method.Guid = kChmLzxGuid;
+ section.Methods.Add(method);
+ }
+
+ {
+ // Control Data
+ RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData));
+ for (int mi = 0; mi < section.Methods.Size(); mi++)
+ {
+ CMethodInfo &method = section.Methods[mi];
+ UInt32 numDWORDS = ReadUInt32();
+ if (method.IsLzx())
+ {
+ if (numDWORDS < 5)
+ return S_FALSE;
+ if (ReadUInt32() != NHeader::kLzxcSignature)
+ return S_FALSE;
+ CLzxInfo &li = method.LzxInfo;
+ li.Version = ReadUInt32();
+ if (li.Version != 2 && li.Version != 3)
+ return S_FALSE;
+ li.ResetInterval = ReadUInt32();
+ li.WindowSize = ReadUInt32();
+ li.CacheSize = ReadUInt32();
+ if (
+ li.ResetInterval != 1 &&
+ li.ResetInterval != 2 &&
+ li.ResetInterval != 4 &&
+ li.ResetInterval != 8 &&
+ li.ResetInterval != 16 &&
+ li.ResetInterval != 32 &&
+ li.ResetInterval != 64)
+ return S_FALSE;
+ if (
+ li.WindowSize != 1 &&
+ li.WindowSize != 2 &&
+ li.WindowSize != 4 &&
+ li.WindowSize != 8 &&
+ li.WindowSize != 16 &&
+ li.WindowSize != 32 &&
+ li.WindowSize != 64)
+ return S_FALSE;
+ numDWORDS -= 5;
+ while (numDWORDS-- != 0)
+ ReadUInt32();
+ }
+ else
+ {
+ UInt32 numBytes = numDWORDS * 4;
+ method.ControlData.SetCapacity(numBytes);
+ ReadBytes(method.ControlData, numBytes);
+ }
+ }
+ }
+
+ {
+ // SpanInfo
+ RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo));
+ section.UncompressedSize = ReadUInt64();
+ }
+
+ // read ResetTable for LZX
+ for (int mi = 0; mi < section.Methods.Size(); mi++)
+ {
+ CMethodInfo &method = section.Methods[mi];
+ if (method.IsLzx())
+ {
+ // ResetTable;
+ RINOK(DecompressStream(inStream, database, transformPrefix +
+ method.GetGuidString() + kResetTable));
+ CResetTable &rt = method.LzxInfo.ResetTable;
+ if (_chunkSize < 4)
+ {
+ if (_chunkSize != 0)
+ return S_FALSE;
+ // ResetTable is empty in .chw files
+ if (section.UncompressedSize != 0)
+ return S_FALSE;
+ rt.UncompressedSize = 0;
+ rt.CompressedSize = 0;
+ rt.BlockSize = 0;
+ }
+ else
+ {
+ UInt32 ver = ReadUInt32(); // 2 unknown (possibly a version number)
+ if (ver != 2 && ver != 3)
+ return S_FALSE;
+ UInt32 numEntries = ReadUInt32();
+ if (ReadUInt32() != 8) // Size of table entry (bytes)
+ return S_FALSE;
+ if (ReadUInt32() != 0x28) // Length of table header
+ return S_FALSE;
+ rt.UncompressedSize = ReadUInt64();
+ rt.CompressedSize = ReadUInt64();
+ rt.BlockSize = ReadUInt64(); // 0x8000 block size for locations below
+ if (rt.BlockSize != 0x8000)
+ return S_FALSE;
+ rt.ResetOffsets.Reserve(numEntries);
+ for (UInt32 i = 0; i < numEntries; i++)
+ rt.ResetOffsets.Add(ReadUInt64());
+ }
+ }
+ }
+ }
+
+ database.SetIndices();
+ database.Sort();
+ return database.Check() ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::Open2(IInStream *inStream,
+ const UInt64 *searchHeaderSizeLimit,
+ CFilesDatabase &database)
+{
+ database.Clear();
+
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+
+ database.Help2Format = false;
+ const UInt32 chmVersion = 3;
+ {
+ if (!_inBuffer.Create(1 << 14))
+ return E_OUTOFMEMORY;
+ _inBuffer.SetStream(inStream);
+ _inBuffer.Init();
+ UInt64 value = 0;
+ const int kSignatureSize = 8;
+ UInt64 hxsSignature = NHeader::GetHxsSignature();
+ UInt64 chmSignature = ((UInt64)chmVersion << 32)| NHeader::kItsfSignature;
+ UInt64 limit = 1 << 18;
+ if (searchHeaderSizeLimit)
+ if (limit > *searchHeaderSizeLimit)
+ limit = *searchHeaderSizeLimit;
+
+ for (;;)
+ {
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ return S_FALSE;
+ value >>= 8;
+ value |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
+ if (_inBuffer.GetProcessedSize() >= kSignatureSize)
+ {
+ if (value == chmSignature)
+ break;
+ if (value == hxsSignature)
+ {
+ database.Help2Format = true;
+ break;
+ }
+ if (_inBuffer.GetProcessedSize() > limit)
+ return S_FALSE;
+ }
+ }
+ _startPosition += _inBuffer.GetProcessedSize() - kSignatureSize;
+ }
+
+ if (database.Help2Format)
+ {
+ RINOK(OpenHelp2(inStream, database));
+ if (database.NewFormat)
+ return S_OK;
+ }
+ else
+ {
+ RINOK(OpenChm(inStream, database));
+ }
+
+ #ifndef CHM_LOW
+ try
+ {
+ HRESULT res = OpenHighLevel(inStream, database);
+ if (res == S_FALSE)
+ {
+ database.HighLevelClear();
+ return S_OK;
+ }
+ RINOK(res);
+ database.LowLevel = false;
+ }
+ catch(...)
+ {
+ return S_OK;
+ }
+ #endif
+ return S_OK;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream,
+ const UInt64 *searchHeaderSizeLimit,
+ CFilesDatabase &database)
+{
+ try
+ {
+ HRESULT res = Open2(inStream, searchHeaderSizeLimit, database);
+ _inBuffer.ReleaseStream();
+ return res;
+ }
+ catch(...)
+ {
+ _inBuffer.ReleaseStream();
+ throw;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.h
new file mode 100644
index 000000000..4719a484d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.h
@@ -0,0 +1,244 @@
+// Archive/ChmIn.h
+
+#ifndef __ARCHIVE_CHM_IN_H
+#define __ARCHIVE_CHM_IN_H
+
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+
+#include "../../IStream.h"
+#include "../../Common/InBuffer.h"
+
+#include "ChmHeader.h"
+
+namespace NArchive {
+namespace NChm {
+
+struct CItem
+{
+ UInt64 Section;
+ UInt64 Offset;
+ UInt64 Size;
+ AString Name;
+
+ bool IsFormatRelatedItem() const
+ {
+ if (Name.Length() < 2)
+ return false;
+ return Name[0] == ':' && Name[1] == ':';
+ }
+
+ bool IsUserItem() const
+ {
+ if (Name.Length() < 2)
+ return false;
+ return Name[0] == '/';
+ }
+
+ bool IsDir() const
+ {
+ if (Name.Length() == 0)
+ return false;
+ return (Name[Name.Length() - 1] == '/');
+ }
+};
+
+struct CDatabase
+{
+ UInt64 ContentOffset;
+ CObjectVector<CItem> Items;
+ AString NewFormatString;
+ bool Help2Format;
+ bool NewFormat;
+
+ int FindItem(const AString &name) const
+ {
+ for (int i = 0; i < Items.Size(); i++)
+ if (Items[i].Name == name)
+ return i;
+ return -1;
+ }
+
+ void Clear()
+ {
+ NewFormat = false;
+ NewFormatString.Empty();
+ Help2Format = false;
+ Items.Clear();
+ }
+};
+
+struct CResetTable
+{
+ UInt64 UncompressedSize;
+ UInt64 CompressedSize;
+ UInt64 BlockSize;
+ CRecordVector<UInt64> ResetOffsets;
+ bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
+ {
+ if (blockIndex >= ResetOffsets.Size())
+ return false;
+ UInt64 startPos = ResetOffsets[(int)blockIndex];
+ if (blockIndex + numBlocks >= ResetOffsets.Size())
+ size = CompressedSize - startPos;
+ else
+ size = ResetOffsets[(int)(blockIndex + numBlocks)] - startPos;
+ return true;
+ }
+ bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const
+ {
+ return GetCompressedSizeOfBlocks(blockIndex, 1, size);
+ }
+ UInt64 GetNumBlocks(UInt64 size) const
+ {
+ return (size + BlockSize - 1) / BlockSize;
+ }
+};
+
+struct CLzxInfo
+{
+ UInt32 Version;
+ UInt32 ResetInterval;
+ UInt32 WindowSize;
+ UInt32 CacheSize;
+ CResetTable ResetTable;
+
+ UInt32 GetNumDictBits() const
+ {
+ if (Version == 2 || Version == 3)
+ {
+ for (int i = 0; i <= 31; i++)
+ if (((UInt32)1 << i) >= WindowSize)
+ return 15 + i;
+ }
+ return 0;
+ }
+
+ UInt64 GetFolderSize() const { return ResetTable.BlockSize * ResetInterval; };
+ UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); };
+ UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); };
+ UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex * ResetInterval; };
+ bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const
+ {
+ UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
+ if (blockIndex >= ResetTable.ResetOffsets.Size())
+ return false;
+ offset = ResetTable.ResetOffsets[(int)blockIndex];
+ return true;
+ }
+ bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const
+ {
+ UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
+ return ResetTable.GetCompressedSizeOfBlocks(blockIndex, ResetInterval, size);
+ }
+};
+
+struct CMethodInfo
+{
+ GUID Guid;
+ CByteBuffer ControlData;
+ CLzxInfo LzxInfo;
+ bool IsLzx() const;
+ bool IsDes() const;
+ AString GetGuidString() const;
+ UString GetName() const;
+};
+
+struct CSectionInfo
+{
+ UInt64 Offset;
+ UInt64 CompressedSize;
+ UInt64 UncompressedSize;
+
+ AString Name;
+ CObjectVector<CMethodInfo> Methods;
+
+ bool IsLzx() const;
+ UString GetMethodName() const;
+};
+
+class CFilesDatabase: public CDatabase
+{
+public:
+ bool LowLevel;
+ CRecordVector<int> Indices;
+ CObjectVector<CSectionInfo> Sections;
+
+ UInt64 GetFileSize(int fileIndex) const { return Items[Indices[fileIndex]].Size; }
+ UInt64 GetFileOffset(int fileIndex) const { return Items[Indices[fileIndex]].Offset; }
+
+ UInt64 GetFolder(int fileIndex) const
+ {
+ const CItem &item = Items[Indices[fileIndex]];
+ const CSectionInfo &section = Sections[(int)item.Section];
+ if (section.IsLzx())
+ return section.Methods[0].LzxInfo.GetFolder(item.Offset);
+ return 0;
+ }
+
+ UInt64 GetLastFolder(int fileIndex) const
+ {
+ const CItem &item = Items[Indices[fileIndex]];
+ const CSectionInfo &section = Sections[(int)item.Section];
+ if (section.IsLzx())
+ return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1);
+ return 0;
+ }
+
+ void HighLevelClear()
+ {
+ LowLevel = true;
+ Indices.Clear();
+ Sections.Clear();
+ }
+
+ void Clear()
+ {
+ CDatabase::Clear();
+ HighLevelClear();
+ }
+ void SetIndices();
+ void Sort();
+ bool Check();
+};
+
+class CProgressVirt
+{
+public:
+ STDMETHOD(SetTotal)(const UInt64 *numFiles) PURE;
+ STDMETHOD(SetCompleted)(const UInt64 *numFiles) PURE;
+};
+
+class CInArchive
+{
+ UInt64 _startPosition;
+ ::CInBuffer _inBuffer;
+ UInt64 _chunkSize;
+
+ Byte ReadByte();
+ void ReadBytes(Byte *data, UInt32 size);
+ void Skip(size_t size);
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ UInt64 ReadEncInt();
+ void ReadString(int size, AString &s);
+ void ReadUString(int size, UString &s);
+ void ReadGUID(GUID &g);
+
+ HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size);
+
+ HRESULT ReadDirEntry(CDatabase &database);
+ HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name);
+
+public:
+ HRESULT OpenChm(IInStream *inStream, CDatabase &database);
+ HRESULT OpenHelp2(IInStream *inStream, CDatabase &database);
+ HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database);
+ HRESULT Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database);
+ HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmRegister.cpp
new file mode 100644
index 000000000..e5f38afa4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmRegister.cpp
@@ -0,0 +1,13 @@
+// ChmRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "ChmHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NChm::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Chm", L"chm chi chq chw hxs hxi hxr hxq hxw lit", 0, 0xE9, { 'I', 'T', 'S', 'F' }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Chm)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Chm/StdAfx.h
new file mode 100644
index 000000000..e7fb6986d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.cpp
new file mode 100644
index 000000000..58f76439f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.cpp
@@ -0,0 +1,239 @@
+// ComHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "ComHandler.h"
+
+namespace NArchive {
+namespace NCom {
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidSectorSize, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
+ case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break;
+ case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CRef &ref = _db.Refs[index];
+ const CItem &item = _db.Items[ref.Did];
+
+ switch(propID)
+ {
+ case kpidPath: prop = _db.GetItemPath(index); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidCTime: prop = item.CTime; break;
+ case kpidMTime: prop = item.MTime; break;
+ case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
+ case kpidSize: if (!item.IsDir()) prop = item.Size; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ if (_db.Open(inStream) != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _db.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _db.Refs.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for(i = 0; i < numItems; i++)
+ {
+ const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _db.Items[_db.Refs[index].Did];
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ totalPackSize += _db.GetItemPackSize(item.Size);
+ totalSize += item.Size;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ Int32 res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(index, &inStream);
+ if (hres == S_FALSE)
+ res = NExtract::NOperationResult::kDataError;
+ else if (hres == E_NOTIMPL)
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize == item.Size)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.Refs.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ const CItem &item = _db.Items[_db.Refs[index].Did];
+ CClusterInStream *streamSpec = new CClusterInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Stream = _stream;
+ streamSpec->StartOffset = 0;
+
+ bool isLargeStream = _db.IsLargeStream(item.Size);
+ int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
+ streamSpec->BlockSizeLog = bsLog;
+ streamSpec->Size = item.Size;
+
+ UInt32 clusterSize = (UInt32)1 << bsLog;
+ UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
+ if (numClusters64 >= ((UInt32)1 << 31))
+ return E_NOTIMPL;
+ streamSpec->Vector.Reserve((int)numClusters64);
+ UInt32 sid = item.Sid;
+ UInt64 size = item.Size;
+
+ if (size != 0)
+ {
+ for (;; size -= clusterSize)
+ {
+ if (isLargeStream)
+ {
+ if (sid >= _db.FatSize)
+ return S_FALSE;
+ streamSpec->Vector.Add(sid + 1);
+ sid = _db.Fat[sid];
+ }
+ else
+ {
+ UInt64 val;
+ if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
+ return S_FALSE;
+ streamSpec->Vector.Add((UInt32)val);
+ sid = _db.Mat[sid];
+ }
+ if (size <= clusterSize)
+ break;
+ }
+ }
+ if (sid != NFatID::kEndOfChain)
+ return S_FALSE;
+ RINOK(streamSpec->InitAndSeek());
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.h
new file mode 100644
index 000000000..f2b7de96d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.h
@@ -0,0 +1,28 @@
+// ComHandler.h
+
+#ifndef __ARCHIVE_COM_HANDLER_H
+#define __ARCHIVE_COM_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "ComIn.h"
+
+namespace NArchive {
+namespace NCom {
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CDatabase _db;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.cpp
new file mode 100644
index 000000000..2203ca531
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.cpp
@@ -0,0 +1,389 @@
+// Archive/ComIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "ComIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive{
+namespace NCom{
+
+static const UInt32 kSignatureSize = 8;
+static const Byte kSignature[kSignatureSize] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
+
+void CUInt32Buf::Free()
+{
+ MyFree(_buf);
+ _buf = 0;
+}
+
+bool CUInt32Buf::Allocate(UInt32 numItems)
+{
+ Free();
+ if (numItems == 0)
+ return true;
+ size_t newSize = (size_t)numItems * sizeof(UInt32);
+ if (newSize / sizeof(UInt32) != numItems)
+ return false;
+ _buf = (UInt32 *)MyAlloc(newSize);
+ return (_buf != 0);
+}
+
+static HRESULT ReadSector(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid)
+{
+ RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(inStream, buf, (UInt32)1 << sectorSizeBits);
+}
+
+static HRESULT ReadIDs(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid, UInt32 *dest)
+{
+ RINOK(ReadSector(inStream, buf, sectorSizeBits, sid));
+ UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
+ for (UInt32 t = 0; t < sectorSize; t += 4)
+ *dest++ = Get32(buf + t);
+ return S_OK;
+}
+
+static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
+{
+ ft->dwLowDateTime = Get32(p);
+ ft->dwHighDateTime = Get32(p + 4);
+}
+
+void CItem::Parse(const Byte *p, bool mode64bit)
+{
+ memcpy(Name, p, kNameSizeMax);
+ // NameSize = Get16(p + 64);
+ Type = p[66];
+ LeftDid = Get32(p + 68);
+ RightDid = Get32(p + 72);
+ SonDid = Get32(p + 76);
+ // Flags = Get32(p + 96);
+ GetFileTimeFromMem(p + 100, &CTime);
+ GetFileTimeFromMem(p + 108, &MTime);
+ Sid = Get32(p + 116);
+ Size = Get32(p + 120);
+ if (mode64bit)
+ Size |= ((UInt64)Get32(p + 124) << 32);
+}
+
+void CDatabase::Clear()
+{
+ Fat.Free();
+ MiniSids.Free();
+ Mat.Free();
+ Items.Clear();
+ Refs.Clear();
+}
+
+static const UInt32 kNoDid = 0xFFFFFFFF;
+
+HRESULT CDatabase::AddNode(int parent, UInt32 did)
+{
+ if (did == kNoDid)
+ return S_OK;
+ if (did >= (UInt32)Items.Size())
+ return S_FALSE;
+ const CItem &item = Items[did];
+ if (item.IsEmpty())
+ return S_FALSE;
+ CRef ref;
+ ref.Parent = parent;
+ ref.Did = did;
+ int index = Refs.Add(ref);
+ if (Refs.Size() > Items.Size())
+ return S_FALSE;
+ RINOK(AddNode(parent, item.LeftDid));
+ RINOK(AddNode(parent, item.RightDid));
+ if (item.IsDir())
+ {
+ RINOK(AddNode(index, item.SonDid));
+ }
+ return S_OK;
+}
+
+static const char kCharOpenBracket = '[';
+static const char kCharCloseBracket = ']';
+
+static UString CompoundNameToFileName(const UString &s)
+{
+ UString res;
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ if (c < 0x20)
+ {
+ res += kCharOpenBracket;
+ wchar_t buf[32];
+ ConvertUInt32ToString(c, buf);
+ res += buf;
+ res += kCharCloseBracket;
+ }
+ else
+ res += c;
+ }
+ return res;
+}
+
+static char g_MsiChars[] =
+"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._";
+
+static const wchar_t *kMsi_ID = L""; // L"{msi}";
+
+static const int kMsiNumBits = 6;
+static const UInt32 kMsiNumChars = 1 << kMsiNumBits;
+static const UInt32 kMsiCharMask = kMsiNumChars - 1;
+static const UInt32 kMsiStartUnicodeChar = 0x3800;
+static const UInt32 kMsiUnicodeRange = kMsiNumChars * (kMsiNumChars + 1);
+
+bool CompoundMsiNameToFileName(const UString &name, UString &resultName)
+{
+ resultName.Empty();
+ for (int i = 0; i < name.Length(); i++)
+ {
+ wchar_t c = name[i];
+ if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange)
+ return false;
+ if (i == 0)
+ resultName += kMsi_ID;
+ c -= kMsiStartUnicodeChar;
+
+ UInt32 c0 = c & kMsiCharMask;
+ UInt32 c1 = c >> kMsiNumBits;
+
+ if (c1 <= kMsiNumChars)
+ {
+ resultName += (wchar_t)g_MsiChars[c0];
+ if (c1 == kMsiNumChars)
+ break;
+ resultName += (wchar_t)g_MsiChars[c1];
+ }
+ else
+ resultName += L'!';
+ }
+ return true;
+}
+
+static UString ConvertName(const Byte *p, bool &isMsi)
+{
+ isMsi = false;
+ UString s;
+ for (int i = 0; i < kNameSizeMax; i += 2)
+ {
+ wchar_t c = (p[i] | (wchar_t)p[i + 1] << 8);
+ if (c == 0)
+ break;
+ s += c;
+ }
+ UString msiName;
+ if (CompoundMsiNameToFileName(s, msiName))
+ {
+ isMsi = true;
+ return msiName;
+ }
+ return CompoundNameToFileName(s);
+}
+
+static UString ConvertName(const Byte *p)
+{
+ bool isMsi;
+ return ConvertName(p, isMsi);
+}
+
+UString CDatabase::GetItemPath(UInt32 index) const
+{
+ UString s;
+ while (index != kNoDid)
+ {
+ const CRef &ref = Refs[index];
+ const CItem &item = Items[ref.Did];
+ if (!s.IsEmpty())
+ s = (UString)WCHAR_PATH_SEPARATOR + s;
+ s = ConvertName(item.Name) + s;
+ index = ref.Parent;
+ }
+ return s;
+}
+
+HRESULT CDatabase::Open(IInStream *inStream)
+{
+ MainSubfile = -1;
+ static const UInt32 kHeaderSize = 512;
+ Byte p[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, p, kHeaderSize));
+ if (memcmp(p, kSignature, kSignatureSize) != 0)
+ return S_FALSE;
+ if (Get16(p + 0x1A) > 4) // majorVer
+ return S_FALSE;
+ if (Get16(p + 0x1C) != 0xFFFE)
+ return S_FALSE;
+ int sectorSizeBits = Get16(p + 0x1E);
+ bool mode64bit = (sectorSizeBits >= 12);
+ int miniSectorSizeBits = Get16(p + 0x20);
+ SectorSizeBits = sectorSizeBits;
+ MiniSectorSizeBits = miniSectorSizeBits;
+
+ if (sectorSizeBits > 28 || miniSectorSizeBits > 28 ||
+ sectorSizeBits < 7 || miniSectorSizeBits < 2 || miniSectorSizeBits > sectorSizeBits)
+ return S_FALSE;
+ UInt32 numSectorsForFAT = Get32(p + 0x2C);
+ LongStreamMinSize = Get32(p + 0x38);
+
+ UInt32 sectSize = (UInt32)1 << (int)sectorSizeBits;
+
+ CByteBuffer sect;
+ sect.SetCapacity(sectSize);
+
+ int ssb2 = (int)(sectorSizeBits - 2);
+ UInt32 numSidsInSec = (UInt32)1 << ssb2;
+ UInt32 numFatItems = numSectorsForFAT << ssb2;
+ if ((numFatItems >> ssb2) != numSectorsForFAT)
+ return S_FALSE;
+ FatSize = numFatItems;
+
+ {
+ CUInt32Buf bat;
+ UInt32 numSectorsForBat = Get32(p + 0x48);
+ const UInt32 kNumHeaderBatItems = 109;
+ UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2);
+ if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat)
+ return S_FALSE;
+ if (!bat.Allocate(numBatItems))
+ return S_FALSE;
+ UInt32 i;
+ for (i = 0; i < kNumHeaderBatItems; i++)
+ bat[i] = Get32(p + 0x4c + i * 4);
+ UInt32 sid = Get32(p + 0x44);
+ for (UInt32 s = 0; s < numSectorsForBat; s++)
+ {
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i));
+ i += numSidsInSec - 1;
+ sid = bat[i];
+ }
+ numBatItems = i;
+
+ if (!Fat.Allocate(numFatItems))
+ return S_FALSE;
+ UInt32 j = 0;
+
+ for (i = 0; i < numFatItems; j++, i += numSidsInSec)
+ {
+ if (j >= numBatItems)
+ return S_FALSE;
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i));
+ }
+ }
+
+ UInt32 numMatItems;
+ {
+ UInt32 numSectorsForMat = Get32(p + 0x40);
+ numMatItems = (UInt32)numSectorsForMat << ssb2;
+ if ((numMatItems >> ssb2) != numSectorsForMat)
+ return S_FALSE;
+ if (!Mat.Allocate(numMatItems))
+ return S_FALSE;
+ UInt32 i;
+ UInt32 sid = Get32(p + 0x3C);
+ for (i = 0; i < numMatItems; i += numSidsInSec)
+ {
+ RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i));
+ if (sid >= numFatItems)
+ return S_FALSE;
+ sid = Fat[sid];
+ }
+ if (sid != NFatID::kEndOfChain)
+ return S_FALSE;
+ }
+
+ {
+ UInt32 sid = Get32(p + 0x30);
+ for (;;)
+ {
+ if (sid >= numFatItems)
+ return S_FALSE;
+ RINOK(ReadSector(inStream, sect, sectorSizeBits, sid));
+ for (UInt32 i = 0; i < sectSize; i += 128)
+ {
+ CItem item;
+ item.Parse(sect + i, mode64bit);
+ Items.Add(item);
+ }
+ sid = Fat[sid];
+ if (sid == NFatID::kEndOfChain)
+ break;
+ }
+ }
+
+ CItem root = Items[0];
+
+ {
+ UInt32 numSectorsInMiniStream;
+ {
+ UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits;
+ if (numSatSects64 > NFatID::kMaxValue)
+ return S_FALSE;
+ numSectorsInMiniStream = (UInt32)numSatSects64;
+ }
+ NumSectorsInMiniStream = numSectorsInMiniStream;
+ if (!MiniSids.Allocate(numSectorsInMiniStream))
+ return S_FALSE;
+ {
+ UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits;
+ if (matSize64 > NFatID::kMaxValue)
+ return S_FALSE;
+ MatSize = (UInt32)matSize64;
+ if (numMatItems < MatSize)
+ return S_FALSE;
+ }
+
+ UInt32 sid = root.Sid;
+ for (UInt32 i = 0; ; i++)
+ {
+ if (sid == NFatID::kEndOfChain)
+ {
+ if (i != numSectorsInMiniStream)
+ return S_FALSE;
+ break;
+ }
+ if (i >= numSectorsInMiniStream)
+ return S_FALSE;
+ MiniSids[i] = sid;
+ if (sid >= numFatItems)
+ return S_FALSE;
+ sid = Fat[sid];
+ }
+ }
+
+ RINOK(AddNode(-1, root.SonDid));
+
+ unsigned numCabs = 0;
+ for (int i = 0; i < Refs.Size(); i++)
+ {
+ const CItem &item = Items[Refs[i].Did];
+ if (item.IsDir() || numCabs > 1)
+ continue;
+ bool isMsiName;
+ UString msiName = ConvertName(item.Name, isMsiName);
+ if (isMsiName && msiName.Right(4).CompareNoCase(L".cab") == 0)
+ {
+ numCabs++;
+ MainSubfile = i;
+ }
+ }
+ if (numCabs > 1)
+ MainSubfile = -1;
+
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.h
new file mode 100644
index 000000000..429d3796e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.h
@@ -0,0 +1,119 @@
+// Archive/ComIn.h
+
+#ifndef __ARCHIVE_COM_IN_H
+#define __ARCHIVE_COM_IN_H
+
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+
+namespace NArchive {
+namespace NCom {
+
+struct CUInt32Buf
+{
+ UInt32 *_buf;
+public:
+ CUInt32Buf(): _buf(0) {}
+ ~CUInt32Buf() { Free(); }
+ void Free();
+ bool Allocate(UInt32 numItems);
+ operator UInt32 *() const { return _buf; };
+};
+
+namespace NFatID
+{
+ const UInt32 kFree = 0xFFFFFFFF;
+ const UInt32 kEndOfChain = 0xFFFFFFFE;
+ const UInt32 kFatSector = 0xFFFFFFFD;
+ const UInt32 kMatSector = 0xFFFFFFFC;
+ const UInt32 kMaxValue = 0xFFFFFFFA;
+}
+
+namespace NItemType
+{
+ const Byte kEmpty = 0;
+ const Byte kStorage = 1;
+ const Byte kStream = 2;
+ const Byte kLockBytes = 3;
+ const Byte kProperty = 4;
+ const Byte kRootStorage = 5;
+}
+
+const UInt32 kNameSizeMax = 64;
+
+struct CItem
+{
+ Byte Name[kNameSizeMax];
+ // UInt16 NameSize;
+ // UInt32 Flags;
+ FILETIME CTime;
+ FILETIME MTime;
+ UInt64 Size;
+ UInt32 LeftDid;
+ UInt32 RightDid;
+ UInt32 SonDid;
+ UInt32 Sid;
+ Byte Type;
+
+ bool IsEmpty() const { return Type == NItemType::kEmpty; }
+ bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; }
+
+ void Parse(const Byte *p, bool mode64bit);
+};
+
+struct CRef
+{
+ int Parent;
+ UInt32 Did;
+};
+
+class CDatabase
+{
+ UInt32 NumSectorsInMiniStream;
+ CUInt32Buf MiniSids;
+
+ HRESULT AddNode(int parent, UInt32 did);
+public:
+
+ CUInt32Buf Fat;
+ UInt32 FatSize;
+
+ CUInt32Buf Mat;
+ UInt32 MatSize;
+
+ CObjectVector<CItem> Items;
+ CRecordVector<CRef> Refs;
+
+ UInt32 LongStreamMinSize;
+ int SectorSizeBits;
+ int MiniSectorSizeBits;
+
+ Int32 MainSubfile;
+
+ void Clear();
+ bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; }
+ UString GetItemPath(UInt32 index) const;
+
+ UInt64 GetItemPackSize(UInt64 size) const
+ {
+ UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
+ return (size + mask) & ~mask;
+ }
+
+ bool GetMiniCluster(UInt32 sid, UInt64 &res) const
+ {
+ int subBits = SectorSizeBits - MiniSectorSizeBits;
+ UInt32 fid = sid >> subBits;
+ if (fid >= NumSectorsInMiniStream)
+ return false;
+ res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
+ return true;
+ }
+
+ HRESULT Open(IInStream *inStream);
+};
+
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComRegister.cpp
new file mode 100644
index 000000000..6712b890f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComRegister.cpp
@@ -0,0 +1,13 @@
+// ComRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "ComHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NCom::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Compound", L"msi msp doc xls ppt", 0, 0xE5, { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, 8, false, CreateArc, 0 };
+
+REGISTER_ARC(Com)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.cpp
new file mode 100644
index 000000000..a19f04579
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.cpp
@@ -0,0 +1,19 @@
+// CoderMixer.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer.h"
+
+namespace NCoderMixer {
+
+void CCoderInfo::SetCoderInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ InSizeAssigned = (inSize != 0);
+ if (InSizeAssigned)
+ InSizeValue = *inSize;
+ OutSizeAssigned = (outSize != 0);
+ if (OutSizeAssigned)
+ OutSizeValue = *outSize;
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.h
new file mode 100644
index 000000000..6379dd808
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.h
@@ -0,0 +1,32 @@
+// CoderMixer.h
+
+#ifndef __CODER_MIXER_H
+#define __CODER_MIXER_H
+
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+
+namespace NCoderMixer {
+
+struct CCoderInfo
+{
+ CMyComPtr<ICompressCoder> Coder;
+ CMyComPtr<ISequentialInStream> InStream;
+ CMyComPtr<ISequentialOutStream> OutStream;
+ CMyComPtr<ICompressProgressInfo> Progress;
+
+ UInt64 InSizeValue;
+ UInt64 OutSizeValue;
+ bool InSizeAssigned;
+ bool OutSizeAssigned;
+
+ void ReInit()
+ {
+ InSizeAssigned = OutSizeAssigned = false;
+ }
+
+ void SetCoderInfo(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+}
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.cpp
new file mode 100644
index 000000000..0b06a489f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.cpp
@@ -0,0 +1,121 @@
+// CoderMixer2.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2.h"
+
+namespace NCoderMixer {
+
+CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo):
+ _srcBindInfo(srcBindInfo)
+{
+ srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams);
+
+ UInt32 j;
+ for (j = 0; j < NumSrcInStreams; j++)
+ {
+ _srcInToDestOutMap.Add(0);
+ DestOutToSrcInMap.Add(0);
+ }
+ for (j = 0; j < _numSrcOutStreams; j++)
+ {
+ _srcOutToDestInMap.Add(0);
+ _destInToSrcOutMap.Add(0);
+ }
+
+ UInt32 destInOffset = 0;
+ UInt32 destOutOffset = 0;
+ UInt32 srcInOffset = NumSrcInStreams;
+ UInt32 srcOutOffset = _numSrcOutStreams;
+
+ for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+ {
+ const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i];
+
+ srcInOffset -= srcCoderInfo.NumInStreams;
+ srcOutOffset -= srcCoderInfo.NumOutStreams;
+
+ UInt32 j;
+ for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++)
+ {
+ UInt32 index = srcInOffset + j;
+ _srcInToDestOutMap[index] = destOutOffset;
+ DestOutToSrcInMap[destOutOffset] = index;
+ }
+ for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++)
+ {
+ UInt32 index = srcOutOffset + j;
+ _srcOutToDestInMap[index] = destInOffset;
+ _destInToSrcOutMap[destInOffset] = index;
+ }
+ }
+}
+
+void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo)
+{
+ destBindInfo.Coders.Clear();
+ destBindInfo.BindPairs.Clear();
+ destBindInfo.InStreams.Clear();
+ destBindInfo.OutStreams.Clear();
+
+ int i;
+ for (i = _srcBindInfo.Coders.Size() - 1; i >= 0; i--)
+ {
+ const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i];
+ CCoderStreamsInfo destCoderInfo;
+ destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams;
+ destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams;
+ destBindInfo.Coders.Add(destCoderInfo);
+ }
+ for (i = _srcBindInfo.BindPairs.Size() - 1; i >= 0; i--)
+ {
+ const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i];
+ CBindPair destBindPair;
+ destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex];
+ destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex];
+ destBindInfo.BindPairs.Add(destBindPair);
+ }
+ for (i = 0; i < _srcBindInfo.InStreams.Size(); i++)
+ destBindInfo.OutStreams.Add(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]);
+ for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++)
+ destBindInfo.InStreams.Add(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]);
+}
+
+CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams):
+ NumInStreams(numInStreams),
+ NumOutStreams(numOutStreams)
+{
+ InSizes.Reserve(NumInStreams);
+ InSizePointers.Reserve(NumInStreams);
+ OutSizes.Reserve(NumOutStreams);
+ OutSizePointers.Reserve(NumOutStreams);
+}
+
+static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
+ CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
+{
+ sizes.Clear();
+ sizePointers.Clear();
+ for(UInt32 i = 0; i < numItems; i++)
+ {
+ if (srcSizes == 0 || srcSizes[i] == NULL)
+ {
+ sizes.Add(0);
+ sizePointers.Add(NULL);
+ }
+ else
+ {
+ sizes.Add(*srcSizes[i]);
+ sizePointers.Add(&sizes.Back());
+ }
+ }
+}
+
+void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes,
+ const UInt64 **outSizes)
+{
+ SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+ SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.h
new file mode 100644
index 000000000..a03722d61
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.h
@@ -0,0 +1,174 @@
+// CoderMixer2.h
+
+#ifndef __CODER_MIXER2_H
+#define __CODER_MIXER2_H
+
+#include "../../../Common/MyVector.h"
+#include "../../../Common/Types.h"
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+
+namespace NCoderMixer {
+
+struct CBindPair
+{
+ UInt32 InIndex;
+ UInt32 OutIndex;
+};
+
+struct CCoderStreamsInfo
+{
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+};
+
+struct CBindInfo
+{
+ CRecordVector<CCoderStreamsInfo> Coders;
+ CRecordVector<CBindPair> BindPairs;
+ CRecordVector<UInt32> InStreams;
+ CRecordVector<UInt32> OutStreams;
+
+ void Clear()
+ {
+ Coders.Clear();
+ BindPairs.Clear();
+ InStreams.Clear();
+ OutStreams.Clear();
+ }
+
+ /*
+ UInt32 GetCoderStartOutStream(UInt32 coderIndex) const
+ {
+ UInt32 numOutStreams = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ numOutStreams += Coders[i].NumOutStreams;
+ return numOutStreams;
+ }
+ */
+
+
+ void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const
+ {
+ numInStreams = 0;
+ numOutStreams = 0;
+ for (int i = 0; i < Coders.Size(); i++)
+ {
+ const CCoderStreamsInfo &coderStreamsInfo = Coders[i];
+ numInStreams += coderStreamsInfo.NumInStreams;
+ numOutStreams += coderStreamsInfo.NumOutStreams;
+ }
+ }
+
+ int FindBinderForInStream(UInt32 inStream) const
+ {
+ for (int i = 0; i < BindPairs.Size(); i++)
+ if (BindPairs[i].InIndex == inStream)
+ return i;
+ return -1;
+ }
+ int FindBinderForOutStream(UInt32 outStream) const
+ {
+ for (int i = 0; i < BindPairs.Size(); i++)
+ if (BindPairs[i].OutIndex == outStream)
+ return i;
+ return -1;
+ }
+
+ UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const
+ {
+ UInt32 streamIndex = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ streamIndex += Coders[i].NumInStreams;
+ return streamIndex;
+ }
+
+ UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const
+ {
+ UInt32 streamIndex = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ streamIndex += Coders[i].NumOutStreams;
+ return streamIndex;
+ }
+
+
+ void FindInStream(UInt32 streamIndex, UInt32 &coderIndex,
+ UInt32 &coderStreamIndex) const
+ {
+ for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++)
+ {
+ UInt32 curSize = Coders[coderIndex].NumInStreams;
+ if (streamIndex < curSize)
+ {
+ coderStreamIndex = streamIndex;
+ return;
+ }
+ streamIndex -= curSize;
+ }
+ throw 1;
+ }
+ void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex,
+ UInt32 &coderStreamIndex) const
+ {
+ for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++)
+ {
+ UInt32 curSize = Coders[coderIndex].NumOutStreams;
+ if (streamIndex < curSize)
+ {
+ coderStreamIndex = streamIndex;
+ return;
+ }
+ streamIndex -= curSize;
+ }
+ throw 1;
+ }
+};
+
+class CBindReverseConverter
+{
+ UInt32 _numSrcOutStreams;
+ NCoderMixer::CBindInfo _srcBindInfo;
+ CRecordVector<UInt32> _srcInToDestOutMap;
+ CRecordVector<UInt32> _srcOutToDestInMap;
+ CRecordVector<UInt32> _destInToSrcOutMap;
+public:
+ UInt32 NumSrcInStreams;
+ CRecordVector<UInt32> DestOutToSrcInMap;
+
+ CBindReverseConverter(const NCoderMixer::CBindInfo &srcBindInfo);
+ void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo);
+};
+
+struct CCoderInfo2
+{
+ CMyComPtr<ICompressCoder> Coder;
+ CMyComPtr<ICompressCoder2> Coder2;
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+
+ CRecordVector<UInt64> InSizes;
+ CRecordVector<UInt64> OutSizes;
+ CRecordVector<const UInt64 *> InSizePointers;
+ CRecordVector<const UInt64 *> OutSizePointers;
+
+ CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams);
+ void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+
+ HRESULT QueryInterface(REFGUID iid, void** pp) const
+ {
+ IUnknown *p = Coder ? (IUnknown *)Coder : (IUnknown *)Coder2;
+ return p->QueryInterface(iid, pp);
+ }
+};
+
+class CCoderMixer2
+{
+public:
+ virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) = 0;
+ virtual void ReInit() = 0;
+ virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0;
+};
+
+}
+#endif
+
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
new file mode 100644
index 000000000..d76450bd1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
@@ -0,0 +1,240 @@
+// CoderMixer2MT.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2MT.h"
+
+namespace NCoderMixer {
+
+CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams):
+ CCoderInfo2(numInStreams, numOutStreams)
+{
+ InStreams.Reserve(NumInStreams);
+ InStreamPointers.Reserve(NumInStreams);
+ OutStreams.Reserve(NumOutStreams);
+ OutStreamPointers.Reserve(NumOutStreams);
+}
+
+void CCoder2::Execute() { Code(NULL); }
+
+void CCoder2::Code(ICompressProgressInfo *progress)
+{
+ InStreamPointers.Clear();
+ OutStreamPointers.Clear();
+ UInt32 i;
+ for (i = 0; i < NumInStreams; i++)
+ {
+ if (InSizePointers[i] != NULL)
+ InSizePointers[i] = &InSizes[i];
+ InStreamPointers.Add((ISequentialInStream *)InStreams[i]);
+ }
+ for (i = 0; i < NumOutStreams; i++)
+ {
+ if (OutSizePointers[i] != NULL)
+ OutSizePointers[i] = &OutSizes[i];
+ OutStreamPointers.Add((ISequentialOutStream *)OutStreams[i]);
+ }
+ if (Coder)
+ Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0],
+ InSizePointers[0], OutSizePointers[0], progress);
+ else
+ Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams,
+ &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress);
+ {
+ int i;
+ for (i = 0; i < InStreams.Size(); i++)
+ InStreams[i].Release();
+ for (i = 0; i < OutStreams.Size(); i++)
+ OutStreams[i].Release();
+ }
+}
+
+static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes,
+ CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems)
+{
+ sizes.Clear();
+ sizePointers.Clear();
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ if (srcSizes == 0 || srcSizes[i] == NULL)
+ {
+ sizes.Add(0);
+ sizePointers.Add(NULL);
+ }
+ else
+ {
+ sizes.Add(*srcSizes[i]);
+ sizePointers.Add(&sizes.Back());
+ }
+ }
+}
+
+
+void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes)
+{
+ SetSizes(inSizes, InSizes, InSizePointers, NumInStreams);
+ SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams);
+}
+
+//////////////////////////////////////
+// CCoderMixer2MT
+
+HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo)
+{
+ _bindInfo = bindInfo;
+ _streamBinders.Clear();
+ for (int i = 0; i < _bindInfo.BindPairs.Size(); i++)
+ {
+ _streamBinders.Add(CStreamBinder());
+ RINOK(_streamBinders.Back().CreateEvents());
+ }
+ return S_OK;
+}
+
+void CCoderMixer2MT::AddCoderCommon()
+{
+ const CCoderStreamsInfo &c = _bindInfo.Coders[_coders.Size()];
+ CCoder2 threadCoderInfo(c.NumInStreams, c.NumOutStreams);
+ _coders.Add(threadCoderInfo);
+}
+
+void CCoderMixer2MT::AddCoder(ICompressCoder *coder)
+{
+ AddCoderCommon();
+ _coders.Back().Coder = coder;
+}
+
+void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder)
+{
+ AddCoderCommon();
+ _coders.Back().Coder2 = coder;
+}
+
+
+void CCoderMixer2MT::ReInit()
+{
+ for (int i = 0; i < _streamBinders.Size(); i++)
+ _streamBinders[i].ReInit();
+}
+
+
+HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams)
+{
+ /*
+ if (_coders.Size() != _bindInfo.Coders.Size())
+ throw 0;
+ */
+ int i;
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ CCoder2 &coderInfo = _coders[i];
+ const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i];
+ coderInfo.InStreams.Clear();
+ UInt32 j;
+ for (j = 0; j < coderStreamsInfo.NumInStreams; j++)
+ coderInfo.InStreams.Add(NULL);
+ coderInfo.OutStreams.Clear();
+ for (j = 0; j < coderStreamsInfo.NumOutStreams; j++)
+ coderInfo.OutStreams.Add(NULL);
+ }
+
+ for (i = 0; i < _bindInfo.BindPairs.Size(); i++)
+ {
+ const CBindPair &bindPair = _bindInfo.BindPairs[i];
+ UInt32 inCoderIndex, inCoderStreamIndex;
+ UInt32 outCoderIndex, outCoderStreamIndex;
+ _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex);
+ _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex);
+
+ _streamBinders[i].CreateStreams(
+ &_coders[inCoderIndex].InStreams[inCoderStreamIndex],
+ &_coders[outCoderIndex].OutStreams[outCoderStreamIndex]);
+
+ CMyComPtr<ICompressSetBufSize> inSetSize, outSetSize;
+ _coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize);
+ _coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize);
+ if (inSetSize && outSetSize)
+ {
+ const UInt32 kBufSize = 1 << 19;
+ inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize);
+ outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize);
+ }
+ }
+
+ for (i = 0; i < _bindInfo.InStreams.Size(); i++)
+ {
+ UInt32 inCoderIndex, inCoderStreamIndex;
+ _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex);
+ _coders[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i];
+ }
+
+ for (i = 0; i < _bindInfo.OutStreams.Size(); i++)
+ {
+ UInt32 outCoderIndex, outCoderStreamIndex;
+ _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex);
+ _coders[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i];
+ }
+ return S_OK;
+}
+
+HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code)
+{
+ for (int i = 0; i < _coders.Size(); i++)
+ if (_coders[i].Result == code)
+ return code;
+ return S_OK;
+}
+
+STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams,
+ const UInt64 ** /* inSizes */,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 ** /* outSizes */,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != (UInt32)_bindInfo.InStreams.Size() ||
+ numOutStreams != (UInt32)_bindInfo.OutStreams.Size())
+ return E_INVALIDARG;
+
+ Init(inStreams, outStreams);
+
+ int i;
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ {
+ RINOK(_coders[i].Create());
+ }
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ _coders[i].Start();
+
+ _coders[_progressCoderIndex].Code(progress);
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ _coders[i].WaitFinish();
+
+ RINOK(ReturnIfError(E_ABORT));
+ RINOK(ReturnIfError(E_OUTOFMEMORY));
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ HRESULT result = _coders[i].Result;
+ if (result != S_OK && result != E_FAIL && result != S_FALSE)
+ return result;
+ }
+
+ RINOK(ReturnIfError(S_FALSE));
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ HRESULT result = _coders[i].Result;
+ if (result != S_OK)
+ return result;
+ }
+ return S_OK;
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.h
new file mode 100644
index 000000000..d1c7f4d07
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.h
@@ -0,0 +1,80 @@
+// CoderMixer2MT.h
+
+#ifndef __CODER_MIXER2_MT_H
+#define __CODER_MIXER2_MT_H
+
+#include "CoderMixer2.h"
+#include "../../../Common/MyCom.h"
+#include "../../Common/StreamBinder.h"
+#include "../../Common/VirtThread.h"
+
+namespace NCoderMixer {
+
+struct CCoder2: public CCoderInfo2, public CVirtThread
+{
+ HRESULT Result;
+ CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
+ CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
+ CRecordVector<ISequentialInStream*> InStreamPointers;
+ CRecordVector<ISequentialOutStream*> OutStreamPointers;
+
+ CCoder2(UInt32 numInStreams, UInt32 numOutStreams);
+ void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes);
+ virtual void Execute();
+ void Code(ICompressProgressInfo *progress);
+};
+
+
+/*
+ SetBindInfo()
+ for each coder
+ AddCoder[2]()
+ SetProgressIndex(UInt32 coderIndex);
+
+ for each file
+ {
+ ReInit()
+ for each coder
+ SetCoderInfo
+ Code
+ }
+*/
+
+class CCoderMixer2MT:
+ public ICompressCoder2,
+ public CCoderMixer2,
+ public CMyUnknownImp
+{
+ CBindInfo _bindInfo;
+ CObjectVector<CStreamBinder> _streamBinders;
+ int _progressCoderIndex;
+
+ void AddCoderCommon();
+ HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams);
+ HRESULT ReturnIfError(HRESULT code);
+public:
+ CObjectVector<CCoder2> _coders;
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Code)(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ HRESULT SetBindInfo(const CBindInfo &bindInfo);
+ void AddCoder(ICompressCoder *coder);
+ void AddCoder2(ICompressCoder2 *coder);
+ void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; }
+
+ void ReInit();
+ void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes)
+ { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); }
+ UInt64 GetWriteProcessedSize(UInt32 binderIndex) const
+ { return _streamBinders[binderIndex].ProcessedSize; }
+};
+
+}
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.cpp
new file mode 100644
index 000000000..a59ce5fc0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.cpp
@@ -0,0 +1,239 @@
+// CoderMixer2ST.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2ST.h"
+
+namespace NCoderMixer2 {
+
+CCoderMixer2ST::CCoderMixer2ST() {}
+
+CCoderMixer2ST::~CCoderMixer2ST(){ }
+
+HRESULT CCoderMixer2ST::SetBindInfo(const CBindInfo &bindInfo)
+{
+ _bindInfo = bindInfo;
+ return S_OK;
+}
+
+void CCoderMixer2ST::AddCoderCommon(bool isMain)
+{
+ const CCoderStreamsInfo &csi = _bindInfo.Coders[_coders.Size()];
+ _coders.Add(CSTCoderInfo(csi.NumInStreams, csi.NumOutStreams, isMain));
+}
+
+void CCoderMixer2ST::AddCoder(ICompressCoder *coder, bool isMain)
+{
+ AddCoderCommon(isMain);
+ _coders.Back().Coder = coder;
+}
+
+void CCoderMixer2ST::AddCoder2(ICompressCoder2 *coder, bool isMain)
+{
+ AddCoderCommon(isMain);
+ _coders.Back().Coder2 = coder;
+}
+
+void CCoderMixer2ST::ReInit() { }
+
+HRESULT CCoderMixer2ST::GetInStream(
+ ISequentialInStream **inStreams, const UInt64 **inSizes,
+ UInt32 streamIndex, ISequentialInStream **inStreamRes)
+{
+ CMyComPtr<ISequentialInStream> seqInStream;
+ int i;
+ for(i = 0; i < _bindInfo.InStreams.Size(); i++)
+ if (_bindInfo.InStreams[i] == streamIndex)
+ {
+ seqInStream = inStreams[i];
+ *inStreamRes = seqInStream.Detach();
+ return S_OK;
+ }
+ int binderIndex = _bindInfo.FindBinderForInStream(streamIndex);
+ if (binderIndex < 0)
+ return E_INVALIDARG;
+
+ UInt32 coderIndex, coderStreamIndex;
+ _bindInfo.FindOutStream(_bindInfo.BindPairs[binderIndex].OutIndex,
+ coderIndex, coderStreamIndex);
+
+ CCoderInfo &coder = _coders[coderIndex];
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ coder.Coder.QueryInterface(IID_ISequentialInStream, &seqInStream);
+ if (!seqInStream)
+ return E_NOTIMPL;
+
+ UInt32 startIndex = _bindInfo.GetCoderInStreamIndex(coderIndex);
+
+ CMyComPtr<ICompressSetInStream> setInStream;
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ coder.Coder.QueryInterface(IID_ICompressSetInStream, &setInStream);
+ if (!setInStream)
+ return E_NOTIMPL;
+
+ if (coder.NumInStreams > 1)
+ return E_NOTIMPL;
+ for (i = 0; i < (int)coder.NumInStreams; i++)
+ {
+ CMyComPtr<ISequentialInStream> seqInStream2;
+ RINOK(GetInStream(inStreams, inSizes, startIndex + i, &seqInStream2));
+ RINOK(setInStream->SetInStream(seqInStream2));
+ }
+ *inStreamRes = seqInStream.Detach();
+ return S_OK;
+}
+
+HRESULT CCoderMixer2ST::GetOutStream(
+ ISequentialOutStream **outStreams, const UInt64 **outSizes,
+ UInt32 streamIndex, ISequentialOutStream **outStreamRes)
+{
+ CMyComPtr<ISequentialOutStream> seqOutStream;
+ int i;
+ for(i = 0; i < _bindInfo.OutStreams.Size(); i++)
+ if (_bindInfo.OutStreams[i] == streamIndex)
+ {
+ seqOutStream = outStreams[i];
+ *outStreamRes = seqOutStream.Detach();
+ return S_OK;
+ }
+ int binderIndex = _bindInfo.FindBinderForOutStream(streamIndex);
+ if (binderIndex < 0)
+ return E_INVALIDARG;
+
+ UInt32 coderIndex, coderStreamIndex;
+ _bindInfo.FindInStream(_bindInfo.BindPairs[binderIndex].InIndex,
+ coderIndex, coderStreamIndex);
+
+ CCoderInfo &coder = _coders[coderIndex];
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ coder.Coder.QueryInterface(IID_ISequentialOutStream, &seqOutStream);
+ if (!seqOutStream)
+ return E_NOTIMPL;
+
+ UInt32 startIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex);
+
+ CMyComPtr<ICompressSetOutStream> setOutStream;
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
+ if (!setOutStream)
+ return E_NOTIMPL;
+
+ if (coder.NumOutStreams > 1)
+ return E_NOTIMPL;
+ for (i = 0; i < (int)coder.NumOutStreams; i++)
+ {
+ CMyComPtr<ISequentialOutStream> seqOutStream2;
+ RINOK(GetOutStream(outStreams, outSizes, startIndex + i, &seqOutStream2));
+ RINOK(setOutStream->SetOutStream(seqOutStream2));
+ }
+ *outStreamRes = seqOutStream.Detach();
+ return S_OK;
+}
+
+
+STDMETHODIMP CCoderMixer2ST::Code(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != (UInt32)_bindInfo.InStreams.Size() ||
+ numOutStreams != (UInt32)_bindInfo.OutStreams.Size())
+ return E_INVALIDARG;
+
+ // Find main coder
+ int _mainCoderIndex = -1;
+ int i;
+ for (i = 0; i < _coders.Size(); i++)
+ if (_coders[i].IsMain)
+ {
+ _mainCoderIndex = i;
+ break;
+ }
+ if (_mainCoderIndex < 0)
+ for (i = 0; i < _coders.Size(); i++)
+ if (_coders[i].NumInStreams > 1)
+ {
+ if (_mainCoderIndex >= 0)
+ return E_NOTIMPL;
+ _mainCoderIndex = i;
+ }
+ if (_mainCoderIndex < 0)
+ _mainCoderIndex = 0;
+
+ // _mainCoderIndex = 0;
+ // _mainCoderIndex = _coders.Size() - 1;
+ CCoderInfo &mainCoder = _coders[_mainCoderIndex];
+
+ CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams;
+ CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams;
+ UInt32 startInIndex = _bindInfo.GetCoderInStreamIndex(_mainCoderIndex);
+ UInt32 startOutIndex = _bindInfo.GetCoderOutStreamIndex(_mainCoderIndex);
+ for (i = 0; i < (int)mainCoder.NumInStreams; i++)
+ {
+ CMyComPtr<ISequentialInStream> seqInStream;
+ RINOK(GetInStream(inStreams, inSizes, startInIndex + i, &seqInStream));
+ seqInStreams.Add(seqInStream);
+ }
+ for (i = 0; i < (int)mainCoder.NumOutStreams; i++)
+ {
+ CMyComPtr<ISequentialOutStream> seqOutStream;
+ RINOK(GetOutStream(outStreams, outSizes, startOutIndex + i, &seqOutStream));
+ seqOutStreams.Add(seqOutStream);
+ }
+ CRecordVector< ISequentialInStream * > seqInStreamsSpec;
+ CRecordVector< ISequentialOutStream * > seqOutStreamsSpec;
+ for (i = 0; i < (int)mainCoder.NumInStreams; i++)
+ seqInStreamsSpec.Add(seqInStreams[i]);
+ for (i = 0; i < (int)mainCoder.NumOutStreams; i++)
+ seqOutStreamsSpec.Add(seqOutStreams[i]);
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ if (i == _mainCoderIndex)
+ continue;
+ CCoderInfo &coder = _coders[i];
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ coder.Coder.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
+ if (setOutStreamSize)
+ {
+ RINOK(setOutStreamSize->SetOutStreamSize(coder.OutSizePointers[0]));
+ }
+ }
+ if (mainCoder.Coder)
+ {
+ RINOK(mainCoder.Coder->Code(
+ seqInStreamsSpec[0], seqOutStreamsSpec[0],
+ mainCoder.InSizePointers[0], mainCoder.OutSizePointers[0],
+ progress));
+ }
+ else
+ {
+ RINOK(mainCoder.Coder2->Code(
+ &seqInStreamsSpec.Front(),
+ &mainCoder.InSizePointers.Front(), mainCoder.NumInStreams,
+ &seqOutStreamsSpec.Front(),
+ &mainCoder.OutSizePointers.Front(), mainCoder.NumOutStreams,
+ progress));
+ }
+ CMyComPtr<IOutStreamFlush> flush;
+ seqOutStreams.Front().QueryInterface(IID_IOutStreamFlush, &flush);
+ if (flush)
+ return flush->Flush();
+ return S_OK;
+}
+
+/*
+UInt64 CCoderMixer2ST::GetWriteProcessedSize(UInt32 binderIndex) const
+{
+ return _streamBinders[binderIndex].ProcessedSize;
+}
+*/
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.h
new file mode 100644
index 000000000..a4ea7e80d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.h
@@ -0,0 +1,88 @@
+// CoderMixer2ST.h
+
+#ifndef __CODER_MIXER2_ST_H
+#define __CODER_MIXER2_ST_H
+
+#include "CoderMixer2.h"
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+
+namespace NCoderMixer2 {
+
+// SetBindInfo()
+// for each coder
+// {
+// AddCoder[2]()
+// }
+//
+// for each file
+// {
+// ReInit()
+// for each coder
+// {
+// SetCoderInfo
+// }
+// SetProgressIndex(UInt32 coderIndex);
+// Code
+// }
+
+struct CSTCoderInfo: public CCoderInfo
+{
+ bool IsMain;
+ CSTCoderInfo(UInt32 numInStreams, UInt32 numOutStreams, bool isMain):
+ CCoderInfo(numInStreams, numOutStreams),IsMain(isMain) {}
+};
+
+class CCoderMixer2ST:
+ public ICompressCoder2,
+ public CCoderMixer2,
+ public CMyUnknownImp
+{
+ MY_UNKNOWN_IMP
+
+ HRESULT GetInStream(
+ ISequentialInStream **inStreams, const UInt64 **inSizes,
+ UInt32 streamIndex, ISequentialInStream **inStreamRes);
+ HRESULT GetOutStream(
+ ISequentialOutStream **outStreams, const UInt64 **outSizes,
+ UInt32 streamIndex, ISequentialOutStream **outStreamRes);
+public:
+ STDMETHOD(Code)(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ CCoderMixer2ST();
+ ~CCoderMixer2ST();
+ void AddCoderCommon(bool isMain);
+ void AddCoder(ICompressCoder *coder, bool isMain);
+ void AddCoder2(ICompressCoder2 *coder, bool isMain);
+
+ void ReInit();
+ void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes)
+ {
+ { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); }
+ }
+
+ void SetProgressCoderIndex(UInt32 /*coderIndex*/)
+ {
+ // _progressCoderIndex = coderIndex;
+ }
+
+ // UInt64 GetWriteProcessedSize(UInt32 binderIndex) const;
+
+private:
+ CBindInfo _bindInfo;
+ CObjectVector<CSTCoderInfo> _coders;
+ int _mainCoderIndex;
+public:
+ HRESULT SetBindInfo(const CBindInfo &bindInfo);
+
+};
+
+}
+#endif
+
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.cpp
new file mode 100644
index 000000000..f43d1612d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.cpp
@@ -0,0 +1,99 @@
+// CoderMixerMT.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixerMT.h"
+
+namespace NCoderMixer {
+
+void CCoder::Execute() { Code(NULL); }
+
+void CCoder::Code(ICompressProgressInfo *progress)
+{
+ Result = Coder->Code(InStream, OutStream,
+ InSizeAssigned ? &InSizeValue : NULL,
+ OutSizeAssigned ? &OutSizeValue : NULL,
+ progress);
+ InStream.Release();
+ OutStream.Release();
+}
+
+void CCoderMixerMT::AddCoder(ICompressCoder *coder)
+{
+ _coders.Add(CCoder());
+ _coders.Back().Coder = coder;
+}
+
+void CCoderMixerMT::ReInit()
+{
+ for(int i = 0; i < _coders.Size(); i++)
+ _coders[i].ReInit();
+}
+
+HRESULT CCoderMixerMT::ReturnIfError(HRESULT code)
+{
+ for (int i = 0; i < _coders.Size(); i++)
+ if (_coders[i].Result == code)
+ return code;
+ return S_OK;
+}
+
+STDMETHODIMP CCoderMixerMT::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */,
+ ICompressProgressInfo *progress)
+{
+ _coders.Front().InStream = inStream;
+ int i;
+ _coders.Back().OutStream = outStream;
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ {
+ RINOK(_coders[i].Create());
+ }
+
+ _streamBinders.Clear();
+ for (i = 0; i + 1 < _coders.Size(); i++)
+ {
+ _streamBinders.Add(CStreamBinder());
+ CStreamBinder &sb = _streamBinders[i];
+ RINOK(sb.CreateEvents());
+ sb.CreateStreams(&_coders[i + 1].InStream, &_coders[i].OutStream);
+ }
+
+ for(i = 0; i < _streamBinders.Size(); i++)
+ _streamBinders[i].ReInit();
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ _coders[i].Start();
+
+ _coders[_progressCoderIndex].Code(progress);
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != _progressCoderIndex)
+ _coders[i].WaitFinish();
+
+ RINOK(ReturnIfError(E_ABORT));
+ RINOK(ReturnIfError(E_OUTOFMEMORY));
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ HRESULT result = _coders[i].Result;
+ if (result != S_OK && result != E_FAIL && result != S_FALSE)
+ return result;
+ }
+
+ RINOK(ReturnIfError(S_FALSE));
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ HRESULT result = _coders[i].Result;
+ if (result != S_OK)
+ return result;
+ }
+ return S_OK;
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.h
new file mode 100644
index 000000000..c70e1829f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.h
@@ -0,0 +1,69 @@
+// CoderMixerMT.h
+
+#ifndef __CODER_MIXER_MT_H
+#define __CODER_MIXER_MT_H
+
+#include "../../../Common/MyVector.h"
+#include "../../../Common/MyCom.h"
+#include "../../ICoder.h"
+#include "../../Common/StreamBinder.h"
+#include "../../Common/VirtThread.h"
+#include "CoderMixer.h"
+
+namespace NCoderMixer {
+
+struct CCoder: public CCoderInfo, public CVirtThread
+{
+ HRESULT Result;
+
+ virtual void Execute();
+ void Code(ICompressProgressInfo *progress);
+};
+
+/*
+ for each coder
+ AddCoder()
+ SetProgressIndex(UInt32 coderIndex);
+
+ for each file
+ {
+ ReInit()
+ for each coder
+ SetCoderInfo
+ Code
+ }
+*/
+
+
+class CCoderMixerMT:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CObjectVector<CStreamBinder> _streamBinders;
+ int _progressCoderIndex;
+
+ HRESULT ReturnIfError(HRESULT code);
+public:
+ CObjectVector<CCoder> _coders;
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ void AddCoder(ICompressCoder *coder);
+ void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; }
+
+ void ReInit();
+ void SetCoderInfo(UInt32 coderIndex, const UInt64 *inSize, const UInt64 *outSize)
+ { _coders[coderIndex].SetCoderInfo(inSize, outSize); }
+
+ /*
+ UInt64 GetWriteProcessedSize(UInt32 binderIndex) const
+ { return _streamBinders[binderIndex].ProcessedSize; }
+ */
+};
+
+}
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
new file mode 100644
index 000000000..a974b54c7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
@@ -0,0 +1,15 @@
+// CrossThreadProgress.cpp
+
+#include "StdAfx.h"
+
+#include "CrossThreadProgress.h"
+
+STDMETHODIMP CCrossThreadProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ InSize = inSize;
+ OutSize = outSize;
+ ProgressEvent.Set();
+ WaitEvent.Lock();
+ return Result;
+}
+
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.h
new file mode 100644
index 000000000..7e0b10538
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.h
@@ -0,0 +1,37 @@
+// CrossThreadProgress.h
+
+#ifndef __CROSSTHREADPROGRESS_H
+#define __CROSSTHREADPROGRESS_H
+
+#include "../../ICoder.h"
+#include "../../../Windows/Synchronization.h"
+#include "../../../Common/MyCom.h"
+
+class CCrossThreadProgress:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ const UInt64 *InSize;
+ const UInt64 *OutSize;
+ HRESULT Result;
+ NWindows::NSynchronization::CAutoResetEvent ProgressEvent;
+ NWindows::NSynchronization::CAutoResetEvent WaitEvent;
+
+ HRes Create()
+ {
+ RINOK(ProgressEvent.CreateIfNotCreated());
+ return WaitEvent.CreateIfNotCreated();
+ }
+ void Init()
+ {
+ ProgressEvent.Reset();
+ WaitEvent.Reset();
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.cpp
new file mode 100644
index 000000000..54bcfec11
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.cpp
@@ -0,0 +1,22 @@
+// DummyOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "DummyOutStream.h"
+
+STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result;
+ if(!_stream)
+ {
+ realProcessedSize = size;
+ result = S_OK;
+ }
+ else
+ result = _stream->Write(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.h
new file mode 100644
index 000000000..13d5b62ca
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.h
@@ -0,0 +1,24 @@
+// DummyOutStream.h
+
+#ifndef __DUMMYOUTSTREAM_H
+#define __DUMMYOUTSTREAM_H
+
+#include "../../IStream.h"
+#include "Common/MyCom.h"
+
+class CDummyOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialOutStream *outStream) { _stream = outStream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _size = 0; }
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ UInt64 GetSize() const { return _size; }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.cpp
new file mode 100644
index 000000000..15aa6ceae
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.cpp
@@ -0,0 +1,62 @@
+// FindSignature.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Buffer.h"
+
+#include "FindSignature.h"
+
+#include "../../Common/StreamUtils.h"
+
+HRESULT FindSignatureInStream(ISequentialInStream *stream,
+ const Byte *signature, unsigned signatureSize,
+ const UInt64 *limit, UInt64 &resPos)
+{
+ resPos = 0;
+ CByteBuffer byteBuffer2;
+ byteBuffer2.SetCapacity(signatureSize);
+ RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize));
+
+ if (memcmp(byteBuffer2, signature, signatureSize) == 0)
+ return S_OK;
+
+ const UInt32 kBufferSize = (1 << 16);
+ CByteBuffer byteBuffer;
+ byteBuffer.SetCapacity(kBufferSize);
+ Byte *buffer = byteBuffer;
+ UInt32 numPrevBytes = signatureSize - 1;
+ memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes);
+ resPos = 1;
+ for (;;)
+ {
+ if (limit != NULL)
+ if (resPos > *limit)
+ return S_FALSE;
+ do
+ {
+ UInt32 numReadBytes = kBufferSize - numPrevBytes;
+ UInt32 processedSize;
+ RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
+ numPrevBytes += processedSize;
+ if (processedSize == 0)
+ return S_FALSE;
+ }
+ while (numPrevBytes < signatureSize);
+ UInt32 numTests = numPrevBytes - signatureSize + 1;
+ for (UInt32 pos = 0; pos < numTests; pos++)
+ {
+ Byte b = signature[0];
+ for (; buffer[pos] != b && pos < numTests; pos++);
+ if (pos == numTests)
+ break;
+ if (memcmp(buffer + pos, signature, signatureSize) == 0)
+ {
+ resPos += pos;
+ return S_OK;
+ }
+ }
+ resPos += numTests;
+ numPrevBytes -= numTests;
+ memmove(buffer, buffer + numTests, numPrevBytes);
+ }
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.h
new file mode 100644
index 000000000..e15af5732
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.h
@@ -0,0 +1,12 @@
+// FindSignature.h
+
+#ifndef __FINDSIGNATURE_H
+#define __FINDSIGNATURE_H
+
+#include "../../IStream.h"
+
+HRESULT FindSignatureInStream(ISequentialInStream *stream,
+ const Byte *signature, unsigned signatureSize,
+ const UInt64 *limit, UInt64 &resPos);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.cpp
new file mode 100644
index 000000000..70ad47aad
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -0,0 +1,623 @@
+// HandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/System.h"
+#endif
+
+#include "../../ICoder.h"
+
+#include "../Common/ParseProperties.h"
+
+#include "HandlerOut.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+
+static const wchar_t *kCopyMethod = L"Copy";
+static const wchar_t *kLZMAMethodName = L"LZMA";
+static const wchar_t *kLZMA2MethodName = L"LZMA2";
+static const wchar_t *kBZip2MethodName = L"BZip2";
+static const wchar_t *kPpmdMethodName = L"PPMd";
+static const wchar_t *kDeflateMethodName = L"Deflate";
+static const wchar_t *kDeflate64MethodName = L"Deflate64";
+
+static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
+static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
+
+static const UInt32 kLzmaAlgoX1 = 0;
+static const UInt32 kLzmaAlgoX5 = 1;
+
+static const UInt32 kLzmaDicSizeX1 = 1 << 16;
+static const UInt32 kLzmaDicSizeX3 = 1 << 20;
+static const UInt32 kLzmaDicSizeX5 = 1 << 24;
+static const UInt32 kLzmaDicSizeX7 = 1 << 25;
+static const UInt32 kLzmaDicSizeX9 = 1 << 26;
+
+static const UInt32 kLzmaFastBytesX1 = 32;
+static const UInt32 kLzmaFastBytesX7 = 64;
+
+static const UInt32 kPpmdMemSizeX1 = (1 << 22);
+static const UInt32 kPpmdMemSizeX5 = (1 << 24);
+static const UInt32 kPpmdMemSizeX7 = (1 << 26);
+static const UInt32 kPpmdMemSizeX9 = (192 << 20);
+
+static const UInt32 kPpmdOrderX1 = 4;
+static const UInt32 kPpmdOrderX5 = 6;
+static const UInt32 kPpmdOrderX7 = 16;
+static const UInt32 kPpmdOrderX9 = 32;
+
+static const UInt32 kDeflateAlgoX1 = 0;
+static const UInt32 kDeflateAlgoX5 = 1;
+
+static const UInt32 kDeflateFastBytesX1 = 32;
+static const UInt32 kDeflateFastBytesX7 = 64;
+static const UInt32 kDeflateFastBytesX9 = 128;
+
+static const UInt32 kDeflatePassesX1 = 1;
+static const UInt32 kDeflatePassesX7 = 3;
+static const UInt32 kDeflatePassesX9 = 10;
+
+static const UInt32 kBZip2NumPassesX1 = 1;
+static const UInt32 kBZip2NumPassesX7 = 2;
+static const UInt32 kBZip2NumPassesX9 = 7;
+
+static const UInt32 kBZip2DicSizeX1 = 100000;
+static const UInt32 kBZip2DicSizeX3 = 500000;
+static const UInt32 kBZip2DicSizeX5 = 900000;
+
+static const wchar_t *kDefaultMethodName = kLZMAMethodName;
+
+static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
+static const UInt32 kDictionaryForHeaders = 1 << 20;
+static const UInt32 kNumFastBytesForHeaders = 273;
+static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5;
+
+static bool AreEqual(const UString &methodName, const wchar_t *s)
+ { return (methodName.CompareNoCase(s) == 0); }
+
+bool COneMethodInfo::IsLzma() const
+{
+ return
+ AreEqual(MethodName, kLZMAMethodName) ||
+ AreEqual(MethodName, kLZMA2MethodName);
+}
+
+static inline bool IsBZip2Method(const UString &methodName)
+ { return AreEqual(methodName, kBZip2MethodName); }
+
+static inline bool IsPpmdMethod(const UString &methodName)
+ { return AreEqual(methodName, kPpmdMethodName); }
+
+static inline bool IsDeflateMethod(const UString &methodName)
+{
+ return
+ AreEqual(methodName, kDeflateMethodName) ||
+ AreEqual(methodName, kDeflate64MethodName);
+}
+
+struct CNameToPropID
+{
+ PROPID PropID;
+ VARTYPE VarType;
+ const wchar_t *Name;
+};
+
+static CNameToPropID g_NameToPropID[] =
+{
+ { NCoderPropID::kBlockSize, VT_UI4, L"C" },
+ { NCoderPropID::kDictionarySize, VT_UI4, L"D" },
+ { NCoderPropID::kUsedMemorySize, VT_UI4, L"MEM" },
+
+ { NCoderPropID::kOrder, VT_UI4, L"O" },
+ { NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
+ { NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
+ { NCoderPropID::kLitPosBits, VT_UI4, L"LP" },
+ { NCoderPropID::kEndMarker, VT_BOOL, L"eos" },
+
+ { NCoderPropID::kNumPasses, VT_UI4, L"Pass" },
+ { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" },
+ { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
+ { NCoderPropID::kAlgorithm, VT_UI4, L"a" },
+ { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
+ { NCoderPropID::kNumThreads, VT_UI4, L"mt" },
+ { NCoderPropID::kDefaultProp, VT_UI4, L"" }
+};
+
+static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
+{
+ if (varType == srcProp.vt)
+ {
+ destProp = srcProp;
+ return true;
+ }
+ if (varType == VT_UI1)
+ {
+ if (srcProp.vt == VT_UI4)
+ {
+ UInt32 value = srcProp.ulVal;
+ if (value > 0xFF)
+ return false;
+ destProp = (Byte)value;
+ return true;
+ }
+ }
+ else if (varType == VT_BOOL)
+ {
+ bool res;
+ if (SetBoolProperty(res, srcProp) != S_OK)
+ return false;
+ destProp = res;
+ return true;
+ }
+ return false;
+}
+
+static int FindPropIdExact(const UString &name)
+{
+ for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
+ if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
+ return i;
+ return -1;
+}
+
+static int FindPropIdStart(const UString &name)
+{
+ for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
+ {
+ UString t = g_NameToPropID[i].Name;
+ if (t.CompareNoCase(name.Left(t.Length())) == 0)
+ return i;
+ }
+ return -1;
+}
+
+static void SetMethodProp(COneMethodInfo &m, PROPID propID, const NCOM::CPropVariant &value)
+{
+ for (int j = 0; j < m.Props.Size(); j++)
+ if (m.Props[j].Id == propID)
+ return;
+ CProp prop;
+ prop.Id = propID;
+ prop.Value = value;
+ m.Props.Add(prop);
+}
+
+void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ )
+{
+ UInt32 level = _level;
+ if (oneMethodInfo.MethodName.IsEmpty())
+ oneMethodInfo.MethodName = kDefaultMethodName;
+
+ if (oneMethodInfo.IsLzma())
+ {
+ UInt32 dicSize =
+ (level >= 9 ? kLzmaDicSizeX9 :
+ (level >= 7 ? kLzmaDicSizeX7 :
+ (level >= 5 ? kLzmaDicSizeX5 :
+ (level >= 3 ? kLzmaDicSizeX3 :
+ kLzmaDicSizeX1))));
+
+ UInt32 algo =
+ (level >= 5 ? kLzmaAlgoX5 :
+ kLzmaAlgoX1);
+
+ UInt32 fastBytes =
+ (level >= 7 ? kLzmaFastBytesX7 :
+ kLzmaFastBytesX1);
+
+ const wchar_t *matchFinder =
+ (level >= 5 ? kLzmaMatchFinderX5 :
+ kLzmaMatchFinderX1);
+
+ SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
+ #ifndef _7ZIP_ST
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+ #endif
+ }
+ else if (IsDeflateMethod(oneMethodInfo.MethodName))
+ {
+ UInt32 fastBytes =
+ (level >= 9 ? kDeflateFastBytesX9 :
+ (level >= 7 ? kDeflateFastBytesX7 :
+ kDeflateFastBytesX1));
+
+ UInt32 numPasses =
+ (level >= 9 ? kDeflatePassesX9 :
+ (level >= 7 ? kDeflatePassesX7 :
+ kDeflatePassesX1));
+
+ UInt32 algo =
+ (level >= 5 ? kDeflateAlgoX5 :
+ kDeflateAlgoX1);
+
+ SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
+ }
+ else if (IsBZip2Method(oneMethodInfo.MethodName))
+ {
+ UInt32 numPasses =
+ (level >= 9 ? kBZip2NumPassesX9 :
+ (level >= 7 ? kBZip2NumPassesX7 :
+ kBZip2NumPassesX1));
+
+ UInt32 dicSize =
+ (level >= 5 ? kBZip2DicSizeX5 :
+ (level >= 3 ? kBZip2DicSizeX3 :
+ kBZip2DicSizeX1));
+
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
+ #ifndef _7ZIP_ST
+ SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+ #endif
+ }
+ else if (IsPpmdMethod(oneMethodInfo.MethodName))
+ {
+ UInt32 useMemSize =
+ (level >= 9 ? kPpmdMemSizeX9 :
+ (level >= 7 ? kPpmdMemSizeX7 :
+ (level >= 5 ? kPpmdMemSizeX5 :
+ kPpmdMemSizeX1)));
+
+ UInt32 order =
+ (level >= 9 ? kPpmdOrderX9 :
+ (level >= 7 ? kPpmdOrderX7 :
+ (level >= 5 ? kPpmdOrderX5 :
+ kPpmdOrderX1)));
+
+ SetMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
+ SetMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
+ }
+}
+
+static void SplitParams(const UString &srcString, UStringVector &subStrings)
+{
+ subStrings.Clear();
+ UString name;
+ int len = srcString.Length();
+ if (len == 0)
+ return;
+ for (int i = 0; i < len; i++)
+ {
+ wchar_t c = srcString[i];
+ if (c == L':')
+ {
+ subStrings.Add(name);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ subStrings.Add(name);
+}
+
+static void SplitParam(const UString &param, UString &name, UString &value)
+{
+ int eqPos = param.Find(L'=');
+ if (eqPos >= 0)
+ {
+ name = param.Left(eqPos);
+ value = param.Mid(eqPos + 1);
+ return;
+ }
+ for(int i = 0; i < param.Length(); i++)
+ {
+ wchar_t c = param[i];
+ if (c >= L'0' && c <= L'9')
+ {
+ name = param.Left(i);
+ value = param.Mid(i);
+ return;
+ }
+ }
+ name = param;
+}
+
+HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value)
+{
+ CProp prop;
+ int index = FindPropIdExact(name);
+ if (index < 0)
+ return E_INVALIDARG;
+ const CNameToPropID &nameToPropID = g_NameToPropID[index];
+ prop.Id = nameToPropID.PropID;
+
+ if (prop.Id == NCoderPropID::kBlockSize ||
+ prop.Id == NCoderPropID::kDictionarySize ||
+ prop.Id == NCoderPropID::kUsedMemorySize)
+ {
+ UInt32 dicSize;
+ RINOK(ParsePropDictionaryValue(value, dicSize));
+ prop.Value = dicSize;
+ }
+ else
+ {
+ NCOM::CPropVariant propValue;
+
+ if (nameToPropID.VarType == VT_BSTR)
+ propValue = value;
+ else if (nameToPropID.VarType == VT_BOOL)
+ {
+ bool res;
+ if (!StringToBool(value, res))
+ return E_INVALIDARG;
+ propValue = res;
+ }
+ else
+ {
+ UInt32 number;
+ if (ParseStringToUInt32(value, number) == value.Length())
+ propValue = number;
+ else
+ propValue = value;
+ }
+
+ if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
+ return E_INVALIDARG;
+ }
+ oneMethodInfo.Props.Add(prop);
+ return S_OK;
+}
+
+HRESULT COutHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString)
+{
+ UStringVector params;
+ SplitParams(srcString, params);
+ if (params.Size() > 0)
+ oneMethodInfo.MethodName = params[0];
+ for (int i = 1; i < params.Size(); i++)
+ {
+ const UString &param = params[i];
+ UString name, value;
+ SplitParam(param, name, value);
+ RINOK(SetParam(oneMethodInfo, name, value));
+ }
+ return S_OK;
+}
+
+HRESULT COutHandler::SetSolidSettings(const UString &s)
+{
+ UString s2 = s;
+ s2.MakeUpper();
+ for (int i = 0; i < s2.Length();)
+ {
+ const wchar_t *start = ((const wchar_t *)s2) + i;
+ const wchar_t *end;
+ UInt64 v = ConvertStringToUInt64(start, &end);
+ if (start == end)
+ {
+ if (s2[i++] != 'E')
+ return E_INVALIDARG;
+ _solidExtension = true;
+ continue;
+ }
+ i += (int)(end - start);
+ if (i == s2.Length())
+ return E_INVALIDARG;
+ wchar_t c = s2[i++];
+ switch(c)
+ {
+ case 'F':
+ if (v < 1)
+ v = 1;
+ _numSolidFiles = v;
+ break;
+ case 'B':
+ _numSolidBytes = v;
+ _numSolidBytesDefined = true;
+ break;
+ case 'K':
+ _numSolidBytes = (v << 10);
+ _numSolidBytesDefined = true;
+ break;
+ case 'M':
+ _numSolidBytes = (v << 20);
+ _numSolidBytesDefined = true;
+ break;
+ case 'G':
+ _numSolidBytes = (v << 30);
+ _numSolidBytesDefined = true;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT COutHandler::SetSolidSettings(const PROPVARIANT &value)
+{
+ bool isSolid;
+ switch(value.vt)
+ {
+ case VT_EMPTY:
+ isSolid = true;
+ break;
+ case VT_BOOL:
+ isSolid = (value.boolVal != VARIANT_FALSE);
+ break;
+ case VT_BSTR:
+ if (StringToBool(value.bstrVal, isSolid))
+ break;
+ return SetSolidSettings(value.bstrVal);
+ default:
+ return E_INVALIDARG;
+ }
+ if (isSolid)
+ InitSolid();
+ else
+ _numSolidFiles = 1;
+ return S_OK;
+}
+
+void COutHandler::Init()
+{
+ _removeSfxBlock = false;
+ _compressHeaders = true;
+ _encryptHeadersSpecified = false;
+ _encryptHeaders = false;
+
+ WriteCTime = false;
+ WriteATime = false;
+ WriteMTime = true;
+
+ #ifndef _7ZIP_ST
+ _numThreads = NSystem::GetNumberOfProcessors();
+ #endif
+
+ _level = 5;
+ _autoFilter = true;
+ _volumeMode = false;
+ _crcSize = 4;
+ InitSolid();
+}
+
+void COutHandler::BeforeSetProperty()
+{
+ Init();
+ #ifndef _7ZIP_ST
+ numProcessors = NSystem::GetNumberOfProcessors();
+ #endif
+
+ mainDicSize = 0xFFFFFFFF;
+ mainDicMethodIndex = 0xFFFFFFFF;
+ minNumber = 0;
+ _crcSize = 4;
+}
+
+HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
+{
+ UString name = nameSpec;
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ if (name[0] == 'X')
+ {
+ name.Delete(0);
+ _level = 9;
+ return ParsePropValue(name, value, _level);
+ }
+
+ if (name[0] == L'S')
+ {
+ name.Delete(0);
+ if (name.IsEmpty())
+ return SetSolidSettings(value);
+ if (value.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return SetSolidSettings(name);
+ }
+
+ if (name == L"CRC")
+ {
+ _crcSize = 4;
+ name.Delete(0, 3);
+ return ParsePropValue(name, value, _crcSize);
+ }
+
+ UInt32 number;
+ int index = ParseStringToUInt32(name, number);
+ UString realName = name.Mid(index);
+ if (index == 0)
+ {
+ if(name.Left(2).CompareNoCase(L"MT") == 0)
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
+ #endif
+ return S_OK;
+ }
+ if (name.CompareNoCase(L"RSFX") == 0) return SetBoolProperty(_removeSfxBlock, value);
+ if (name.CompareNoCase(L"F") == 0) return SetBoolProperty(_autoFilter, value);
+ if (name.CompareNoCase(L"HC") == 0) return SetBoolProperty(_compressHeaders, value);
+ if (name.CompareNoCase(L"HCF") == 0)
+ {
+ bool compressHeadersFull = true;
+ RINOK(SetBoolProperty(compressHeadersFull, value));
+ if (!compressHeadersFull)
+ return E_INVALIDARG;
+ return S_OK;
+ }
+ if (name.CompareNoCase(L"HE") == 0)
+ {
+ RINOK(SetBoolProperty(_encryptHeaders, value));
+ _encryptHeadersSpecified = true;
+ return S_OK;
+ }
+ if (name.CompareNoCase(L"TC") == 0) return SetBoolProperty(WriteCTime, value);
+ if (name.CompareNoCase(L"TA") == 0) return SetBoolProperty(WriteATime, value);
+ if (name.CompareNoCase(L"TM") == 0) return SetBoolProperty(WriteMTime, value);
+ if (name.CompareNoCase(L"V") == 0) return SetBoolProperty(_volumeMode, value);
+ number = 0;
+ }
+ if (number > 10000)
+ return E_FAIL;
+ if (number < minNumber)
+ return E_INVALIDARG;
+ number -= minNumber;
+ for(int j = _methods.Size(); j <= (int)number; j++)
+ {
+ COneMethodInfo oneMethodInfo;
+ _methods.Add(oneMethodInfo);
+ }
+
+ COneMethodInfo &oneMethodInfo = _methods[number];
+
+ if (realName.Length() == 0)
+ {
+ if (value.vt != VT_BSTR)
+ return E_INVALIDARG;
+
+ RINOK(SetParams(oneMethodInfo, value.bstrVal));
+ }
+ else
+ {
+ int index = FindPropIdStart(realName);
+ if (index < 0)
+ return E_INVALIDARG;
+ const CNameToPropID &nameToPropID = g_NameToPropID[index];
+ CProp prop;
+ prop.Id = nameToPropID.PropID;
+
+ if (prop.Id == NCoderPropID::kBlockSize ||
+ prop.Id == NCoderPropID::kDictionarySize ||
+ prop.Id == NCoderPropID::kUsedMemorySize)
+ {
+ UInt32 dicSize;
+ RINOK(ParsePropDictionaryValue(realName.Mid(MyStringLen(nameToPropID.Name)), value, dicSize));
+ prop.Value = dicSize;
+ if (number <= mainDicMethodIndex)
+ mainDicSize = dicSize;
+ }
+ else
+ {
+ int index = FindPropIdExact(realName);
+ if (index < 0)
+ return E_INVALIDARG;
+ const CNameToPropID &nameToPropID = g_NameToPropID[index];
+ prop.Id = nameToPropID.PropID;
+ if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
+ return E_INVALIDARG;
+ }
+ oneMethodInfo.Props.Add(prop);
+ }
+ return S_OK;
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.h
new file mode 100644
index 000000000..72ea40321
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/HandlerOut.h
@@ -0,0 +1,87 @@
+// HandlerOut.h
+
+#ifndef __HANDLER_OUT_H
+#define __HANDLER_OUT_H
+
+#include "../../../Common/MyString.h"
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+
+struct COneMethodInfo
+{
+ CObjectVector<CProp> Props;
+ UString MethodName;
+
+ bool IsLzma() const;
+};
+
+class COutHandler
+{
+public:
+ HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
+
+ HRESULT SetSolidSettings(const UString &s);
+ HRESULT SetSolidSettings(const PROPVARIANT &value);
+
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ #endif
+
+ UInt32 _crcSize;
+
+ CObjectVector<COneMethodInfo> _methods;
+ bool _removeSfxBlock;
+
+ UInt64 _numSolidFiles;
+ UInt64 _numSolidBytes;
+ bool _numSolidBytesDefined;
+ bool _solidExtension;
+
+ bool _compressHeaders;
+ bool _encryptHeadersSpecified;
+ bool _encryptHeaders;
+
+ bool WriteCTime;
+ bool WriteATime;
+ bool WriteMTime;
+
+ bool _autoFilter;
+ UInt32 _level;
+
+ bool _volumeMode;
+
+ HRESULT SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value);
+ HRESULT SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString);
+
+ void SetCompressionMethod2(COneMethodInfo &oneMethodInfo
+ #ifndef _7ZIP_ST
+ , UInt32 numThreads
+ #endif
+ );
+
+ void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); }
+ void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); }
+ void InitSolid()
+ {
+ InitSolidFiles();
+ InitSolidSize();
+ _solidExtension = false;
+ _numSolidBytesDefined = false;
+ }
+
+ void Init();
+
+ COutHandler() { Init(); }
+
+ void BeforeSetProperty();
+
+ UInt32 minNumber;
+ UInt32 numProcessors;
+ UInt32 mainDicSize;
+ UInt32 mainDicMethodIndex;
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
new file mode 100644
index 000000000..569a56f3b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
@@ -0,0 +1,42 @@
+// InStreamWithCRC.cpp
+
+#include "StdAfx.h"
+
+#include "InStreamWithCRC.h"
+
+STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (size > 0 && realProcessedSize == 0)
+ _wasFinished = true;
+ _crc = CrcUpdate(_crc, data, realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ /*
+ if (size > 0 && realProcessedSize == 0)
+ _wasFinished = true;
+ */
+ _size += realProcessedSize;
+ _crc = CrcUpdate(_crc, data, realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+STDMETHODIMP CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if (seekOrigin != STREAM_SEEK_SET || offset != 0)
+ return E_FAIL;
+ _size = 0;
+ _crc = CRC_INIT_VAL;
+ return _stream->Seek(offset, seekOrigin, newPosition);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.h
new file mode 100644
index 000000000..31b761e45
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/InStreamWithCRC.h
@@ -0,0 +1,67 @@
+// InStreamWithCRC.h
+
+#ifndef __IN_STREAM_WITH_CRC_H
+#define __IN_STREAM_WITH_CRC_H
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+class CSequentialInStreamWithCRC:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+private:
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _wasFinished;
+public:
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ _wasFinished = false;
+ _crc = CRC_INIT_VAL;
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+ UInt64 GetSize() const { return _size; }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+class CInStreamWithCRC:
+ public IInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+private:
+ CMyComPtr<IInStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ // bool _wasFinished;
+public:
+ void SetStream(IInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ // _wasFinished = false;
+ _crc = CRC_INIT_VAL;
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+ UInt64 GetSize() const { return _size; }
+ // bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.cpp
new file mode 100644
index 000000000..a5e0dc0be
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.cpp
@@ -0,0 +1,61 @@
+// Archive/Common/ItemNameUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Types.h"
+
+#include "ItemNameUtils.h"
+
+namespace NArchive {
+namespace NItemName {
+
+static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR;
+static const wchar_t kDirDelimiter = L'/';
+
+UString MakeLegalName(const UString &name)
+{
+ UString zipName = name;
+ zipName.Replace(kOSDirDelimiter, kDirDelimiter);
+ return zipName;
+}
+
+UString GetOSName(const UString &name)
+{
+ UString newName = name;
+ newName.Replace(kDirDelimiter, kOSDirDelimiter);
+ return newName;
+}
+
+UString GetOSName2(const UString &name)
+{
+ if (name.IsEmpty())
+ return UString();
+ UString newName = GetOSName(name);
+ if (newName[newName.Length() - 1] == kOSDirDelimiter)
+ newName.Delete(newName.Length() - 1);
+ return newName;
+}
+
+bool HasTailSlash(const AString &name, UINT codePage)
+{
+ if (name.IsEmpty())
+ return false;
+ LPCSTR prev =
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ CharPrevExA((WORD)codePage, name, &name[name.Length()], 0);
+ #else
+ (LPCSTR)(name) + (name.Length() - 1);
+ #endif
+ return (*prev == '/');
+}
+
+#ifndef _WIN32
+UString WinNameToOSName(const UString &name)
+{
+ UString newName = name;
+ newName.Replace(L'\\', kOSDirDelimiter);
+ return newName;
+}
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.h
new file mode 100644
index 000000000..5eafacb12
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -0,0 +1,24 @@
+// Archive/Common/ItemNameUtils.h
+
+#ifndef __ARCHIVE_ITEMNAMEUTILS_H
+#define __ARCHIVE_ITEMNAMEUTILS_H
+
+#include "../../../Common/MyString.h"
+
+namespace NArchive {
+namespace NItemName {
+
+ UString MakeLegalName(const UString &name);
+ UString GetOSName(const UString &name);
+ UString GetOSName2(const UString &name);
+ bool HasTailSlash(const AString &name, UINT codePage);
+
+ #ifdef _WIN32
+ inline UString WinNameToOSName(const UString &name) { return name; }
+ #else
+ UString WinNameToOSName(const UString &name);
+ #endif
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.cpp
new file mode 100644
index 000000000..04d11cafb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.cpp
@@ -0,0 +1,190 @@
+// MultiStream.cpp
+
+#include "StdAfx.h"
+
+#include "MultiStream.h"
+
+STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos >= _totalLength)
+ return (_pos == _totalLength) ? S_OK : E_FAIL;
+
+ {
+ int left = 0, mid = _streamIndex, right = Streams.Size();
+ for (;;)
+ {
+ CSubStreamInfo &m = Streams[mid];
+ if (_pos < m.GlobalOffset)
+ right = mid;
+ else if (_pos >= m.GlobalOffset + m.Size)
+ left = mid + 1;
+ else
+ {
+ _streamIndex = mid;
+ break;
+ }
+ mid = (left + right) / 2;
+ }
+ _streamIndex = mid;
+ }
+
+ CSubStreamInfo &s = Streams[_streamIndex];
+ UInt64 localPos = _pos - s.GlobalOffset;
+ if (localPos != s.LocalPos)
+ {
+ RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos));
+ }
+ UInt64 rem = s.Size - localPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ HRESULT result = s.Stream->Read(data, size, &size);
+ _pos += size;
+ s.LocalPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _pos = offset; break;
+ case STREAM_SEEK_CUR: _pos = _pos + offset; break;
+ case STREAM_SEEK_END: _pos = _totalLength + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition != 0)
+ *newPosition = _pos;
+ return S_OK;
+}
+
+
+/*
+class COutVolumeStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ int _volIndex;
+ UInt64 _volSize;
+ UInt64 _curPos;
+ CMyComPtr<ISequentialOutStream> _volumeStream;
+ COutArchive _archive;
+ CCRC _crc;
+
+public:
+ MY_UNKNOWN_IMP
+
+ CFileItem _file;
+ CUpdateOptions _options;
+ CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ void Init(IArchiveUpdateCallback2 *volumeCallback,
+ const UString &name)
+ {
+ _file.Name = name;
+ _file.IsStartPosDefined = true;
+ _file.StartPos = 0;
+
+ VolumeCallback = volumeCallback;
+ _volIndex = 0;
+ _volSize = 0;
+ }
+
+ HRESULT Flush();
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+HRESULT COutVolumeStream::Flush()
+{
+ if (_volumeStream)
+ {
+ _file.UnPackSize = _curPos;
+ _file.FileCRC = _crc.GetDigest();
+ RINOK(WriteVolumeHeader(_archive, _file, _options));
+ _archive.Close();
+ _volumeStream.Release();
+ _file.StartPos += _file.UnPackSize;
+ }
+ return S_OK;
+}
+*/
+
+/*
+STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if(processedSize != NULL)
+ *processedSize = 0;
+ while(size > 0)
+ {
+ if (_streamIndex >= Streams.Size())
+ {
+ CSubStreamInfo subStream;
+ RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size));
+ RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream));
+ subStream.Pos = 0;
+ Streams.Add(subStream);
+ continue;
+ }
+ CSubStreamInfo &subStream = Streams[_streamIndex];
+ if (_offsetPos >= subStream.Size)
+ {
+ _offsetPos -= subStream.Size;
+ _streamIndex++;
+ continue;
+ }
+ if (_offsetPos != subStream.Pos)
+ {
+ CMyComPtr<IOutStream> outStream;
+ RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
+ RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
+ subStream.Pos = _offsetPos;
+ }
+
+ UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);
+ UInt32 realProcessed;
+ RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
+ data = (void *)((Byte *)data + realProcessed);
+ size -= realProcessed;
+ subStream.Pos += realProcessed;
+ _offsetPos += realProcessed;
+ _absPos += realProcessed;
+ if (_absPos > _length)
+ _length = _absPos;
+ if(processedSize != NULL)
+ *processedSize += realProcessed;
+ if (subStream.Pos == subStream.Size)
+ {
+ _streamIndex++;
+ _offsetPos = 0;
+ }
+ if (realProcessed != curSize && realProcessed == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if(seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET:
+ _absPos = offset;
+ break;
+ case STREAM_SEEK_CUR:
+ _absPos += offset;
+ break;
+ case STREAM_SEEK_END:
+ _absPos = _length + offset;
+ break;
+ }
+ _offsetPos = _absPos;
+ _streamIndex = 0;
+ return S_OK;
+}
+*/
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.h
new file mode 100644
index 000000000..3fceb7cce
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/MultiStream.h
@@ -0,0 +1,84 @@
+// MultiStream.h
+
+#ifndef __MULTI_STREAM_H
+#define __MULTI_STREAM_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyVector.h"
+
+#include "../../IStream.h"
+
+class CMultiStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _pos;
+ UInt64 _totalLength;
+ int _streamIndex;
+public:
+ struct CSubStreamInfo
+ {
+ CMyComPtr<IInStream> Stream;
+ UInt64 Size;
+ UInt64 GlobalOffset;
+ UInt64 LocalPos;
+ };
+ CObjectVector<CSubStreamInfo> Streams;
+
+ HRESULT Init()
+ {
+ UInt64 total = 0;
+ for (int i = 0; i < Streams.Size(); i++)
+ {
+ CSubStreamInfo &s = Streams[i];
+ s.GlobalOffset = total;
+ total += Streams[i].Size;
+ RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos));
+ }
+ _totalLength = total;
+ _pos = 0;
+ _streamIndex = 0;
+ return S_OK;
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+/*
+class COutMultiStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ int _streamIndex; // required stream
+ UInt64 _offsetPos; // offset from start of _streamIndex index
+ UInt64 _absPos;
+ UInt64 _length;
+
+ struct CSubStreamInfo
+ {
+ CMyComPtr<ISequentialOutStream> Stream;
+ UInt64 Size;
+ UInt64 Pos;
+ };
+ CObjectVector<CSubStreamInfo> Streams;
+public:
+ CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ void Init()
+ {
+ _streamIndex = 0;
+ _offsetPos = 0;
+ _absPos = 0;
+ _length = 0;
+ }
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+*/
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
new file mode 100644
index 000000000..f955c2254
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
@@ -0,0 +1,18 @@
+// OutStreamWithCRC.cpp
+
+#include "StdAfx.h"
+
+#include "OutStreamWithCRC.h"
+
+STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ _crc = CrcUpdate(_crc, data, size);
+ _size += size;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.h
new file mode 100644
index 000000000..115b442aa
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithCRC.h
@@ -0,0 +1,36 @@
+// OutStreamWithCRC.h
+
+#ifndef __OUT_STREAM_WITH_CRC_H
+#define __OUT_STREAM_WITH_CRC_H
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+class COutStreamWithCRC:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _calculate;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ _crc = CRC_INIT_VAL;
+ }
+ void InitCRC() { _crc = CRC_INIT_VAL; }
+ UInt64 GetSize() const { return _size; }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
new file mode 100644
index 000000000..0526c1b1d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
@@ -0,0 +1,18 @@
+// OutStreamWithSha1.cpp
+
+#include "StdAfx.h"
+
+#include "OutStreamWithSha1.h"
+
+STDMETHODIMP COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ _sha.Update((const Byte *)data, size);
+ _size += size;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithSha1.h
new file mode 100644
index 000000000..3bbfbbe19
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/OutStreamWithSha1.h
@@ -0,0 +1,36 @@
+// OutStreamWithSha1.h
+
+#ifndef __OUT_STREAM_WITH_SHA1_H
+#define __OUT_STREAM_WITH_SHA1_H
+
+#include "../../Crypto/Sha1.h"
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+class COutStreamWithSha1:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ NCrypto::NSha1::CContext _sha;
+ bool _calculate;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ _sha.Init();
+ }
+ void InitSha1() { _sha.Init(); }
+ UInt64 GetSize() const { return _size; }
+ void Final(Byte *digest) { _sha.Final(digest); }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.cpp
new file mode 100644
index 000000000..5cd849e29
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.cpp
@@ -0,0 +1,177 @@
+// ParseProperties.cpp
+
+#include "StdAfx.h"
+
+#include "ParseProperties.h"
+
+#include "Common/StringToInt.h"
+#include "Common/MyCom.h"
+
+HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
+{
+ if (prop.vt == VT_UI4)
+ {
+ if (!name.IsEmpty())
+ return E_INVALIDARG;
+ resValue = prop.ulVal;
+ }
+ else if (prop.vt == VT_EMPTY)
+ {
+ if(!name.IsEmpty())
+ {
+ const wchar_t *start = name;
+ const wchar_t *end;
+ UInt64 v = ConvertStringToUInt64(start, &end);
+ if (end - start != name.Length())
+ return E_INVALIDARG;
+ resValue = (UInt32)v;
+ }
+ }
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+static const int kLogarithmicSizeLimit = 32;
+static const wchar_t kByteSymbol = L'B';
+static const wchar_t kKiloByteSymbol = L'K';
+static const wchar_t kMegaByteSymbol = L'M';
+
+HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize)
+{
+ UString srcString = srcStringSpec;
+ srcString.MakeUpper();
+
+ const wchar_t *start = srcString;
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(start, &end);
+ int numDigits = (int)(end - start);
+ if (numDigits == 0 || srcString.Length() > numDigits + 1)
+ return E_INVALIDARG;
+ if (srcString.Length() == numDigits)
+ {
+ if (number >= kLogarithmicSizeLimit)
+ return E_INVALIDARG;
+ dicSize = (UInt32)1 << (int)number;
+ return S_OK;
+ }
+ switch (srcString[numDigits])
+ {
+ case kByteSymbol:
+ if (number >= ((UInt64)1 << kLogarithmicSizeLimit))
+ return E_INVALIDARG;
+ dicSize = (UInt32)number;
+ break;
+ case kKiloByteSymbol:
+ if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 10)))
+ return E_INVALIDARG;
+ dicSize = (UInt32)(number << 10);
+ break;
+ case kMegaByteSymbol:
+ if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 20)))
+ return E_INVALIDARG;
+ dicSize = (UInt32)(number << 20);
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
+{
+ if (name.IsEmpty())
+ {
+ if (prop.vt == VT_UI4)
+ {
+ UInt32 logDicSize = prop.ulVal;
+ if (logDicSize >= 32)
+ return E_INVALIDARG;
+ resValue = (UInt32)1 << logDicSize;
+ return S_OK;
+ }
+ if (prop.vt == VT_BSTR)
+ return ParsePropDictionaryValue(prop.bstrVal, resValue);
+ return E_INVALIDARG;
+ }
+ return ParsePropDictionaryValue(name, resValue);
+}
+
+bool StringToBool(const UString &s, bool &res)
+{
+ if (s.IsEmpty() || s.CompareNoCase(L"ON") == 0 || s.Compare(L"+") == 0)
+ {
+ res = true;
+ return true;
+ }
+ if (s.CompareNoCase(L"OFF") == 0 || s.Compare(L"-") == 0)
+ {
+ res = false;
+ return true;
+ }
+ return false;
+}
+
+HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value)
+{
+ switch(value.vt)
+ {
+ case VT_EMPTY:
+ dest = true;
+ return S_OK;
+ case VT_BOOL:
+ dest = (value.boolVal != VARIANT_FALSE);
+ return S_OK;
+ /*
+ case VT_UI4:
+ dest = (value.ulVal != 0);
+ break;
+ */
+ case VT_BSTR:
+ return StringToBool(value.bstrVal, dest) ? S_OK : E_INVALIDARG;
+ }
+ return E_INVALIDARG;
+}
+
+int ParseStringToUInt32(const UString &srcString, UInt32 &number)
+{
+ const wchar_t *start = srcString;
+ const wchar_t *end;
+ UInt64 number64 = ConvertStringToUInt64(start, &end);
+ if (number64 > 0xFFFFFFFF)
+ {
+ number = 0;
+ return 0;
+ }
+ number = (UInt32)number64;
+ return (int)(end - start);
+}
+
+HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads)
+{
+ if (name.IsEmpty())
+ {
+ switch(prop.vt)
+ {
+ case VT_UI4:
+ numThreads = prop.ulVal;
+ break;
+ default:
+ {
+ bool val;
+ RINOK(SetBoolProperty(val, prop));
+ numThreads = (val ? defaultNumThreads : 1);
+ break;
+ }
+ }
+ }
+ else
+ {
+ UInt32 number;
+ int index = ParseStringToUInt32(name, number);
+ if (index != name.Length())
+ return E_INVALIDARG;
+ numThreads = number;
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.h
new file mode 100644
index 000000000..6f80f6344
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/ParseProperties.h
@@ -0,0 +1,18 @@
+// ParseProperties.h
+
+#ifndef __PARSEPROPERTIES_H
+#define __PARSEPROPERTIES_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
+HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize);
+HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
+
+bool StringToBool(const UString &s, bool &res);
+HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value);
+int ParseStringToUInt32(const UString &srcString, UInt32 &number);
+HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/StdAfx.h
new file mode 100644
index 000000000..2e4be10b2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/CpioHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/CpioHandler.cpp
new file mode 100644
index 000000000..0f32ef663
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/CpioHandler.cpp
@@ -0,0 +1,624 @@
+// CpioHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+
+namespace NArchive {
+namespace NCpio {
+
+namespace NFileHeader
+{
+ namespace NMagic
+ {
+ const char *kMagic1 = "070701";
+ const char *kMagic2 = "070702";
+ const char *kMagic3 = "070707";
+ const char *kEndName = "TRAILER!!!";
+
+ const Byte kMagicForRecord2[2] = { 0xC7, 0x71 };
+ }
+
+ const UInt32 kRecord2Size = 26;
+ /*
+ struct CRecord2
+ {
+ unsigned short c_magic;
+ short c_dev;
+ unsigned short c_ino;
+ unsigned short c_mode;
+ unsigned short c_uid;
+ unsigned short c_gid;
+ unsigned short c_nlink;
+ short c_rdev;
+ unsigned short c_mtimes[2];
+ unsigned short c_namesize;
+ unsigned short c_filesizes[2];
+ };
+ */
+
+ const UInt32 kRecordSize = 110;
+ /*
+ struct CRecord
+ {
+ char Magic[6]; // "070701" for "new" portable format, "070702" for CRC format
+ char inode[8];
+ char Mode[8];
+ char UID[8];
+ char GID[8];
+ char nlink[8];
+ char mtime[8];
+ char Size[8]; // must be 0 for FIFOs and directories
+ char DevMajor[8];
+ char DevMinor[8];
+ char RDevMajor[8]; //only valid for chr and blk special files
+ char RDevMinor[8]; //only valid for chr and blk special files
+ char NameSize[8]; // count includes terminating NUL in pathname
+ char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file
+ bool CheckMagic() const
+ { return memcmp(Magic, NMagic::kMagic1, 6) == 0 ||
+ memcmp(Magic, NMagic::kMagic2, 6) == 0; };
+ };
+ */
+
+ const UInt32 kOctRecordSize = 76;
+
+}
+
+struct CItem
+{
+ AString Name;
+ UInt32 inode;
+ UInt32 Mode;
+ UInt32 UID;
+ UInt32 GID;
+ UInt32 Size;
+ UInt32 MTime;
+
+ // char LinkFlag;
+ // AString LinkName; ?????
+ char Magic[8];
+ UInt32 NumLinks;
+ UInt32 DevMajor;
+ UInt32 DevMinor;
+ UInt32 RDevMajor;
+ UInt32 RDevMinor;
+ UInt32 ChkSum;
+
+ UInt32 Align;
+
+ bool IsDir() const { return (Mode & 0170000) == 0040000; }
+};
+
+class CItemEx: public CItem
+{
+public:
+ UInt64 HeaderPosition;
+ UInt32 HeaderSize;
+ UInt64 GetDataPosition() const { return HeaderPosition + HeaderSize; };
+};
+
+const UInt32 kMaxBlockSize = NFileHeader::kRecordSize;
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+ UInt64 m_Position;
+
+ UInt16 _blockSize;
+ Byte _block[kMaxBlockSize];
+ UInt32 _blockPos;
+ Byte ReadByte();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+
+ bool ReadNumber(UInt32 &resultValue);
+ bool ReadOctNumber(int size, UInt32 &resultValue);
+
+ HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
+public:
+ HRESULT Open(IInStream *inStream);
+ HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
+ HRESULT Skip(UInt64 numBytes);
+ HRESULT SkipDataRecords(UInt64 dataSize, UInt32 align);
+};
+
+HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
+{
+ size_t realProcessedSize = size;
+ RINOK(ReadStream(m_Stream, data, &realProcessedSize));
+ processedSize = (UInt32)realProcessedSize;
+ m_Position += processedSize;
+ return S_OK;
+}
+
+Byte CInArchive::ReadByte()
+{
+ if (_blockPos >= _blockSize)
+ throw "Incorrect cpio archive";
+ return _block[_blockPos++];
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = ReadByte();
+ value |= (UInt16(b) << (8 * i));
+ }
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b = ReadByte();
+ value |= (UInt32(b) << (8 * i));
+ }
+ return value;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
+ m_Stream = inStream;
+ return S_OK;
+}
+
+bool CInArchive::ReadNumber(UInt32 &resultValue)
+{
+ resultValue = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ char c = char(ReadByte());
+ int d;
+ if (c >= '0' && c <= '9')
+ d = c - '0';
+ else if (c >= 'A' && c <= 'F')
+ d = 10 + c - 'A';
+ else if (c >= 'a' && c <= 'f')
+ d = 10 + c - 'a';
+ else
+ return false;
+ resultValue *= 0x10;
+ resultValue += d;
+ }
+ return true;
+}
+
+static bool OctalToNumber(const char *s, UInt64 &res)
+{
+ const char *end;
+ res = ConvertOctStringToUInt64(s, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool OctalToNumber32(const char *s, UInt32 &res)
+{
+ UInt64 res64;
+ if (!OctalToNumber(s, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+bool CInArchive::ReadOctNumber(int size, UInt32 &resultValue)
+{
+ char sz[32 + 4];
+ int i;
+ for (i = 0; i < size && i < 32; i++)
+ sz[i] = (char)ReadByte();
+ sz[i] = 0;
+ return OctalToNumber32(sz, resultValue);
+}
+
+#define GetFromHex(y) { if (!ReadNumber(y)) return S_FALSE; }
+#define GetFromOct6(y) { if (!ReadOctNumber(6, y)) return S_FALSE; }
+#define GetFromOct11(y) { if (!ReadOctNumber(11, y)) return S_FALSE; }
+
+static unsigned short ConvertValue(unsigned short value, bool convert)
+{
+ if (!convert)
+ return value;
+ return (unsigned short)((((unsigned short)(value & 0xFF)) << 8) | (value >> 8));
+}
+
+static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
+{
+ while ((size & (align - 1)) != 0)
+ size++;
+ return size;
+}
+
+
+HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
+{
+ filled = false;
+
+ UInt32 processedSize;
+ item.HeaderPosition = m_Position;
+
+ _blockSize = kMaxBlockSize;
+ RINOK(ReadBytes(_block, 2, processedSize));
+ if (processedSize != 2)
+ return S_FALSE;
+ _blockPos = 0;
+
+ UInt32 nameSize;
+
+ bool oldBE =
+ _block[0] == NFileHeader::NMagic::kMagicForRecord2[1] &&
+ _block[1] == NFileHeader::NMagic::kMagicForRecord2[0];
+
+ bool binMode = (_block[0] == NFileHeader::NMagic::kMagicForRecord2[0] &&
+ _block[1] == NFileHeader::NMagic::kMagicForRecord2[1]) ||
+ oldBE;
+
+ if (binMode)
+ {
+ RINOK(ReadBytes(_block + 2, NFileHeader::kRecord2Size - 2, processedSize));
+ if (processedSize != NFileHeader::kRecord2Size - 2)
+ return S_FALSE;
+ item.Align = 2;
+ _blockPos = 2;
+ item.DevMajor = 0;
+ item.DevMinor = ConvertValue(ReadUInt16(), oldBE);
+ item.inode = ConvertValue(ReadUInt16(), oldBE);
+ item.Mode = ConvertValue(ReadUInt16(), oldBE);
+ item.UID = ConvertValue(ReadUInt16(), oldBE);
+ item.GID = ConvertValue(ReadUInt16(), oldBE);
+ item.NumLinks = ConvertValue(ReadUInt16(), oldBE);
+ item.RDevMajor =0;
+ item.RDevMinor = ConvertValue(ReadUInt16(), oldBE);
+ UInt16 timeHigh = ConvertValue(ReadUInt16(), oldBE);
+ UInt16 timeLow = ConvertValue(ReadUInt16(), oldBE);
+ item.MTime = (UInt32(timeHigh) << 16) + timeLow;
+ nameSize = ConvertValue(ReadUInt16(), oldBE);
+ UInt16 sizeHigh = ConvertValue(ReadUInt16(), oldBE);
+ UInt16 sizeLow = ConvertValue(ReadUInt16(), oldBE);
+ item.Size = (UInt32(sizeHigh) << 16) + sizeLow;
+
+ item.ChkSum = 0;
+ item.HeaderSize = GetAlignedSize(
+ nameSize + NFileHeader::kRecord2Size, item.Align);
+ nameSize = item.HeaderSize - NFileHeader::kRecord2Size;
+ }
+ else
+ {
+ RINOK(ReadBytes(_block + 2, 4, processedSize));
+ if (processedSize != 4)
+ return S_FALSE;
+
+ bool magicOK =
+ memcmp(_block, NFileHeader::NMagic::kMagic1, 6) == 0 ||
+ memcmp(_block, NFileHeader::NMagic::kMagic2, 6) == 0;
+ _blockPos = 6;
+ if (magicOK)
+ {
+ RINOK(ReadBytes(_block + 6, NFileHeader::kRecordSize - 6, processedSize));
+ if (processedSize != NFileHeader::kRecordSize - 6)
+ return S_FALSE;
+ item.Align = 4;
+
+ GetFromHex(item.inode);
+ GetFromHex(item.Mode);
+ GetFromHex(item.UID);
+ GetFromHex(item.GID);
+ GetFromHex(item.NumLinks);
+ UInt32 mTime;
+ GetFromHex(mTime);
+ item.MTime = mTime;
+ GetFromHex(item.Size);
+ GetFromHex(item.DevMajor);
+ GetFromHex(item.DevMinor);
+ GetFromHex(item.RDevMajor);
+ GetFromHex(item.RDevMinor);
+ GetFromHex(nameSize);
+ GetFromHex(item.ChkSum);
+ item.HeaderSize = GetAlignedSize(
+ nameSize + NFileHeader::kRecordSize, item.Align);
+ nameSize = item.HeaderSize - NFileHeader::kRecordSize;
+ }
+ else
+ {
+ if (!memcmp(_block, NFileHeader::NMagic::kMagic3, 6) == 0)
+ return S_FALSE;
+ RINOK(ReadBytes(_block + 6, NFileHeader::kOctRecordSize - 6, processedSize));
+ if (processedSize != NFileHeader::kOctRecordSize - 6)
+ return S_FALSE;
+ item.Align = 1;
+ item.DevMajor = 0;
+ GetFromOct6(item.DevMinor);
+ GetFromOct6(item.inode);
+ GetFromOct6(item.Mode);
+ GetFromOct6(item.UID);
+ GetFromOct6(item.GID);
+ GetFromOct6(item.NumLinks);
+ item.RDevMajor = 0;
+ GetFromOct6(item.RDevMinor);
+ UInt32 mTime;
+ GetFromOct11(mTime);
+ item.MTime = mTime;
+ GetFromOct6(nameSize);
+ GetFromOct11(item.Size); // ?????
+ item.HeaderSize = GetAlignedSize(
+ nameSize + NFileHeader::kOctRecordSize, item.Align);
+ nameSize = item.HeaderSize - NFileHeader::kOctRecordSize;
+ }
+ }
+ if (nameSize == 0 || nameSize >= (1 << 27))
+ return E_FAIL;
+ RINOK(ReadBytes(item.Name.GetBuffer(nameSize), nameSize, processedSize));
+ if (processedSize != nameSize)
+ return E_FAIL;
+ item.Name.ReleaseBuffer();
+ if (strcmp(item.Name, NFileHeader::NMagic::kEndName) == 0)
+ return S_OK;
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CInArchive::Skip(UInt64 numBytes)
+{
+ UInt64 newPostion;
+ RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
+ m_Position += numBytes;
+ if (m_Position != newPostion)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT CInArchive::SkipDataRecords(UInt64 dataSize, UInt32 align)
+{
+ while ((dataSize & (align - 1)) != 0)
+ dataSize++;
+ return Skip(dataSize);
+}
+
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CObjectVector<CItemEx> _items;
+ CMyComPtr<IInStream> _stream;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+/*
+enum
+{
+ kpidinode = kpidUserDefined,
+ kpidiChkSum
+};
+*/
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidPosixAttrib, VT_UI4},
+ // { L"inode", kpidinode, VT_UI4}
+ // { L"CheckSum", kpidiChkSum, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ // try
+ {
+ CInArchive archive;
+
+ UInt64 endPos = 0;
+ bool needSetTotal = true;
+
+ if (callback != NULL)
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+
+ RINOK(archive.Open(stream));
+
+ _items.Clear();
+
+ for (;;)
+ {
+ CItemEx item;
+ bool filled;
+ HRESULT result = archive.GetNextItem(filled, item);
+ if (result == S_FALSE)
+ return S_FALSE;
+ if (result != S_OK)
+ return S_FALSE;
+ if (!filled)
+ break;
+ _items.Add(item);
+ archive.SkipDataRecords(item.Size, item.Align);
+ if (callback != NULL)
+ {
+ if (needSetTotal)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos));
+ needSetTotal = false;
+ }
+ if (_items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = item.HeaderPosition;
+ RINOK(callback->SetCompleted(&numFiles, &numBytes));
+ }
+ }
+ }
+ if (_items.Size() == 0)
+ return S_FALSE;
+
+ _stream = stream;
+ }
+ /*
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ */
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItemEx &item = _items[index];
+
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size;
+ break;
+ case kpidMTime:
+ {
+ if (item.MTime != 0)
+ {
+ FILETIME utc;
+ NWindows::NTime::UnixTimeToFileTime(item.MTime, utc);
+ prop = utc;
+ }
+ break;
+ }
+ case kpidPosixAttrib: prop = item.Mode; break;
+ /*
+ case kpidinode: prop = item.inode; break;
+ case kpidiChkSum: prop = item.ChkSum; break;
+ */
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItemEx &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ currentTotalSize += item.Size;
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItemEx &item = _items[index];
+ return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NCpio::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Cpio", L"cpio", 0, 0xED, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Cpio)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/CramfsHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/CramfsHandler.cpp
new file mode 100644
index 000000000..a55e3743d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/CramfsHandler.cpp
@@ -0,0 +1,644 @@
+// CramfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/Alloc.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+namespace NArchive {
+namespace NCramfs {
+
+#define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' }
+
+static const UInt32 kSignatureSize = 16;
+static const char kSignature[kSignatureSize] = SIGNATURE;
+
+static const UInt32 kArcSizeMax = (256 + 16) << 20;
+static const UInt32 kNumFilesMax = (1 << 19);
+static const unsigned kNumDirLevelsMax = (1 << 8);
+
+static const UInt32 kHeaderSize = 0x40;
+static const unsigned kHeaderNameSize = 16;
+static const UInt32 kNodeSize = 12;
+
+static const UInt32 kFlag_FsVer2 = (1 << 0);
+
+static const CUInt32PCharPair k_Flags[] =
+{
+ { 0, "Ver2" },
+ { 1, "SortedDirs" },
+ { 8, "Holes" },
+ { 9, "WrongSignature" },
+ { 10, "ShiftedRootOffset" }
+};
+
+static const unsigned kBlockSizeLog = 12;
+static const UInt32 kBlockSize = 1 << kBlockSizeLog;
+
+/*
+struct CNode
+{
+ UInt16 Mode;
+ UInt16 Uid;
+ UInt32 Size;
+ Byte Gid;
+ UInt32 NameLen;
+ UInt32 Offset;
+
+ void Parse(const Byte *p)
+ {
+ Mode = GetUi16(p);
+ Uid = GetUi16(p + 2);
+ Size = Get32(p + 4) & 0xFFFFFF;
+ Gid = p[7];
+ NameLen = p[8] & 0x3F;
+ Offset = Get32(p + 8) >> 6;
+ }
+};
+*/
+
+#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
+
+static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
+static bool IsDir(const Byte *p, bool be) { return (GetMode(p, be) & 0xF000) == 0x4000; }
+
+static UInt32 GetSize(const Byte *p, bool be)
+{
+ if (be)
+ return GetBe32(p + 4) >> 8;
+ else
+ return GetUi32(p + 4) & 0xFFFFFF;
+}
+
+static UInt32 GetNameLen(const Byte *p, bool be)
+{
+ if (be)
+ return (p[8] & 0xFC);
+ else
+ return (p[8] & 0x3F) << 2;
+}
+
+static UInt32 GetOffset(const Byte *p, bool be)
+{
+ if (be)
+ return (GetBe32(p + 8) & 0x03FFFFFF) << 2;
+ else
+ return GetUi32(p + 8) >> 6 << 2;
+}
+
+struct CItem
+{
+ UInt32 Offset;
+ int Parent;
+};
+
+struct CHeader
+{
+ bool be;
+ UInt32 Size;
+ UInt32 Flags;
+ // UInt32 Future;
+ UInt32 Crc;
+ // UInt32 Edition;
+ UInt32 NumBlocks;
+ UInt32 NumFiles;
+ char Name[kHeaderNameSize];
+
+ bool Parse(const Byte *p)
+ {
+ if (memcmp(p + 16, kSignature, kSignatureSize) != 0)
+ return false;
+ switch(GetUi32(p))
+ {
+ case 0x28CD3D45: be = false; break;
+ case 0x453DCD28: be = true; break;
+ default: return false;
+ }
+ Size = Get32(p + 4);
+ Flags = Get32(p + 8);
+ // Future = Get32(p + 0xC);
+ Crc = Get32(p + 0x20);
+ // Edition = Get32(p + 0x24);
+ NumBlocks = Get32(p + 0x28);
+ NumFiles = Get32(p + 0x2C);
+ memcpy(Name, p + 0x30, kHeaderNameSize);
+ return true;
+ }
+
+ bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; }
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CRecordVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ Byte *_data;
+ UInt32 _size;
+ UInt32 _headersSize;
+ AString _errorMessage;
+ CHeader _h;
+
+ // Current file
+
+ NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+ CMyComPtr<ICompressCoder> _zlibDecoder;
+
+ CBufInStream *_inStreamSpec;
+ CMyComPtr<ISequentialInStream> _inStream;
+
+ CBufPtrSeqOutStream *_outStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outStream;
+
+ UInt32 _curBlocksOffset;
+ UInt32 _curNumBlocks;
+
+ HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level);
+ HRESULT Open2(IInStream *inStream);
+ AString GetPath(int index) const;
+ bool GetPackSize(int index, UInt32 &res) const;
+ void Free();
+public:
+ CHandler(): _data(0) {}
+ ~CHandler() { Free(); }
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+};
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI4},
+ { NULL, kpidPackSize, VT_UI4},
+ { NULL, kpidPosixAttrib, VT_UI4}
+ // { NULL, kpidOffset, VT_UI4}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidName, VT_BSTR},
+ { NULL, kpidBigEndian, VT_BOOL},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI4},
+ { NULL, kpidHeadersSize, VT_UI4},
+ { NULL, kpidNumSubFiles, VT_UI4},
+ { NULL, kpidNumBlocks, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level)
+{
+ const Byte *p = _data + baseOffset;
+ bool be = _h.be;
+ if (!IsDir(p, be))
+ return S_OK;
+ UInt32 offset = GetOffset(p, be);
+ UInt32 size = GetSize(p, be);
+ if (offset == 0 && size == 0)
+ return S_OK;
+ UInt32 end = offset + size;
+ if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax)
+ return S_FALSE;
+ if (end > _headersSize)
+ _headersSize = end;
+
+ int startIndex = _items.Size();
+
+ while (size != 0)
+ {
+ if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax)
+ return S_FALSE;
+ CItem item;
+ item.Parent = parent;
+ item.Offset = offset;
+ _items.Add(item);
+ UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be);
+ if (size < nodeLen)
+ return S_FALSE;
+ offset += nodeLen;
+ size -= nodeLen;
+ }
+
+ int endIndex = _items.Size();
+ for (int i = startIndex; i < endIndex; i++)
+ {
+ RINOK(OpenDir(i, _items[i].Offset, level + 1));
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *inStream)
+{
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
+ if (!_h.Parse(buf))
+ return S_FALSE;
+ if (_h.IsVer2())
+ {
+ if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax)
+ return S_FALSE;
+ }
+ else
+ {
+ UInt64 size;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &size));
+ if (size > kArcSizeMax)
+ return S_FALSE;
+ _h.Size = (UInt32)size;
+ RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL));
+ }
+ _data = (Byte *)MidAlloc(_h.Size);
+ if (_data == 0)
+ return E_OUTOFMEMORY;
+ memcpy(_data, buf, kHeaderSize);
+ size_t processed = _h.Size - kHeaderSize;
+ RINOK(ReadStream(inStream, _data + kHeaderSize, &processed));
+ if (processed < kNodeSize)
+ return S_FALSE;
+ _size = kHeaderSize + (UInt32)processed;
+ if (_size != _h.Size)
+ _errorMessage = "Unexpected end of archive";
+ else
+ {
+ SetUi32(_data + 0x20, 0);
+ if (_h.IsVer2())
+ if (CrcCalc(_data, _h.Size) != _h.Crc)
+ _errorMessage = "CRC error";
+ }
+ if (_h.IsVer2())
+ _items.Reserve(_h.NumFiles - 1);
+ return OpenDir(-1, kHeaderSize, 0);
+}
+
+AString CHandler::GetPath(int index) const
+{
+ unsigned len = 0;
+ int indexMem = index;
+ do
+ {
+ const CItem &item = _items[index];
+ index = item.Parent;
+ const Byte *p = _data + item.Offset;
+ unsigned size = GetNameLen(p, _h.be);
+ p += kNodeSize;
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ len += i + 1;
+ }
+ while (index >= 0);
+ len--;
+
+ AString path;
+ char *dest = path.GetBuffer(len) + len;
+ index = indexMem;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ index = item.Parent;
+ const Byte *p = _data + item.Offset;
+ unsigned size = GetNameLen(p, _h.be);
+ p += kNodeSize;
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ dest -= i;
+ memcpy(dest, p, i);
+ if (index < 0)
+ break;
+ *(--dest) = CHAR_PATH_SEPARATOR;
+ }
+ path.ReleaseBuffer(len);
+ return path;
+}
+
+bool CHandler::GetPackSize(int index, UInt32 &res) const
+{
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+ bool be = _h.be;
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ return false;
+ UInt32 numBlocks = (GetSize(p, be) + kBlockSize - 1) >> kBlockSizeLog;
+ UInt32 start = offset + numBlocks * 4;
+ if (start > _size)
+ return false;
+ UInt32 end = Get32(_data + start - 4);
+ if (end < start)
+ return false;
+ res = end - start;
+ return true;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ RINOK(Open2(stream));
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::Free()
+{
+ MidFree(_data);
+ _data = 0;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _headersSize = 0;
+ _items.Clear();
+ _stream.Release();
+ _errorMessage.Empty();
+ Free();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidName:
+ {
+ char dest[kHeaderNameSize + 4];
+ memcpy(dest, _h.Name, kHeaderNameSize);
+ dest[kHeaderNameSize] = 0;
+ prop = dest;
+ break;
+ }
+ case kpidBigEndian: prop = _h.be; break;
+ case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
+ case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break;
+ case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break;
+ case kpidPhySize: if (_h.IsVer2()) prop = _h.Size; break;
+ case kpidHeadersSize: prop = _headersSize; break;
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+ bool be = _h.be;
+ bool isDir = IsDir(p, be);
+ switch(propID)
+ {
+ case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
+ case kpidIsDir: prop = isDir; break;
+ // case kpidOffset: prop = (UInt32)GetOffset(p, be); break;
+ case kpidSize: if (!isDir) prop = GetSize(p, be); break;
+ case kpidPackSize:
+ if (!isDir)
+ {
+ UInt32 size;
+ if (GetPackSize(index, size))
+ prop = size;
+ }
+ break;
+ case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CCramfsInStream: public CCachedInStream
+{
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+public:
+ CHandler *Handler;
+};
+
+HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ return Handler->ReadBlock(blockIndex, dest, blockSize);
+}
+
+HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ if (!_zlibDecoder)
+ {
+ _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+ _zlibDecoder = _zlibDecoderSpec;
+ }
+ if (!_inStream)
+ {
+ _inStreamSpec = new CBufInStream();
+ _inStream = _inStreamSpec;
+ }
+ if (!_outStream)
+ {
+ _outStreamSpec = new CBufPtrSeqOutStream();
+ _outStream = _outStreamSpec;
+ }
+ bool be = _h.be;
+ const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4);
+ UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4));
+ UInt32 end = Get32(p);
+ if (end < start || end > _size)
+ return S_FALSE;
+ UInt32 inSize = end - start;
+ _inStreamSpec->Init(_data + start, inSize);
+ _outStreamSpec->Init(dest, blockSize);
+ RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL));
+ return (_zlibDecoderSpec->GetInputProcessedSize() == inSize &&
+ _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ bool be = _h.be;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset;
+ if (!IsDir(p, be))
+ totalSize += GetSize(p, be);
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ const Byte *p = _data + item.Offset;
+
+ if (IsDir(p, be))
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ UInt32 curSize = GetSize(p, be);
+ totalSize += curSize;
+ UInt32 packSize;
+ if (GetPackSize(index, packSize))
+ totalPackSize += packSize;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ curSize = 0;
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ CMyComPtr<IInStream> inStream;
+ HRESULT hres = GetStream(index, &inSeqStream);
+ if (inSeqStream)
+ inSeqStream.QueryInterface(IID_IInStream, &inStream);
+ if (hres == E_OUTOFMEMORY)
+ return E_OUTOFMEMORY;
+ if (hres == S_FALSE || !inStream)
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres != S_OK && hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ if (copyCoderSpec->TotalSize == curSize && hres == S_OK)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+
+ bool be = _h.be;
+ if (IsDir(p, be))
+ return E_FAIL;
+
+ UInt32 size = GetSize(p, be);
+ UInt32 numBlocks = (size + kBlockSize - 1) >> kBlockSizeLog;
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ {
+ if (offset != 0)
+ return S_FALSE;
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Init(NULL, 0);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+
+ if (offset + numBlocks * 4 > _size)
+ return S_FALSE;
+ UInt32 prev = offset;
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt32 next = Get32(_data + offset + i * 4);
+ if (next < prev || next > _size)
+ return S_FALSE;
+ prev = next;
+ }
+
+ CCramfsInStream *streamSpec = new CCramfsInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ _curNumBlocks = numBlocks;
+ _curBlocksOffset = offset;
+ streamSpec->Handler = this;
+ if (!streamSpec->Alloc(kBlockSizeLog, 21 - kBlockSizeLog))
+ return E_OUTOFMEMORY;
+ streamSpec->Init(size);
+ *stream = streamTemp.Detach();
+
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NCramfs::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"CramFS", L"cramfs", 0, 0xD3, SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+
+REGISTER_ARC(Cramfs)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/DebHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/DebHandler.cpp
new file mode 100644
index 000000000..82d2cde88
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/DebHandler.cpp
@@ -0,0 +1,413 @@
+// DebHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NDeb {
+
+namespace NHeader
+{
+ const int kSignatureLen = 8;
+
+ const char *kSignature = "!<arch>\n";
+
+ const int kNameSize = 16;
+ const int kTimeSize = 12;
+ const int kModeSize = 8;
+ const int kSizeSize = 10;
+
+ /*
+ struct CHeader
+ {
+ char Name[kNameSize];
+ char MTime[kTimeSize];
+ char Number0[6];
+ char Number1[6];
+ char Mode[kModeSize];
+ char Size[kSizeSize];
+ char Quote;
+ char NewLine;
+ };
+ */
+ const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1;
+}
+
+struct CItem
+{
+ AString Name;
+ UInt64 Size;
+ UInt32 MTime;
+ UInt32 Mode;
+
+ UInt64 HeaderPos;
+ UInt64 GetDataPos() const { return HeaderPos + NHeader::kHeaderSize; };
+ // UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; };
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+
+ HRESULT GetNextItemReal(bool &filled, CItem &itemInfo);
+public:
+ UInt64 m_Position;
+ HRESULT Open(IInStream *inStream);
+ HRESULT GetNextItem(bool &filled, CItem &itemInfo);
+ HRESULT SkipData(UInt64 dataSize);
+};
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
+ char signature[NHeader::kSignatureLen];
+ RINOK(ReadStream_FALSE(inStream, signature, NHeader::kSignatureLen));
+ m_Position += NHeader::kSignatureLen;
+ if (memcmp(signature, NHeader::kSignature, NHeader::kSignatureLen) != 0)
+ return S_FALSE;
+ m_Stream = inStream;
+ return S_OK;
+}
+
+static void MyStrNCpy(char *dest, const char *src, int size)
+{
+ for (int i = 0; i < size; i++)
+ {
+ char c = src[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+}
+
+static bool OctalToNumber(const char *s, int size, UInt64 &res)
+{
+ char sz[32];
+ MyStrNCpy(sz, s, size);
+ sz[size] = 0;
+ const char *end;
+ int i;
+ for (i = 0; sz[i] == ' '; i++);
+ res = ConvertOctStringToUInt64(sz + i, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool OctalToNumber32(const char *s, int size, UInt32 &res)
+{
+ UInt64 res64;
+ if (!OctalToNumber(s, size, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+static bool DecimalToNumber(const char *s, int size, UInt64 &res)
+{
+ char sz[32];
+ MyStrNCpy(sz, s, size);
+ sz[size] = 0;
+ const char *end;
+ int i;
+ for (i = 0; sz[i] == ' '; i++);
+ res = ConvertStringToUInt64(sz + i, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool DecimalToNumber32(const char *s, int size, UInt32 &res)
+{
+ UInt64 res64;
+ if (!DecimalToNumber(s, size, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+
+HRESULT CInArchive::GetNextItemReal(bool &filled, CItem &item)
+{
+ filled = false;
+
+ char header[NHeader::kHeaderSize];
+ const char *cur = header;
+
+ size_t processedSize = sizeof(header);
+ item.HeaderPos = m_Position;
+ RINOK(ReadStream(m_Stream, header, &processedSize));
+ if (processedSize != sizeof(header))
+ return S_OK;
+ m_Position += processedSize;
+
+ char tempString[NHeader::kNameSize + 1];
+ MyStrNCpy(tempString, cur, NHeader::kNameSize);
+ cur += NHeader::kNameSize;
+ tempString[NHeader::kNameSize] = '\0';
+ item.Name = tempString;
+ item.Name.Trim();
+
+ for (int i = 0; i < item.Name.Length(); i++)
+ if (((Byte)item.Name[i]) < 0x20)
+ return S_FALSE;
+
+ RIF(DecimalToNumber32(cur, NHeader::kTimeSize, item.MTime));
+ cur += NHeader::kTimeSize;
+
+ cur += 6 + 6;
+
+ RIF(OctalToNumber32(cur, NHeader::kModeSize, item.Mode));
+ cur += NHeader::kModeSize;
+
+ RIF(DecimalToNumber(cur, NHeader::kSizeSize, item.Size));
+ cur += NHeader::kSizeSize;
+
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
+{
+ for (;;)
+ {
+ RINOK(GetNextItemReal(filled, item));
+ if (!filled)
+ return S_OK;
+ if (item.Name.Compare("debian-binary") != 0)
+ return S_OK;
+ if (item.Size != 4)
+ return S_OK;
+ SkipData(item.Size);
+ }
+}
+
+HRESULT CInArchive::SkipData(UInt64 dataSize)
+{
+ return m_Stream->Seek((dataSize + 1) & (~((UInt64)0x1)), STREAM_SEEK_CUR, &m_Position);
+}
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CObjectVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ Int32 _mainSubfile;
+ UInt64 _phySize;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidPhySize, VT_UI8}
+};
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ {
+ _mainSubfile = -1;
+ CInArchive archive;
+ if (archive.Open(stream) != S_OK)
+ return S_FALSE;
+ _items.Clear();
+
+ if (openArchiveCallback != NULL)
+ {
+ RINOK(openArchiveCallback->SetTotal(NULL, NULL));
+ UInt64 numFiles = _items.Size();
+ RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
+ }
+
+ for (;;)
+ {
+ CItem item;
+ bool filled;
+ HRESULT result = archive.GetNextItem(filled, item);
+ if (result == S_FALSE)
+ return S_FALSE;
+ if (result != S_OK)
+ return S_FALSE;
+ if (!filled)
+ break;
+ if (item.Name.Left(5) == "data.")
+ _mainSubfile = _items.Size();
+ _items.Add(item);
+ archive.SkipData(item.Size);
+ if (openArchiveCallback != NULL)
+ {
+ UInt64 numFiles = _items.Size();
+ RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
+ }
+ }
+ _stream = stream;
+ _phySize = archive.m_Position;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _items.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: prop = _phySize; break;
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+
+ switch(propID)
+ {
+ case kpidPath: prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = item.Size;
+ break;
+ case kpidMTime:
+ {
+ if (item.MTime != 0)
+ {
+ FILETIME fileTime;
+ NTime::UnixTimeToFileTime(item.MTime, fileTime);
+ prop = fileTime;
+ }
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ currentTotalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 };
+
+REGISTER_ARC(Deb)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/DeflateProps.cpp b/src/libs/7zip/win/CPP/7zip/Archive/DeflateProps.cpp
new file mode 100644
index 000000000..8498e0565
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/DeflateProps.cpp
@@ -0,0 +1,118 @@
+// DeflateProps.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/PropVariant.h"
+
+#include "Common/ParseProperties.h"
+
+#include "DeflateProps.h"
+
+namespace NArchive {
+
+static const UInt32 kAlgo1 = 0;
+static const UInt32 kAlgo5 = 1;
+
+static const UInt32 kPasses1 = 1;
+static const UInt32 kPasses7 = 3;
+static const UInt32 kPasses9 = 10;
+
+static const UInt32 kFb1 = 32;
+static const UInt32 kFb7 = 64;
+static const UInt32 kFb9 = 128;
+
+void CDeflateProps::Normalize()
+{
+ UInt32 level = Level;
+ if (level == 0xFFFFFFFF)
+ level = 5;
+
+ if (Algo == 0xFFFFFFFF)
+ Algo = (level >= 5 ?
+ kAlgo5 :
+ kAlgo1);
+
+ if (NumPasses == 0xFFFFFFFF)
+ NumPasses =
+ (level >= 9 ? kPasses9 :
+ (level >= 7 ? kPasses7 :
+ kPasses1));
+ if (Fb == 0xFFFFFFFF)
+ Fb =
+ (level >= 9 ? kFb9 :
+ (level >= 7 ? kFb7 :
+ kFb1));
+}
+
+HRESULT CDeflateProps::SetCoderProperties(ICompressSetCoderProperties *setCoderProperties)
+{
+ Normalize();
+
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ Algo,
+ NumPasses,
+ Fb,
+ Mc
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumPasses,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinderCycles
+ };
+ int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ if (!McDefined)
+ numProps--;
+ return setCoderProperties->SetCoderProperties(propIDs, props, numProps);
+}
+
+HRESULT CDeflateProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ Init();
+ for (int i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &prop = values[i];
+ if (name[0] == L'X')
+ {
+ UInt32 a = 9;
+ RINOK(ParsePropValue(name.Mid(1), prop, a));
+ Level = a;
+ }
+ else if (name.Left(1) == L"A")
+ {
+ UInt32 a = kAlgo5;
+ RINOK(ParsePropValue(name.Mid(1), prop, a));
+ Algo = a;
+ }
+ else if (name.Left(4) == L"PASS")
+ {
+ UInt32 a = kPasses9;
+ RINOK(ParsePropValue(name.Mid(4), prop, a));
+ NumPasses = a;
+ }
+ else if (name.Left(2) == L"FB")
+ {
+ UInt32 a = kFb9;
+ RINOK(ParsePropValue(name.Mid(2), prop, a));
+ Fb = a;
+ }
+ else if (name.Left(2) == L"MC")
+ {
+ UInt32 a = 0xFFFFFFFF;
+ RINOK(ParsePropValue(name.Mid(2), prop, a));
+ Mc = a;
+ McDefined = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/DeflateProps.h b/src/libs/7zip/win/CPP/7zip/Archive/DeflateProps.h
new file mode 100644
index 000000000..e05a9d4aa
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/DeflateProps.h
@@ -0,0 +1,35 @@
+// DeflateProps.h
+
+#ifndef __DEFLATE_PROPS_H
+#define __DEFLATE_PROPS_H
+
+#include "../ICoder.h"
+
+namespace NArchive {
+
+class CDeflateProps
+{
+ UInt32 Level;
+ UInt32 NumPasses;
+ UInt32 Fb;
+ UInt32 Algo;
+ UInt32 Mc;
+ bool McDefined;
+
+ void Init()
+ {
+ Level = NumPasses = Fb = Algo = Mc = 0xFFFFFFFF;
+ McDefined = false;
+ }
+ void Normalize();
+public:
+ CDeflateProps() { Init(); }
+ bool IsMaximum() const { return Algo > 0; }
+
+ HRESULT SetCoderProperties(ICompressSetCoderProperties *setCoderProperties);
+ HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/DllExports.cpp b/src/libs/7zip/win/CPP/7zip/Archive/DllExports.cpp
new file mode 100644
index 000000000..6c72dea71
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/DllExports.cpp
@@ -0,0 +1,47 @@
+// DLLExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/Types.h"
+
+#include "../../Windows/NtCheck.h"
+#include "../../Windows/PropVariant.h"
+
+#include "IArchive.h"
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+HINSTANCE g_hInstance;
+
+#define NT_CHECK_FAIL_ACTION return FALSE;
+
+extern "C"
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hInstance = hInstance;
+ NT_CHECK;
+ }
+ return TRUE;
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler,
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ return CreateArchiver(clsid, iid, outObject);
+}
+
+STDAPI SetLargePageMode()
+{
+ #if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+ SetLargePageSize();
+ #endif
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/DllExports2.cpp b/src/libs/7zip/win/CPP/7zip/Archive/DllExports2.cpp
new file mode 100644
index 000000000..ad14ff06a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/DllExports2.cpp
@@ -0,0 +1,74 @@
+// DLLExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+
+#if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+#include "../../../C/Alloc.h"
+#endif
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/NtCheck.h"
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#include "IArchive.h"
+
+HINSTANCE g_hInstance;
+
+#define NT_CHECK_FAIL_ACTION return FALSE;
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hInstance = (HINSTANCE)hInstance;
+ NT_CHECK;
+ }
+ return TRUE;
+}
+
+DEFINE_GUID(CLSID_CArchiveHandler,
+0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ // COM_TRY_BEGIN
+ *outObject = 0;
+ if (*iid == IID_ICompressCoder || *iid == IID_ICompressCoder2 || *iid == IID_ICompressFilter)
+ {
+ return CreateCoder(clsid, iid, outObject);
+ }
+ else
+ {
+ return CreateArchiver(clsid, iid, outObject);
+ }
+ // COM_TRY_END
+}
+
+STDAPI SetLargePageMode()
+{
+ #if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+ SetLargePageSize();
+ #endif
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp
new file mode 100644
index 000000000..5040d5182
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/DmgHandler.cpp
@@ -0,0 +1,918 @@
+// DmgHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyXml.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BZip2Decoder.h"
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+// #define DMG_SHOW_RAW
+
+// #include <stdio.h>
+#define PRF(x) // x
+
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+static int Base64ToByte(char c)
+{
+ if (c >= 'A' && c <= 'Z') return c - 'A';
+ if (c >= 'a' && c <= 'z') return c - 'a' + 26;
+ if (c >= '0' && c <= '9') return c - '0' + 52;
+ if (c == '+') return 62;
+ if (c == '/') return 63;
+ if (c == '=') return 0;
+ return -1;
+}
+
+static int Base64ToBin(Byte *dest, const char *src, int srcLen)
+{
+ int srcPos = 0;
+ int destPos = 0;
+ while (srcPos < srcLen)
+ {
+ Byte buf[4];
+ int filled = 0;
+ while (srcPos < srcLen)
+ {
+ int n = Base64ToByte(src[srcPos++]);
+ if (n >= 0)
+ {
+ buf[filled++] = (Byte)n;
+ if (filled == 4)
+ break;
+ }
+ }
+ if (filled >= 2) { if (dest) dest[destPos] = (buf[0] << 2) | (buf[1] >> 4); destPos++; }
+ if (filled >= 3) { if (dest) dest[destPos] = (buf[1] << 4) | (buf[2] >> 2); destPos++; }
+ if (filled >= 4) { if (dest) dest[destPos] = (buf[2] << 6) | (buf[3] ); destPos++; }
+ }
+ return destPos;
+}
+
+static UString GetSizeString(UInt64 value)
+{
+ wchar_t s[32];
+ wchar_t c;
+ if (value < (UInt64)20000) c = 0;
+ else if (value < ((UInt64)20000 << 10)) { value >>= 10; c = L'K'; }
+ else if (value < ((UInt64)20000 << 20)) { value >>= 20; c = L'M'; }
+ else { value >>= 30; c = L'G'; }
+ ConvertUInt64ToString(value, s);
+ int p = MyStringLen(s);
+ s[p++] = c;
+ s[p++] = L'\0';
+ return s;
+}
+
+namespace NArchive {
+namespace NDmg {
+
+struct CBlock
+{
+ UInt32 Type;
+ UInt64 UnpPos;
+ UInt64 UnpSize;
+ UInt64 PackPos;
+ UInt64 PackSize;
+
+ UInt64 GetNextPackOffset() const { return PackPos + PackSize; }
+};
+
+struct CFile
+{
+ CByteBuffer Raw;
+ UInt64 StartPos;
+ CRecordVector<CBlock> Blocks;
+ UInt64 GetUnpackSize() const
+ {
+ UInt64 size = 0;
+ for (int i = 0; i < Blocks.Size(); i++)
+ size += Blocks[i].UnpSize;
+ return size;
+ };
+ UInt64 GetPackSize() const
+ {
+ UInt64 size = 0;
+ for (int i = 0; i < Blocks.Size(); i++)
+ size += Blocks[i].PackSize;
+ return size;
+ };
+
+ AString Name;
+};
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+
+ AString _xml;
+ CObjectVector<CFile> _files;
+ CRecordVector<int> _fileIndices;
+
+ HRESULT Open2(IInStream *stream);
+ HRESULT Extract(IInStream *stream);
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+const UInt32 kXmlSizeMax = ((UInt32)1 << 31) - (1 << 14);
+
+enum
+{
+ METHOD_ZERO_0 = 0,
+ METHOD_COPY = 1,
+ METHOD_ZERO_2 = 2,
+ METHOD_ADC = 0x80000004,
+ METHOD_ZLIB = 0x80000005,
+ METHOD_BZIP2 = 0x80000006,
+ METHOD_DUMMY = 0x7FFFFFFE,
+ METHOD_END = 0xFFFFFFFF
+};
+
+struct CMethodStat
+{
+ UInt32 NumBlocks;
+ UInt64 PackSize;
+ UInt64 UnpSize;
+ CMethodStat(): NumBlocks(0), PackSize(0), UnpSize(0) {}
+};
+
+struct CMethods
+{
+ CRecordVector<CMethodStat> Stats;
+ CRecordVector<UInt32> Types;
+ void Update(const CFile &file);
+ UString GetString() const;
+};
+
+void CMethods::Update(const CFile &file)
+{
+ for (int i = 0; i < file.Blocks.Size(); i++)
+ {
+ const CBlock &b = file.Blocks[i];
+ int index = Types.FindInSorted(b.Type);
+ if (index < 0)
+ {
+ index = Types.AddToUniqueSorted(b.Type);
+ Stats.Insert(index, CMethodStat());
+ }
+ CMethodStat &m = Stats[index];
+ m.PackSize += b.PackSize;
+ m.UnpSize += b.UnpSize;
+ m.NumBlocks++;
+ }
+}
+
+UString CMethods::GetString() const
+{
+ UString res;
+ for (int i = 0; i < Types.Size(); i++)
+ {
+ if (i != 0)
+ res += L' ';
+ wchar_t buf[32];
+ const wchar_t *s;
+ const CMethodStat &m = Stats[i];
+ bool showPack = true;
+ UInt32 type = Types[i];
+ switch(type)
+ {
+ case METHOD_ZERO_0: s = L"zero0"; showPack = (m.PackSize != 0); break;
+ case METHOD_ZERO_2: s = L"zero2"; showPack = (m.PackSize != 0); break;
+ case METHOD_COPY: s = L"copy"; showPack = (m.UnpSize != m.PackSize); break;
+ case METHOD_ADC: s = L"adc"; break;
+ case METHOD_ZLIB: s = L"zlib"; break;
+ case METHOD_BZIP2: s = L"bzip2"; break;
+ default: ConvertUInt64ToString(type, buf); s = buf;
+ }
+ res += s;
+ if (m.NumBlocks != 1)
+ {
+ res += L'[';
+ ConvertUInt64ToString(m.NumBlocks, buf);
+ res += buf;
+ res += L']';
+ }
+ res += L'-';
+ res += GetSizeString(m.UnpSize);
+ if (showPack)
+ {
+ res += L'-';
+ res += GetSizeString(m.PackSize);
+ }
+ }
+ return res;
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidNumBlocks, VT_UI4}
+};
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ CMethods m;
+ for (int i = 0; i < _files.Size(); i++)
+ m.Update(_files[i]);
+ prop = m.GetString();
+ break;
+ }
+ case kpidNumBlocks:
+ {
+ UInt64 numBlocks = 0;
+ for (int i = 0; i < _files.Size(); i++)
+ numBlocks += _files[i].Blocks.Size();
+ prop = numBlocks;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+IMP_IInArchive_ArcProps
+
+static int FindKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag)
+{
+ for (int i = 0; i + 1 < item.SubItems.Size(); i++)
+ {
+ const CXmlItem &si = item.SubItems[i];
+ if (si.IsTagged("key") && si.GetSubString() == key && item.SubItems[i + 1].IsTagged(nextTag))
+ return i + 1;
+ }
+ return -1;
+}
+
+static AString GetStringFromKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag)
+{
+ int index = FindKeyPair(item, key, nextTag);
+ if (index >= 0)
+ return item.SubItems[index].GetSubString();
+ return AString();
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ const int HEADER_SIZE = 0x1E0;
+
+ UInt64 headerPos;
+ RINOK(stream->Seek(-HEADER_SIZE, STREAM_SEEK_END, &headerPos));
+ Byte buf[HEADER_SIZE];
+ RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE));
+ UInt64 address1 = Get64(buf + 0);
+ UInt64 address2 = Get64(buf + 0xB8);
+ UInt64 size64 = Get64(buf + 0xC0);
+ if (address1 != address2 || size64 >= kXmlSizeMax || size64 == 0 ||
+ address1 >= headerPos || address1 + size64 > headerPos)
+ return S_FALSE;
+ RINOK(stream->Seek(address1, STREAM_SEEK_SET, NULL));
+ size_t size = (size_t)size64;
+
+ char *ss = _xml.GetBuffer((int)size + 1);
+ RINOK(ReadStream_FALSE(stream, ss, size));
+ ss[size] = 0;
+ _xml.ReleaseBuffer();
+
+ CXml xml;
+ if (!xml.Parse(_xml))
+ return S_FALSE;
+ if (xml.Root.Name != "plist")
+ return S_FALSE;
+
+ int dictIndex = xml.Root.FindSubTag("dict");
+ if (dictIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &dictItem = xml.Root.SubItems[dictIndex];
+ int rfDictIndex = FindKeyPair(dictItem, "resource-fork", "dict");
+ if (rfDictIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &rfDictItem = dictItem.SubItems[rfDictIndex];
+ int arrIndex = FindKeyPair(rfDictItem, "blkx", "array");
+ if (arrIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex];
+
+ int i;
+ for (i = 0; i < arrItem.SubItems.Size(); i++)
+ {
+ const CXmlItem &item = arrItem.SubItems[i];
+ if (!item.IsTagged("dict"))
+ continue;
+
+ CFile file;
+ file.StartPos = 0;
+
+ int destLen;
+ {
+ AString dataString;
+ AString name = GetStringFromKeyPair(item, "Name", "string");
+ if (name.IsEmpty())
+ name = GetStringFromKeyPair(item, "CFName", "string");
+ file.Name = name;
+ dataString = GetStringFromKeyPair(item, "Data", "data");
+
+ destLen = Base64ToBin(NULL, dataString, dataString.Length());
+ file.Raw.SetCapacity(destLen);
+ Base64ToBin(file.Raw, dataString, dataString.Length());
+ }
+
+ if (destLen > 0xCC && Get32(file.Raw) == 0x6D697368)
+ {
+ PRF(printf("\n\n index = %d", _files.Size()));
+ const int kRecordSize = 40;
+ for (int offset = 0xCC; offset + kRecordSize <= destLen; offset += kRecordSize)
+ {
+ const Byte *p = (const Byte *)file.Raw + offset;
+ CBlock b;
+ b.Type = Get32(p);
+ if (b.Type == METHOD_END)
+ break;
+ if (b.Type == METHOD_DUMMY)
+ continue;
+
+ b.UnpPos = Get64(p + 0x08) << 9;
+ b.UnpSize = Get64(p + 0x10) << 9;
+ b.PackPos = Get64(p + 0x18);
+ b.PackSize = Get64(p + 0x20);
+
+ file.Blocks.Add(b);
+
+ PRF(printf("\nType=%8x m[1]=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x",
+ b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize));
+ }
+ }
+ int itemIndex = _files.Add(file);
+ if (file.Blocks.Size() > 0)
+ {
+ // if (file.Name.Find("HFS") >= 0)
+ _fileIndices.Add(itemIndex);
+ }
+ }
+
+ // PackPos for each new file is 0 in some DMG files. So we use additional StartPos
+
+ bool allStartAreZeros = true;
+ for (i = 0; i < _files.Size(); i++)
+ {
+ const CFile &file = _files[i];
+ if (!file.Blocks.IsEmpty() && file.Blocks[0].PackPos != 0)
+ allStartAreZeros = false;
+ }
+ UInt64 startPos = 0;
+ if (allStartAreZeros)
+ {
+ for (i = 0; i < _files.Size(); i++)
+ {
+ CFile &file = _files[i];
+ file.StartPos = startPos;
+ if (!file.Blocks.IsEmpty())
+ startPos += file.Blocks.Back().GetNextPackOffset();
+ }
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ if (Open2(stream) != S_OK)
+ return S_FALSE;
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _fileIndices.Clear();
+ _files.Clear();
+ _xml.Empty();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _fileIndices.Size()
+ #ifdef DMG_SHOW_RAW
+ + _files.Size() + 1;
+ #endif
+ ;
+ return S_OK;
+}
+
+#define RAW_PREFIX L"raw" WSTRING_PATH_SEPARATOR
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ #ifdef DMG_SHOW_RAW
+ if ((int)index == _fileIndices.Size())
+ {
+ switch(propID)
+ {
+ case kpidPath:
+ prop = RAW_PREFIX L"a.xml";
+ break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)_xml.Length();
+ break;
+ }
+ }
+ else if ((int)index > _fileIndices.Size())
+ {
+ int rawIndex = (int)index - (_fileIndices.Size() + 1);
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ wchar_t s[32] = RAW_PREFIX;
+ ConvertUInt64ToString(rawIndex, s + MyStringLen(s));
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)_files[rawIndex].Raw.GetCapacity();
+ break;
+ }
+ }
+ else
+ #endif
+ {
+ int itemIndex = _fileIndices[index];
+ const CFile &item = _files[itemIndex];
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ CMethods m;
+ m.Update(item);
+ UString resString = m.GetString();
+ if (!resString.IsEmpty())
+ prop = resString;
+ break;
+ }
+
+ // case kpidExtension: prop = L"hfs"; break;
+
+ case kpidPath:
+ {
+ // break;
+ UString name;
+ wchar_t s[32];
+ ConvertUInt64ToString(index, s);
+ name = s;
+ int num = 10;
+ int numDigits;
+ for (numDigits = 1; num < _fileIndices.Size(); numDigits++)
+ num *= 10;
+ while (name.Length() < numDigits)
+ name = L'0' + name;
+
+ AString subName;
+ int pos1 = item.Name.Find('(');
+ if (pos1 >= 0)
+ {
+ pos1++;
+ int pos2 = item.Name.Find(')', pos1);
+ if (pos2 >= 0)
+ {
+ subName = item.Name.Mid(pos1, pos2 - pos1);
+ pos1 = subName.Find(':');
+ if (pos1 >= 0)
+ subName = subName.Left(pos1);
+ }
+ }
+ subName.Trim();
+ if (!subName.IsEmpty())
+ {
+ if (subName == "Apple_HFS")
+ subName = "hfs";
+ else if (subName == "Apple_HFSX")
+ subName = "hfsx";
+ else if (subName == "Apple_Free")
+ subName = "free";
+ else if (subName == "DDM")
+ subName = "ddm";
+ UString name2;
+ ConvertUTF8ToUnicode(subName, name2);
+ name += L'.';
+ name += name2;
+ }
+ else
+ {
+ UString name2;
+ ConvertUTF8ToUnicode(item.Name, name2);
+ if (!name2.IsEmpty())
+ name += L" - ";
+ name += name2;
+ }
+ prop = name;
+ break;
+ }
+ case kpidComment:
+ {
+ UString name;
+ ConvertUTF8ToUnicode(item.Name, name);
+ prop = name;
+ break;
+ }
+
+ case kpidSize: prop = item.GetUnpackSize(); break;
+ case kpidPackSize: prop = item.GetPackSize(); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CAdcDecoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ CInBuffer m_InStream;
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InStream.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CAdcDecoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(CodeReal)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+};
+
+STDMETHODIMP CAdcDecoder::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ if (!m_OutWindowStream.Create(1 << 18))
+ return E_OUTOFMEMORY;
+ if (!m_InStream.Create(1 << 18))
+ return E_OUTOFMEMORY;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InStream.SetStream(inStream);
+ m_InStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ const UInt32 kStep = (1 << 20);
+ UInt64 nextLimit = kStep;
+
+ UInt64 pos = 0;
+ while (pos < *outSize)
+ {
+ if (pos > nextLimit && progress)
+ {
+ UInt64 packSize = m_InStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ nextLimit += kStep;
+ }
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ UInt64 rem = *outSize - pos;
+ if (b & 0x80)
+ {
+ unsigned num = (b & 0x7F) + 1;
+ if (num > rem)
+ return S_FALSE;
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ m_OutWindowStream.PutByte(b);
+ }
+ pos += num;
+ continue;
+ }
+ Byte b1;
+ if (!m_InStream.ReadByte(b1))
+ return S_FALSE;
+
+ UInt32 len, distance;
+
+ if (b & 0x40)
+ {
+ len = ((UInt32)b & 0x3F) + 4;
+ Byte b2;
+ if (!m_InStream.ReadByte(b2))
+ return S_FALSE;
+ distance = ((UInt32)b1 << 8) + b2;
+ }
+ else
+ {
+ b &= 0x3F;
+ len = ((UInt32)b >> 2) + 3;
+ distance = (((UInt32)b & 3) << 8) + b1;
+ }
+
+ if (distance >= pos || len > rem)
+ return S_FALSE;
+ m_OutWindowStream.CopyBlock(distance, len);
+ pos += len;
+ }
+ if (*inSize != m_InStream.GetProcessedSize())
+ return S_FALSE;
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CAdcDecoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _files.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ int index = (int)(allFilesMode ? i : indices[i]);
+ #ifdef DMG_SHOW_RAW
+ if (index == _fileIndices.Size())
+ totalSize += _xml.Length();
+ else if (index > _fileIndices.Size())
+ totalSize += _files[index - (_fileIndices.Size() + 1)].Raw.GetCapacity();
+ else
+ #endif
+ totalSize += _files[_fileIndices[index]].GetUnpackSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentPackTotal = 0;
+ UInt64 currentUnpTotal = 0;
+ UInt64 currentPackSize = 0;
+ UInt64 currentUnpSize = 0;
+
+ const UInt32 kZeroBufSize = (1 << 14);
+ CByteBuffer zeroBuf;
+ zeroBuf.SetCapacity(kZeroBufSize);
+ memset(zeroBuf, 0, kZeroBufSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+ CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ CAdcDecoder *adcCoderSpec = new CAdcDecoder();
+ CMyComPtr<ICompressCoder> adcCoder = adcCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
+ {
+ lps->InSize = currentPackTotal;
+ lps->OutSize = currentUnpTotal;
+ currentPackSize = 0;
+ currentUnpSize = 0;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ // const CItemEx &item = _files[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+
+ realOutStream.Release();
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ #ifdef DMG_SHOW_RAW
+ if (index > _fileIndices.Size())
+ {
+ const CByteBuffer &buf = _files[index - (_fileIndices.Size() + 1)].Raw;
+ outStreamSpec->Init(buf.GetCapacity());
+ RINOK(WriteStream(outStream, buf, buf.GetCapacity()));
+ currentPackSize = currentUnpSize = buf.GetCapacity();
+ }
+ else if (index == _fileIndices.Size())
+ {
+ outStreamSpec->Init(_xml.Length());
+ RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
+ currentPackSize = currentUnpSize = _xml.Length();
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[_fileIndices[index]];
+ currentPackSize = item.GetPackSize();
+ currentUnpSize = item.GetUnpackSize();
+
+ UInt64 unpPos = 0;
+ UInt64 packPos = 0;
+ {
+ for (int j = 0; j < item.Blocks.Size(); j++)
+ {
+ lps->InSize = currentPackTotal + packPos;
+ lps->OutSize = currentUnpTotal + unpPos;
+ RINOK(lps->SetCur());
+
+ const CBlock &block = item.Blocks[j];
+
+ packPos += block.PackSize;
+ if (block.UnpPos != unpPos)
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ RINOK(_inStream->Seek(item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(block.PackSize);
+ // UInt64 startSize = outStreamSpec->GetSize();
+ bool realMethod = true;
+ outStreamSpec->Init(block.UnpSize);
+ HRESULT res = S_OK;
+
+ switch(block.Type)
+ {
+ case METHOD_ZERO_0:
+ case METHOD_ZERO_2:
+ realMethod = false;
+ if (block.PackSize != 0)
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ break;
+
+ case METHOD_COPY:
+ if (block.UnpSize != block.PackSize)
+ {
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ break;
+ }
+ res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ break;
+
+ case METHOD_ADC:
+ {
+ res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress);
+ break;
+ }
+
+ case METHOD_ZLIB:
+ {
+ res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress);
+ break;
+ }
+
+ case METHOD_BZIP2:
+ {
+ res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress);
+ if (res == S_OK)
+ if (streamSpec->GetSize() != block.PackSize)
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ default:
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ break;
+ }
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ if (opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ unpPos += block.UnpSize;
+ if (!outStreamSpec->IsFinishedOK())
+ {
+ if (realMethod && opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+
+ while (outStreamSpec->GetRem() != 0)
+ {
+ UInt64 rem = outStreamSpec->GetRem();
+ UInt32 size = (UInt32)MyMin(rem, (UInt64)kZeroBufSize);
+ RINOK(WriteStream(outStream, zeroBuf, size));
+ }
+ }
+ }
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Dmg", L"dmg", 0, 0xE4, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Dmg)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ElfHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ElfHandler.cpp
new file mode 100644
index 000000000..c4ad78e9e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/ElfHandler.cpp
@@ -0,0 +1,534 @@
+// ElfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+static UInt16 Get16(const Byte *p, int be) { if (be) return GetBe16(p); return GetUi16(p); }
+static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
+static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NElf {
+
+#define ELF_CLASS_32 1
+#define ELF_CLASS_64 2
+
+#define ELF_DATA_2LSB 1
+#define ELF_DATA_2MSB 2
+
+#define NUM_SCAN_SECTIONS_MAX (1 << 6)
+
+struct CHeader
+{
+ bool Mode64;
+ bool Be;
+ Byte Os;
+ Byte AbiVer;
+
+ UInt16 Type;
+ UInt16 Machine;
+ // UInt32 Version;
+
+ // UInt64 EntryVa;
+ UInt64 ProgOffset;
+ UInt64 SectOffset;
+ UInt32 Flags;
+ UInt16 ElfHeaderSize;
+ UInt16 SegmentEntrySize;
+ UInt16 NumSegments;
+ UInt16 SectEntrySize;
+ UInt16 NumSections;
+ // UInt16 SectNameStringTableIndex;
+
+ bool Parse(const Byte *buf);
+
+ bool CheckSegmentEntrySize() const
+ {
+ return (Mode64 && SegmentEntrySize == 0x38) || (!Mode64 && SegmentEntrySize == 0x20);
+ };
+
+ UInt64 GetHeadersSize() const
+ { return ElfHeaderSize +
+ (UInt64)SegmentEntrySize * NumSegments +
+ (UInt64)SectEntrySize * NumSections; }
+
+};
+
+bool CHeader::Parse(const Byte *p)
+{
+ switch(p[4])
+ {
+ case ELF_CLASS_32: Mode64 = false; break;
+ case ELF_CLASS_64: Mode64 = true; break;
+ default: return false;
+ }
+ bool be;
+ switch(p[5])
+ {
+ case ELF_DATA_2LSB: be = false; break;
+ case ELF_DATA_2MSB: be = true; break;
+ default: return false;
+ }
+ Be = be;
+ if (p[6] != 1) // Version
+ return false;
+ Os = p[7];
+ AbiVer = p[8];
+ for (int i = 9; i < 16; i++)
+ if (p[i] != 0)
+ return false;
+
+ Type = Get16(p + 0x10, be);
+ Machine = Get16(p + 0x12, be);
+ if (Get32(p + 0x14, be) != 1) // Version
+ return false;
+
+ if (Mode64)
+ {
+ // EntryVa = Get64(p + 0x18, be);
+ ProgOffset = Get64(p + 0x20, be);
+ SectOffset = Get64(p + 0x28, be);
+ p += 0x30;
+ }
+ else
+ {
+ // EntryVa = Get32(p + 0x18, be);
+ ProgOffset = Get32(p + 0x1C, be);
+ SectOffset = Get32(p + 0x20, be);
+ p += 0x24;
+ }
+
+ Flags = Get32(p + 0, be);
+ ElfHeaderSize = Get16(p + 4, be);
+ SegmentEntrySize = Get16(p + 6, be);
+ NumSegments = Get16(p + 8, be);
+ SectEntrySize = Get16(p + 10, be);
+ NumSections = Get16(p + 12, be);
+ // SectNameStringTableIndex = Get16(p + 14, be);
+ return CheckSegmentEntrySize();
+}
+
+struct CSegment
+{
+ UInt32 Type;
+ UInt32 Flags;
+ UInt64 Offset;
+ UInt64 Va;
+ // UInt64 Pa;
+ UInt64 PSize;
+ UInt64 VSize;
+ // UInt64 Align;
+
+ void UpdateTotalSize(UInt64 &totalSize)
+ {
+ UInt64 t = Offset + PSize;
+ if (t > totalSize)
+ totalSize = t;
+ }
+ void Parse(const Byte *p, bool mode64, bool be);
+};
+
+void CSegment::Parse(const Byte *p, bool mode64, bool be)
+{
+ Type = Get32(p, be);
+ if (mode64)
+ {
+ Flags = Get32(p + 4, be);
+ Offset = Get64(p + 8, be);
+ Va = Get64(p + 0x10, be);
+ // Pa = Get64(p + 0x18, be);
+ PSize = Get64(p + 0x20, be);
+ VSize = Get64(p + 0x28, be);
+ // Align = Get64(p + 0x30, be);
+ }
+ else
+ {
+ Offset = Get32(p + 4, be);
+ Va = Get32(p + 8, be);
+ // Pa = Get32(p + 12, be);
+ PSize = Get32(p + 16, be);
+ VSize = Get32(p + 20, be);
+ Flags = Get32(p + 24, be);
+ // Align = Get32(p + 28, be);
+ }
+}
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { 0, "None" },
+ { 1, "AT&T WE 32100" },
+ { 2, "SPARC" },
+ { 3, "Intel 386" },
+ { 4, "Motorola 68000" },
+ { 5, "Motorola 88000" },
+ { 6, "Intel 486" },
+ { 7, "Intel i860" },
+ { 8, "MIPS" },
+ { 9, "IBM S/370" },
+ { 10, "MIPS RS3000 LE" },
+ { 11, "RS6000" },
+
+ { 15, "PA-RISC" },
+ { 16, "nCUBE" },
+ { 17, "Fujitsu VPP500" },
+ { 18, "SPARC 32+" },
+ { 19, "Intel i960" },
+ { 20, "PowerPC" },
+ { 21, "PowerPC 64-bit" },
+ { 22, "IBM S/390" },
+
+ { 36, "NEX v800" },
+ { 37, "Fujitsu FR20" },
+ { 38, "TRW RH-32" },
+ { 39, "Motorola RCE" },
+ { 40, "ARM" },
+ { 41, "Alpha" },
+ { 42, "Hitachi SH" },
+ { 43, "SPARC-V9" },
+ { 44, "Siemens Tricore" },
+ { 45, "ARC" },
+ { 46, "H8/300" },
+ { 47, "H8/300H" },
+ { 48, "H8S" },
+ { 49, "H8/500" },
+ { 50, "IA-64" },
+ { 51, "Stanford MIPS-X" },
+ { 52, "Motorola ColdFire" },
+ { 53, "M68HC12" },
+ { 54, "Fujitsu MMA" },
+ { 55, "Siemens PCP" },
+ { 56, "Sony nCPU" },
+ { 57, "Denso NDR1" },
+ { 58, "Motorola StarCore" },
+ { 59, "Toyota ME16" },
+ { 60, "ST100" },
+ { 61, "Advanced Logic TinyJ" },
+ { 62, "AMD64" },
+ { 63, "Sony DSP" },
+
+ { 66, "Siemens FX66" },
+ { 67, "ST9+" },
+ { 68, "ST7" },
+ { 69, "MC68HC16" },
+ { 70, "MC68HC11" },
+ { 71, "MC68HC08" },
+ { 72, "MC68HC05" },
+ { 73, "Silicon Graphics SVx" },
+ { 74, "ST19" },
+ { 75, "Digital VAX" },
+ { 76, "Axis CRIS" },
+ { 77, "Infineon JAVELIN" },
+ { 78, "Element 14 FirePath" },
+ { 79, "LSI ZSP" },
+ { 80, "MMIX" },
+ { 81, "HUANY" },
+ { 82, "SiTera Prism" },
+ { 83, "Atmel AVR" },
+ { 84, "Fujitsu FR30" },
+ { 85, "Mitsubishi D10V" },
+ { 86, "Mitsubishi D30V" },
+ { 87, "NEC v850" },
+ { 88, "Mitsubishi M32R" },
+ { 89, "Matsushita MN10300" },
+ { 90, "Matsushita MN10200" },
+ { 91, "picoJava" },
+ { 92, "OpenRISC" },
+ { 93, "ARC Tangent-A5" },
+ { 94, "Tensilica Xtensa" },
+ { 0x9026, "Alpha" }
+};
+
+static const CUInt32PCharPair g_AbiOS[] =
+{
+ { 0, "None" },
+ { 1, "HP-UX" },
+ { 2, "NetBSD" },
+ { 3, "Linux" },
+
+ { 6, "Solaris" },
+ { 7, "AIX" },
+ { 8, "IRIX" },
+ { 9, "FreeBSD" },
+ { 10, "TRU64" },
+ { 11, "Novell Modesto" },
+ { 12, "OpenBSD" },
+ { 13, "OpenVMS" },
+ { 14, "HP NSK" },
+ { 15, "AROS" },
+ { 97, "ARM" },
+ { 255, "Standalone" }
+};
+
+static const CUInt32PCharPair g_SegmentFlags[] =
+{
+ { 0, "Execute" },
+ { 1, "Write" },
+ { 2, "Read" }
+};
+
+static const char *g_Types[] =
+{
+ "None",
+ "Relocatable file",
+ "Executable file",
+ "Shared object file",
+ "Core file"
+};
+
+static const char *g_SegnmentTypes[] =
+{
+ "Unused",
+ "Loadable segment",
+ "Dynamic linking tables",
+ "Program interpreter path name",
+ "Note section",
+ "SHLIB",
+ "Program header table",
+ "TLS"
+};
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+ CObjectVector<CSegment> _sections;
+ UInt32 _peOffset;
+ CHeader _header;
+ UInt64 _totalSize;
+ HRESULT Open2(IInStream *stream);
+ bool Parse(const Byte *buf, UInt32 size);
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+#define ELF_PT_PHDR 6
+
+bool CHandler::Parse(const Byte *buf, UInt32 size)
+{
+ if (size < 64)
+ return false;
+ if (!_header.Parse(buf))
+ return false;
+ if (_header.ProgOffset > size ||
+ _header.ProgOffset + (UInt64)_header.SegmentEntrySize * _header.NumSegments > size ||
+ _header.NumSegments > NUM_SCAN_SECTIONS_MAX)
+ return false;
+ const Byte *p = buf + _header.ProgOffset;
+ _totalSize = _header.ProgOffset;
+
+ for (int i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize)
+ {
+ CSegment sect;
+ sect.Parse(p, _header.Mode64, _header.Be);
+ sect.UpdateTotalSize(_totalSize);
+ if (sect.Type != ELF_PT_PHDR)
+ _sections.Add(sect);
+ }
+ UInt64 total2 = _header.SectOffset + (UInt64)_header.SectEntrySize * _header.NumSections;
+ if (total2 > _totalSize)
+ _totalSize = total2;
+ return true;
+}
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCpu, VT_BSTR},
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidBigEndian, VT_BOOL},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8}
+ };
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidType, VT_BSTR},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidVa, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _header.GetHeadersSize(); break;
+ case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break;
+ case kpidBigEndian: if (_header.Be) prop = _header.Be; break;
+ case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
+ case kpidHostOS: PAIR_TO_PROP(g_AbiOS, _header.Os, prop); break;
+ case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CSegment &item = _sections[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ wchar_t sz[32];
+ ConvertUInt64ToString(index, sz);
+ prop = sz;
+ break;
+ }
+ case kpidSize: prop = (UInt64)item.VSize; break;
+ case kpidPackSize: prop = (UInt64)item.PSize; break;
+ case kpidOffset: prop = item.Offset; break;
+ case kpidVa: prop = item.Va; break;
+ case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break;
+ case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ const UInt32 kBufSize = 1 << 18;
+ const UInt32 kSigSize = 4;
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ size_t processed = kSigSize;
+ RINOK(ReadStream_FALSE(stream, buf, processed));
+ if (buf[0] != 0x7F || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F')
+ return S_FALSE;
+ processed = kBufSize - kSigSize;
+ RINOK(ReadStream(stream, buf + kSigSize, &processed));
+ processed += kSigSize;
+ if (!Parse(buf, (UInt32)processed))
+ return S_FALSE;
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ return (fileSize == _totalSize) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream));
+ _inStream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _sections.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _sections.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _sections.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _sections[allFilesMode ? i : indices[i]].PSize;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CSegment &item = _sections[index];
+ currentItemSize = item.PSize;
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(_inStream->Seek(item.Offset, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"ELF", L"", 0, 0xDE, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Elf)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp
new file mode 100644
index 000000000..1c374a444
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/FatHandler.cpp
@@ -0,0 +1,996 @@
+// FatHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/DummyOutStream.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+#define PRF(x) /* x */
+
+namespace NArchive {
+namespace NFat {
+
+static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31;
+
+struct CHeader
+{
+ UInt32 NumSectors;
+ UInt16 NumReservedSectors;
+ Byte NumFats;
+ UInt32 NumFatSectors;
+ UInt32 RootDirSector;
+ UInt32 NumRootDirSectors;
+ UInt32 DataSector;
+
+ UInt32 FatSize;
+ UInt32 BadCluster;
+
+ Byte NumFatBits;
+ Byte SectorSizeLog;
+ Byte SectorsPerClusterLog;
+ Byte ClusterSizeLog;
+
+ UInt16 SectorsPerTrack;
+ UInt16 NumHeads;
+ UInt32 NumHiddenSectors;
+
+ bool VolFieldsDefined;
+
+ UInt32 VolId;
+ // Byte VolName[11];
+ // Byte FileSys[8];
+
+ // Byte OemName[5];
+ Byte MediaType;
+
+ // 32-bit FAT
+ UInt16 Flags;
+ UInt16 FsInfoSector;
+ UInt32 RootCluster;
+
+ bool IsFat32() const { return NumFatBits == 32; }
+ UInt64 GetPhySize() const { return (UInt64)NumSectors << SectorSizeLog; }
+ UInt32 SectorSize() const { return (UInt32)1 << SectorSizeLog; }
+ UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
+ UInt32 ClusterToSector(UInt32 c) const { return DataSector + ((c - 2) << SectorsPerClusterLog); }
+ UInt32 IsEoc(UInt32 c) const { return c > BadCluster; }
+ UInt32 IsEocAndUnused(UInt32 c) const { return c > BadCluster && (c & kFatItemUsedByDirMask) == 0; }
+ UInt32 IsValidCluster(UInt32 c) const { return c >= 2 && c < FatSize; }
+ UInt32 SizeToSectors(UInt32 size) const { return (size + SectorSize() - 1) >> SectorSizeLog; }
+ UInt32 CalcFatSizeInSectors() const { return SizeToSectors((FatSize * (NumFatBits / 4) + 1) / 2); }
+
+ UInt32 GetFatSector() const
+ {
+ UInt32 index = (IsFat32() && (Flags & 0x80) != 0) ? (Flags & 0xF) : 0;
+ if (index > NumFats)
+ index = 0;
+ return NumReservedSectors + index * NumFatSectors;
+ }
+
+ UInt64 GetFilePackSize(UInt32 unpackSize) const
+ {
+ UInt64 mask = ClusterSize() - 1;
+ return (unpackSize + mask) & ~mask;
+ }
+
+ UInt32 GetNumClusters(UInt32 size) const
+ { return (UInt32)(((UInt64)size + ClusterSize() - 1) >> ClusterSizeLog); }
+
+ bool Parse(const Byte *p);
+};
+
+static int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+
+ int codeOffset = 0;
+ switch (p[0])
+ {
+ case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break;
+ case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break;
+ default: return false;
+ }
+ {
+ int s = GetLog(Get16(p + 11));
+ if (s < 9 || s > 12)
+ return false;
+ SectorSizeLog = (Byte)s;
+ s = GetLog(p[13]);
+ if (s < 0)
+ return false;
+ SectorsPerClusterLog = (Byte)s;
+ ClusterSizeLog = SectorSizeLog + SectorsPerClusterLog;
+ }
+
+ NumReservedSectors = Get16(p + 14);
+ if (NumReservedSectors == 0)
+ return false;
+
+ NumFats = p[16];
+ if (NumFats < 1 || NumFats > 4)
+ return false;
+
+ UInt16 numRootDirEntries = Get16(p + 17);
+ if (numRootDirEntries == 0)
+ {
+ if (codeOffset < 90)
+ return false;
+ NumFatBits = 32;
+ NumRootDirSectors = 0;
+ }
+ else
+ {
+ if (codeOffset < 62)
+ return false;
+ NumFatBits = 0;
+ UInt32 mask = (1 << (SectorSizeLog - 5)) - 1;
+ if ((numRootDirEntries & mask) != 0)
+ return false;
+ NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5);
+ }
+
+ NumSectors = Get16(p + 19);
+ if (NumSectors == 0)
+ NumSectors = Get32(p + 32);
+ else if (IsFat32())
+ return false;
+
+ MediaType = p[21];
+ NumFatSectors = Get16(p + 22);
+ SectorsPerTrack = Get16(p + 24);
+ NumHeads = Get16(p + 26);
+ NumHiddenSectors = Get32(p + 28);
+
+ // memcpy(OemName, p + 3, 5);
+
+ p += 36;
+ if (IsFat32())
+ {
+ if (NumFatSectors != 0)
+ return false;
+ NumFatSectors = Get32(p);
+ if (NumFatSectors >= (1 << 24))
+ return false;
+
+ Flags = Get16(p + 4);
+ if (Get16(p + 6) != 0)
+ return false;
+ RootCluster = Get32(p + 8);
+ FsInfoSector = Get16(p + 12);
+ for (int i = 16; i < 28; i++)
+ if (p[i] != 0)
+ return false;
+ p += 28;
+ }
+
+ // DriveNumber = p[0];
+ VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig
+ VolId = Get32(p + 3);
+ // memcpy(VolName, p + 7, 11);
+ // memcpy(FileSys, p + 18, 8);
+
+ if (NumFatSectors == 0)
+ return false;
+ RootDirSector = NumReservedSectors + NumFatSectors * NumFats;
+ DataSector = RootDirSector + NumRootDirSectors;
+ if (NumSectors < DataSector)
+ return false;
+ UInt32 numDataSectors = NumSectors - DataSector;
+ UInt32 numClusters = numDataSectors >> SectorsPerClusterLog;
+
+ BadCluster = 0x0FFFFFF7;
+ if (numClusters < 0xFFF5)
+ {
+ if (NumFatBits == 32)
+ return false;
+ NumFatBits = (numClusters < 0xFF5) ? 12: 16;
+ BadCluster &= ((1 << NumFatBits) - 1);
+ }
+ else if (NumFatBits != 32)
+ return false;
+
+ FatSize = numClusters + 2;
+ if (FatSize > BadCluster || CalcFatSizeInSectors() > NumFatSectors)
+ return false;
+ return true;
+}
+
+struct CItem
+{
+ UString UName;
+ char DosName[11];
+ Byte CTime2;
+ UInt32 CTime;
+ UInt32 MTime;
+ UInt16 ADate;
+ Byte Attrib;
+ Byte Flags;
+ UInt32 Size;
+ UInt32 Cluster;
+ Int32 Parent;
+
+ // NT uses Flags to store Low Case status
+ bool NameIsLow() const { return (Flags & 0x8) != 0; }
+ bool ExtIsLow() const { return (Flags & 0x10) != 0; }
+ bool IsDir() const { return (Attrib & 0x10) != 0; }
+ UString GetShortName() const;
+ UString GetName() const;
+ UString GetVolName() const;
+};
+
+static int CopyAndTrim(char *dest, const char *src, int size, bool toLower)
+{
+ int i;
+ memcpy(dest, src, size);
+ if (toLower)
+ for (i = 0; i < size; i++)
+ {
+ char c = dest[i];
+ if (c >= 'A' && c <= 'Z')
+ dest[i] = c + 0x20;
+ }
+ for (i = size - 1; i >= 0 && dest[i] == ' '; i--);
+ return i + 1;
+}
+
+static UString FatStringToUnicode(const char *s)
+{
+ return MultiByteToUnicodeString(s, CP_OEMCP);
+}
+
+UString CItem::GetShortName() const
+{
+ char s[16];
+ int i = CopyAndTrim(s, DosName, 8, NameIsLow());
+ s[i++] = '.';
+ int j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow());
+ if (j == 0)
+ j--;
+ s[i + j] = 0;
+ return FatStringToUnicode(s);
+}
+
+UString CItem::GetName() const
+{
+ if (!UName.IsEmpty())
+ return UName;
+ return GetShortName();
+}
+
+UString CItem::GetVolName() const
+{
+ if (!UName.IsEmpty())
+ return UName;
+ char s[12];
+ int i = CopyAndTrim(s, DosName, 11, false);
+ s[i] = 0;
+ return FatStringToUnicode(s);
+}
+
+struct CDatabase
+{
+ CHeader Header;
+ CObjectVector<CItem> Items;
+ UInt32 *Fat;
+ CMyComPtr<IInStream> InStream;
+ IArchiveOpenCallback *OpenCallback;
+
+ UInt32 NumFreeClusters;
+ bool VolItemDefined;
+ CItem VolItem;
+ UInt32 NumDirClusters;
+ CByteBuffer ByteBuf;
+ UInt64 NumCurUsedBytes;
+
+ CDatabase(): Fat(0) {}
+ ~CDatabase() { ClearAndClose(); }
+
+ void Clear();
+ void ClearAndClose();
+ HRESULT OpenProgressFat(bool changeTotal = true);
+ HRESULT OpenProgress();
+
+ UString GetItemPath(Int32 index) const;
+ HRESULT Open();
+ HRESULT ReadDir(Int32 parent, UInt32 cluster, int level);
+
+ UInt64 GetHeadersSize() const
+ {
+ return (UInt64)(Header.DataSector + (NumDirClusters << Header.SectorsPerClusterLog)) << Header.SectorSizeLog;
+ }
+ HRESULT SeekToSector(UInt32 sector);
+ HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); }
+};
+
+HRESULT CDatabase::SeekToSector(UInt32 sector)
+{
+ return InStream->Seek((UInt64)sector << Header.SectorSizeLog, STREAM_SEEK_SET, NULL);
+}
+
+void CDatabase::Clear()
+{
+ VolItemDefined = false;
+ NumDirClusters = 0;
+ NumCurUsedBytes = 0;
+
+ Items.Clear();
+ delete []Fat;
+ Fat = 0;
+}
+
+void CDatabase::ClearAndClose()
+{
+ Clear();
+ InStream.Release();
+}
+
+HRESULT CDatabase::OpenProgressFat(bool changeTotal)
+{
+ if (!OpenCallback)
+ return S_OK;
+ if (changeTotal)
+ {
+ UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) +
+ ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog);
+ RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes));
+ }
+ return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes);
+}
+
+HRESULT CDatabase::OpenProgress()
+{
+ if (!OpenCallback)
+ return S_OK;
+ UInt64 numItems = Items.Size();
+ return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes);
+}
+
+UString CDatabase::GetItemPath(Int32 index) const
+{
+ const CItem *item = &Items[index];
+ UString name = item->GetName();
+ for (;;)
+ {
+ index = item->Parent;
+ if (index < 0)
+ return name;
+ item = &Items[index];
+ name = item->GetName() + WCHAR_PATH_SEPARATOR + name;
+ }
+}
+
+static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, int numChars)
+{
+ for (int i = 0; i < numChars; i++)
+ {
+ wchar_t c = Get16(p + i * 2);
+ if (c != 0 && c != 0xFFFF)
+ *dest++ = c;
+ }
+ *dest = 0;
+ return dest;
+}
+
+HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level)
+{
+ int startIndex = Items.Size();
+ if (startIndex >= (1 << 30) || level > 256)
+ return S_FALSE;
+
+ UInt32 sectorIndex = 0;
+ UInt32 blockSize = Header.ClusterSize();
+ bool clusterMode = (Header.IsFat32() || parent >= 0);
+ if (!clusterMode)
+ {
+ blockSize = Header.SectorSize();
+ RINOK(SeekToSector(Header.RootDirSector));
+ }
+
+ ByteBuf.SetCapacity(blockSize);
+ UString curName;
+ int checkSum = -1;
+ int numLongRecords = -1;
+ for (UInt32 pos = blockSize;; pos += 32)
+ {
+ if (pos == blockSize)
+ {
+ pos = 0;
+
+ if ((NumDirClusters & 0xFF) == 0)
+ {
+ RINOK(OpenProgress());
+ }
+
+ if (clusterMode)
+ {
+ if (Header.IsEoc(cluster))
+ break;
+ if (!Header.IsValidCluster(cluster))
+ return S_FALSE;
+ PRF(printf("\nCluster = %4X", cluster));
+ RINOK(SeekToCluster(cluster));
+ UInt32 newCluster = Fat[cluster];
+ if ((newCluster & kFatItemUsedByDirMask) != 0)
+ return S_FALSE;
+ Fat[cluster] |= kFatItemUsedByDirMask;
+ cluster = newCluster;
+ NumDirClusters++;
+ NumCurUsedBytes += Header.ClusterSize();
+ }
+ else if (sectorIndex++ >= Header.NumRootDirSectors)
+ break;
+
+ RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize));
+ }
+ const Byte *p = ByteBuf + pos;
+ if (p[0] == 0)
+ {
+ /*
+ // FreeDOS formats FAT partition with cluster chain longer than required.
+ if (clusterMode && !Header.IsEoc(cluster))
+ return S_FALSE;
+ */
+ break;
+ }
+ if (p[0] == 0xE5)
+ {
+ if (numLongRecords > 0)
+ return S_FALSE;
+ continue;
+ }
+
+ Byte attrib = p[11];
+ if ((attrib & 0x3F) == 0xF)
+ {
+ if (p[0] > 0x7F || Get16(p + 26) != 0)
+ return S_FALSE;
+ int longIndex = p[0] & 0x3F;
+ if (longIndex == 0)
+ return S_FALSE;
+ bool isLast = (p[0] & 0x40) != 0;
+ if (numLongRecords < 0)
+ {
+ if (!isLast)
+ return S_FALSE;
+ numLongRecords = longIndex;
+ }
+ else if (isLast || numLongRecords != longIndex)
+ return S_FALSE;
+
+ numLongRecords--;
+
+ if (p[12] == 0)
+ {
+ wchar_t nameBuf[14];
+ wchar_t *dest;
+
+ dest = AddSubStringToName(nameBuf, p + 1, 5);
+ dest = AddSubStringToName(dest, p + 14, 6);
+ AddSubStringToName(dest, p + 28, 2);
+ curName = nameBuf + curName;
+ if (isLast)
+ checkSum = p[13];
+ if (checkSum != p[13])
+ return S_FALSE;
+ }
+ }
+ else
+ {
+ if (numLongRecords > 0)
+ return S_FALSE;
+ CItem item;
+ memcpy(item.DosName, p, 11);
+
+ if (checkSum >= 0)
+ {
+ Byte sum = 0;
+ for (int i = 0; i < 11; i++)
+ sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i];
+ if (sum == checkSum)
+ item.UName = curName;
+ }
+
+ if (item.DosName[0] == 5)
+ item.DosName[0] = (char)(Byte)0xE5;
+ item.Attrib = attrib;
+ item.Flags = p[12];
+ item.Size = Get32(p + 28);
+ item.Cluster = Get16(p + 26);
+ if (Header.NumFatBits > 16)
+ item.Cluster |= ((UInt32)Get16(p + 20) << 16);
+ else
+ {
+ // OS/2 and WinNT probably can store EA (extended atributes) in that field.
+ }
+
+ item.CTime = Get32(p + 14);
+ item.CTime2 = p[13];
+ item.ADate = Get16(p + 18);
+ item.MTime = Get32(p + 22);
+ item.Parent = parent;
+
+ if (attrib == 8)
+ {
+ VolItem = item;
+ VolItemDefined = true;
+ }
+ else
+ if (memcmp(item.DosName, ". ", 11) != 0 &&
+ memcmp(item.DosName, ".. ", 11) != 0)
+ {
+ if (!item.IsDir())
+ NumCurUsedBytes += Header.GetFilePackSize(item.Size);
+ Items.Add(item);
+ PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1)));
+ }
+ numLongRecords = -1;
+ curName.Empty();
+ checkSum = -1;
+ }
+ }
+
+ int finishIndex = Items.Size();
+ for (int i = startIndex; i < finishIndex; i++)
+ {
+ const CItem &item = Items[i];
+ if (item.IsDir())
+ {
+ PRF(printf("\n%S", GetItemPath(i)));
+ RINOK(CDatabase::ReadDir(i, item.Cluster, level + 1));
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CDatabase::Open()
+{
+ Clear();
+ bool numFreeClustersDefined = false;
+ {
+ static const UInt32 kHeaderSize = 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
+ if (!Header.Parse(buf))
+ return S_FALSE;
+ UInt64 fileSize;
+ RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize));
+
+ /* we comment that check to support truncated images */
+ /*
+ if (fileSize < Header.GetPhySize())
+ return S_FALSE;
+ */
+
+ if (Header.IsFat32())
+ {
+ SeekToSector(Header.FsInfoSector);
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
+ if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+ return S_FALSE;
+ if (Get32(buf) == 0x41615252 && Get32(buf + 484) == 0x61417272)
+ {
+ NumFreeClusters = Get32(buf + 488);
+ numFreeClustersDefined = (NumFreeClusters <= Header.FatSize);
+ }
+ }
+ }
+
+ // numFreeClustersDefined = false; // to recalculate NumFreeClusters
+ if (!numFreeClustersDefined)
+ NumFreeClusters = 0;
+
+ CByteBuffer byteBuf;
+ Fat = new UInt32[Header.FatSize];
+
+ RINOK(OpenProgressFat());
+ RINOK(SeekToSector(Header.GetFatSector()));
+ if (Header.NumFatBits == 32)
+ {
+ const UInt32 kBufSize = (1 << 15);
+ byteBuf.SetCapacity(kBufSize);
+ for (UInt32 i = 0; i < Header.FatSize;)
+ {
+ UInt32 size = Header.FatSize - i;
+ const UInt32 kBufSize32 = kBufSize / 4;
+ if (size > kBufSize32)
+ size = kBufSize32;
+ UInt32 readSize = Header.SizeToSectors(size * 4) << Header.SectorSizeLog;
+ RINOK(ReadStream_FALSE(InStream, byteBuf, readSize));
+ NumCurUsedBytes += readSize;
+
+ const UInt32 *src = (const UInt32 *)(const Byte *)byteBuf;
+ UInt32 *dest = Fat + i;
+ if (numFreeClustersDefined)
+ for (UInt32 j = 0; j < size; j++)
+ dest[j] = Get32(src + j) & 0x0FFFFFFF;
+ else
+ {
+ UInt32 numFreeClusters = 0;
+ for (UInt32 j = 0; j < size; j++)
+ {
+ UInt32 v = Get32(src + j) & 0x0FFFFFFF;
+ numFreeClusters += (UInt32)(v - 1) >> 31;
+ dest[j] = v;
+ }
+ NumFreeClusters += numFreeClusters;
+ }
+ i += size;
+ if ((i & 0xFFFFF) == 0)
+ {
+ RINOK(OpenProgressFat(!numFreeClustersDefined));
+ }
+ }
+ }
+ else
+ {
+ const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog;
+ NumCurUsedBytes += kBufSize;
+ byteBuf.SetCapacity(kBufSize);
+ Byte *p = byteBuf;
+ RINOK(ReadStream_FALSE(InStream, p, kBufSize));
+ UInt32 fatSize = Header.FatSize;
+ UInt32 *fat = &Fat[0];
+ if (Header.NumFatBits == 16)
+ for (UInt32 j = 0; j < fatSize; j++)
+ fat[j] = Get16(p + j * 2);
+ else
+ for (UInt32 j = 0; j < fatSize; j++)
+ fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF;
+
+ if (!numFreeClustersDefined)
+ {
+ UInt32 numFreeClusters = 0;
+ for (UInt32 i = 0; i < fatSize; i++)
+ numFreeClusters += (UInt32)(fat[i] - 1) >> 31;
+ NumFreeClusters = numFreeClusters;
+ }
+ }
+
+ RINOK(OpenProgressFat());
+
+ if ((Fat[0] & 0xFF) != Header.MediaType)
+ return S_FALSE;
+
+ return ReadDir(-1, Header.RootCluster, 0);
+}
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ CDatabase
+{
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ const CItem &item = Items[index];
+ CClusterInStream *streamSpec = new CClusterInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Stream = InStream;
+ streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog;
+ streamSpec->BlockSizeLog = Header.ClusterSizeLog;
+ streamSpec->Size = item.Size;
+
+ UInt32 numClusters = Header.GetNumClusters(item.Size);
+ streamSpec->Vector.Reserve(numClusters);
+ UInt32 cluster = item.Cluster;
+ UInt32 size = item.Size;
+
+ if (size == 0)
+ {
+ if (cluster != 0)
+ return S_FALSE;
+ }
+ else
+ {
+ UInt32 clusterSize = Header.ClusterSize();
+ for (;; size -= clusterSize)
+ {
+ if (!Header.IsValidCluster(cluster))
+ return S_FALSE;
+ streamSpec->Vector.Add(cluster - 2);
+ cluster = Fat[cluster];
+ if (size <= clusterSize)
+ break;
+ }
+ if (!Header.IsEocAndUnused(cluster))
+ return S_FALSE;
+ }
+ RINOK(streamSpec->InitAndSeek());
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI8},
+ { NULL, kpidShortName, VT_BSTR}
+};
+
+enum
+{
+ kpidNumFats = kpidUserDefined
+ // kpidOemName,
+ // kpidVolName,
+ // kpidFileSysType
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidFreeSpace, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidVolumeName, VT_BSTR},
+
+ { L"FATs", kpidNumFats, VT_UI4},
+ { NULL, kpidSectorSize, VT_UI4},
+ { NULL, kpidId, VT_UI4},
+ // { L"OEM Name", kpidOemName, VT_BSTR},
+ // { L"Volume Name", kpidVolName, VT_BSTR},
+ // { L"File System Type", kpidFileSysType, VT_BSTR}
+ // { NULL, kpidSectorsPerTrack, VT_UI4},
+ // { NULL, kpidNumHeads, VT_UI4},
+ // { NULL, kpidHiddenSectors, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME localFileTime, utc;
+ if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime))
+ if (LocalFileTimeToFileTime(&localFileTime, &utc))
+ {
+ UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
+ t64 += ms10 * 100000;
+ utc.dwLowDateTime = (DWORD)t64;
+ utc.dwHighDateTime = (DWORD)(t64 >> 32);
+ prop = utc;
+ }
+}
+
+/*
+static void StringToProp(const Byte *src, int size, NWindows::NCOM::CPropVariant &prop)
+{
+ char dest[32];
+ memcpy(dest, src, size);
+ dest[size] = 0;
+ prop = FatStringToUnicode(dest);
+}
+
+#define STRING_TO_PROP(s, p) StringToProp(s, sizeof(s), prop)
+*/
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidFileSystem:
+ {
+ wchar_t s[32] = { L'F', L'A', L'T' };
+ ConvertUInt32ToString(Header.NumFatBits, s + 3);
+ prop = s;
+ break;
+ }
+ case kpidClusterSize: prop = Header.ClusterSize(); break;
+ case kpidPhySize: prop = Header.GetPhySize(); break;
+ case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
+ case kpidHeadersSize: prop = GetHeadersSize(); break;
+ case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break;
+ case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
+ case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
+ case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
+ // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
+ // case kpidNumHeads: prop = Header.NumHeads; break;
+ // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break;
+ case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break;
+ // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break;
+ // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break;
+ // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = Items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = GetItemPath(index); break;
+ case kpidShortName: prop = item.GetShortName(); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break;
+ case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
+ case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break;
+ case kpidAttrib: prop = (UInt32)item.Attrib; break;
+ case kpidSize: if (!item.IsDir()) prop = item.Size; break;
+ case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ OpenCallback = callback;
+ InStream = stream;
+ HRESULT res;
+ try
+ {
+ res = CDatabase::Open();
+ if (res == S_OK)
+ return S_OK;
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ Close();
+ return res;
+ }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ ClearAndClose();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = Items[allFilesMode ? i : indices[i]];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = Items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ totalPackSize += Header.GetFilePackSize(item.Size);
+ totalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init();
+
+ int res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(index, &inStream);
+ if (hres != S_FALSE)
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize == item.Size)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = Items.Size();
+ return S_OK;
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"FAT", L"fat img", 0, 0xDA, { 0x55, 0xAA }, 2, false, CreateArc, 0 };
+
+REGISTER_ARC(Fat)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/FlvHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/FlvHandler.cpp
new file mode 100644
index 000000000..a22c29e30
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/FlvHandler.cpp
@@ -0,0 +1,544 @@
+// FlvHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+// #include "Common/Defs.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#define GetBe24(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 16) | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((const Byte *)(p))[2] )
+
+#define Get16(p) GetBe16(p)
+#define Get24(p) GetBe24(p)
+#define Get32(p) GetBe32(p)
+
+namespace NArchive {
+namespace NFlv {
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 30;
+static const int kNumChunksMax = (UInt32)1 << 23;
+
+const UInt32 kTagHeaderSize = 11;
+
+static const Byte kFlag_Video = 1;
+static const Byte kFlag_Audio = 4;
+
+static const Byte kType_Audio = 8;
+static const Byte kType_Video = 9;
+static const Byte kType_Meta = 18;
+static const int kNumTypes = 19;
+
+struct CItem
+{
+ UInt32 Offset;
+ UInt32 Size;
+ // UInt32 Time;
+ Byte Type;
+};
+
+struct CItem2
+{
+ Byte Type;
+ Byte SubType;
+ Byte Props;
+ bool SameSubTypes;
+ int NumChunks;
+ size_t Size;
+
+ CReferenceBuf *BufSpec;
+ CMyComPtr<IUnknown> RefBuf;
+
+ bool IsAudio() const { return Type == kType_Audio; }
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ int _isRaw;
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CItem2> _items2;
+ // CByteBuffer _metadata;
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ AString GetComment();
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidNumBlocks, VT_UI4},
+ { NULL, kpidComment, VT_BSTR}
+};
+
+/*
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidComment, VT_BSTR}
+};
+*/
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+static const char *g_AudioTypes[16] =
+{
+ "pcm",
+ "adpcm",
+ "mp3",
+ "pcm_le",
+ "nellymoser16",
+ "nellymoser8",
+ "nellymoser",
+ "g711a",
+ "g711m",
+ "audio9",
+ "aac",
+ "speex",
+ "audio12",
+ "audio13",
+ "mp3",
+ "audio15"
+};
+
+static const char *g_VideoTypes[16] =
+{
+ "video0",
+ "jpeg",
+ "h263",
+ "screen",
+ "vp6",
+ "vp6alpha",
+ "screen2",
+ "avc",
+ "video8",
+ "video9",
+ "video10",
+ "video11",
+ "video12",
+ "video13",
+ "video14",
+ "video15"
+};
+
+static const char *g_Rates[4] =
+{
+ "5.5 kHz",
+ "11 kHz",
+ "22 kHz",
+ "44 kHz"
+};
+
+static void MyStrCat(char *d, const char *s)
+{
+ MyStringCopy(d + MyStringLen(d), s);
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ const CItem2 &item = _items2[index];
+ switch(propID)
+ {
+ case kpidExtension:
+ prop = _isRaw ?
+ (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) :
+ (item.IsAudio() ? "audio.flv" : "video.flv");
+ break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size;
+ break;
+ case kpidNumBlocks: prop = (UInt32)item.NumChunks; break;
+ case kpidComment:
+ {
+ char sz[64];
+ MyStringCopy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) );
+ if (item.IsAudio())
+ {
+ MyStrCat(sz, " ");
+ MyStrCat(sz, g_Rates[(item.Props >> 2) & 3]);
+ MyStrCat(sz, (item.Props & 2) ? " 16-bit" : " 8-bit");
+ MyStrCat(sz, (item.Props & 1) ? " stereo" : " mono");
+ }
+ prop = sz;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+/*
+AString CHandler::GetComment()
+{
+ const Byte *p = _metadata;
+ size_t size = _metadata.GetCapacity();
+ AString res;
+ if (size > 0)
+ {
+ p++;
+ size--;
+ for (;;)
+ {
+ if (size < 2)
+ break;
+ int len = Get16(p);
+ p += 2;
+ size -= 2;
+ if (len == 0 || (size_t)len > size)
+ break;
+ {
+ AString temp;
+ char *sz = temp.GetBuffer(len);
+ memcpy(sz, p, len);
+ sz[len] = 0;
+ temp.ReleaseBuffer();
+ if (!res.IsEmpty())
+ res += '\n';
+ res += temp;
+ }
+ p += len;
+ size -= len;
+ if (size < 1)
+ break;
+ Byte type = *p++;
+ size--;
+ bool ok = false;
+ switch(type)
+ {
+ case 0:
+ {
+ if (size < 8)
+ break;
+ ok = true;
+ Byte reverse[8];
+ for (int i = 0; i < 8; i++)
+ {
+ bool little_endian = 1;
+ if (little_endian)
+ reverse[i] = p[7 - i];
+ else
+ reverse[i] = p[i];
+ }
+ double d = *(double *)reverse;
+ char temp[32];
+ sprintf(temp, " = %.3f", d);
+ res += temp;
+ p += 8;
+ size -= 8;
+ break;
+ }
+ case 8:
+ {
+ if (size < 4)
+ break;
+ ok = true;
+ // UInt32 numItems = Get32(p);
+ p += 4;
+ size -= 4;
+ break;
+ }
+ }
+ if (!ok)
+ break;
+ }
+ }
+ return res;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidComment: prop = GetComment(); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+*/
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ CRecordVector<CItem> items;
+
+ const UInt32 kHeaderSize = 13;
+ Byte header[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, header, kHeaderSize));
+ if (header[0] != 'F' ||
+ header[1] != 'L' ||
+ header[2] != 'V' ||
+ header[3] != 1 ||
+ (header[4] & 0xFA) != 0)
+ return S_FALSE;
+ UInt32 offset = Get32(header + 5);
+ if (offset != 9 || Get32(header + 9) != 0)
+ return S_FALSE;
+ offset += 4;
+
+ CByteBuffer inBuf;
+ size_t fileSize;
+ {
+ UInt64 fileSize64;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize64));
+ if (fileSize64 > kFileSizeMax)
+ return S_FALSE;
+
+ if (callback)
+ RINOK(callback->SetTotal(NULL, &fileSize64))
+
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ fileSize = (size_t)fileSize64;
+ inBuf.SetCapacity(fileSize);
+ for (size_t pos = 0; pos < fileSize;)
+ {
+ UInt64 offset64 = pos;
+ if (callback)
+ RINOK(callback->SetCompleted(NULL, &offset64))
+ size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20));
+ RINOK(ReadStream_FALSE(stream, inBuf + pos, rem));
+ pos += rem;
+ }
+ }
+
+ int lasts[kNumTypes];
+ int i;
+ for (i = 0; i < kNumTypes; i++)
+ lasts[i] = -1;
+
+ while (offset < fileSize)
+ {
+ CItem item;
+ item.Offset = offset;
+ const Byte *buf = inBuf + offset;
+ offset += kTagHeaderSize;
+ if (offset > fileSize)
+ return S_FALSE;
+
+ item.Type = buf[0];
+ UInt32 size = Get24(buf + 1);
+ if (size < 1)
+ return S_FALSE;
+ // item.Time = Get24(buf + 4);
+ // item.Time |= (UInt32)buf[7] << 24;
+ if (Get24(buf + 8) != 0) // streamID
+ return S_FALSE;
+
+ UInt32 curSize = kTagHeaderSize + size + 4;
+ item.Size = curSize;
+
+ offset += curSize - kTagHeaderSize;
+ if (offset > fileSize)
+ return S_FALSE;
+
+ if (Get32(buf + kTagHeaderSize + size) != kTagHeaderSize + size)
+ return S_FALSE;
+
+ // printf("\noffset = %6X type = %2d time = %6d size = %6d", (UInt32)offset, item.Type, item.Time, item.Size);
+
+ if (item.Type == kType_Meta)
+ {
+ // _metadata = item.Buf;
+ }
+ else
+ {
+ if (item.Type != kType_Audio && item.Type != kType_Video)
+ return S_FALSE;
+ if (items.Size() >= kNumChunksMax)
+ return S_FALSE;
+ Byte firstByte = buf[kTagHeaderSize];
+ Byte subType, props;
+ if (item.Type == kType_Audio)
+ {
+ subType = firstByte >> 4;
+ props = firstByte & 0xF;
+ }
+ else
+ {
+ subType = firstByte & 0xF;
+ props = firstByte >> 4;
+ }
+ int last = lasts[item.Type];
+ if (last < 0)
+ {
+ CItem2 item2;
+ item2.RefBuf = item2.BufSpec = new CReferenceBuf;
+ item2.Size = curSize;
+ item2.Type = item.Type;
+ item2.SubType = subType;
+ item2.Props = props;
+ item2.NumChunks = 1;
+ item2.SameSubTypes = true;
+ lasts[item.Type] = _items2.Add(item2);
+ }
+ else
+ {
+ CItem2 &item2 = _items2[last];
+ if (subType != item2.SubType)
+ item2.SameSubTypes = false;
+ item2.Size += curSize;
+ item2.NumChunks++;
+ }
+ items.Add(item);
+ }
+ }
+
+ _isRaw = (_items2.Size() == 1);
+ for (i = 0; i < _items2.Size(); i++)
+ {
+ CItem2 &item2 = _items2[i];
+ CByteBuffer &itemBuf = item2.BufSpec->Buf;
+ if (_isRaw)
+ {
+ if (!item2.SameSubTypes)
+ return S_FALSE;
+ itemBuf.SetCapacity((size_t)item2.Size - (kTagHeaderSize + 4 + 1) * item2.NumChunks);
+ item2.Size = 0;
+ }
+ else
+ {
+ itemBuf.SetCapacity(kHeaderSize + (size_t)item2.Size);
+ memcpy(itemBuf, header, kHeaderSize);
+ itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video;
+ item2.Size = kHeaderSize;
+ }
+ }
+
+ for (i = 0; i < items.Size(); i++)
+ {
+ const CItem &item = items[i];
+ CItem2 &item2 = _items2[lasts[item.Type]];
+ size_t size = item.Size;
+ const Byte *src = inBuf + item.Offset;
+ if (_isRaw)
+ {
+ src += kTagHeaderSize + 1;
+ size -= (kTagHeaderSize + 4 + 1);
+ }
+ memcpy(item2.BufSpec->Buf + item2.Size, src, size);
+ item2.Size += size;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ HRESULT res;
+ try
+ {
+ res = Open2(inStream, callback);
+ if (res == S_OK)
+ _stream = inStream;
+ }
+ catch(...) { res = S_FALSE; }
+ if (res != S_OK)
+ {
+ Close();
+ return S_FALSE;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _items2.Clear();
+ // _metadata.SetCapacity(0);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items2.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items2[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CItem2 &item = _items2[index];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ totalSize += item.Size;
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.GetCapacity()));
+ }
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Init(_items2[index].BufSpec);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"FLV", L"flv", 0, 0xD6, { 'F', 'L', 'V' }, 3, false, CreateArc, 0 };
+
+REGISTER_ARC(Flv)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/GzHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/GzHandler.cpp
new file mode 100644
index 000000000..7b73bddc3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/GzHandler.cpp
@@ -0,0 +1,698 @@
+// GzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/DeflateDecoder.h"
+#include "../Compress/DeflateEncoder.h"
+
+#include "Common/InStreamWithCRC.h"
+#include "Common/OutStreamWithCRC.h"
+
+#include "DeflateProps.h"
+
+#define Get32(p) GetUi32(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NGz {
+
+static const UInt16 kSignature = 0x8B1F;
+
+namespace NHeader
+{
+ namespace NFlags
+ {
+ const Byte kIsText = 1 << 0;
+ const Byte kCrc = 1 << 1;
+ const Byte kExtra = 1 << 2;
+ const Byte kName = 1 << 3;
+ const Byte kComment = 1 << 4;
+ }
+
+ namespace NExtraFlags
+ {
+ const Byte kMaximum = 2;
+ const Byte kFastest = 4;
+ }
+
+ namespace NCompressionMethod
+ {
+ const Byte kDeflate = 8;
+ }
+
+ namespace NHostOS
+ {
+ enum EEnum
+ {
+ kFAT = 0,
+ kAMIGA,
+ kVMS,
+ kUnix,
+ kVM_CMS,
+ kAtari,
+ kHPFS,
+ kMac,
+ kZ_System,
+ kCPM,
+ kTOPS20,
+ kNTFS,
+ kQDOS,
+ kAcorn,
+ kVFAT,
+ kMVS,
+ kBeOS,
+ kTandem,
+
+ kUnknown = 255
+ };
+ }
+}
+
+static const char *kHostOSes[] =
+{
+ "FAT",
+ "AMIGA",
+ "VMS",
+ "Unix",
+ "VM/CMS",
+ "Atari",
+ "HPFS",
+ "Macintosh",
+ "Z-System",
+ "CP/M",
+ "TOPS-20",
+ "NTFS",
+ "SMS/QDOS",
+ "Acorn",
+ "VFAT",
+ "MVS",
+ "BeOS",
+ "Tandem",
+ "OS/400",
+ "OS/X"
+};
+
+static const char *kUnknownOS = "Unknown";
+
+class CItem
+{
+ bool TestFlag(Byte flag) const { return (Flags & flag) != 0; }
+public:
+ Byte Method;
+ Byte Flags;
+ Byte ExtraFlags;
+ Byte HostOS;
+ UInt32 Time;
+ UInt32 Crc;
+ UInt32 Size32;
+
+ AString Name;
+ AString Comment;
+ // CByteBuffer Extra;
+
+ // bool IsText() const { return TestFlag(NHeader::NFlags::kIsText); }
+ bool HeaderCrcIsPresent() const { return TestFlag(NHeader::NFlags::kCrc); }
+ bool ExtraFieldIsPresent() const { return TestFlag(NHeader::NFlags::kExtra); }
+ bool NameIsPresent() const { return TestFlag(NHeader::NFlags::kName); }
+ bool CommentIsPresent() const { return TestFlag(NHeader::NFlags::kComment); }
+
+ void Clear()
+ {
+ Name.Empty();
+ Comment.Empty();
+ // Extra.SetCapacity(0);
+ }
+
+ HRESULT ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream);
+ HRESULT ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream);
+ HRESULT ReadFooter2(ISequentialInStream *stream);
+
+ HRESULT WriteHeader(ISequentialOutStream *stream);
+ HRESULT WriteFooter(ISequentialOutStream *stream);
+};
+
+static HRESULT ReadBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ data[i] = stream->ReadByte();
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+static HRESULT SkipBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ stream->ReadByte();
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+static HRESULT ReadUInt16(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt16 &value /* , UInt32 &crc */)
+{
+ value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = stream->ReadByte();
+ if (stream->InputEofError())
+ return S_FALSE;
+ // crc = CRC_UPDATE_BYTE(crc, b);
+ value |= (UInt16(b) << (8 * i));
+ }
+ return S_OK;
+}
+
+static HRESULT ReadString(NCompress::NDeflate::NDecoder::CCOMCoder *stream, AString &s, UInt32 limit /* , UInt32 &crc */)
+{
+ s.Empty();
+ for (UInt32 i = 0; i < limit; i++)
+ {
+ Byte b = stream->ReadByte();
+ if (stream->InputEofError())
+ return S_FALSE;
+ // crc = CRC_UPDATE_BYTE(crc, b);
+ if (b == 0)
+ return S_OK;
+ s += (char)b;
+ }
+ return S_FALSE;
+}
+
+HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
+{
+ Clear();
+
+ // Header-CRC field had another meaning in old version of gzip!
+ // UInt32 crc = CRC_INIT_VAL;
+ Byte buf[10];
+
+ RINOK(ReadBytes(stream, buf, 10));
+
+ if (GetUi16(buf) != kSignature)
+ return S_FALSE;
+
+ Method = buf[2];
+
+ if (Method != NHeader::NCompressionMethod::kDeflate)
+ return S_FALSE;
+
+ Flags = buf[3];
+ Time = Get32(buf + 4);
+ ExtraFlags = buf[8];
+ HostOS = buf[9];
+
+ // crc = CrcUpdate(crc, buf, 10);
+
+ if (ExtraFieldIsPresent())
+ {
+ UInt16 extraSize;
+ RINOK(ReadUInt16(stream, extraSize /* , crc */));
+ RINOK(SkipBytes(stream, extraSize));
+ // Extra.SetCapacity(extraSize);
+ // RINOK(ReadStream_FALSE(stream, Extra, extraSize));
+ // crc = CrcUpdate(crc, Extra, extraSize);
+ }
+ if (NameIsPresent())
+ RINOK(ReadString(stream, Name, (1 << 10) /* , crc */));
+ if (CommentIsPresent())
+ RINOK(ReadString(stream, Comment, (1 << 16) /* , crc */));
+
+ if (HeaderCrcIsPresent())
+ {
+ UInt16 headerCRC;
+ // UInt32 dummy = 0;
+ RINOK(ReadUInt16(stream, headerCRC /* , dummy */));
+ /*
+ if ((UInt16)CRC_GET_DIGEST(crc) != headerCRC)
+ return S_FALSE;
+ */
+ }
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+HRESULT CItem::ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
+{
+ Byte buf[8];
+ RINOK(ReadBytes(stream, buf, 8));
+ Crc = Get32(buf);
+ Size32 = Get32(buf + 4);
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+HRESULT CItem::ReadFooter2(ISequentialInStream *stream)
+{
+ Byte buf[8];
+ RINOK(ReadStream_FALSE(stream, buf, 8));
+ Crc = Get32(buf);
+ Size32 = Get32(buf + 4);
+ return S_OK;
+}
+
+HRESULT CItem::WriteHeader(ISequentialOutStream *stream)
+{
+ Byte buf[10];
+ SetUi16(buf, kSignature);
+ buf[2] = Method;
+ buf[3] = Flags & NHeader::NFlags::kName;
+ // buf[3] |= NHeader::NFlags::kCrc;
+ SetUi32(buf + 4, Time);
+ buf[8] = ExtraFlags;
+ buf[9] = HostOS;
+ RINOK(WriteStream(stream, buf, 10));
+ // crc = CrcUpdate(CRC_INIT_VAL, buf, 10);
+ if (NameIsPresent())
+ {
+ // crc = CrcUpdate(crc, (const char *)Name, Name.Length() + 1);
+ RINOK(WriteStream(stream, (const char *)Name, Name.Length() + 1));
+ }
+ // SetUi16(buf, (UInt16)CRC_GET_DIGEST(crc));
+ // RINOK(WriteStream(stream, buf, 2));
+ return S_OK;
+}
+
+HRESULT CItem::WriteFooter(ISequentialOutStream *stream)
+{
+ Byte buf[8];
+ SetUi32(buf, Crc);
+ SetUi32(buf + 4, Size32);
+ return WriteStream(stream, buf, 8);
+}
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IOutArchive,
+ public ISetProperties,
+ public CMyUnknownImp
+{
+ CItem _item;
+ UInt64 _startPosition;
+ UInt64 _headerSize;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ICompressCoder> _decoder;
+ NCompress::NDeflate::NDecoder::CCOMCoder *_decoderSpec;
+
+ CDeflateProps _method;
+
+public:
+ MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+
+ CHandler()
+ {
+ _decoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
+ _decoder = _decoderSpec;
+ }
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidCRC, VT_UI4}
+ // { NULL, kpidComment, VT_BSTR}
+}
+;
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPath:
+ if (_item.NameIsPresent())
+ prop = MultiByteToUnicodeString(_item.Name, CP_ACP);
+ break;
+ // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
+ case kpidMTime:
+ {
+ if (_item.Time != 0)
+ {
+ FILETIME utc;
+ NTime::UnixTimeToFileTime(_item.Time, utc);
+ prop = utc;
+ }
+ break;
+ }
+ case kpidSize: if (_stream) prop = (UInt64)_item.Size32; break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidHostOS: prop = (_item.HostOS < sizeof(kHostOSes) / sizeof(kHostOSes[0])) ?
+ kHostOSes[_item.HostOS] : kUnknownOS; break;
+ case kpidCRC: if (_stream) prop = _item.Crc; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+ res = OpenSeq(stream);
+ if (res == S_OK)
+ {
+ UInt64 endPos;
+ res = stream->Seek(-8, STREAM_SEEK_END, &endPos);
+ _packSize = endPos + 8 - _startPosition;
+ _packSizeDefined = true;
+ if (res == S_OK)
+ {
+ res = _item.ReadFooter2(stream);
+ _stream = stream;
+ }
+ }
+ }
+ catch(...) { res = S_FALSE; }
+ if (res != S_OK)
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ Close();
+ _decoderSpec->SetInStream(stream);
+ _decoderSpec->InitInStream(true);
+ res = _item.ReadHeader(_decoderSpec);
+ _headerSize = _decoderSpec->GetInputProcessedSize();
+ }
+ catch(...) { res = S_FALSE; }
+ if (res != S_OK)
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _stream.Release();
+ _decoderSpec->ReleaseInStream();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_stream)
+ extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ _decoderSpec->InitInStream(true);
+ }
+ bool firstItem = true;
+ Int32 opRes;
+ for (;;)
+ {
+ lps->InSize = _packSize = _decoderSpec->GetInputProcessedSize();
+ _packSizeDefined = true;
+ lps->OutSize = outStreamSpec->GetSize();
+ RINOK(lps->SetCur());
+
+ CItem item;
+ if (!firstItem || _stream)
+ {
+ HRESULT result = item.ReadHeader(_decoderSpec);
+ if (result != S_OK)
+ {
+ if (result != S_FALSE)
+ return result;
+ opRes = firstItem ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK;
+ break;
+ }
+ }
+ firstItem = false;
+
+ UInt64 startOffset = outStreamSpec->GetSize();
+ outStreamSpec->InitCRC();
+
+ HRESULT result = _decoderSpec->CodeResume(outStream, NULL, progress);
+ if (result != S_OK)
+ {
+ if (result != S_FALSE)
+ return result;
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ _decoderSpec->AlignToByte();
+ if (item.ReadFooter1(_decoderSpec) != S_OK)
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ if (item.Crc != outStreamSpec->GetCRC() ||
+ item.Size32 != (UInt32)(outStreamSpec->GetSize() - startOffset))
+ {
+ opRes = NExtract::NOperationResult::kCRCError;
+ break;
+ }
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+static const Byte kHostOS =
+ #ifdef _WIN32
+ NHeader::NHostOS::kFAT;
+ #else
+ NHeader::NHostOS::kUnix;
+ #endif
+
+static HRESULT UpdateArchive(
+ ISequentialOutStream *outStream,
+ UInt64 unpackSize,
+ const CItem &newItem,
+ CDeflateProps &deflateProps,
+ IArchiveUpdateCallback *updateCallback)
+{
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetTotal(unpackSize));
+ RINOK(updateCallback->SetCompleted(&complexity));
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+
+ CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
+ CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
+ inStreamSpec->SetStream(fileInStream);
+ inStreamSpec->Init();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CItem item = newItem;
+ item.Method = NHeader::NCompressionMethod::kDeflate;
+ item.ExtraFlags = deflateProps.IsMaximum() ?
+ NHeader::NExtraFlags::kMaximum :
+ NHeader::NExtraFlags::kFastest;
+
+ item.HostOS = kHostOS;
+
+ RINOK(item.WriteHeader(outStream));
+
+ NCompress::NDeflate::NEncoder::CCOMCoder *deflateEncoderSpec = new NCompress::NDeflate::NEncoder::CCOMCoder;
+ CMyComPtr<ICompressCoder> deflateEncoder = deflateEncoderSpec;
+ RINOK(deflateProps.SetCoderProperties(deflateEncoderSpec));
+ RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
+
+ item.Crc = inStreamSpec->GetCRC();
+ item.Size32 = (UInt32)inStreamSpec->GetSize();
+ RINOK(item.WriteFooter(outStream));
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+}
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+
+ CItem newItem = _item;
+ newItem.ExtraFlags = 0;
+ newItem.Flags = 0;
+ if (IntToBool(newProps))
+ {
+ {
+ FILETIME utcTime;
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidMTime, &prop));
+ if (prop.vt != VT_FILETIME)
+ return E_INVALIDARG;
+ utcTime = prop.filetime;
+ if (!NTime::FileTimeToUnixTime(utcTime, newItem.Time))
+ return E_INVALIDARG;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidPath, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ UString name = prop.bstrVal;
+ int dirDelimiterPos = name.ReverseFind(CHAR_PATH_SEPARATOR);
+ if (dirDelimiterPos >= 0)
+ name = name.Mid(dirDelimiterPos + 1);
+ newItem.Name = UnicodeStringToMultiByte(name, CP_ACP);
+ if (!newItem.Name.IsEmpty())
+ newItem.Flags |= NHeader::NFlags::kName;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
+ if (prop.vt == VT_BOOL)
+ {
+ if (prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+
+ return UpdateArchive(outStream, size, newItem, _method, updateCallback);
+ }
+
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+
+ if (!_stream)
+ return E_NOTIMPL;
+
+ UInt64 offset = _startPosition;
+ if (IntToBool(newProps))
+ {
+ newItem.WriteHeader(outStream);
+ offset += _headerSize;
+ }
+ RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
+ return NCompress::CopyStream(_stream, outStream, NULL);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ return _method.SetProperties(names, values, numProps);
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"gzip", L"gz gzip tgz tpz", L"* * .tar .tar", 0xEF, { 0x1F, 0x8B, 8 }, 3, true, CreateArc, CreateArcOut };
+
+REGISTER_ARC(GZip)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.cpp
new file mode 100644
index 000000000..f226458d4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.cpp
@@ -0,0 +1,243 @@
+// HfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Windows/PropVariant.h"
+#include "../../Common/StreamUtils.h"
+#include "HfsHandler.h"
+
+namespace NArchive {
+namespace NHfs {
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidFreeSpace, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME ft;
+ HfsTimeToFileTime(hfsTime, ft);
+ prop = ft;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod: prop = _db.Header.IsHfsX() ? L"HFSX" : L"HFS+"; break;
+ case kpidClusterSize: prop = (UInt32)1 << _db.Header.BlockSizeLog; break;
+ case kpidFreeSpace: prop = (UInt64)_db.Header.NumFreeBlocks << _db.Header.BlockSizeLog; break;
+ case kpidMTime: HfsTimeToProp(_db.Header.MTime, prop); break;
+ case kpidCTime:
+ {
+ FILETIME localFt, ft;
+ HfsTimeToFileTime(_db.Header.CTime, localFt);
+ if (LocalFileTimeToFileTime(&localFt, &ft))
+ prop = ft;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _db.Items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = _db.GetItemPath(index); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+
+ case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
+ case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
+ case kpidATime: HfsTimeToProp(item.ATime, prop); break;
+
+ case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumBlocks << _db.Header.BlockSizeLog; break;
+ case kpidSize: if (!item.IsDir()) prop = item.Size; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+public:
+ HRESULT SetTotal(UInt64 numFiles);
+ HRESULT SetCompleted(UInt64 numFiles);
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
+};
+
+HRESULT CProgressImp::SetTotal(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetTotal(&numFiles, NULL);
+ return S_OK;
+}
+
+HRESULT CProgressImp::SetCompleted(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ CProgressImp progressImp(callback);
+ HRESULT res = _db.Open(inStream, &progressImp);
+ if (res == E_ABORT)
+ return res;
+ if (res != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _db.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _db.Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _db.Items[allFilesMode ? i : indices[i]];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 currentTotalSize = 0, currentItemSize = 0;
+
+ CByteBuffer buf;
+ const UInt32 kBufSize = (1 << 16);
+ buf.SetCapacity(kBufSize);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _db.Items[index];
+ currentItemSize = 0;
+ if (!item.IsDir())
+ currentItemSize = item.Size;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ UInt64 pos = 0;
+ int res = NExtract::NOperationResult::kOK;
+ int i;
+ for (i = 0; i < item.Extents.Size(); i++)
+ {
+ if (item.Size == pos)
+ break;
+ if (res != NExtract::NOperationResult::kOK)
+ break;
+ const CExtent &e = item.Extents[i];
+ RINOK(_stream->Seek((UInt64)e.Pos << _db.Header.BlockSizeLog, STREAM_SEEK_SET, NULL));
+ UInt64 extentSize = (UInt64)e.NumBlocks << _db.Header.BlockSizeLog;
+ for (;;)
+ {
+ if (extentSize == 0)
+ break;
+ UInt64 rem = item.Size - pos;
+ if (rem == 0)
+ {
+ if (extentSize >= (UInt64)((UInt32)1 << _db.Header.BlockSizeLog))
+ res = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ UInt32 curSize = kBufSize;
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ if (curSize > extentSize)
+ curSize = (UInt32)extentSize;
+ RINOK(ReadStream_FALSE(_stream, buf, curSize));
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, buf, curSize));
+ }
+ pos += curSize;
+ extentSize -= curSize;
+ UInt64 processed = currentTotalSize + pos;
+ RINOK(extractCallback->SetCompleted(&processed));
+ }
+ }
+ if (i != item.Extents.Size() || item.Size != pos)
+ res = NExtract::NOperationResult::kDataError;
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.Items.Size();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.h
new file mode 100644
index 000000000..269af218e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsHandler.h
@@ -0,0 +1,26 @@
+// HfsHandler.h
+
+#ifndef __ARCHIVE_HFS_HANDLER_H
+#define __ARCHIVE_HFS_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+#include "HfsIn.h"
+
+namespace NArchive {
+namespace NHfs {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CDatabase _db;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.cpp
new file mode 100644
index 000000000..8391dd936
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.cpp
@@ -0,0 +1,480 @@
+// HfsIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/StreamUtils.h"
+#include "Common/IntToString.h"
+
+#include "HfsIn.h"
+
+#include "../../../../C/CpuArch.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+namespace NArchive {
+namespace NHfs {
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareIdToIndex(const CIdIndexPair *p1, const CIdIndexPair *p2, void * /* param */)
+{
+ RINOZ(MyCompare(p1->ID, p2->ID));
+ return MyCompare(p1->Index, p2->Index);
+}
+
+bool operator< (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID < a2.ID); }
+bool operator> (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID > a2.ID); }
+bool operator==(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID == a2.ID); }
+bool operator!=(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID != a2.ID); }
+
+static UString GetSpecName(const UString &name, UInt32 /* id */)
+{
+ UString name2 = name;
+ name2.Trim();
+ if (name2.IsEmpty())
+ {
+ /*
+ wchar_t s[32];
+ ConvertUInt64ToString(id, s);
+ return L"[" + (UString)s + L"]";
+ */
+ return L"[]";
+ }
+ return name;
+}
+
+UString CDatabase::GetItemPath(int index) const
+{
+ const CItem *item = &Items[index];
+ UString name = GetSpecName(item->Name, item->ID);
+
+ for (int i = 0; i < 1000; i++)
+ {
+ if (item->ParentID < 16 && item->ParentID != 2)
+ {
+ if (item->ParentID != 1)
+ break;
+ return name;
+ }
+ CIdIndexPair pair;
+ pair.ID = item->ParentID;
+ pair.Index = 0;
+ int indexInMap = IdToIndexMap.FindInSorted(pair);
+ if (indexInMap < 0)
+ break;
+ item = &Items[IdToIndexMap[indexInMap].Index];
+ name = GetSpecName(item->Name, item->ID) + WCHAR_PATH_SEPARATOR + name;
+ }
+ return (UString)L"Unknown" + WCHAR_PATH_SEPARATOR + name;
+}
+
+void CFork::Parse(const Byte *p)
+{
+ Size = Get64(p);
+ // ClumpSize = Get32(p + 8);
+ NumBlocks = Get32(p + 0xC);
+ for (int i = 0; i < 8; i++)
+ {
+ CExtent &e = Extents[i];
+ e.Pos = Get32(p + 0x10 + i * 8);
+ e.NumBlocks = Get32(p + 0x10 + i * 8 + 4);
+ }
+}
+
+static HRESULT ReadExtent(int blockSizeLog, IInStream *inStream, Byte *buf, const CExtent &e)
+{
+ RINOK(inStream->Seek((UInt64)e.Pos << blockSizeLog, STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(inStream, buf, (size_t)e.NumBlocks << blockSizeLog);
+}
+
+HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream)
+{
+ if (fork.NumBlocks >= Header.NumBlocks)
+ return S_FALSE;
+ size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog;
+ if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks)
+ return S_FALSE;
+ buf.SetCapacity(totalSize);
+ UInt32 curBlock = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ if (curBlock >= fork.NumBlocks)
+ break;
+ const CExtent &e = fork.Extents[i];
+ if (fork.NumBlocks - curBlock < e.NumBlocks || e.Pos >= Header.NumBlocks)
+ return S_FALSE;
+ RINOK(ReadExtent(Header.BlockSizeLog, inStream,
+ (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog), e));
+ curBlock += e.NumBlocks;
+ }
+ return S_OK;
+}
+
+struct CNodeDescriptor
+{
+ UInt32 fLink;
+ UInt32 bLink;
+ Byte Kind;
+ Byte Height;
+ UInt16 NumRecords;
+ // UInt16 Reserved;
+ void Parse(const Byte *p);
+};
+
+void CNodeDescriptor::Parse(const Byte *p)
+{
+ fLink = Get32(p);
+ bLink = Get32(p + 4);
+ Kind = p[8];
+ Height = p[9];
+ NumRecords = Get16(p + 10);
+}
+
+struct CHeaderRec
+{
+ // UInt16 TreeDepth;
+ // UInt32 RootNode;
+ // UInt32 LeafRecords;
+ UInt32 FirstLeafNode;
+ // UInt32 LastLeafNode;
+ int NodeSizeLog;
+ // UInt16 MaxKeyLength;
+ UInt32 TotalNodes;
+ // UInt32 FreeNodes;
+ // UInt16 Reserved1;
+ // UInt32 ClumpSize;
+ // Byte BtreeType;
+ // Byte KeyCompareType;
+ // UInt32 Attributes;
+ // UInt32 Reserved3[16];
+
+ HRESULT Parse(const Byte *p);
+};
+
+HRESULT CHeaderRec::Parse(const Byte *p)
+{
+ // TreeDepth = Get16(p);
+ // RootNode = Get32(p + 2);
+ // LeafRecords = Get32(p + 6);
+ FirstLeafNode = Get32(p + 0xA);
+ // LastLeafNode = Get32(p + 0xE);
+ UInt32 nodeSize = Get16(p + 0x12);
+
+ int i;
+ for (i = 9; ((UInt32)1 << i) != nodeSize; i++)
+ if (i == 16)
+ return S_FALSE;
+ NodeSizeLog = i;
+
+ // MaxKeyLength = Get16(p + 0x14);
+ TotalNodes = Get32(p + 0x16);
+ // FreeNodes = Get32(p + 0x1A);
+ // Reserved1 = Get16(p + 0x1E);
+ // ClumpSize = Get32(p + 0x20);
+ // BtreeType = p[0x24];
+ // KeyCompareType = p[0x25];
+ // Attributes = Get32(p + 0x26);
+ /*
+ for (int i = 0; i < 16; i++)
+ Reserved3[i] = Get32(p + 0x2A + i * 4);
+ */
+ return S_OK;
+}
+
+
+enum ENodeType
+{
+ NODE_TYPE_LEAF = 0xFF,
+ NODE_TYPE_INDEX = 0,
+ NODE_TYPE_HEADER = 1,
+ NODE_TYPE_MODE = 2
+};
+
+HRESULT CDatabase::LoadExtentFile(IInStream *inStream)
+{
+ // FileExtents.Clear();
+ // ResExtents.Clear();
+
+ CByteBuffer extents;
+ RINOK(ReadFile(Header.ExtentsFile, extents, inStream));
+
+ const Byte *p = (const Byte *)extents;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ RINOK(hr.Parse(p + 14));
+
+ UInt32 node = hr.FirstLeafNode;
+ if (node != 0)
+ return S_FALSE;
+ /*
+ while (node != 0)
+ {
+ size_t nodeOffset = node * hr.NodeSize;
+ if ((node + 1)* hr.NodeSize > CatalogBuf.GetCapacity())
+ return S_FALSE;
+ CNodeDescriptor desc;
+ desc.Parse(p + nodeOffset);
+ if (desc.Kind != NODE_TYPE_LEAF)
+ return S_FALSE;
+ UInt32 ptr = hr.NodeSize;
+ for (int i = 0; i < desc.NumRecords; i++)
+ {
+ UInt32 offs = Get16(p + nodeOffset + hr.NodeSize - (i + 1) * 2);
+ UInt32 offsNext = Get16(p + nodeOffset + hr.NodeSize - (i + 2) * 2);
+
+ const Byte *r = p + nodeOffset + offs;
+ int keyLength = Get16(r);
+ Byte forkType = r[2];
+ UInt32 id = Get16(r + 4);
+ UInt32 startBlock = Get16(r + 4);
+ CObjectVector<CIdExtents> *extents = (forkType == 0) ? &FileExtents : &ResExtents;
+ if (extents->Size() == 0)
+ extents->Add(CIdExtents());
+ else
+ {
+ CIdExtents &e = extents->Back();
+ if (e.ID != id)
+ {
+ if (e.ID > id)
+ return S_FALSE;
+ extents->Add(CIdExtents());
+ }
+ }
+ CIdExtents &e = extents->Back();
+ for (UInt32 k = offs + 10 + 2; k + 8 <= offsNext; k += 8)
+ {
+ CExtent ee;
+ ee.Pos = Get32(p + nodeOffset + k);
+ ee.NumBlocks = Get32(p + nodeOffset + k * 4);
+ e.Extents.Add(ee);
+ }
+ }
+ node = desc.fLink;
+ }
+ */
+ return S_OK;
+}
+
+
+HRESULT CDatabase::LoadCatalog(IInStream *inStream, CProgressVirt *progress)
+{
+ Items.Clear();
+ IdToIndexMap.ClearAndFree();
+
+ CByteBuffer catalogBuf;
+ RINOK(ReadFile(Header.CatalogFile, catalogBuf, inStream));
+ const Byte *p = (const Byte *)catalogBuf;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ hr.Parse(p + 14);
+
+ // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
+
+ if ((catalogBuf.GetCapacity() >> hr.NodeSizeLog) < hr.TotalNodes)
+ return S_FALSE;
+
+ CByteBuffer usedBuf;
+ usedBuf.SetCapacity(hr.TotalNodes);
+ for (UInt32 i = 0; i < hr.TotalNodes; i++)
+ usedBuf[i] = 0;
+
+ UInt32 node = hr.FirstLeafNode;
+ while (node != 0)
+ {
+ if (node >= hr.TotalNodes)
+ return S_FALSE;
+ if (usedBuf[node])
+ return S_FALSE;
+ usedBuf[node] = 1;
+ size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
+ CNodeDescriptor desc;
+ desc.Parse(p + nodeOffset);
+ if (desc.Kind != NODE_TYPE_LEAF)
+ return S_FALSE;
+ for (int i = 0; i < desc.NumRecords; i++)
+ {
+ UInt32 nodeSize = (1 << hr.NodeSizeLog);
+ UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2);
+ UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2);
+ UInt32 recSize = offsNext - offs;
+ if (offsNext >= nodeSize || offsNext < offs || recSize < 6)
+ return S_FALSE;
+
+ CItem item;
+
+ const Byte *r = p + nodeOffset + offs;
+ UInt32 keyLength = Get16(r);
+ item.ParentID = Get32(r + 2);
+ UString name;
+ if (keyLength < 6 || (keyLength & 1) != 0 || keyLength + 2 > recSize)
+ return S_FALSE;
+ r += 6;
+ recSize -= 6;
+ keyLength -= 6;
+
+ int nameLength = Get16(r);
+ if (nameLength * 2 != (int)keyLength)
+ return S_FALSE;
+ r += 2;
+ recSize -= 2;
+
+ wchar_t *pp = name.GetBuffer(nameLength + 1);
+
+ int j;
+ for (j = 0; j < nameLength; j++)
+ pp[j] = ((wchar_t)r[j * 2] << 8) | r[j * 2 + 1];
+ pp[j] = 0;
+ name.ReleaseBuffer();
+ r += j * 2;
+ recSize -= j * 2;
+
+ if (recSize < 2)
+ return S_FALSE;
+ item.Type = Get16(r);
+
+ if (item.Type != RECORD_TYPE_FOLDER && item.Type != RECORD_TYPE_FILE)
+ continue;
+ if (recSize < 0x58)
+ return S_FALSE;
+
+ // item.Flags = Get16(r + 2);
+ // item.Valence = Get32(r + 4);
+ item.ID = Get32(r + 8);
+ item.CTime = Get32(r + 0xC);
+ item.MTime = Get32(r + 0x10);
+ // item.AttrMTime = Get32(r + 0x14);
+ item.ATime = Get32(r + 0x18);
+ // item.BackupDate = Get32(r + 0x1C);
+
+ /*
+ item.OwnerID = Get32(r + 0x20);
+ item.GroupID = Get32(r + 0x24);
+ item.AdminFlags = r[0x28];
+ item.OwnerFlags = r[0x29];
+ item.FileMode = Get16(r + 0x2A);
+ item.special.iNodeNum = Get16(r + 0x2C);
+ */
+
+ item.Name = name;
+
+ if (item.IsDir())
+ {
+ CIdIndexPair pair;
+ pair.ID = item.ID;
+ pair.Index = Items.Size();
+ IdToIndexMap.Add(pair);
+ }
+ else
+ {
+ CFork fd;
+ recSize -= 0x58;
+ r += 0x58;
+ if (recSize < 0x50 * 2)
+ return S_FALSE;
+ fd.Parse(r);
+ item.Size = fd.Size;
+ item.NumBlocks = fd.NumBlocks;
+ UInt32 curBlock = 0;
+ for (int j = 0; j < 8; j++)
+ {
+ if (curBlock >= fd.NumBlocks)
+ break;
+ const CExtent &e = fd.Extents[j];
+ item.Extents.Add(e);
+ curBlock += e.NumBlocks;
+ }
+ }
+ Items.Add(item);
+ if (progress && Items.Size() % 100 == 0)
+ {
+ RINOK(progress->SetCompleted(Items.Size()));
+ }
+ }
+ node = desc.fLink;
+ }
+ IdToIndexMap.Sort(CompareIdToIndex, NULL);
+ return S_OK;
+}
+
+HRESULT CDatabase::Open(IInStream *inStream, CProgressVirt *progress)
+{
+ static const UInt32 kHeaderSize = 1024 + 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize));
+ int i;
+ for (i = 0; i < 1024; i++)
+ if (buf[i] != 0)
+ return S_FALSE;
+ const Byte *p = buf + 1024;
+ CVolHeader &h = Header;
+
+ h.Header[0] = p[0];
+ h.Header[1] = p[1];
+ if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X'))
+ return S_FALSE;
+ h.Version = Get16(p + 2);
+ if (h.Version < 4 || h.Version > 5)
+ return S_FALSE;
+
+ // h.Attr = Get32(p + 4);
+ // h.LastMountedVersion = Get32(p + 8);
+ // h.JournalInfoBlock = Get32(p + 0xC);
+
+ h.CTime = Get32(p + 0x10);
+ h.MTime = Get32(p + 0x14);
+ // h.BackupTime = Get32(p + 0x18);
+ // h.CheckedTime = Get32(p + 0x1C);
+
+ // h.NumFiles = Get32(p + 0x20);
+ // h.NumFolders = Get32(p + 0x24);
+
+ UInt32 numFiles = Get32(p + 0x20);
+ UInt32 numFolders = Get32(p + 0x24);;
+ if (progress)
+ {
+ RINOK(progress->SetTotal(numFolders + numFiles));
+ }
+
+ UInt32 blockSize = Get32(p + 0x28);
+
+ for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+ if (i == 31)
+ return S_FALSE;
+ h.BlockSizeLog = i;
+
+ h.NumBlocks = Get32(p + 0x2C);
+ h.NumFreeBlocks = Get32(p + 0x30);
+
+ /*
+ h.WriteCount = Get32(p + 0x44);
+ for (i = 0; i < 6; i++)
+ h.FinderInfo[i] = Get32(p + 0x50 + i * 4);
+ h.VolID = Get64(p + 0x68);
+ */
+
+ UInt64 endPos;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
+ if ((endPos >> h.BlockSizeLog) < h.NumBlocks)
+ return S_FALSE;
+
+ // h.AllocationFile.Parse(p + 0x70 + 0x50 * 0);
+ h.ExtentsFile.Parse( p + 0x70 + 0x50 * 1);
+ h.CatalogFile.Parse( p + 0x70 + 0x50 * 2);
+ // h.AttributesFile.Parse(p + 0x70 + 0x50 * 3);
+ // h.StartupFile.Parse( p + 0x70 + 0x50 * 4);
+
+ RINOK(LoadExtentFile(inStream));
+ RINOK(LoadCatalog(inStream, progress));
+
+ // if (Header.NumFiles + Header.NumFolders != (UInt32)Items.Size()) return S_OK;
+
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.h
new file mode 100644
index 000000000..c19539057
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsIn.h
@@ -0,0 +1,154 @@
+// HfsIn.h
+
+#ifndef __ARCHIVE_HFS_IN_H
+#define __ARCHIVE_HFS_IN_H
+
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+
+namespace NArchive {
+namespace NHfs {
+
+struct CExtent
+{
+ UInt32 Pos;
+ UInt32 NumBlocks;
+};
+
+struct CFork
+{
+ UInt64 Size;
+ // UInt32 ClumpSize;
+ UInt32 NumBlocks;
+ CExtent Extents[8];
+ void Parse(const Byte *p);
+};
+
+struct CVolHeader
+{
+ Byte Header[2];
+ UInt16 Version;
+ // UInt32 Attr;
+ // UInt32 LastMountedVersion;
+ // UInt32 JournalInfoBlock;
+
+ UInt32 CTime;
+ UInt32 MTime;
+ // UInt32 BackupTime;
+ // UInt32 CheckedTime;
+
+ // UInt32 NumFiles;
+ // UInt32 NumFolders;
+ int BlockSizeLog;
+ UInt32 NumBlocks;
+ UInt32 NumFreeBlocks;
+
+ // UInt32 WriteCount;
+ // UInt32 FinderInfo[8];
+ // UInt64 VolID;
+
+ // CFork AllocationFile;
+ CFork ExtentsFile;
+ CFork CatalogFile;
+ // CFork AttributesFile;
+ // CFork StartupFile;
+
+ bool IsHfsX() const { return Version > 4; }
+};
+
+inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft)
+{
+ UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+enum ERecordType
+{
+ RECORD_TYPE_FOLDER = 1,
+ RECORD_TYPE_FILE = 2,
+ RECORD_TYPE_FOLDER_THREAD = 3,
+ RECORD_TYPE_FILE_THREAD = 4
+};
+
+struct CItem
+{
+ UString Name;
+
+ UInt32 ParentID;
+
+ UInt16 Type;
+ // UInt16 Flags;
+ // UInt32 Valence;
+ UInt32 ID;
+ UInt32 CTime;
+ UInt32 MTime;
+ // UInt32 AttrMTime;
+ UInt32 ATime;
+ // UInt32 BackupDate;
+
+ /*
+ UInt32 OwnerID;
+ UInt32 GroupID;
+ Byte AdminFlags;
+ Byte OwnerFlags;
+ UInt16 FileMode;
+ union
+ {
+ UInt32 iNodeNum;
+ UInt32 LinkCount;
+ UInt32 RawDevice;
+ } special;
+ */
+
+ UInt64 Size;
+ UInt32 NumBlocks;
+ CRecordVector<CExtent> Extents;
+
+ bool IsDir() const { return Type == RECORD_TYPE_FOLDER; }
+ CItem(): Size(0), NumBlocks(0) {}
+};
+
+struct CIdIndexPair
+{
+ UInt32 ID;
+ int Index;
+};
+
+struct CProgressVirt
+{
+ virtual HRESULT SetTotal(UInt64 numFiles) PURE;
+ virtual HRESULT SetCompleted(UInt64 numFiles) PURE;
+};
+
+class CDatabase
+{
+ // CObjectVector<CIdExtents> FileExtents;
+ // CObjectVector<CIdExtents> ResExtents;
+ CRecordVector<CIdIndexPair> IdToIndexMap;
+
+ HRESULT LoadExtentFile(IInStream *inStream);
+ HRESULT LoadCatalog(IInStream *inStream, CProgressVirt *progress);
+
+ HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream);
+public:
+ CVolHeader Header;
+ CObjectVector<CItem> Items;
+ // bool CaseSensetive;
+
+ void Clear()
+ {
+ // CaseSensetive = false;
+ Items.Clear();
+ // FileExtents.Clear();
+ // ResExtents.Clear();
+ IdToIndexMap.Clear();
+ }
+
+ UString GetItemPath(int index) const;
+ HRESULT Open(IInStream *inStream, CProgressVirt *progress);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsRegister.cpp
new file mode 100644
index 000000000..51c3c2b15
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Hfs/HfsRegister.cpp
@@ -0,0 +1,13 @@
+// HfsRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "HfsHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NHfs::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"HFS", L"hfs", 0, 0xE3, { 'H', '+', 0, 4 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Hfs)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/IArchive.h b/src/libs/7zip/win/CPP/7zip/Archive/IArchive.h
new file mode 100644
index 000000000..853202767
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/IArchive.h
@@ -0,0 +1,234 @@
+// IArchive.h
+
+#ifndef __IARCHIVE_H
+#define __IARCHIVE_H
+
+#include "../IProgress.h"
+#include "../IStream.h"
+#include "../PropID.h"
+
+#define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x)
+#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x)
+
+namespace NFileTimeType
+{
+ enum EEnum
+ {
+ kWindows,
+ kUnix,
+ kDOS
+ };
+}
+
+namespace NArchive
+{
+ enum
+ {
+ kName = 0,
+ kClassID,
+ kExtension,
+ kAddExtension,
+ kUpdate,
+ kKeepName,
+ kStartSignature,
+ kFinishSignature,
+ kAssociate
+ };
+
+ namespace NExtract
+ {
+ namespace NAskMode
+ {
+ enum
+ {
+ kExtract = 0,
+ kTest,
+ kSkip
+ };
+ }
+ namespace NOperationResult
+ {
+ enum
+ {
+ kOK = 0,
+ kUnSupportedMethod,
+ kDataError,
+ kCRCError
+ };
+ }
+ }
+ namespace NUpdate
+ {
+ namespace NOperationResult
+ {
+ enum
+ {
+ kOK = 0,
+ kError
+ };
+ }
+ }
+}
+
+#define INTERFACE_IArchiveOpenCallback(x) \
+ STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) x; \
+ STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) x; \
+
+ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
+{
+ INTERFACE_IArchiveOpenCallback(PURE);
+};
+
+
+#define INTERFACE_IArchiveExtractCallback(x) \
+ INTERFACE_IProgress(x) \
+ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
+ STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \
+ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \
+
+ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20)
+{
+ INTERFACE_IArchiveExtractCallback(PURE)
+};
+
+
+#define INTERFACE_IArchiveOpenVolumeCallback(x) \
+ STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \
+ STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \
+
+ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30)
+{
+ INTERFACE_IArchiveOpenVolumeCallback(PURE);
+};
+
+
+ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40)
+{
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE;
+};
+
+
+ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)
+{
+ STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE;
+};
+
+
+/*
+IInArchive::Extract:
+ indices must be sorted
+ numItems = 0xFFFFFFFF means "all files"
+ testMode != 0 means "test files without writing to outStream"
+*/
+
+#define INTERFACE_IInArchive(x) \
+ STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) x; \
+ STDMETHOD(Close)() x; \
+ STDMETHOD(GetNumberOfItems)(UInt32 *numItems) x; \
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
+ STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) x; \
+ STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) x; \
+ STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \
+ STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \
+ STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties) x; \
+ STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x;
+
+ARCHIVE_INTERFACE(IInArchive, 0x60)
+{
+ INTERFACE_IInArchive(PURE)
+};
+
+ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61)
+{
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE;
+};
+
+#define INTERFACE_IArchiveUpdateCallback(x) \
+ INTERFACE_IProgress(x); \
+ STDMETHOD(GetUpdateItemInfo)(UInt32 index, \
+ Int32 *newData, /*1 - new data, 0 - old data */ \
+ Int32 *newProperties, /* 1 - new properties, 0 - old properties */ \
+ UInt32 *indexInArchive /* -1 if there is no in archive, or if doesn't matter */ \
+ ) x; \
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \
+ STDMETHOD(SetOperationResult)(Int32 operationResult) x; \
+
+ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80)
+{
+ INTERFACE_IArchiveUpdateCallback(PURE);
+};
+
+#define INTERFACE_IArchiveUpdateCallback2(x) \
+ INTERFACE_IArchiveUpdateCallback(x) \
+ STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) x; \
+ STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) x; \
+
+ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
+{
+ INTERFACE_IArchiveUpdateCallback2(PURE);
+};
+
+
+#define INTERFACE_IOutArchive(x) \
+ STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \
+ STDMETHOD(GetFileTimeType)(UInt32 *type) x;
+
+ARCHIVE_INTERFACE(IOutArchive, 0xA0)
+{
+ INTERFACE_IOutArchive(PURE)
+};
+
+
+ARCHIVE_INTERFACE(ISetProperties, 0x03)
+{
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) PURE;
+};
+
+
+#define IMP_IInArchive_GetProp(k) \
+ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
+ { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \
+ const STATPROPSTG &srcItem = k[index]; \
+ *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \
+
+#define IMP_IInArchive_GetProp_WITH_NAME(k) \
+ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
+ { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \
+ const STATPROPSTG &srcItem = k[index]; \
+ *propID = srcItem.propid; *varType = srcItem.vt; \
+ if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \
+
+#define IMP_IInArchive_Props \
+ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \
+ { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps)
+
+#define IMP_IInArchive_Props_WITH_NAME \
+ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \
+ { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps)
+
+
+#define IMP_IInArchive_ArcProps \
+ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
+ { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps)
+
+#define IMP_IInArchive_ArcProps_WITH_NAME \
+ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
+ { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \
+ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps)
+
+#define IMP_IInArchive_ArcProps_NO_Table \
+ STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
+ { *numProperties = 0; return S_OK; } \
+ STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \
+ { return E_NOTIMPL; } \
+
+#define IMP_IInArchive_ArcProps_NO \
+ IMP_IInArchive_ArcProps_NO_Table \
+ STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \
+ { value->vt = VT_EMPTY; return S_OK; }
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHandler.cpp
new file mode 100644
index 000000000..4bfb7dc68
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -0,0 +1,326 @@
+// IsoHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "IsoHandler.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NIso {
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME}
+ // { NULL, kpidPhySize, VT_UI8},
+ // { NULL, kpidHeadersSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ // try
+ {
+ if (_archive.Open(stream) != S_OK)
+ return S_FALSE;
+ _stream = stream;
+ }
+ // catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _archive.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _archive.Refs.Size() + _archive.BootEntries.Size();
+ return S_OK;
+}
+
+static void AddString(AString &s, const char *name, const Byte *p, int size)
+{
+ int i;
+ for (i = 0; i < size && p[i]; i++);
+ for (; i > 0 && p[i - 1] == ' '; i--);
+ if (i != 0)
+ {
+ AString d;
+ memcpy(d.GetBuffer(i), p, i);
+ d.ReleaseBuffer(i);
+ s += '\n';
+ s += name;
+ s += ": ";
+ s += d;
+ }
+}
+
+#define ADD_STRING(n, v) AddString(s, n, vol. ## v, sizeof(vol. ## v))
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex];
+ switch(propID)
+ {
+ case kpidComment:
+ {
+ AString s;
+ ADD_STRING("System", SystemId);
+ ADD_STRING("Volume", VolumeId);
+ ADD_STRING("VolumeSet", VolumeSetId);
+ ADD_STRING("Publisher", PublisherId);
+ ADD_STRING("Preparer", DataPreparerId);
+ ADD_STRING("Application", ApplicationId);
+ ADD_STRING("Copyright", CopyrightFileId);
+ ADD_STRING("Abstract", AbstractFileId);
+ ADD_STRING("Bib", BibFileId);
+ prop = s;
+ break;
+ }
+ case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; }
+ case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; }
+ // case kpidPhySize: break;
+ // case kpidHeadersSize: break;
+ case kpidError: if (_archive.IncorrectBigEndian) prop = "Incorrect big-endian headers"; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ if (index >= (UInt32)_archive.Refs.Size())
+ {
+ index -= _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ // wchar_t name[32];
+ // ConvertUInt64ToString(index + 1, name);
+ UString s = L"[BOOT]" WSTRING_PATH_SEPARATOR;
+ // s += name;
+ // s += L"-";
+ s += be.GetName();
+ prop = (const wchar_t *)s;
+ break;
+ }
+ case kpidIsDir: prop = false; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)_archive.GetBootItemSize(index);
+ break;
+ }
+ }
+ else
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ switch(propID)
+ {
+ case kpidPath:
+ // if (item.FileId.GetCapacity() >= 0)
+ {
+ UString s;
+ if (_archive.IsJoliet())
+ s = item.GetPathU();
+ else
+ s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP);
+
+ int pos = s.ReverseFind(L';');
+ if (pos >= 0 && pos == s.Length() - 2)
+ if (s[s.Length() - 1] == L'1')
+ s = s.Left(pos);
+ if (!s.IsEmpty())
+ if (s[s.Length() - 1] == L'.')
+ s = s.Left(s.Length() - 1);
+ prop = (const wchar_t *)NItemName::GetOSName2(s);
+ }
+ break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize:
+ case kpidPackSize:
+ if (!item.IsDir())
+ prop = (UInt64)item.DataLength;
+ break;
+ case kpidMTime:
+ {
+ FILETIME utc;
+ if (item.DateTime.GetFileTime(utc))
+ prop = utc;
+ break;
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _archive.Refs.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for(i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ totalSize += item.DataLength;
+ }
+ else
+ {
+ totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
+ }
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ currentItemSize = 0;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ UInt64 blockIndex;
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ currentItemSize = item.DataLength;
+ blockIndex = item.ExtentLocation;
+ }
+ else
+ {
+ int bootIndex = index - _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
+ currentItemSize = _archive.GetBootItemSize(bootIndex);
+ blockIndex = be.LoadRBA;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(currentItemSize);
+ RINOK(_stream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(outStreamSpec->IsFinishedOK() ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ UInt64 blockIndex;
+ UInt64 currentItemSize;
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ if (item.IsDir())
+ return S_FALSE;
+ currentItemSize = item.DataLength;
+ blockIndex = item.ExtentLocation;
+ }
+ else
+ {
+ int bootIndex = index - _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
+ currentItemSize = _archive.GetBootItemSize(bootIndex);
+ blockIndex = be.LoadRBA;
+ }
+ return CreateLimitedInStream(_stream, blockIndex * _archive.BlockSize, currentItemSize, stream);
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHandler.h
new file mode 100644
index 000000000..1dcade8f9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHandler.h
@@ -0,0 +1,30 @@
+// IsoHandler.h
+
+#ifndef __ISO_HANDLER_H
+#define __ISO_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+
+#include "IsoIn.h"
+#include "IsoItem.h"
+
+namespace NArchive {
+namespace NIso {
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CInArchive _archive;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHeader.cpp
new file mode 100644
index 000000000..b3e418bbc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHeader.cpp
@@ -0,0 +1,21 @@
+// Archive/Iso/Header.h
+
+#include "StdAfx.h"
+
+#include "IsoHeader.h"
+
+namespace NArchive {
+namespace NIso {
+
+const char *kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0";
+
+const wchar_t *kMediaTypes[5] =
+{
+ L"NoEmulation",
+ L"1.2M",
+ L"1.44M",
+ L"2.88M",
+ L"HardDisk"
+};
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHeader.h
new file mode 100644
index 000000000..9702d70ae
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoHeader.h
@@ -0,0 +1,61 @@
+// Archive/IsoHeader.h
+
+#ifndef __ARCHIVE_ISO_HEADER_H
+#define __ARCHIVE_ISO_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NIso {
+
+namespace NVolDescType
+{
+ const Byte kBootRecord = 0;
+ const Byte kPrimaryVol = 1;
+ const Byte kSupplementaryVol = 2;
+ const Byte kVolParttition = 3;
+ const Byte kTerminator = 255;
+}
+
+const Byte kVersion = 1;
+
+namespace NFileFlags
+{
+ const Byte kDirectory = 1 << 1;
+}
+
+extern const char *kElToritoSpec;
+
+const UInt32 kStartPos = 0x8000;
+
+namespace NBootEntryId
+{
+ const Byte kValidationEntry = 1;
+ const Byte kInitialEntryNotBootable = 0;
+ const Byte kInitialEntryBootable = 0x88;
+}
+
+namespace NBootPlatformId
+{
+ const Byte kX86 = 0;
+ const Byte kPowerPC = 1;
+ const Byte kMac = 2;
+}
+
+const BYTE kBootMediaTypeMask = 0xF;
+
+namespace NBootMediaType
+{
+ const Byte kNoEmulation = 0;
+ const Byte k1d2Floppy = 1;
+ const Byte k1d44Floppy = 2;
+ const Byte k2d88Floppy = 3;
+ const Byte kHardDisk = 4;
+}
+
+const int kNumBootMediaTypes = 5;
+extern const wchar_t *kMediaTypes[];
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoIn.cpp
new file mode 100644
index 000000000..7ed618d29
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -0,0 +1,453 @@
+// Archive/IsoIn.cpp
+
+#include "StdAfx.h"
+
+#include "IsoIn.h"
+
+#include "../../Common/StreamUtils.h"
+
+namespace NArchive {
+namespace NIso {
+
+Byte CInArchive::ReadByte()
+{
+ if (m_BufferPos >= BlockSize)
+ m_BufferPos = 0;
+ if (m_BufferPos == 0)
+ {
+ size_t processedSize = BlockSize;
+ if (ReadStream(_stream, m_Buffer, &processedSize) != S_OK)
+ throw 1;
+ if (processedSize != BlockSize)
+ throw 1;
+ }
+ Byte b = m_Buffer[m_BufferPos++];
+ _position++;
+ return b;
+}
+
+void CInArchive::ReadBytes(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ data[i] = ReadByte();
+}
+
+void CInArchive::Skip(size_t size)
+{
+ while (size-- != 0)
+ ReadByte();
+}
+
+void CInArchive::SkipZeros(size_t size)
+{
+ while (size-- != 0)
+ {
+ Byte b = ReadByte();
+ if (b != 0)
+ throw 1;
+ }
+}
+
+UInt16 CInArchive::ReadUInt16Spec()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ value |= ((UInt16)(ReadByte()) << (8 * i));
+ return value;
+}
+
+
+UInt16 CInArchive::ReadUInt16()
+{
+ Byte b[4];
+ ReadBytes(b, 4);
+ UInt32 value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ if (b[i] != b[3 - i])
+ IncorrectBigEndian = true;
+ value |= ((UInt16)(b[i]) << (8 * i));
+ }
+ return (UInt16)value;
+}
+
+UInt32 CInArchive::ReadUInt32Le()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ value |= ((UInt32)(ReadByte()) << (8 * i));
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32Be()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ value <<= 8;
+ value |= ReadByte();
+ }
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ Byte b[8];
+ ReadBytes(b, 8);
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ if (b[i] != b[7 - i])
+ throw 1;
+ value |= ((UInt32)(b[i]) << (8 * i));
+ }
+ return value;
+}
+
+UInt32 CInArchive::ReadDigits(int numDigits)
+{
+ UInt32 res = 0;
+ for (int i = 0; i < numDigits; i++)
+ {
+ Byte b = ReadByte();
+ if (b < '0' || b > '9')
+ {
+ if (b == 0) // it's bug in some CD's
+ b = '0';
+ else
+ throw 1;
+ }
+ UInt32 d = (UInt32)(b - '0');
+ res *= 10;
+ res += d;
+ }
+ return res;
+}
+
+void CInArchive::ReadDateTime(CDateTime &d)
+{
+ d.Year = (UInt16)ReadDigits(4);
+ d.Month = (Byte)ReadDigits(2);
+ d.Day = (Byte)ReadDigits(2);
+ d.Hour = (Byte)ReadDigits(2);
+ d.Minute = (Byte)ReadDigits(2);
+ d.Second = (Byte)ReadDigits(2);
+ d.Hundredths = (Byte)ReadDigits(2);
+ d.GmtOffset = (signed char)ReadByte();
+}
+
+void CInArchive::ReadBootRecordDescriptor(CBootRecordDescriptor &d)
+{
+ ReadBytes(d.BootSystemId, sizeof(d.BootSystemId));
+ ReadBytes(d.BootId, sizeof(d.BootId));
+ ReadBytes(d.BootSystemUse, sizeof(d.BootSystemUse));
+}
+
+void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t)
+{
+ t.Year = ReadByte();
+ t.Month = ReadByte();
+ t.Day = ReadByte();
+ t.Hour = ReadByte();
+ t.Minute = ReadByte();
+ t.Second = ReadByte();
+ t.GmtOffset = (signed char)ReadByte();
+}
+
+void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
+{
+ r.ExtendedAttributeRecordLen = ReadByte();
+ if (r.ExtendedAttributeRecordLen != 0)
+ throw 1;
+ r.ExtentLocation = ReadUInt32();
+ r.DataLength = ReadUInt32();
+ ReadRecordingDateTime(r.DateTime);
+ r.FileFlags = ReadByte();
+ r.FileUnitSize = ReadByte();
+ r.InterleaveGapSize = ReadByte();
+ r.VolSequenceNumber = ReadUInt16();
+ Byte idLen = ReadByte();
+ r.FileId.SetCapacity(idLen);
+ ReadBytes((Byte *)r.FileId, idLen);
+ int padSize = 1 - (idLen & 1);
+
+ // SkipZeros(1 - (idLen & 1));
+ Skip(1 - (idLen & 1)); // it's bug in some cd's. Must be zeros
+
+ int curPos = 33 + idLen + padSize;
+ if (curPos > len)
+ throw 1;
+ int rem = len - curPos;
+ r.SystemUse.SetCapacity(rem);
+ ReadBytes((Byte *)r.SystemUse, rem);
+}
+
+void CInArchive::ReadDirRecord(CDirRecord &r)
+{
+ Byte len = ReadByte();
+ // Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor.
+ // But maybe we must use real "len" for other records.
+ len = 34;
+ ReadDirRecord2(r, len);
+}
+
+void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
+{
+ d.VolFlags = ReadByte();
+ ReadBytes(d.SystemId, sizeof(d.SystemId));
+ ReadBytes(d.VolumeId, sizeof(d.VolumeId));
+ SkipZeros(8);
+ d.VolumeSpaceSize = ReadUInt32();
+ ReadBytes(d.EscapeSequence, sizeof(d.EscapeSequence));
+ d.VolumeSetSize = ReadUInt16();
+ d.VolumeSequenceNumber = ReadUInt16();
+ d.LogicalBlockSize = ReadUInt16();
+ d.PathTableSize = ReadUInt32();
+ d.LPathTableLocation = ReadUInt32Le();
+ d.LOptionalPathTableLocation = ReadUInt32Le();
+ d.MPathTableLocation = ReadUInt32Be();
+ d.MOptionalPathTableLocation = ReadUInt32Be();
+ ReadDirRecord(d.RootDirRecord);
+ ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId));
+ ReadBytes(d.PublisherId, sizeof(d.PublisherId));
+ ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId));
+ ReadBytes(d.ApplicationId, sizeof(d.ApplicationId));
+ ReadBytes(d.CopyrightFileId, sizeof(d.CopyrightFileId));
+ ReadBytes(d.AbstractFileId, sizeof(d.AbstractFileId));
+ ReadBytes(d.BibFileId, sizeof(d.BibFileId));
+ ReadDateTime(d.CTime);
+ ReadDateTime(d.MTime);
+ ReadDateTime(d.ExpirationTime);
+ ReadDateTime(d.EffectiveTime);
+ d.FileStructureVersion = ReadByte(); // = 1
+ SkipZeros(1);
+ ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse));
+ SkipZeros(653);
+}
+
+static const Byte kSig_CD001[5] = { 'C', 'D', '0', '0', '1' };
+
+static const Byte kSig_NSR02[5] = { 'N', 'S', 'R', '0', '2' };
+static const Byte kSig_NSR03[5] = { 'N', 'S', 'R', '0', '3' };
+static const Byte kSig_BEA01[5] = { 'B', 'E', 'A', '0', '1' };
+static const Byte kSig_TEA01[5] = { 'T', 'E', 'A', '0', '1' };
+
+static inline bool CheckSignature(const Byte *sig, const Byte *data)
+{
+ for (int i = 0; i < 5; i++)
+ if (sig[i] != data[i])
+ return false;
+ return true;
+}
+
+void CInArchive::SeekToBlock(UInt32 blockIndex)
+{
+ if (_stream->Seek((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize, STREAM_SEEK_SET, &_position) != S_OK)
+ throw 1;
+ m_BufferPos = 0;
+}
+
+void CInArchive::ReadDir(CDir &d, int level)
+{
+ if (!d.IsDir())
+ return;
+ SeekToBlock(d.ExtentLocation);
+ UInt64 startPos = _position;
+
+ bool firstItem = true;
+ for (;;)
+ {
+ UInt64 offset = _position - startPos;
+ if (offset >= d.DataLength)
+ break;
+ Byte len = ReadByte();
+ if (len == 0)
+ continue;
+ CDir subItem;
+ ReadDirRecord2(subItem, len);
+ if (firstItem && level == 0)
+ IsSusp = subItem.CheckSusp(SuspSkipSize);
+
+ if (!subItem.IsSystemItem())
+ d._subItems.Add(subItem);
+
+ firstItem = false;
+ }
+ for (int i = 0; i < d._subItems.Size(); i++)
+ ReadDir(d._subItems[i], level + 1);
+}
+
+void CInArchive::CreateRefs(CDir &d)
+{
+ if (!d.IsDir())
+ return;
+ for (int i = 0; i < d._subItems.Size(); i++)
+ {
+ CRef ref;
+ CDir &subItem = d._subItems[i];
+ subItem.Parent = &d;
+ ref.Dir = &d;
+ ref.Index = i;
+ Refs.Add(ref);
+ CreateRefs(subItem);
+ }
+}
+
+void CInArchive::ReadBootInfo()
+{
+ if (!_bootIsDefined)
+ return;
+ if (memcmp(_bootDesc.BootSystemId, kElToritoSpec, sizeof(_bootDesc.BootSystemId)) != 0)
+ return;
+
+ const Byte *p = (const Byte *)_bootDesc.BootSystemUse;
+ UInt32 blockIndex = p[0] | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16) | ((UInt32)p[3] << 24);
+ SeekToBlock(blockIndex);
+ Byte b = ReadByte();
+ if (b != NBootEntryId::kValidationEntry)
+ return;
+ {
+ CBootValidationEntry e;
+ e.PlatformId = ReadByte();
+ if (ReadUInt16Spec() != 0)
+ throw 1;
+ ReadBytes(e.Id, sizeof(e.Id));
+ /* UInt16 checkSum = */ ReadUInt16Spec();
+ if (ReadByte() != 0x55)
+ throw 1;
+ if (ReadByte() != 0xAA)
+ throw 1;
+ }
+ b = ReadByte();
+ if (b == NBootEntryId::kInitialEntryBootable || b == NBootEntryId::kInitialEntryNotBootable)
+ {
+ CBootInitialEntry e;
+ e.Bootable = (b == NBootEntryId::kInitialEntryBootable);
+ e.BootMediaType = ReadByte();
+ e.LoadSegment = ReadUInt16Spec();
+ e.SystemType = ReadByte();
+ if (ReadByte() != 0)
+ throw 1;
+ e.SectorCount = ReadUInt16Spec();
+ e.LoadRBA = ReadUInt32Le();
+ if (ReadByte() != 0)
+ throw 1;
+ BootEntries.Add(e);
+ }
+ else
+ return;
+}
+
+HRESULT CInArchive::Open2()
+{
+ Clear();
+ RINOK(_stream->Seek(kStartPos, STREAM_SEEK_CUR, &_position));
+
+ m_BufferPos = 0;
+ BlockSize = kBlockSize;
+ for (;;)
+ {
+ Byte sig[7];
+ ReadBytes(sig, 7);
+ Byte ver = sig[6];
+ if (!CheckSignature(kSig_CD001, sig + 1))
+ {
+ return S_FALSE;
+ /*
+ if (sig[0] != 0 || ver != 1)
+ break;
+ if (CheckSignature(kSig_BEA01, sig + 1))
+ {
+ }
+ else if (CheckSignature(kSig_TEA01, sig + 1))
+ {
+ break;
+ }
+ else if (CheckSignature(kSig_NSR02, sig + 1))
+ {
+ }
+ else
+ break;
+ SkipZeros(0x800 - 7);
+ continue;
+ */
+ }
+ // version = 2 for ISO 9660:1999?
+ if (ver > 2)
+ throw S_FALSE;
+
+ if (sig[0] == NVolDescType::kTerminator)
+ {
+ break;
+ // Skip(0x800 - 7);
+ // continue;
+ }
+ switch(sig[0])
+ {
+ case NVolDescType::kBootRecord:
+ {
+ _bootIsDefined = true;
+ ReadBootRecordDescriptor(_bootDesc);
+ break;
+ }
+ case NVolDescType::kPrimaryVol:
+ case NVolDescType::kSupplementaryVol:
+ {
+ // some ISOs have two PrimaryVols.
+ CVolumeDescriptor vd;
+ ReadVolumeDescriptor(vd);
+ if (sig[0] == NVolDescType::kPrimaryVol)
+ {
+ // some burners write "Joliet" Escape Sequence to primary volume
+ memset(vd.EscapeSequence, 0, sizeof(vd.EscapeSequence));
+ }
+ VolDescs.Add(vd);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (VolDescs.IsEmpty())
+ return S_FALSE;
+ for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
+ if (VolDescs[MainVolDescIndex].IsJoliet())
+ break;
+ // MainVolDescIndex = 0; // to read primary volume
+ const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
+ if (vd.LogicalBlockSize != kBlockSize)
+ return S_FALSE;
+ (CDirRecord &)_rootDir = vd.RootDirRecord;
+ ReadDir(_rootDir, 0);
+ CreateRefs(_rootDir);
+ ReadBootInfo();
+ return S_OK;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ _stream = inStream;
+ UInt64 pos;
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &pos));
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &_archiveSize));
+ RINOK(_stream->Seek(pos, STREAM_SEEK_SET, &_position));
+ HRESULT res = S_FALSE;
+ try { res = Open2(); }
+ catch(...) { Clear(); res = S_FALSE; }
+ _stream.Release();
+ return res;
+}
+
+void CInArchive::Clear()
+{
+ IncorrectBigEndian = false;
+ Refs.Clear();
+ _rootDir.Clear();
+ VolDescs.Clear();
+ _bootIsDefined = false;
+ BootEntries.Clear();
+ SuspSkipSize = 0;
+ IsSusp = false;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoIn.h
new file mode 100644
index 000000000..f9c6f6403
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoIn.h
@@ -0,0 +1,315 @@
+// Archive/IsoIn.h
+
+#ifndef __ARCHIVE_ISO_IN_H
+#define __ARCHIVE_ISO_IN_H
+
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+
+#include "../../IStream.h"
+
+#include "IsoHeader.h"
+#include "IsoItem.h"
+
+namespace NArchive {
+namespace NIso {
+
+struct CDir: public CDirRecord
+{
+ CDir *Parent;
+ CObjectVector<CDir> _subItems;
+
+ void Clear()
+ {
+ Parent = 0;
+ _subItems.Clear();
+ }
+
+ int GetLength(bool checkSusp, int skipSize) const
+ {
+ int len = GetLengthCur(checkSusp, skipSize);
+ if (Parent != 0)
+ if (Parent->Parent != 0)
+ len += 1 + Parent->GetLength(checkSusp, skipSize);
+ return len;
+ }
+
+ int GetLengthU() const
+ {
+ int len = (int)(FileId.GetCapacity() / 2);
+ if (Parent != 0)
+ if (Parent->Parent != 0)
+ len += 1 + Parent->GetLengthU();
+ return len;
+ }
+
+ AString GetPath(bool checkSusp, int skipSize) const
+ {
+ AString s;
+ int len = GetLength(checkSusp, skipSize);
+ char *p = s.GetBuffer(len + 1);
+ p += len;
+ *p = 0;
+ const CDir *cur = this;
+ for (;;)
+ {
+ int curLen = cur->GetLengthCur(checkSusp, skipSize);
+ p -= curLen;
+ memmove(p, (const char *)(const Byte *)cur->GetNameCur(checkSusp, skipSize), curLen);
+ cur = cur->Parent;
+ if (cur == 0)
+ break;
+ if (cur->Parent == 0)
+ break;
+ p--;
+ *p = CHAR_PATH_SEPARATOR;
+ }
+ s.ReleaseBuffer();
+ return s;
+ }
+
+ UString GetPathU() const
+ {
+ UString s;
+ int len = GetLengthU();
+ wchar_t *p = s.GetBuffer(len + 1);
+ p += len;
+ *p = 0;
+ const CDir *cur = this;
+ for (;;)
+ {
+ int curLen = (int)(cur->FileId.GetCapacity() / 2);
+ p -= curLen;
+ for (int i = 0; i < curLen; i++)
+ {
+ Byte b0 = ((const Byte *)cur->FileId)[i * 2];
+ Byte b1 = ((const Byte *)cur->FileId)[i * 2 + 1];
+ p[i] = (wchar_t)(((wchar_t)b0 << 8) | b1);
+ }
+ cur = cur->Parent;
+ if (cur == 0)
+ break;
+ if (cur->Parent == 0)
+ break;
+ p--;
+ *p = WCHAR_PATH_SEPARATOR;
+ }
+ s.ReleaseBuffer();
+ return s;
+ }
+};
+
+struct CDateTime
+{
+ UInt16 Year;
+ Byte Month;
+ Byte Day;
+ Byte Hour;
+ Byte Minute;
+ Byte Second;
+ Byte Hundredths;
+ signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
+ bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
+ Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
+
+ bool GetFileTime(FILETIME &ft) const
+ {
+ UInt64 value;
+ bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value);
+ if (res)
+ {
+ value -= (UInt64)((Int64)GmtOffset * 15 * 60);
+ value *= 10000000;
+ }
+ ft.dwLowDateTime = (DWORD)value;
+ ft.dwHighDateTime = (DWORD)(value >> 32);
+ return res;
+ }
+};
+
+struct CBootRecordDescriptor
+{
+ Byte BootSystemId[32]; // a-characters
+ Byte BootId[32]; // a-characters
+ Byte BootSystemUse[1977];
+};
+
+struct CBootValidationEntry
+{
+ Byte PlatformId;
+ Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM.
+};
+
+struct CBootInitialEntry
+{
+ bool Bootable;
+ Byte BootMediaType;
+ UInt16 LoadSegment;
+ /* This is the load segment for the initial boot image. If this
+ value is 0 the system will use the traditional segment of 7C0. If this value
+ is non-zero the system will use the specified segment. This applies to x86
+ architectures only. For "flat" model architectures (such as Motorola) this
+ is the address divided by 10. */
+ Byte SystemType; // This must be a copy of byte 5 (System Type) from the
+ // Partition Table found in the boot image.
+ UInt16 SectorCount; // This is the number of virtual/emulated sectors the system
+ // will store at Load Segment during the initial boot procedure.
+ UInt32 LoadRBA; // This is the start address of the virtual disk. CD’s use
+ // Relative/Logical block addressing.
+
+ UInt64 GetSize() const
+ {
+ // if (BootMediaType == NBootMediaType::k1d44Floppy) (1440 << 10);
+ return SectorCount * 512;
+ }
+
+ UString GetName() const
+ {
+ UString s;
+ if (Bootable)
+ s += L"Bootable";
+ else
+ s += L"NotBootable";
+ s += L"_";
+ if (BootMediaType >= kNumBootMediaTypes)
+ {
+ wchar_t name[16];
+ ConvertUInt32ToString(BootMediaType, name);
+ s += name;
+ }
+ else
+ s += kMediaTypes[BootMediaType];
+ s += L".img";
+ return s;
+ }
+};
+
+struct CVolumeDescriptor
+{
+ Byte VolFlags;
+ Byte SystemId[32]; // a-characters. An identification of a system
+ // which can recognize and act upon the content of the Logical
+ // Sectors with logical Sector Numbers 0 to 15 of the volume.
+ Byte VolumeId[32]; // d-characters. An identification of the volume.
+ UInt32 VolumeSpaceSize; // the number of Logical Blocks in which the Volume Space of the volume is recorded
+ Byte EscapeSequence[32];
+ UInt16 VolumeSetSize;
+ UInt16 VolumeSequenceNumber; // the ordinal number of the volume in the Volume Set of which the volume is a member.
+ UInt16 LogicalBlockSize;
+ UInt32 PathTableSize;
+ UInt32 LPathTableLocation;
+ UInt32 LOptionalPathTableLocation;
+ UInt32 MPathTableLocation;
+ UInt32 MOptionalPathTableLocation;
+ CDirRecord RootDirRecord;
+ Byte VolumeSetId[128];
+ Byte PublisherId[128];
+ Byte DataPreparerId[128];
+ Byte ApplicationId[128];
+ Byte CopyrightFileId[37];
+ Byte AbstractFileId[37];
+ Byte BibFileId[37];
+ CDateTime CTime;
+ CDateTime MTime;
+ CDateTime ExpirationTime;
+ CDateTime EffectiveTime;
+ Byte FileStructureVersion; // = 1;
+ Byte ApplicationUse[512];
+
+ bool IsJoliet() const
+ {
+ if ((VolFlags & 1) != 0)
+ return false;
+ Byte b = EscapeSequence[2];
+ return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F &&
+ (b == 0x40 || b == 0x43 || b == 0x45));
+ }
+};
+
+struct CRef
+{
+ CDir *Dir;
+ UInt32 Index;
+};
+
+const UInt32 kBlockSize = 1 << 11;
+
+class CInArchive
+{
+ CMyComPtr<IInStream> _stream;
+ UInt64 _position;
+
+ Byte m_Buffer[kBlockSize];
+ UInt32 m_BufferPos;
+
+ CDir _rootDir;
+ bool _bootIsDefined;
+ CBootRecordDescriptor _bootDesc;
+
+ void Skip(size_t size);
+ void SkipZeros(size_t size);
+ Byte ReadByte();
+ void ReadBytes(Byte *data, UInt32 size);
+ UInt16 ReadUInt16Spec();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32Le();
+ UInt32 ReadUInt32Be();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ UInt32 ReadDigits(int numDigits);
+ void ReadDateTime(CDateTime &d);
+ void ReadRecordingDateTime(CRecordingDateTime &t);
+ void ReadDirRecord2(CDirRecord &r, Byte len);
+ void ReadDirRecord(CDirRecord &r);
+
+ void ReadBootRecordDescriptor(CBootRecordDescriptor &d);
+ void ReadVolumeDescriptor(CVolumeDescriptor &d);
+
+ void SeekToBlock(UInt32 blockIndex);
+ void ReadDir(CDir &d, int level);
+ void CreateRefs(CDir &d);
+
+ void ReadBootInfo();
+ HRESULT Open2();
+public:
+ HRESULT Open(IInStream *inStream);
+ void Clear();
+
+ UInt64 _archiveSize;
+
+ CRecordVector<CRef> Refs;
+ CObjectVector<CVolumeDescriptor> VolDescs;
+ int MainVolDescIndex;
+ UInt32 BlockSize;
+ CObjectVector<CBootInitialEntry> BootEntries;
+ bool IncorrectBigEndian;
+
+
+ bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }
+
+ UInt64 GetBootItemSize(int index) const
+ {
+ const CBootInitialEntry &be = BootEntries[index];
+ UInt64 size = be.GetSize();
+ if (be.BootMediaType == NBootMediaType::k1d2Floppy)
+ size = (1200 << 10);
+ else if (be.BootMediaType == NBootMediaType::k1d44Floppy)
+ size = (1440 << 10);
+ else if (be.BootMediaType == NBootMediaType::k2d88Floppy)
+ size = (2880 << 10);
+ UInt64 startPos = be.LoadRBA * BlockSize;
+ if (startPos < _archiveSize)
+ {
+ if (_archiveSize - startPos < size)
+ size = _archiveSize - startPos;
+ }
+ return size;
+ }
+
+ bool IsSusp;
+ int SuspSkipSize;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoItem.h b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoItem.h
new file mode 100644
index 000000000..f39c2f5d2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoItem.h
@@ -0,0 +1,141 @@
+// Archive/IsoItem.h
+
+#ifndef __ARCHIVE_ISO_ITEM_H
+#define __ARCHIVE_ISO_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+
+#include "Windows/Time.h"
+
+#include "IsoHeader.h"
+
+namespace NArchive {
+namespace NIso {
+
+struct CRecordingDateTime
+{
+ Byte Year;
+ Byte Month;
+ Byte Day;
+ Byte Hour;
+ Byte Minute;
+ Byte Second;
+ signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
+
+ bool GetFileTime(FILETIME &ft) const
+ {
+ UInt64 value;
+ bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value);
+ if (res)
+ {
+ value -= (UInt64)((Int64)GmtOffset * 15 * 60);
+ value *= 10000000;
+ }
+ ft.dwLowDateTime = (DWORD)value;
+ ft.dwHighDateTime = (DWORD)(value >> 32);
+ return res;
+ }
+};
+
+struct CDirRecord
+{
+ Byte ExtendedAttributeRecordLen;
+ UInt32 ExtentLocation;
+ UInt32 DataLength;
+ CRecordingDateTime DateTime;
+ Byte FileFlags;
+ Byte FileUnitSize;
+ Byte InterleaveGapSize;
+ UInt16 VolSequenceNumber;
+ CByteBuffer FileId;
+ CByteBuffer SystemUse;
+
+ bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; }
+ bool IsSystemItem() const
+ {
+ if (FileId.GetCapacity() != 1)
+ return false;
+ Byte b = *(const Byte *)FileId;
+ return (b == 0 || b == 1);
+ }
+
+ const Byte* FindSuspName(int skipSize, int &lenRes) const
+ {
+ lenRes = 0;
+ const Byte *p = (const Byte *)SystemUse + skipSize;
+ int length = (int)(SystemUse.GetCapacity() - skipSize);
+ while (length >= 5)
+ {
+ int len = p[2];
+ if (p[0] == 'N' && p[1] == 'M' && p[3] == 1)
+ {
+ lenRes = len - 5;
+ return p + 5;
+ }
+ p += len;
+ length -= len;
+ }
+ return 0;
+ }
+
+ int GetLengthCur(bool checkSusp, int skipSize) const
+ {
+ if (checkSusp)
+ {
+ int len;
+ const Byte *res = FindSuspName(skipSize, len);
+ if (res != 0)
+ return len;
+ }
+ return (int)FileId.GetCapacity();
+ }
+
+ const Byte* GetNameCur(bool checkSusp, int skipSize) const
+ {
+ if (checkSusp)
+ {
+ int len;
+ const Byte *res = FindSuspName(skipSize, len);
+ if (res != 0)
+ return res;
+ }
+ return (const Byte *)FileId;
+ }
+
+
+ bool CheckSusp(const Byte *p, int &startPos) const
+ {
+ if (p[0] == 'S' &&
+ p[1] == 'P' &&
+ p[2] == 0x7 &&
+ p[3] == 0x1 &&
+ p[4] == 0xBE &&
+ p[5] == 0xEF)
+ {
+ startPos = p[6];
+ return true;
+ }
+ return false;
+ }
+
+ bool CheckSusp(int &startPos) const
+ {
+ const Byte *p = (const Byte *)SystemUse;
+ int length = (int)SystemUse.GetCapacity();
+ const int kMinLen = 7;
+ if (length < kMinLen)
+ return false;
+ if (CheckSusp(p, startPos))
+ return true;
+ const int kOffset2 = 14;
+ if (length < kOffset2 + kMinLen)
+ return false;
+ return CheckSusp(p + kOffset2, startPos);
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoRegister.cpp
new file mode 100644
index 000000000..67a09c769
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/IsoRegister.cpp
@@ -0,0 +1,13 @@
+// IsoRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "IsoHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NIso::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Iso", L"iso img", 0, 0xE7, { 'C', 'D', '0', '0', '1', 0x1 }, 7, false, CreateArc, 0 };
+
+REGISTER_ARC(Iso)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Iso/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Iso/StdAfx.h
new file mode 100644
index 000000000..2e4be10b2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Iso/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/LzhHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/LzhHandler.cpp
new file mode 100644
index 000000000..95efc5013
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/LzhHandler.cpp
@@ -0,0 +1,775 @@
+// LzhHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../ICoder.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/LzhDecoder.h"
+
+#include "IArchive.h"
+
+#include "Common/ItemNameUtils.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NLzh{
+
+const int kMethodIdSize = 5;
+
+const Byte kExtIdFileName = 0x01;
+const Byte kExtIdDirName = 0x02;
+const Byte kExtIdUnixTime = 0x54;
+
+struct CExtension
+{
+ Byte Type;
+ CByteBuffer Data;
+ AString GetString() const
+ {
+ AString s;
+ for (size_t i = 0; i < Data.GetCapacity(); i++)
+ {
+ char c = (char)Data[i];
+ if (c == 0)
+ break;
+ s += c;
+ }
+ return s;
+ }
+};
+
+struct CItem
+{
+ AString Name;
+ Byte Method[kMethodIdSize];
+ Byte Attributes;
+ Byte Level;
+ Byte OsId;
+ UInt32 PackSize;
+ UInt32 Size;
+ UInt32 ModifiedTime;
+ UInt16 CRC;
+ CObjectVector<CExtension> Extensions;
+
+ bool IsValidMethod() const { return (Method[0] == '-' && Method[1] == 'l' && Method[4] == '-'); }
+ bool IsLhMethod() const {return (IsValidMethod() && Method[2] == 'h'); }
+ bool IsDir() const {return (IsLhMethod() && Method[3] == 'd'); }
+
+ bool IsCopyMethod() const
+ {
+ return (IsLhMethod() && Method[3] == '0') ||
+ (IsValidMethod() && Method[2] == 'z' && Method[3] == '4');
+ }
+
+ bool IsLh1GroupMethod() const
+ {
+ if (!IsLhMethod())
+ return false;
+ switch(Method[3])
+ {
+ case '1':
+ return true;
+ }
+ return false;
+ }
+
+ bool IsLh4GroupMethod() const
+ {
+ if (!IsLhMethod())
+ return false;
+ switch(Method[3])
+ {
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ return true;
+ }
+ return false;
+ }
+
+ int GetNumDictBits() const
+ {
+ if (!IsLhMethod())
+ return 0;
+ switch(Method[3])
+ {
+ case '1': return 12;
+ case '2': return 13;
+ case '3': return 13;
+ case '4': return 12;
+ case '5': return 13;
+ case '6': return 15;
+ case '7': return 16;
+ }
+ return 0;
+ }
+
+ int FindExt(Byte type) const
+ {
+ for (int i = 0; i < Extensions.Size(); i++)
+ if (Extensions[i].Type == type)
+ return i;
+ return -1;
+ }
+ bool GetUnixTime(UInt32 &value) const
+ {
+ int index = FindExt(kExtIdUnixTime);
+ if (index < 0)
+ {
+ if (Level == 2)
+ {
+ value = ModifiedTime;
+ return true;
+ }
+ return false;
+ }
+ const Byte *data = (const Byte *)(Extensions[index].Data);
+ value = GetUi32(data);
+ return true;
+ }
+
+ AString GetDirName() const
+ {
+ int index = FindExt(kExtIdDirName);
+ if (index < 0)
+ return AString();
+ return Extensions[index].GetString();
+ }
+
+ AString GetFileName() const
+ {
+ int index = FindExt(kExtIdFileName);
+ if (index < 0)
+ return Name;
+ return Extensions[index].GetString();
+ }
+
+ AString GetName() const
+ {
+ AString dirName = GetDirName();
+ const char kDirSeparator = '\\';
+ // check kDirSeparator in Linux
+ dirName.Replace((char)(unsigned char)0xFF, kDirSeparator);
+ if (!dirName.IsEmpty() && dirName.Back() != kDirSeparator)
+ dirName += kDirSeparator;
+ return dirName + GetFileName();
+ }
+};
+
+struct CItemEx: public CItem
+{
+ UInt64 DataPosition;
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+ UInt64 m_Position;
+
+ HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
+ HRESULT CheckReadBytes(void *data, UInt32 size);
+public:
+ HRESULT Open(IInStream *inStream);
+ HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
+ HRESULT Skip(UInt64 numBytes);
+};
+
+HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
+{
+ size_t realProcessedSize = size;
+ RINOK(ReadStream(m_Stream, data, &realProcessedSize));
+ processedSize = (UInt32)realProcessedSize;
+ m_Position += processedSize;
+ return S_OK;
+}
+
+HRESULT CInArchive::CheckReadBytes(void *data, UInt32 size)
+{
+ UInt32 processedSize;
+ RINOK(ReadBytes(data, size, processedSize));
+ return (processedSize == size) ? S_OK: S_FALSE;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
+ m_Stream = inStream;
+ return S_OK;
+}
+
+static const Byte *ReadUInt16(const Byte *p, UInt16 &v)
+{
+ v = Get16(p);
+ return p + 2;
+}
+
+static const Byte *ReadString(const Byte *p, size_t size, AString &s)
+{
+ s.Empty();
+ for (size_t i = 0; i < size; i++)
+ {
+ char c = p[i];
+ if (c == 0)
+ break;
+ s += c;
+ }
+ return p + size;
+}
+
+static Byte CalcSum(const Byte *data, size_t size)
+{
+ Byte sum = 0;
+ for (size_t i = 0; i < size; i++)
+ sum = (Byte)(sum + data[i]);
+ return sum;
+}
+
+HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
+{
+ filled = false;
+
+ UInt32 processedSize;
+ Byte startHeader[2];
+ RINOK(ReadBytes(startHeader, 2, processedSize))
+ if (processedSize == 0)
+ return S_OK;
+ if (processedSize == 1)
+ return (startHeader[0] == 0) ? S_OK: S_FALSE;
+ if (startHeader[0] == 0 && startHeader[1] == 0)
+ return S_OK;
+
+ Byte header[256];
+ const UInt32 kBasicPartSize = 22;
+ RINOK(ReadBytes(header, kBasicPartSize, processedSize));
+ if (processedSize != kBasicPartSize)
+ return (startHeader[0] == 0) ? S_OK: S_FALSE;
+
+ const Byte *p = header;
+ memcpy(item.Method, p, kMethodIdSize);
+ if (!item.IsValidMethod())
+ return S_OK;
+ p += kMethodIdSize;
+ item.PackSize = Get32(p);
+ item.Size = Get32(p + 4);
+ item.ModifiedTime = Get32(p + 8);
+ item.Attributes = p[12];
+ item.Level = p[13];
+ p += 14;
+ if (item.Level > 2)
+ return S_FALSE;
+ UInt32 headerSize;
+ if (item.Level < 2)
+ {
+ headerSize = startHeader[0];
+ if (headerSize < kBasicPartSize)
+ return S_FALSE;
+ UInt32 remain = headerSize - kBasicPartSize;
+ RINOK(CheckReadBytes(header + kBasicPartSize, remain));
+ if (startHeader[1] != CalcSum(header, headerSize))
+ return S_FALSE;
+ size_t nameLength = *p++;
+ if ((p - header) + nameLength + 2 > headerSize)
+ return S_FALSE;
+ p = ReadString(p, nameLength, item.Name);
+ }
+ else
+ headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8);
+ p = ReadUInt16(p, item.CRC);
+ if (item.Level != 0)
+ {
+ if (item.Level == 2)
+ {
+ RINOK(CheckReadBytes(header + kBasicPartSize, 2));
+ }
+ if ((size_t)(p - header) + 3 > headerSize)
+ return S_FALSE;
+ item.OsId = *p++;
+ UInt16 nextSize;
+ p = ReadUInt16(p, nextSize);
+ while (nextSize != 0)
+ {
+ if (nextSize < 3)
+ return S_FALSE;
+ if (item.Level == 1)
+ {
+ if (item.PackSize < nextSize)
+ return S_FALSE;
+ item.PackSize -= nextSize;
+ }
+ CExtension ext;
+ RINOK(CheckReadBytes(&ext.Type, 1))
+ nextSize -= 3;
+ ext.Data.SetCapacity(nextSize);
+ RINOK(CheckReadBytes((Byte *)ext.Data, nextSize))
+ item.Extensions.Add(ext);
+ Byte hdr2[2];
+ RINOK(CheckReadBytes(hdr2, 2));
+ ReadUInt16(hdr2, nextSize);
+ }
+ }
+ item.DataPosition = m_Position;
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CInArchive::Skip(UInt64 numBytes)
+{
+ UInt64 newPostion;
+ RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
+ m_Position += numBytes;
+ if (m_Position != newPostion)
+ return E_FAIL;
+ return S_OK;
+}
+
+struct COsPair
+{
+ Byte Id;
+ const char *Name;
+};
+
+static COsPair g_OsPairs[] =
+{
+ { 0, "MS-DOS" },
+ { 'M', "MS-DOS" },
+ { '2', "OS/2" },
+ { '9', "OS9" },
+ { 'K', "OS/68K" },
+ { '3', "OS/386" },
+ { 'H', "HUMAN" },
+ { 'U', "UNIX" },
+ { 'C', "CP/M" },
+ { 'F', "FLEX" },
+ { 'm', "Mac" },
+ { 'R', "Runser" },
+ { 'T', "TownsOS" },
+ { 'X', "XOSK" },
+ { 'w', "Windows 95" },
+ { 'W', "Windows NT" },
+ { 'J', "Java VM" }
+};
+
+static const char *kUnknownOS = "Unknown";
+
+static const char *GetOS(Byte osId)
+{
+ for (int i = 0; i < sizeof(g_OsPairs) / sizeof(g_OsPairs[0]); i++)
+ if (g_OsPairs[i].Id == osId)
+ return g_OsPairs[i].Name;
+ return kUnknownOS;
+}
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ // { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR}
+};
+
+class CCRC
+{
+ UInt16 _value;
+public:
+ static UInt16 Table[256];
+ static void InitTable();
+
+ CCRC(): _value(0) {}
+ void Init() { _value = 0; }
+ void Update(const void *data, size_t size);
+ UInt16 GetDigest() const { return _value; }
+};
+
+static const UInt16 kCRCPoly = 0xA001;
+
+UInt16 CCRC::Table[256];
+
+void CCRC::InitTable()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ for (int j = 0; j < 8; j++)
+ if (r & 1)
+ r = (r >> 1) ^ kCRCPoly;
+ else
+ r >>= 1;
+ CCRC::Table[i] = (UInt16)r;
+ }
+}
+
+class CCRCTableInit
+{
+public:
+ CCRCTableInit() { CCRC::InitTable(); }
+} g_CRCTableInit;
+
+void CCRC::Update(const void *data, size_t size)
+{
+ UInt16 v = _value;
+ const Byte *p = (const Byte *)data;
+ for (; size > 0; size--, p++)
+ v = (UInt16)(Table[((Byte)(v)) ^ *p] ^ (v >> 8));
+ _value = v;
+}
+
+
+class COutStreamWithCRC:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+private:
+ CCRC _crc;
+ CMyComPtr<ISequentialOutStream> _stream;
+public:
+ void Init(ISequentialOutStream *stream)
+ {
+ _stream = stream;
+ _crc.Init();
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return _crc.GetDigest(); }
+ void InitCRC() { _crc.Init(); }
+};
+
+STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result;
+ if (!_stream)
+ {
+ realProcessedSize = size;
+ result = S_OK;
+ }
+ else
+ result = _stream->Write(data, size, &realProcessedSize);
+ _crc.Update(data, realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CObjectVector<CItemEx> _items;
+ CMyComPtr<IInStream> _stream;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+ CHandler();
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+CHandler::CHandler() {}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItemEx &item = _items[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString s = NItemName::WinNameToOSName(MultiByteToUnicodeString(item.GetName(), CP_OEMCP));
+ if (!s.IsEmpty())
+ {
+ if (s[s.Length() - 1] == WCHAR_PATH_SEPARATOR)
+ s.Delete(s.Length() - 1);
+ prop = s;
+ }
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidCRC: prop = (UInt32)item.CRC; break;
+ case kpidHostOS: prop = GetOS(item.OsId); break;
+ case kpidMTime:
+ {
+ FILETIME utc;
+ UInt32 unixTime;
+ if (item.GetUnixTime(unixTime))
+ NTime::UnixTimeToFileTime(unixTime, utc);
+ else
+ {
+ FILETIME localFileTime;
+ if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utc))
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ else
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ prop = utc;
+ break;
+ }
+ // case kpidAttrib: prop = (UInt32)item.Attributes; break;
+ case kpidMethod:
+ {
+ char method2[kMethodIdSize + 1];
+ method2[kMethodIdSize] = 0;
+ memcpy(method2, item.Method, kMethodIdSize);
+ prop = method2;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ _items.Clear();
+ CInArchive archive;
+
+ UInt64 endPos = 0;
+ bool needSetTotal = true;
+
+ if (callback != NULL)
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+
+ RINOK(archive.Open(stream));
+ for (;;)
+ {
+ CItemEx item;
+ bool filled;
+ HRESULT result = archive.GetNextItem(filled, item);
+ if (result == S_FALSE)
+ return S_FALSE;
+ if (result != S_OK)
+ return S_FALSE;
+ if (!filled)
+ break;
+ _items.Add(item);
+ archive.Skip(item.PackSize);
+ if (callback != NULL)
+ {
+ if (needSetTotal)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos));
+ needSetTotal = false;
+ }
+ if (_items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = item.DataPosition;
+ RINOK(callback->SetCompleted(&numFiles, &numBytes));
+ }
+ }
+ }
+ if (_items.IsEmpty())
+ return S_FALSE;
+
+ _stream = stream;
+ }
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ COM_TRY_END
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool testMode = (testModeSpec != 0);
+ UInt64 totalUnPacked = 0, totalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItemEx &item = _items[allFilesMode ? i : indices[i]];
+ totalUnPacked += item.Size;
+ totalPacked += item.PackSize;
+ }
+ RINOK(extractCallback->SetTotal(totalUnPacked));
+
+ UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
+ UInt64 currentItemUnPacked, currentItemPacked;
+
+ NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0;
+ CMyComPtr<ICompressCoder> lzhDecoder;
+ CMyComPtr<ICompressCoder> lzh1Decoder;
+ CMyComPtr<ICompressCoder> arj2Decoder;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
+ currentTotalPacked += currentItemPacked)
+ {
+ currentItemUnPacked = 0;
+ currentItemPacked = 0;
+
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = currentTotalUnPacked;
+ RINOK(lps->SetCur());
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode;
+ askMode = testMode ? NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItemEx &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (item.IsDir())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ continue;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ currentItemUnPacked = item.Size;
+ currentItemPacked = item.PackSize;
+
+ {
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init(realOutStream);
+ realOutStream.Release();
+
+ UInt64 pos;
+ _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
+
+ streamSpec->Init(item.PackSize);
+
+ HRESULT result = S_OK;
+ Int32 opRes = NExtract::NOperationResult::kOK;
+
+ if (item.IsCopyMethod())
+ {
+ result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
+ result = S_FALSE;
+ }
+ else if (item.IsLh4GroupMethod())
+ {
+ if (!lzhDecoder)
+ {
+ lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
+ lzhDecoder = lzhDecoderSpec;
+ }
+ lzhDecoderSpec->SetDictionary(item.GetNumDictBits());
+ result = lzhDecoder->Code(inStream, outStream, NULL, &currentItemUnPacked, progress);
+ }
+ /*
+ else if (item.IsLh1GroupMethod())
+ {
+ if (!lzh1Decoder)
+ {
+ lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder;
+ lzh1Decoder = lzh1DecoderSpec;
+ }
+ lzh1DecoderSpec->SetDictionary(item.GetNumDictBits());
+ result = lzh1Decoder->Code(inStream, outStream, NULL, &currentItemUnPacked, progress);
+ }
+ */
+ else
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ if (result == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(result);
+ if (outStreamSpec->GetCRC() != item.CRC)
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Lzh", L"lzh lha", 0, 6, { '-', 'l' }, 2, false, CreateArc, 0 };
+
+REGISTER_ARC(Lzh)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp
new file mode 100644
index 000000000..a83e6a1ad
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp
@@ -0,0 +1,430 @@
+// LzmaHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/CreateCoder.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/LzmaDecoder.h"
+
+#include "Common/DummyOutStream.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NLzma {
+
+static bool CheckDicSize(const Byte *p)
+{
+ UInt32 dicSize = GetUi32(p);
+ for (int i = 1; i <= 30; i++)
+ if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i))
+ return true;
+ return (dicSize == 0xFFFFFFFF);
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+struct CHeader
+{
+ UInt64 Size;
+ Byte FilterID;
+ Byte LzmaProps[5];
+
+ UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); }
+ bool HasSize() const { return (Size != (UInt64)(Int64)-1); }
+ bool Parse(const Byte *buf, bool isThereFilter);
+};
+
+bool CHeader::Parse(const Byte *buf, bool isThereFilter)
+{
+ FilterID = 0;
+ if (isThereFilter)
+ FilterID = buf[0];
+ const Byte *sig = buf + (isThereFilter ? 1 : 0);
+ for (int i = 0; i < 5; i++)
+ LzmaProps[i] = sig[i];
+ Size = GetUi64(sig + 5);
+ return
+ LzmaProps[0] < 5 * 5 * 9 &&
+ FilterID < 2 &&
+ (!HasSize() || Size < ((UInt64)1 << 56)) &&
+ CheckDicSize(LzmaProps + 1);
+}
+
+class CDecoder
+{
+ NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+ CMyComPtr<ICompressCoder> _lzmaDecoder;
+ CMyComPtr<ISequentialOutStream> _bcjStream;
+public:
+ ~CDecoder();
+ HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS
+ bool filtered, ISequentialInStream *inStream);
+
+ HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+
+ UInt64 GetInputProcessedSize() const { return _lzmaDecoderSpec->GetInputProcessedSize(); }
+
+ void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoderSpec->ReleaseInStream(); }
+
+ HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize)
+ { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); }
+};
+
+static const UInt64 k_BCJ = 0x03030103;
+
+HRESULT CDecoder::Create(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ bool filteredMode, ISequentialInStream *inStream)
+{
+ if (!_lzmaDecoder)
+ {
+ _lzmaDecoderSpec = new NCompress::NLzma::CDecoder;
+ _lzmaDecoder = _lzmaDecoderSpec;
+ }
+
+ if (filteredMode)
+ {
+ if (!_bcjStream)
+ {
+ CMyComPtr<ICompressCoder> coder;
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS k_BCJ, coder, false));
+ if (!coder)
+ return E_NOTIMPL;
+ coder.QueryInterface(IID_ISequentialOutStream, &_bcjStream);
+ if (!_bcjStream)
+ return E_NOTIMPL;
+ }
+ }
+
+ return _lzmaDecoderSpec->SetInStream(inStream);
+}
+
+CDecoder::~CDecoder()
+{
+ ReleaseInStream();
+}
+
+HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream,
+ ICompressProgressInfo *progress)
+{
+ if (header.FilterID > 1)
+ return E_NOTIMPL;
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ _lzmaDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+ if (!setDecoderProperties)
+ return E_NOTIMPL;
+ RINOK(setDecoderProperties->SetDecoderProperties2(header.LzmaProps, 5));
+ }
+
+ CMyComPtr<ICompressSetOutStream> setOutStream;
+
+ bool filteredMode = (header.FilterID == 1);
+
+ if (filteredMode)
+ {
+ _bcjStream.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
+ if (!setOutStream)
+ return E_NOTIMPL;
+ RINOK(setOutStream->SetOutStream(outStream));
+ outStream = _bcjStream;
+ }
+
+ const UInt64 *Size = header.HasSize() ? &header.Size : NULL;
+ HRESULT res = _lzmaDecoderSpec->CodeResume(outStream, Size, progress);
+
+ if (filteredMode)
+ {
+ CMyComPtr<IOutStreamFlush> flush;
+ _bcjStream.QueryInterface(IID_IOutStreamFlush, &flush);
+ if (flush)
+ {
+ HRESULT res2 = flush->Flush();
+ if (res == S_OK)
+ res = res2;
+ }
+ HRESULT res2 = setOutStream->ReleaseOutStream();
+ if (res == S_OK)
+ res = res2;
+ }
+ RINOK(res);
+
+ return S_OK;
+}
+
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+ CHeader _header;
+ bool _lzma86;
+ UInt64 _startPosition;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ DECL_EXTERNAL_CODECS_VARS
+ DECL_ISetCompressCodecsInfo
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+
+ CHandler(bool lzma86) { _lzma86 = lzma86; }
+
+ unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); }
+
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+static void DictSizeToString(UInt32 value, char *s)
+{
+ for (int i = 0; i <= 31; i++)
+ if ((UInt32(1) << i) == value)
+ {
+ ::ConvertUInt32ToString(i, s);
+ return;
+ }
+ char c = 'b';
+ if ((value & ((1 << 20) - 1)) == 0)
+ {
+ value >>= 20;
+ c = 'm';
+ }
+ else if ((value & ((1 << 10) - 1)) == 0)
+ {
+ value >>= 10;
+ c = 'k';
+ }
+ ::ConvertUInt32ToString(value, s);
+ int p = MyStringLen(s);
+ s[p++] = c;
+ s[p++] = '\0';
+}
+
+static void MyStrCat(char *d, const char *s)
+{
+ MyStringCopy(d + MyStringLen(d), s);
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidMethod:
+ if (_stream)
+ {
+ char s[64];
+ s[0] = '\0';
+ if (_header.FilterID != 0)
+ MyStrCat(s, "BCJ ");
+ MyStrCat(s, "LZMA:");
+ DictSizeToString(_header.GetDicSize(), s + MyStringLen(s));
+ prop = s;
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *)
+{
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
+
+ const UInt32 kBufSize = 1 + 5 + 8 + 1;
+ Byte buf[kBufSize];
+
+ RINOK(ReadStream_FALSE(inStream, buf, kBufSize));
+
+ if (!_header.Parse(buf, _lzma86))
+ return S_FALSE;
+ const Byte *start = buf + GetHeaderSize();
+ if (start[0] != 0)
+ return S_FALSE;
+
+ UInt64 endPos;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
+ _packSize = endPos - _startPosition;
+ _packSizeDefined = true;
+
+ _stream = inStream;
+ _seqStream = inStream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _stream.Release();
+ _seqStream.Release();
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_stream)
+ extractCallback->SetTotal(_packSize);
+
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ }
+
+ CDecoder decoder;
+ HRESULT result = decoder.Create(
+ EXTERNAL_CODECS_VARS
+ _lzma86, _seqStream);
+ RINOK(result);
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ bool firstItem = true;
+
+ for (;;)
+ {
+ lps->OutSize = outStreamSpec->GetSize();
+ lps->InSize = _packSize = decoder.GetInputProcessedSize();
+ _packSizeDefined = true;
+ RINOK(lps->SetCur());
+
+ CHeader st;
+
+ const UInt32 kBufSize = 1 + 5 + 8;
+ Byte buf[kBufSize];
+ const UInt32 headerSize = GetHeaderSize();
+ UInt32 processed;
+ RINOK(decoder.ReadInput(buf, headerSize, &processed));
+ if (processed != headerSize)
+ break;
+
+ if (!st.Parse(buf, _lzma86))
+ break;
+ firstItem = false;
+
+ result = decoder.Code(st, outStream, progress);
+ if (result == E_NOTIMPL)
+ {
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ break;
+ }
+ if (result == S_FALSE)
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ RINOK(result);
+ }
+ if (firstItem)
+ return E_FAIL;
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+static IInArchive *CreateArc() { return new CHandler(false); }
+static IInArchive *CreateArc86() { return new CHandler(true); }
+
+namespace NLzmaAr {
+
+static CArcInfo g_ArcInfo =
+ { L"lzma", L"lzma", 0, 0xA, { 0 }, 0, true, CreateArc, NULL };
+REGISTER_ARC(Lzma)
+
+}
+
+namespace NLzma86Ar {
+
+static CArcInfo g_ArcInfo =
+ { L"lzma86", L"lzma86", 0, 0xB, { 0 }, 0, true, CreateArc86, NULL };
+REGISTER_ARC(Lzma86)
+
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/MachoHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/MachoHandler.cpp
new file mode 100644
index 000000000..a6261f34d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/MachoHandler.cpp
@@ -0,0 +1,500 @@
+// MachoHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
+static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NMacho {
+
+#define MACH_ARCH_ABI64 (1 << 24)
+#define MACH_MACHINE_386 7
+#define MACH_MACHINE_ARM 12
+#define MACH_MACHINE_SPARC 14
+#define MACH_MACHINE_PPC 18
+
+#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC)
+#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386)
+
+#define MACH_CMD_SEGMENT_32 1
+#define MACH_CMD_SEGMENT_64 0x19
+
+#define MACH_SECT_TYPE_MASK 0x000000FF
+#define MACH_SECT_ATTR_MASK 0xFFFFFF00
+
+#define MACH_SECT_ATTR_ZEROFILL 1
+
+static const char *g_SectTypes[] =
+{
+ "REGULAR",
+ "ZEROFILL",
+ "CSTRINGS",
+ "4BYTE_LITERALS",
+ "8BYTE_LITERALS",
+ "LITERAL_POINTERS",
+ "NON_LAZY_SYMBOL_POINTERS",
+ "LAZY_SYMBOL_POINTERS",
+ "SYMBOL_STUBS",
+ "MOD_INIT_FUNC_POINTERS",
+ "MOD_TERM_FUNC_POINTERS",
+ "COALESCED",
+ "GB_ZEROFILL",
+ "INTERPOSING",
+ "16BYTE_LITERALS"
+};
+
+static const char *g_FileTypes[] =
+{
+ "0",
+ "OBJECT",
+ "EXECUTE",
+ "FVMLIB",
+ "CORE",
+ "PRELOAD",
+ "DYLIB",
+ "DYLINKER",
+ "BUNDLE",
+ "DYLIB_STUB",
+ "DSYM"
+};
+
+static const CUInt32PCharPair g_Flags[] =
+{
+ { 31, "PURE_INSTRUCTIONS" },
+ { 30, "NO_TOC" },
+ { 29, "STRIP_STATIC_SYMS" },
+ { 28, "NO_DEAD_STRIP" },
+ { 27, "LIVE_SUPPORT" },
+ { 26, "SELF_MODIFYING_CODE" },
+ { 25, "DEBUG" },
+ { 10, "SOME_INSTRUCTIONS" },
+ { 9, "EXT_RELOC" },
+ { 8, "LOC_RELOC" }
+};
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { MACH_MACHINE_386, "x86" },
+ { MACH_MACHINE_ARM, "ARM" },
+ { MACH_MACHINE_SPARC, "SPARC" },
+ { MACH_MACHINE_PPC, "PowerPC" },
+ { MACH_MACHINE_PPC64, "PowerPC 64-bit" },
+ { MACH_MACHINE_AMD64, "x64" }
+};
+
+static const int kNameSize = 16;
+
+struct CSegment
+{
+ char Name[kNameSize];
+};
+
+struct CSection
+{
+ char Name[kNameSize];
+ char SegName[kNameSize];
+ UInt64 Va;
+ UInt64 Pa;
+ UInt64 VSize;
+ UInt64 PSize;
+
+ UInt32 Flags;
+ int SegmentIndex;
+
+ bool IsDummy;
+
+ CSection(): IsDummy(false) {}
+ // UInt64 GetPackSize() const { return Flags == MACH_SECT_ATTR_ZEROFILL ? 0 : Size; }
+ UInt64 GetPackSize() const { return PSize; }
+};
+
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+ CObjectVector<CSegment> _segments;
+ CObjectVector<CSection> _sections;
+ bool _mode64;
+ bool _be;
+ UInt32 _machine;
+ UInt32 _type;
+ UInt32 _headersSize;
+ UInt64 _totalSize;
+ HRESULT Open2(ISequentialInStream *stream);
+ bool Parse(const Byte *buf, UInt32 size);
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+bool CHandler::Parse(const Byte *buf, UInt32 size)
+{
+ bool mode64 = _mode64;
+ bool be = _be;
+
+ const Byte *bufStart = buf;
+ bool reduceCommands = false;
+ if (size < 512)
+ return false;
+
+ _machine = Get32(buf + 4, be);
+ _type = Get32(buf + 0xC, be);
+
+ UInt32 numCommands = Get32(buf + 0x10, be);
+ UInt32 commandsSize = Get32(buf + 0x14, be);
+ if (commandsSize > size)
+ return false;
+
+ if (commandsSize > (1 << 24) || numCommands > (1 << 18))
+ return false;
+
+ if (numCommands > 16)
+ {
+ reduceCommands = true;
+ numCommands = 16;
+ }
+
+ _headersSize = 0;
+
+ buf += 0x1C;
+ size -= 0x1C;
+
+ if (mode64)
+ {
+ buf += 4;
+ size -= 4;
+ }
+
+ _totalSize = (UInt32)(buf - bufStart);
+ if (commandsSize < size)
+ size = commandsSize;
+
+ for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++)
+ {
+ if (size < 8)
+ return false;
+ UInt32 cmd = Get32(buf, be);
+ UInt32 cmdSize = Get32(buf + 4, be);
+ if (size < cmdSize)
+ return false;
+ if (cmd == MACH_CMD_SEGMENT_32 || cmd == MACH_CMD_SEGMENT_64)
+ {
+ UInt32 offs = (cmd == MACH_CMD_SEGMENT_64) ? 0x48 : 0x38;
+ if (cmdSize < offs)
+ break;
+
+ UInt64 vmAddr, vmSize, phAddr, phSize;
+
+ {
+ if (cmd == MACH_CMD_SEGMENT_64)
+ {
+ vmAddr = Get64(buf + 0x18, be);
+ vmSize = Get64(buf + 0x20, be);
+ phAddr = Get64(buf + 0x28, be);
+ phSize = Get64(buf + 0x30, be);
+ }
+ else
+ {
+ vmAddr = Get32(buf + 0x18, be);
+ vmSize = Get32(buf + 0x1C, be);
+ phAddr = Get32(buf + 0x20, be);
+ phSize = Get32(buf + 0x24, be);
+ }
+ {
+ UInt64 totalSize = phAddr + phSize;
+ if (totalSize > _totalSize)
+ _totalSize = totalSize;
+ }
+ }
+
+ CSegment seg;
+ memcpy(seg.Name, buf + 8, kNameSize);
+ _segments.Add(seg);
+
+ UInt32 numSections = Get32(buf + offs - 8, be);
+ if (numSections > (1 << 8))
+ return false;
+
+ if (numSections == 0)
+ {
+ CSection section;
+ section.IsDummy = true;
+ section.SegmentIndex = _segments.Size() - 1;
+ section.Va = vmAddr;
+ section.PSize = phSize;
+ section.VSize = vmSize;
+ section.Pa = phAddr;
+ section.Flags = 0;
+ _sections.Add(section);
+ }
+ else do
+ {
+ CSection section;
+ UInt32 headerSize = (cmd == MACH_CMD_SEGMENT_64) ? 0x50 : 0x44;
+ const Byte *p = buf + offs;
+ if (cmdSize - offs < headerSize)
+ break;
+ if (cmd == MACH_CMD_SEGMENT_64)
+ {
+ section.Va = Get64(p + 0x20, be);
+ section.VSize = Get64(p + 0x28, be);
+ section.Pa = Get32(p + 0x30, be);
+ section.Flags = Get32(p + 0x40, be);
+ }
+ else
+ {
+ section.Va = Get32(p + 0x20, be);
+ section.VSize = Get32(p + 0x24, be);
+ section.Pa = Get32(p + 0x28, be);
+ section.Flags = Get32(p + 0x38, be);
+ }
+ if (section.Flags == MACH_SECT_ATTR_ZEROFILL)
+ section.PSize = 0;
+ else
+ section.PSize = section.VSize;
+ memcpy(section.Name, p, kNameSize);
+ memcpy(section.SegName, p + kNameSize, kNameSize);
+ section.SegmentIndex = _segments.Size() - 1;
+ _sections.Add(section);
+ offs += headerSize;
+ }
+ while (--numSections);
+
+ if (offs != cmdSize)
+ return false;
+ }
+ buf += cmdSize;
+ size -= cmdSize;
+ }
+ _headersSize = (UInt32)(buf - bufStart);
+ return reduceCommands || (size == 0);
+}
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCpu, VT_BSTR},
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidBigEndian, VT_BOOL},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI4}
+};
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidVa, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _machine, prop); break;
+ case kpidCharacts: TYPE_TO_PROP(g_FileTypes, _type, prop); break;
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _headersSize; break;
+ case kpidBit64: if (_mode64) prop = _mode64; break;
+ case kpidBigEndian: if (_be) prop = _be; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static AString GetName(const char *name)
+{
+ char res[kNameSize + 1];
+ memcpy(res, name, kNameSize);
+ res[kNameSize] = 0;
+ return res;
+}
+
+static AString SectFlagsToString(UInt32 flags)
+{
+ AString res = TypeToString(g_SectTypes, sizeof(g_SectTypes) / sizeof(g_SectTypes[0]),
+ flags & MACH_SECT_TYPE_MASK);
+ AString s = FlagsToString(g_Flags, sizeof(g_Flags) / sizeof(g_Flags[0]),
+ flags & MACH_SECT_ATTR_MASK);
+ if (!s.IsEmpty())
+ {
+ res += ' ';
+ res += s;
+ }
+ return res;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CSection &item = _sections[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ AString s = GetName(_segments[item.SegmentIndex].Name);
+ if (!item.IsDummy)
+ s += GetName(item.Name);
+ StringToProp(s, prop);
+ break;
+ }
+ case kpidSize: /* prop = (UInt64)item.VSize; break; */
+ case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
+ case kpidCharacts: if (!item.IsDummy) StringToProp(SectFlagsToString(item.Flags), prop); break;
+ case kpidOffset: prop = item.Pa; break;
+ case kpidVa: prop = item.Va; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(ISequentialInStream *stream)
+{
+ const UInt32 kBufSize = 1 << 18;
+ const UInt32 kSigSize = 4;
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ size_t processed = kSigSize;
+ RINOK(ReadStream_FALSE(stream, buf, processed));
+ UInt32 sig = GetUi32(buf);
+ bool be, mode64;
+ switch(sig)
+ {
+ case 0xCEFAEDFE: be = true; mode64 = false; break;
+ case 0xCFFAEDFE: be = true; mode64 = true; break;
+ case 0xFEEDFACE: be = false; mode64 = false; break;
+ case 0xFEEDFACF: be = false; mode64 = true; break;
+ default: return S_FALSE;
+ }
+ processed = kBufSize - kSigSize;
+ RINOK(ReadStream(stream, buf + kSigSize, &processed));
+ _mode64 = mode64;
+ _be = be;
+ return Parse(buf, (UInt32)processed + kSigSize) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream));
+ _inStream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _sections.Clear();
+ _segments.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _sections.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _sections.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _sections[allFilesMode ? i : indices[i]].GetPackSize();
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CSection &item = _sections[index];
+ currentItemSize = item.GetPackSize();
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(_inStream->Seek(item.Pa, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"MachO", L"", 0, 0xDF, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Macho)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/MbrHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/MbrHandler.cpp
new file mode 100644
index 000000000..b6d791829
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/MbrHandler.cpp
@@ -0,0 +1,507 @@
+// MbrHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NMbr {
+
+struct CChs
+{
+ Byte Head;
+ Byte SectCyl;
+ Byte Cyl8;
+
+ UInt32 GetSector() const { return SectCyl & 0x3F; }
+ UInt32 GetCyl() const { return ((UInt32)SectCyl >> 6 << 8) | Cyl8; }
+ void ToString(NCOM::CPropVariant &prop) const;
+
+ void Parse(const Byte *p)
+ {
+ Head = p[0];
+ SectCyl = p[1];
+ Cyl8 = p[2];
+ }
+ bool Check() const { return GetSector() > 0; }
+};
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareChs(const CChs &c1, const CChs &c2)
+{
+ RINOZ(MyCompare(c1.GetCyl(), c2.GetCyl()));
+ RINOZ(MyCompare(c1.Head, c2.Head));
+ return MyCompare(c1.GetSector(), c2.GetSector());
+}
+
+static void AddUIntToString(UInt32 val, AString &res)
+{
+ char s[16];
+ ConvertUInt32ToString(val, s);
+ res += s;
+}
+
+void CChs::ToString(NCOM::CPropVariant &prop) const
+{
+ AString s;
+ AddUIntToString(GetCyl(), s);
+ s += '-';
+ AddUIntToString(Head, s);
+ s += '-';
+ AddUIntToString(GetSector(), s);
+ prop = s;
+}
+
+struct CPartition
+{
+ Byte Status;
+ CChs BeginChs;
+ Byte Type;
+ CChs EndChs;
+ UInt32 Lba;
+ UInt32 NumBlocks;
+
+ CPartition() { memset (this, 0, sizeof(*this)); }
+
+ bool IsEmpty() const { return Type == 0; }
+ bool IsExtended() const { return Type == 5 || Type == 0xF; }
+ UInt32 GetLimit() const { return Lba + NumBlocks; }
+ // bool IsActive() const { return Status == 0x80; }
+ UInt64 GetPos() const { return (UInt64)Lba * 512; }
+ UInt64 GetSize() const { return (UInt64)NumBlocks * 512; }
+
+ bool CheckLbaLimits() const { return (UInt32)0xFFFFFFFF - Lba >= NumBlocks; }
+ bool Parse(const Byte *p)
+ {
+ Status = p[0];
+ BeginChs.Parse(p + 1);
+ Type = p[4];
+ EndChs.Parse(p + 5);
+ Lba = GetUi32(p + 8);
+ NumBlocks = GetUi32(p + 12);
+ if (Type == 0)
+ return true;
+ if (Status != 0 && Status != 0x80)
+ return false;
+ return
+ BeginChs.Check() &&
+ EndChs.Check() &&
+ CompareChs(BeginChs, EndChs) <= 0 &&
+ NumBlocks > 0 &&
+ CheckLbaLimits();
+ }
+
+ #ifdef SHOW_DEBUG_INFO
+ void Print() const
+ {
+ NCOM::CPropVariant prop, prop2;
+ BeginChs.ToString(prop);
+ EndChs.ToString(prop2);
+ printf(" %2x %2x %8X %8X %12S %12S", (int)Status, (int)Type, Lba, NumBlocks, prop.bstrVal, prop2.bstrVal);
+ }
+ #endif
+};
+
+struct CPartType
+{
+ UInt32 Id;
+ const char *Ext;
+ const char *Name;
+};
+
+static const char *kFat = "fat";
+
+static const CPartType kPartTypes[] =
+{
+ { 0x01, kFat, "FAT12" },
+ { 0x04, kFat, "FAT16 DOS 3.0+" },
+ { 0x05, 0, "Extended" },
+ { 0x06, kFat, "FAT16 DOS 3.31+" },
+ { 0x07, "ntfs", "NTFS" },
+ { 0x0B, kFat, "FAT32" },
+ { 0x0C, kFat, "FAT32-LBA" },
+ { 0x0E, kFat, "FAT16-LBA" },
+ { 0x0F, 0, "Extended-LBA" },
+ { 0x11, kFat, "FAT12-Hidden" },
+ { 0x14, kFat, "FAT16-Hidden < 32 MB" },
+ { 0x16, kFat, "FAT16-Hidden >= 32 MB" },
+ { 0x1B, kFat, "FAT32-Hidden" },
+ { 0x1C, kFat, "FAT32-LBA-Hidden" },
+ { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" },
+ { 0x82, 0, "Solaris x86 / Linux swap" },
+ { 0x83, 0, "Linux" },
+ { 0xBE, 0, "Solaris 8 boot" },
+ { 0xBF, 0, "New Solaris x86" },
+ { 0xC2, 0, "Linux-Hidden" },
+ { 0xC3, 0, "Linux swap-Hidden" },
+ { 0xEE, 0, "EFI-MBR" },
+ { 0xEE, 0, "EFI" }
+};
+
+static int FindPartType(UInt32 type)
+{
+ for (int i = 0; i < sizeof(kPartTypes) / sizeof(kPartTypes[0]); i++)
+ if (kPartTypes[i].Id == type)
+ return i;
+ return -1;
+}
+
+struct CItem
+{
+ bool IsReal;
+ bool IsPrim;
+ UInt64 Size;
+ CPartition Part;
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CItem> _items;
+ UInt64 _totalSize;
+ CByteBuffer _buffer;
+
+ HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int level);
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int level)
+{
+ if (level >= 128 || _items.Size() >= 128)
+ return S_FALSE;
+
+ const int kNumHeaderParts = 4;
+ CPartition parts[kNumHeaderParts];
+
+ {
+ const UInt32 kSectorSize = 512;
+ _buffer.SetCapacity(kSectorSize);
+ Byte *buf = _buffer;
+ UInt64 newPos = (UInt64)lba << 9;
+ if (newPos + 512 > _totalSize)
+ return S_FALSE;
+ RINOK(stream->Seek(newPos, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize));
+
+ if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+ return S_FALSE;
+
+ for (int i = 0; i < kNumHeaderParts; i++)
+ if (!parts[i].Parse(buf + 0x1BE + 16 * i))
+ return S_FALSE;
+ }
+
+ PRF(printf("\n# %8X", lba));
+
+ UInt32 limLba = lba + 1;
+ if (limLba == 0)
+ return S_FALSE;
+
+ for (int i = 0; i < kNumHeaderParts; i++)
+ {
+ CPartition &part = parts[i];
+
+ if (part.IsEmpty())
+ continue;
+ PRF(printf("\n %2d ", (int)level));
+ #ifdef SHOW_DEBUG_INFO
+ part.Print();
+ #endif
+
+ int numItems = _items.Size();
+ UInt32 newLba = lba + part.Lba;
+
+ if (part.IsExtended())
+ {
+ // if (part.Type == 5) // Check it!
+ newLba = baseLba + part.Lba;
+ if (newLba < limLba)
+ return S_FALSE;
+ HRESULT res = ReadTables(stream, level < 1 ? newLba : baseLba, newLba, level + 1);
+ if (res != S_FALSE && res != S_OK)
+ return res;
+ }
+ if (newLba < limLba)
+ return S_FALSE;
+ part.Lba = newLba;
+ if (!part.CheckLbaLimits())
+ return S_FALSE;
+
+ CItem n;
+ n.Part = part;
+ bool addItem = false;
+ if (numItems == _items.Size())
+ {
+ n.IsPrim = (level == 0);
+ n.IsReal = true;
+ addItem = true;
+ }
+ else
+ {
+ const CItem &back = _items.Back();
+ UInt32 backLimit = back.Part.GetLimit();
+ UInt32 partLimit = part.GetLimit();
+ if (backLimit < partLimit)
+ {
+ n.IsReal = false;
+ n.Part.Lba = backLimit;
+ n.Part.NumBlocks = partLimit - backLimit;
+ addItem = true;
+ }
+ }
+ if (addItem)
+ {
+ if (n.Part.GetLimit() < limLba)
+ return S_FALSE;
+ limLba = n.Part.GetLimit();
+ n.Size = n.Part.GetSize();
+ _items.Add(n);
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &_totalSize));
+ RINOK(ReadTables(stream, 0, 0, 0));
+ if (_items.IsEmpty())
+ return S_FALSE;
+ UInt32 lbaLimit = _items.Back().Part.GetLimit();
+ UInt64 lim = (UInt64)lbaLimit << 9;
+ if (lim < _totalSize)
+ {
+ CItem n;
+ n.Part.Lba = lbaLimit;
+ n.Size = _totalSize - lim;
+ n.IsReal = false;
+ _items.Add(n);
+ }
+ _stream = stream;
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+enum
+{
+ kpidPrimary = kpidUserDefined,
+ kpidBegChs,
+ kpidEndChs
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { L"Primary", kpidPrimary, VT_BOOL},
+ { L"Begin CHS", kpidBegChs, VT_BSTR},
+ { L"End CHS", kpidEndChs, VT_BSTR}
+};
+
+IMP_IInArchive_Props_WITH_NAME
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMainSubfile:
+ {
+ int mainIndex = -1;
+ for (int i = 0; i < _items.Size(); i++)
+ if (_items[i].IsReal)
+ {
+ if (mainIndex >= 0)
+ {
+ mainIndex = -1;
+ break;
+ }
+ mainIndex = i;
+ }
+ if (mainIndex >= 0)
+ prop = (UInt32)mainIndex;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CItem &item = _items[index];
+ const CPartition &part = item.Part;
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ AString s;
+ AddUIntToString(index, s);
+ if (item.IsReal)
+ {
+ int typeIndex = FindPartType(part.Type);
+ s += '.';
+ const char *ext = "img";
+ if (typeIndex >= 0 && kPartTypes[typeIndex].Ext != 0)
+ ext = kPartTypes[typeIndex].Ext;
+ s += ext;
+ }
+ prop = s;
+ break;
+ }
+ case kpidFileSystem:
+ if (item.IsReal)
+ {
+ char s[32];
+ ConvertUInt32ToString(part.Type, s);
+ const char *res = s;
+ int typeIndex = FindPartType(part.Type);
+ if (typeIndex >= 0 && kPartTypes[typeIndex].Name)
+ res = kPartTypes[typeIndex].Name;
+ prop = res;
+ }
+ break;
+ case kpidSize: prop = item.Size; break;;
+ case kpidPackSize: prop = item.Size; break;
+ case kpidOffset: prop = part.GetPos(); break;
+ case kpidPrimary: if (item.IsReal) prop = item.IsPrim; break;
+ case kpidBegChs: if (item.IsReal) part.BeginChs.ToString(prop); break;
+ case kpidEndChs: if (item.IsReal) part.EndChs.ToString(prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ const CPartition &part = item.Part;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ totalSize += item.Size;
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ RINOK(_stream->Seek(part.GetPos(), STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == item.Size ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ return CreateLimitedInStream(_stream, item.Part.GetPos(), item.Size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"MBR", L"mbr", 0, 0xDB, { 1, 1, 0 }, 3, false, CreateArc, 0 };
+
+REGISTER_ARC(Mbr)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/MslzHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/MslzHandler.cpp
new file mode 100644
index 000000000..67495e765
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/MslzHandler.cpp
@@ -0,0 +1,257 @@
+// MslzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "Common/DummyOutStream.h"
+
+namespace NArchive {
+namespace NMslz {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ UInt32 _size;
+ UInt64 _packSize;
+ UString _name;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPath: if (!_name.IsEmpty()) prop = _name; break;
+ case kpidSize: prop = _size; break;
+ case kpidPackSize: prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static const unsigned kSignatureSize = 9;
+static const unsigned kHeaderSize = kSignatureSize + 1 + 4;
+#define MSLZ_SIGNATURE { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41 }
+// old signature: 53 5A 20 88 F0 27 33
+static const Byte signature[kSignatureSize] = MSLZ_SIGNATURE;
+
+static const wchar_t *g_Exts[] =
+{
+ L"dll",
+ L"exe",
+ L"kmd",
+ L"sys"
+};
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ Byte buffer[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buffer, kHeaderSize));
+ if (memcmp(buffer, signature, kSignatureSize) != 0)
+ return S_FALSE;
+ _size = GetUi32(buffer + 10);
+ if (_size > 0xFFFFFFE0)
+ return S_FALSE;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &_packSize));
+
+ if (callback)
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+ if (openVolumeCallback)
+ {
+ NWindows::NCOM::CPropVariant prop;
+ if (openVolumeCallback->GetProperty(kpidName, &prop) == S_OK && prop.vt == VT_BSTR)
+ {
+ UString baseName = prop.bstrVal;
+ if (!baseName.IsEmpty() && baseName.Back() == L'_')
+ {
+ baseName.DeleteBack();
+ Byte replaceByte = buffer[kSignatureSize];
+ if (replaceByte == 0)
+ {
+ for (int i = 0; i < sizeof(g_Exts) / sizeof(g_Exts[0]); i++)
+ {
+ UString s = g_Exts[i];
+ int len = s.Length();
+ Byte b = (Byte)s.Back();
+ s.DeleteBack();
+ if (baseName.Length() >= len &&
+ baseName[baseName.Length() - len] == '.' &&
+ s.CompareNoCase(baseName.Right(len - 1)) == 0)
+ {
+ replaceByte = b;
+ break;
+ }
+ }
+ }
+ if (replaceByte >= 0x20 && replaceByte < 0x80)
+ _name = baseName + (wchar_t)replaceByte;
+ }
+ }
+ }
+ }
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _name.Empty();
+ return S_OK;
+}
+
+// MslzDec is modified LZSS algorithm of Haruhiko Okumura:
+// maxLen = 18; Okumura
+// maxLen = 16; MS
+
+#define PROGRESS_AND_WRITE \
+ if ((dest & kMask) == 0) { RINOK(WriteStream(outStream, buf, kBufSize)); \
+ if ((dest & ((1 << 20) - 1)) == 0) \
+ { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \
+ RINOK(progress->SetRatioInfo(&inSize, &outSize)); }}
+
+static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, ICompressProgressInfo *progress)
+{
+ const unsigned kBufSize = (1 << 12);
+ const unsigned kMask = kBufSize - 1;
+ Byte buf[kBufSize];
+ UInt32 dest = 0;
+ memset(buf, ' ', kBufSize);
+ while (dest < unpackSize)
+ {
+ Byte b;
+ if (!inStream.ReadByte(b))
+ return S_FALSE;
+ for (unsigned mask = (unsigned)b | 0x100; mask > 1 && dest < unpackSize; mask >>= 1)
+ {
+ if (!inStream.ReadByte(b))
+ return S_FALSE;
+ if (mask & 1)
+ {
+ buf[dest++ & kMask] = b;
+ PROGRESS_AND_WRITE
+ }
+ else
+ {
+ Byte b1;
+ if (!inStream.ReadByte(b1))
+ return S_FALSE;
+ const unsigned kMaxLen = 16; // 18 in Okumura's code.
+ unsigned src = (((((unsigned)b1 & 0xF0) << 4) | b) + kMaxLen) & kMask;
+ unsigned len = (b1 & 0xF) + 3;
+ if (len > kMaxLen || dest + len > unpackSize)
+ return S_FALSE;
+ do
+ {
+ buf[dest++ & kMask] = buf[src++ & kMask];
+ PROGRESS_AND_WRITE
+ }
+ while (--len != 0);
+ }
+ }
+ }
+ return WriteStream(outStream, buf, dest & kMask);
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_size);
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ CInBuffer s;
+ if (!s.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ s.SetStream(_stream);
+ s.Init();
+ Byte buffer[kHeaderSize];
+ Int32 opRes = NExtract::NOperationResult::kDataError;
+ if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize)
+ {
+ HRESULT result = MslzDec(s, outStream, _size, progress);
+ if (result == S_OK)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (result != S_FALSE)
+ return result;
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"MsLZ", L"", 0, 0xD5, MSLZ_SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+
+REGISTER_ARC(Mslz)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/MubHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/MubHandler.cpp
new file mode 100644
index 000000000..da4df24c9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/MubHandler.cpp
@@ -0,0 +1,266 @@
+// MubHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get32(p) GetBe32(p)
+
+namespace NArchive {
+namespace NMub {
+
+struct CItem
+{
+ UInt32 Type;
+ UInt32 SubType;
+ UInt64 Offset;
+ UInt64 Size;
+ UInt32 Align;
+ bool IsTail;
+};
+
+const UInt32 kNumFilesMax = 10;
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ UInt64 _startPos;
+ CMyComPtr<IInStream> _stream;
+ UInt32 _numItems;
+ CItem _items[kNumFilesMax + 1];
+ HRESULT Open2(IInStream *stream);
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+#define MACH_ARCH_ABI64 0x1000000
+#define MACH_MACHINE_386 7
+#define MACH_MACHINE_ARM 12
+#define MACH_MACHINE_SPARC 14
+#define MACH_MACHINE_PPC 18
+
+#define MACH_MACHINE_PPC64 (MACH_MACHINE_PPC | MACH_ARCH_ABI64)
+#define MACH_MACHINE_AMD64 (MACH_MACHINE_386 | MACH_ARCH_ABI64)
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ switch(propID)
+ {
+ case kpidExtension:
+ {
+ const wchar_t *ext;
+ if (item.IsTail)
+ ext = L"tail";
+ else
+ {
+ switch(item.Type)
+ {
+ case MACH_MACHINE_386: ext = L"86"; break;
+ case MACH_MACHINE_ARM: ext = L"arm"; break;
+ case MACH_MACHINE_SPARC: ext = L"sparc"; break;
+ case MACH_MACHINE_PPC: ext = L"ppc"; break;
+ case MACH_MACHINE_PPC64: ext = L"ppc64"; break;
+ case MACH_MACHINE_AMD64: ext = L"x64"; break;
+ default: ext = L"unknown"; break;
+ }
+ }
+ prop = ext;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+#define MACH_TYPE_ABI64 (1 << 24)
+#define MACH_SUBTYPE_ABI64 (1 << 31)
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, &_startPos));
+
+ const UInt32 kHeaderSize = 8;
+ const UInt32 kRecordSize = 5 * 4;
+ const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize;
+ Byte buf[kBufSize];
+ size_t processed = kBufSize;
+ RINOK(ReadStream(stream, buf, &processed));
+ if (processed < kHeaderSize)
+ return S_FALSE;
+ UInt32 num = Get32(buf + 4);
+ if (Get32(buf) != 0xCAFEBABE || num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize)
+ return S_FALSE;
+ UInt64 endPosMax = kHeaderSize;
+ for (UInt32 i = 0; i < num; i++)
+ {
+ const Byte *p = buf + kHeaderSize + i * kRecordSize;
+ CItem &sb = _items[i];
+ sb.IsTail = false;
+ sb.Type = Get32(p);
+ sb.SubType = Get32(p + 4);
+ sb.Offset = Get32(p + 8);
+ sb.Size = Get32(p + 12);
+ sb.Align = Get32(p + 16);
+
+ if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 ||
+ (sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 ||
+ sb.Align > 31)
+ return S_FALSE;
+
+ UInt64 endPos = (UInt64)sb.Offset + sb.Size;
+ if (endPos > endPosMax)
+ endPosMax = endPos;
+ }
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ fileSize -= _startPos;
+ _numItems = num;
+ if (fileSize > endPosMax)
+ {
+ CItem &sb = _items[_numItems++];
+ sb.IsTail = true;
+ sb.Type = 0;
+ sb.SubType = 0;
+ sb.Offset = endPosMax;
+ sb.Size = fileSize - endPosMax;
+ sb.Align = 0;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ if (Open2(inStream) != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _numItems = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _numItems;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _numItems;
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ currentTotalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(_stream->Seek(_startPos + item.Offset, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ return CreateLimitedInStream(_stream, _startPos + item.Offset, item.Size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Mub", L"", 0, 0xE2, { 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0 }, 7, false, CreateArc, 0 };
+
+REGISTER_ARC(Mub)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisDecode.cpp
new file mode 100644
index 000000000..0845f965d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisDecode.cpp
@@ -0,0 +1,130 @@
+// NsisDecode.cpp
+
+#include "StdAfx.h"
+
+#include "NsisDecode.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "../../Common/MethodId.h"
+
+#include "../../Compress/BZip2Decoder.h"
+#include "../../Compress/DeflateDecoder.h"
+#include "../../Compress/LzmaDecoder.h"
+
+namespace NArchive {
+namespace NNsis {
+
+static const CMethodId k_BCJ_X86 = 0x03030103;
+
+HRESULT CDecoder::Init(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter)
+{
+ useFilter = false;
+ CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
+
+ if (_decoderInStream)
+ if (method != _method)
+ Release();
+ _method = method;
+ if (!_codecInStream)
+ {
+ switch (method)
+ {
+ // case NMethodType::kCopy: return E_NOTIMPL;
+ case NMethodType::kDeflate: _codecInStream = new NCompress::NDeflate::NDecoder::CNsisCOMCoder(); break;
+ case NMethodType::kBZip2: _codecInStream = new NCompress::NBZip2::CNsisDecoder(); break;
+ case NMethodType::kLZMA: _codecInStream = new NCompress::NLzma::CDecoder(); break;
+ default: return E_NOTIMPL;
+ }
+ }
+
+ if (thereIsFilterFlag)
+ {
+ UInt32 processedSize;
+ BYTE flag;
+ RINOK(inStream->Read(&flag, 1, &processedSize));
+ if (processedSize != 1)
+ return E_FAIL;
+ if (flag > 1)
+ return E_NOTIMPL;
+ useFilter = (flag != 0);
+ }
+
+ if (useFilter)
+ {
+ if (!_filterInStream)
+ {
+ CMyComPtr<ICompressCoder> coder;
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ k_BCJ_X86, coder, false));
+ if (!coder)
+ return E_NOTIMPL;
+ coder.QueryInterface(IID_ISequentialInStream, &_filterInStream);
+ if (!_filterInStream)
+ return E_NOTIMPL;
+ }
+ CMyComPtr<ICompressSetInStream> setInStream;
+ _filterInStream.QueryInterface(IID_ICompressSetInStream, &setInStream);
+ if (!setInStream)
+ return E_NOTIMPL;
+ RINOK(setInStream->SetInStream(_codecInStream));
+ _decoderInStream = _filterInStream;
+ }
+ else
+ _decoderInStream = _codecInStream;
+
+ if (method == NMethodType::kLZMA)
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ _codecInStream.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ static const UInt32 kPropertiesSize = 5;
+ BYTE properties[kPropertiesSize];
+ UInt32 processedSize;
+ RINOK(inStream->Read(properties, kPropertiesSize, &processedSize));
+ if (processedSize != kPropertiesSize)
+ return E_FAIL;
+ RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, kPropertiesSize));
+ }
+ }
+
+ {
+ CMyComPtr<ICompressSetInStream> setInStream;
+ _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream);
+ if (!setInStream)
+ return E_NOTIMPL;
+ RINOK(setInStream->SetInStream(inStream));
+ }
+
+ {
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ _codecInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
+ if (!setOutStreamSize)
+ return E_NOTIMPL;
+ RINOK(setOutStreamSize->SetOutStreamSize(NULL));
+ }
+
+ if (useFilter)
+ {
+ /*
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ _filterInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
+ if (!setOutStreamSize)
+ return E_NOTIMPL;
+ RINOK(setOutStreamSize->SetOutStreamSize(NULL));
+ */
+ }
+
+ return S_OK;
+}
+
+HRESULT CDecoder::Read(void *data, size_t *processedSize)
+{
+ return ReadStream(_decoderInStream, data, processedSize);;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisDecode.h b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisDecode.h
new file mode 100644
index 000000000..36aeb2b14
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisDecode.h
@@ -0,0 +1,47 @@
+// NsisDecode.h
+
+#ifndef __NSIS_DECODE_H
+#define __NSIS_DECODE_H
+
+#include "../../IStream.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace NNsis {
+
+namespace NMethodType
+{
+ enum EEnum
+ {
+ kCopy,
+ kDeflate,
+ kBZip2,
+ kLZMA
+ };
+}
+
+class CDecoder
+{
+ NMethodType::EEnum _method;
+
+ CMyComPtr<ISequentialInStream> _filterInStream;
+ CMyComPtr<ISequentialInStream> _codecInStream;
+ CMyComPtr<ISequentialInStream> _decoderInStream;
+
+public:
+ void Release()
+ {
+ _filterInStream.Release();
+ _codecInStream.Release();
+ _decoderInStream.Release();
+ }
+ HRESULT Init(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter);
+ HRESULT Read(void *data, size_t *processedSize);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisHandler.cpp
new file mode 100644
index 000000000..4058bd2af
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisHandler.cpp
@@ -0,0 +1,510 @@
+// NSisHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "NsisHandler.h"
+
+#define Get32(p) GetUi32(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NNsis {
+
+static const char *kBcjMethod = "BCJ";
+static const char *kUnknownMethod = "Unknown";
+
+static const char *kMethods[] =
+{
+ "Copy",
+ "Deflate",
+ "BZip2",
+ "LZMA"
+};
+
+static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidSolid, VT_BOOL}
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidSolid, VT_BOOL}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ UInt32 dict = 1;
+ bool filter = false;
+ for (int i = 0; i < _archive.Items.Size(); i++)
+ {
+ const CItem &item = _archive.Items[i];
+ filter |= item.UseFilter;
+ if (item.DictionarySize > dict)
+ dict = item.DictionarySize;
+ }
+ prop = GetMethod(filter, dict);
+ break;
+ }
+ case kpidSolid: prop = _archive.IsSolid; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ Close();
+ {
+ if (_archive.Open(
+ EXTERNAL_CODECS_VARS
+ stream, maxCheckStartPosition) != S_OK)
+ return S_FALSE;
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _archive.Clear();
+ _archive.Release();
+ _inStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _archive.Items.Size()
+ #ifdef NSIS_SCRIPT
+ + 1
+ #endif
+ ;
+ return S_OK;
+}
+
+static AString UInt32ToString(UInt32 value)
+{
+ char buffer[16];
+ ConvertUInt32ToString(value, buffer);
+ return buffer;
+}
+
+static AString GetStringForSizeValue(UInt32 value)
+{
+ for (int i = 31; i >= 0; i--)
+ if (((UInt32)1 << i) == value)
+ return UInt32ToString(i);
+ char c = 'b';
+ if (value % (1 << 20) == 0)
+ {
+ value >>= 20;
+ c = 'm';
+ }
+ else if (value % (1 << 10) == 0)
+ {
+ value >>= 10;
+ c = 'k';
+ }
+ return UInt32ToString(value) + c;
+}
+
+AString CHandler::GetMethod(bool useItemFilter, UInt32 dictionary) const
+{
+ NMethodType::EEnum methodIndex = _archive.Method;
+ AString method;
+ if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter)
+ {
+ method += kBcjMethod;
+ method += ' ';
+ }
+ method += (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
+ if (methodIndex == NMethodType::kLZMA)
+ {
+ method += ':';
+ method += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary);
+ }
+ return method;
+}
+
+bool CHandler::GetUncompressedSize(int index, UInt32 &size)
+{
+ size = 0;
+ const CItem &item = _archive.Items[index];
+ if (item.SizeIsDefined)
+ size = item.Size;
+ else if (_archive.IsSolid && item.EstimatedSizeIsDefined)
+ size = item.EstimatedSize;
+ else
+ return false;
+ return true;
+}
+
+bool CHandler::GetCompressedSize(int index, UInt32 &size)
+{
+ size = 0;
+ const CItem &item = _archive.Items[index];
+ if (item.CompressedSizeIsDefined)
+ size = item.CompressedSize;
+ else
+ {
+ if (_archive.IsSolid)
+ {
+ if (index == 0)
+ size = _archive.FirstHeader.GetDataSize();
+ else
+ return false;
+ }
+ else
+ {
+ if (!item.IsCompressed)
+ size = item.Size;
+ else
+ return false;
+ }
+ }
+ return true;
+}
+
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ #ifdef NSIS_SCRIPT
+ if (index >= (UInt32)_archive.Items.Size())
+ {
+ switch(propID)
+ {
+ case kpidPath: prop = L"[NSIS].nsi"; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)_archive.Script.Length(); break;
+ case kpidSolid: prop = false; break;
+ }
+ }
+ else
+ #endif
+ {
+ const CItem &item = _archive.Items[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString s = NItemName::WinNameToOSName(item.GetReducedName(_archive.IsUnicode));
+ if (!s.IsEmpty())
+ prop = (const wchar_t *)s;
+ break;
+ }
+ case kpidSize:
+ {
+ UInt32 size;
+ if (GetUncompressedSize(index, size))
+ prop = (UInt64)size;
+ break;
+ }
+ case kpidPackSize:
+ {
+ UInt32 size;
+ if (GetCompressedSize(index, size))
+ prop = (UInt64)size;
+ break;
+ }
+ case kpidMTime:
+ {
+ if (item.MTime.dwHighDateTime > 0x01000000 &&
+ item.MTime.dwHighDateTime < 0xFF000000)
+ prop = item.MTime;
+ break;
+ }
+ case kpidMethod: prop = GetMethod(item.UseFilter, item.DictionarySize); break;
+ case kpidSolid: prop = _archive.IsSolid; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ GetNumberOfItems(&numItems);
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ #ifdef NSIS_SCRIPT
+ if (index >= (UInt32)_archive.Items.Size())
+ totalSize += _archive.Script.Length();
+ else
+ #endif
+ {
+ UInt32 size;
+ if (_archive.IsSolid)
+ {
+ GetUncompressedSize(index, size);
+ UInt64 pos = _archive.GetPosOfSolidItem(index);
+ if (pos > totalSize)
+ totalSize = pos + size;
+ }
+ else
+ {
+ GetCompressedSize(index, size);
+ totalSize += size;
+ }
+ }
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt32 currentItemSize = 0;
+
+ UInt64 streamPos = 0;
+ if (_archive.IsSolid)
+ {
+ RINOK(_inStream->Seek(_archive.StreamOffset, STREAM_SEEK_SET, NULL));
+ bool useFilter;
+ RINOK(_archive.Decoder.Init(
+ EXTERNAL_CODECS_VARS
+ _inStream, _archive.Method, _archive.FilterFlag, useFilter));
+ }
+
+ CByteBuffer byteBuf;
+ const UInt32 kBufferLength = 1 << 16;
+ byteBuf.SetCapacity(kBufferLength);
+ Byte *buffer = byteBuf;
+
+ CByteBuffer tempBuf;
+
+ bool dataError = false;
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ currentItemSize = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalSize));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ #ifdef NSIS_SCRIPT
+ if (index >= (UInt32)_archive.Items.Size())
+ {
+ currentItemSize = _archive.Script.Length();
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (!testMode)
+ RINOK(WriteStream(realOutStream, (const char *)_archive.Script, (UInt32)_archive.Script.Length()));
+ }
+ else
+ #endif
+ {
+ const CItem &item = _archive.Items[index];
+
+ if (_archive.IsSolid)
+ GetUncompressedSize(index, currentItemSize);
+ else
+ GetCompressedSize(index, currentItemSize);
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ if (!dataError)
+ {
+ bool needDecompress = false;
+ bool sizeIsKnown = false;
+ UInt32 fullSize = 0;
+
+ bool writeToTemp = false;
+ bool readFromTemp = false;
+
+ if (_archive.IsSolid)
+ {
+ UInt64 pos = _archive.GetPosOfSolidItem(index);
+ while (streamPos < pos)
+ {
+ size_t processedSize = (UInt32)MyMin(pos - streamPos, (UInt64)kBufferLength);
+ HRESULT res = _archive.Decoder.Read(buffer, &processedSize);
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ dataError = true;
+ break;
+ }
+ if (processedSize == 0)
+ {
+ dataError = true;
+ break;
+ }
+ streamPos += processedSize;
+ }
+ if (streamPos == pos)
+ {
+ Byte buffer2[4];
+ size_t processedSize = 4;
+ RINOK(_archive.Decoder.Read(buffer2, &processedSize));
+ if (processedSize != 4)
+ return E_FAIL;
+ streamPos += processedSize;
+ fullSize = Get32(buffer2);
+ sizeIsKnown = true;
+ needDecompress = true;
+
+ if (!testMode && i + 1 < numItems)
+ {
+ UInt64 nextPos = _archive.GetPosOfSolidItem(allFilesMode ? i : indices[i + 1]);
+ if (nextPos < streamPos + fullSize)
+ {
+ tempBuf.Free();
+ tempBuf.SetCapacity(fullSize);
+ writeToTemp = true;
+ }
+ }
+ }
+ else
+ readFromTemp = true;
+ }
+ else
+ {
+ RINOK(_inStream->Seek(_archive.GetPosOfNonSolidItem(index) + 4, STREAM_SEEK_SET, NULL));
+ if (item.IsCompressed)
+ {
+ needDecompress = true;
+ bool useFilter;
+ RINOK(_archive.Decoder.Init(
+ EXTERNAL_CODECS_VARS
+ _inStream, _archive.Method, _archive.FilterFlag, useFilter));
+ // fullSize = Get32(buffer); // It's bug !!!
+ // Test it: what is exact fullSize?
+ fullSize = 0xFFFFFFFF;
+ }
+ else
+ fullSize = item.Size;
+ }
+ if (!dataError)
+ {
+ if (needDecompress)
+ {
+ UInt64 offset = 0;
+ while (!sizeIsKnown || fullSize > 0)
+ {
+ UInt32 curSize = kBufferLength;
+ if (sizeIsKnown && curSize > fullSize)
+ curSize = fullSize;
+ size_t processedSize = curSize;
+ HRESULT res = _archive.Decoder.Read(buffer, &processedSize);
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ dataError = true;
+ break;
+ }
+ if (processedSize == 0)
+ {
+ if (sizeIsKnown)
+ dataError = true;
+ break;
+ }
+
+ if (writeToTemp)
+ memcpy((Byte *)tempBuf + (size_t)offset, buffer, processedSize);
+
+ fullSize -= (UInt32)processedSize;
+ streamPos += processedSize;
+ offset += processedSize;
+
+ UInt64 completed;
+ if (_archive.IsSolid)
+ completed = currentTotalSize + offset;
+ else
+ completed = streamPos;
+ RINOK(extractCallback->SetCompleted(&completed));
+ if (!testMode)
+ RINOK(WriteStream(realOutStream, buffer, processedSize));
+ }
+ }
+ else
+ {
+ if (readFromTemp)
+ {
+ if (!testMode)
+ RINOK(WriteStream(realOutStream, tempBuf, tempBuf.GetCapacity()));
+ }
+ else
+ while (fullSize > 0)
+ {
+ UInt32 curSize = MyMin(fullSize, kBufferLength);
+ UInt32 processedSize;
+ RINOK(_inStream->Read(buffer, curSize, &processedSize));
+ if (processedSize == 0)
+ {
+ dataError = true;
+ break;
+ }
+ fullSize -= processedSize;
+ streamPos += processedSize;
+ if (!testMode)
+ RINOK(WriteStream(realOutStream, buffer, processedSize));
+ }
+ }
+ }
+ }
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(dataError ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisHandler.h
new file mode 100644
index 000000000..6de493df8
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisHandler.h
@@ -0,0 +1,43 @@
+// NSisHandler.h
+
+#ifndef __NSIS_HANDLER_H
+#define __NSIS_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+
+#include "NsisIn.h"
+
+#include "../../Common/CreateCoder.h"
+
+namespace NArchive {
+namespace NNsis {
+
+class CHandler:
+ public IInArchive,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+ CInArchive _archive;
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ bool GetUncompressedSize(int index, UInt32 &size);
+ bool GetCompressedSize(int index, UInt32 &size);
+
+ AString GetMethod(bool useItemFilter, UInt32 dictionary) const;
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+
+ DECL_ISetCompressCodecsInfo
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisIn.cpp
new file mode 100644
index 000000000..407560085
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisIn.cpp
@@ -0,0 +1,1461 @@
+// NsisIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/IntToString.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "NsisIn.h"
+
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NNsis {
+
+Byte kSignature[kSignatureSize] = NSIS_SIGNATURE;
+
+#ifdef NSIS_SCRIPT
+static const char *kCrLf = "\x0D\x0A";
+#endif
+
+#define NS_UN_SKIP_CODE 0xE000
+#define NS_UN_VAR_CODE 0xE001
+#define NS_UN_SHELL_CODE 0xE002
+#define NS_UN_LANG_CODE 0xE003
+#define NS_UN_CODES_START NS_UN_SKIP_CODE
+#define NS_UN_CODES_END NS_UN_LANG_CODE
+
+Byte CInArchive::ReadByte()
+{
+ if (_posInData >= _size)
+ throw 1;
+ return _data[_posInData++];
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ value |= ((UInt32)(ReadByte()) << (8 * i));
+ return value;
+}
+
+void CInArchive::ReadBlockHeader(CBlockHeader &bh)
+{
+ bh.Offset = ReadUInt32();
+ bh.Num = ReadUInt32();
+}
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareItems(void *const *p1, void *const *p2, void * /* param */)
+{
+ const CItem &i1 = **(CItem **)p1;
+ const CItem &i2 = **(CItem **)p2;
+ RINOZ(MyCompare(i1.Pos, i2.Pos));
+ if (i1.IsUnicode)
+ {
+ RINOZ(i1.PrefixU.Compare(i2.PrefixU));
+ RINOZ(i1.NameU.Compare(i2.NameU));
+ }
+ else
+ {
+ RINOZ(i1.PrefixA.Compare(i2.PrefixA));
+ RINOZ(i1.NameA.Compare(i2.NameA));
+ }
+ return 0;
+}
+
+static AString UIntToString(UInt32 v)
+{
+ char sz[32];
+ ConvertUInt64ToString(v, sz);
+ return sz;
+}
+
+static AString IntToString(Int32 v)
+{
+ char sz[32];
+ ConvertInt64ToString(v, sz);
+ return sz;
+}
+
+AString CInArchive::ReadStringA(UInt32 pos) const
+{
+ AString s;
+ if (pos >= _size)
+ return IntToString((Int32)pos);
+ UInt32 offset = GetOffset() + _stringsPos + pos;
+ for (;;)
+ {
+ if (offset >= _size)
+ break; // throw 1;
+ char c = _data[offset++];
+ if (c == 0)
+ break;
+ s += c;
+ }
+ return s;
+}
+
+UString CInArchive::ReadStringU(UInt32 pos) const
+{
+ UString s;
+ UInt32 offset = GetOffset() + _stringsPos + (pos * 2);
+ for (;;)
+ {
+ if (offset >= _size || offset + 1 >= _size)
+ return s; // throw 1;
+ char c0 = _data[offset++];
+ char c1 = _data[offset++];
+ wchar_t c = (c0 | ((wchar_t)c1 << 8));
+ if (c == 0)
+ break;
+ s += c;
+ }
+ return s;
+}
+
+/*
+static AString ParsePrefix(const AString &prefix)
+{
+ AString res = prefix;
+ if (prefix.Length() >= 3)
+ {
+ if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x95 && (Byte)prefix[2] == 0x80)
+ res = "$INSTDIR" + prefix.Mid(3);
+ else if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x96 && (Byte)prefix[2] == 0x80)
+ res = "$OUTDIR" + prefix.Mid(3);
+ }
+ return res;
+}
+*/
+
+#define SYSREGKEY "Software\\Microsoft\\Windows\\CurrentVersion"
+
+/*
+# define CSIDL_PROGRAMS 0x2
+# define CSIDL_PRINTERS 0x4
+# define CSIDL_PERSONAL 0x5
+# define CSIDL_FAVORITES 0x6
+# define CSIDL_STARTUP 0x7
+# define CSIDL_RECENT 0x8
+# define CSIDL_SENDTO 0x9
+# define CSIDL_STARTMENU 0xB
+# define CSIDL_MYMUSIC 0xD
+# define CSIDL_MYVIDEO 0xE
+
+# define CSIDL_DESKTOPDIRECTORY 0x10
+# define CSIDL_NETHOOD 0x13
+# define CSIDL_FONTS 0x14
+# define CSIDL_TEMPLATES 0x15
+# define CSIDL_COMMON_STARTMENU 0x16
+# define CSIDL_COMMON_PROGRAMS 0x17
+# define CSIDL_COMMON_STARTUP 0x18
+# define CSIDL_COMMON_DESKTOPDIRECTORY 0x19
+# define CSIDL_APPDATA 0x1A
+# define CSIDL_PRINTHOOD 0x1B
+# define CSIDL_LOCAL_APPDATA 0x1C
+# define CSIDL_ALTSTARTUP 0x1D
+# define CSIDL_COMMON_ALTSTARTUP 0x1E
+# define CSIDL_COMMON_FAVORITES 0x1F
+
+# define CSIDL_INTERNET_CACHE 0x20
+# define CSIDL_COOKIES 0x21
+# define CSIDL_HISTORY 0x22
+# define CSIDL_COMMON_APPDATA 0x23
+# define CSIDL_WINDOWS 0x24
+# define CSIDL_SYSTEM 0x25
+# define CSIDL_PROGRAM_FILES 0x26
+# define CSIDL_MYPICTURES 0x27
+# define CSIDL_PROFILE 0x28
+# define CSIDL_PROGRAM_FILES_COMMON 0x2B
+# define CSIDL_COMMON_TEMPLATES 0x2D
+# define CSIDL_COMMON_DOCUMENTS 0x2E
+# define CSIDL_COMMON_ADMINTOOLS 0x2F
+
+# define CSIDL_ADMINTOOLS 0x30
+# define CSIDL_COMMON_MUSIC 0x35
+# define CSIDL_COMMON_PICTURES 0x36
+# define CSIDL_COMMON_VIDEO 0x37
+# define CSIDL_RESOURCES 0x38
+# define CSIDL_RESOURCES_LOCALIZED 0x39
+# define CSIDL_CDBURN_AREA 0x3B
+*/
+
+struct CCommandPair
+{
+ int NumParams;
+ const char *Name;
+};
+
+enum
+{
+ // 0
+ EW_INVALID_OPCODE, // zero is invalid. useful for catching errors. (otherwise an all zeroes instruction
+ // does nothing, which is easily ignored but means something is wrong.
+ EW_RET, // return from function call
+ EW_NOP, // Nop/Jump, do nothing: 1, [?new address+1:advance one]
+ EW_ABORT, // Abort: 1 [status]
+ EW_QUIT, // Quit: 0
+ EW_CALL, // Call: 1 [new address+1]
+ EW_UPDATETEXT, // Update status text: 2 [update str, ui_st_updateflag=?ui_st_updateflag:this]
+ EW_SLEEP, // Sleep: 1 [sleep time in milliseconds]
+ EW_BRINGTOFRONT, // BringToFront: 0
+ EW_CHDETAILSVIEW, // SetDetailsView: 2 [listaction,buttonaction]
+
+ // 10
+ EW_SETFILEATTRIBUTES, // SetFileAttributes: 2 [filename, attributes]
+ EW_CREATEDIR, // Create directory: 2, [path, ?update$INSTDIR]
+ EW_IFFILEEXISTS, // IfFileExists: 3, [file name, jump amount if exists, jump amount if not exists]
+ EW_SETFLAG, // Sets a flag: 2 [id, data]
+ EW_IFFLAG, // If a flag: 4 [on, off, id, new value mask]
+ EW_GETFLAG, // Gets a flag: 2 [output, id]
+ EW_RENAME, // Rename: 3 [old, new, rebootok]
+ EW_GETFULLPATHNAME, // GetFullPathName: 2 [output, input, ?lfn:sfn]
+ EW_SEARCHPATH, // SearchPath: 2 [output, filename]
+ EW_GETTEMPFILENAME, // GetTempFileName: 2 [output, base_dir]
+
+ // 20
+ EW_EXTRACTFILE, // File to extract: 6 [overwriteflag, output filename, compressed filedata, filedatetimelow, filedatetimehigh, allow ignore]
+ // overwriteflag: 0x1 = no. 0x0=force, 0x2=try, 0x3=if date is newer
+ EW_DELETEFILE, // Delete File: 2, [filename, rebootok]
+ EW_MESSAGEBOX, // MessageBox: 5,[MB_flags,text,retv1:retv2,moveonretv1:moveonretv2]
+ EW_RMDIR, // RMDir: 2 [path, recursiveflag]
+ EW_STRLEN, // StrLen: 2 [output, input]
+ EW_ASSIGNVAR, // Assign: 4 [variable (0-9) to assign, string to assign, maxlen, startpos]
+ EW_STRCMP, // StrCmp: 5 [str1, str2, jump_if_equal, jump_if_not_equal, case-sensitive?]
+ EW_READENVSTR, // ReadEnvStr/ExpandEnvStrings: 3 [output, string_with_env_variables, IsRead]
+ EW_INTCMP, // IntCmp: 6 [val1, val2, equal, val1<val2, val1>val2, unsigned?]
+ EW_INTOP, // IntOp: 4 [output, input1, input2, op] where op: 0=add, 1=sub, 2=mul, 3=div, 4=bor, 5=band, 6=bxor, 7=bnot input1, 8=lnot input1, 9=lor, 10=land], 11=1%2
+
+ // 30
+ EW_INTFMT, // IntFmt: [output, format, input]
+ EW_PUSHPOP, // Push/Pop/Exchange: 3 [variable/string, ?pop:push, ?exch]
+ EW_FINDWINDOW, // FindWindow: 5, [outputvar, window class,window name, window_parent, window_after]
+ EW_SENDMESSAGE, // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2]
+ EW_ISWINDOW, // IsWindow: 3 [hwnd, jump_if_window, jump_if_notwindow]
+ EW_GETDLGITEM, // GetDlgItem: 3: [outputvar, dialog, item_id]
+ EW_SETCTLCOLORS, // SerCtlColors: 3: [hwnd, pointer to struct colors]
+ EW_SETBRANDINGIMAGE, // SetBrandingImage: 1: [Bitmap file]
+ EW_CREATEFONT, // CreateFont: 5: [handle output, face name, height, weight, flags]
+ EW_SHOWWINDOW, // ShowWindow: 2: [hwnd, show state]
+
+ // 40
+ EW_SHELLEXEC, // ShellExecute program: 4, [shell action, complete commandline, parameters, showwindow]
+ EW_EXECUTE, // Execute program: 3,[complete command line,waitflag,>=0?output errorcode]
+ EW_GETFILETIME, // GetFileTime; 3 [file highout lowout]
+ EW_GETDLLVERSION, // GetDLLVersion: 3 [file highout lowout]
+ EW_REGISTERDLL, // Register DLL: 3,[DLL file name, string ptr of function to call, text to put in display (<0 if none/pass parms), 1 - no unload, 0 - unload]
+ EW_CREATESHORTCUT, // Make Shortcut: 5, [link file, target file, parameters, icon file, iconindex|show mode<<8|hotkey<<16]
+ EW_COPYFILES, // CopyFiles: 3 [source mask, destination location, flags]
+ EW_REBOOT, // Reboot: 0
+ EW_WRITEINI, // Write INI String: 4, [Section, Name, Value, INI File]
+ EW_READINISTR, // ReadINIStr: 4 [output, section, name, ini_file]
+
+ // 50
+ EW_DELREG, // DeleteRegValue/DeleteRegKey: 4, [root key(int), KeyName, ValueName, delkeyonlyifempty]. ValueName is -1 if delete key
+ EW_WRITEREG, // Write Registry value: 5, [RootKey(int),KeyName,ItemName,ItemData,typelen]
+ // typelen=1 for str, 2 for dword, 3 for binary, 0 for expanded str
+ EW_READREGSTR, // ReadRegStr: 5 [output, rootkey(int), keyname, itemname, ==1?int::str]
+ EW_REGENUM, // RegEnum: 5 [output, rootkey, keyname, index, ?key:value]
+ EW_FCLOSE, // FileClose: 1 [handle]
+ EW_FOPEN, // FileOpen: 4 [name, openmode, createmode, outputhandle]
+ EW_FPUTS, // FileWrite: 3 [handle, string, ?int:string]
+ EW_FGETS, // FileRead: 4 [handle, output, maxlen, ?getchar:gets]
+ EW_FSEEK, // FileSeek: 4 [handle, offset, mode, >=0?positionoutput]
+ EW_FINDCLOSE, // FindClose: 1 [handle]
+
+ // 60
+ EW_FINDNEXT, // FindNext: 2 [output, handle]
+ EW_FINDFIRST, // FindFirst: 2 [filespec, output, handleoutput]
+ EW_WRITEUNINSTALLER, // WriteUninstaller: 3 [name, offset, icon_size]
+ EW_LOG, // LogText: 2 [0, text] / LogSet: [1, logstate]
+ EW_SECTIONSET, // SectionSetText: 3: [idx, 0, text]
+ // SectionGetText: 3: [idx, 1, output]
+ // SectionSetFlags: 3: [idx, 2, flags]
+ // SectionGetFlags: 3: [idx, 3, output]
+ EW_INSTTYPESET, // InstTypeSetFlags: 3: [idx, 0, flags]
+ // InstTypeGetFlags: 3: [idx, 1, output]
+ // instructions not actually implemented in exehead, but used in compiler.
+ EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR
+ EW_GETFUNCTIONADDR,
+
+ EW_LOCKWINDOW
+};
+
+#ifdef NSIS_SCRIPT
+static CCommandPair kCommandPairs[] =
+{
+ { 0, "Invalid" },
+ { 0, "Return" },
+ { 1, "Goto" },
+ { 0, "Abort" },
+ { 0, "Quit" },
+ { 1, "Call" },
+ { 2, "UpdateSatusText" },
+ { 1, "Sleep" },
+ { 0, "BringToFront" },
+ { 2, "SetDetailsView" },
+
+ { 2, "SetFileAttributes" },
+ { 2, "SetOutPath" },
+ { 3, "IfFileExists" },
+ { 2, "SetFlag" },
+ { 4, "IfFlag" },
+ { 2, "GetFlag" },
+ { 3, "Rename" },
+ { 2, "GetFullPathName" },
+ { 2, "SearchPath" },
+ { 2, "GetTempFileName" },
+
+ { 6, "File" },
+ { 2, "Delete" },
+ { 5, "MessageBox" },
+ { 2, "RMDir" },
+ { 2, "StrLen" },
+ { 4, "StrCpy" },
+ { 5, "StrCmp" },
+ { 3, "ReadEnvStr" },
+ { 6, "IntCmp" },
+ { 4, "IntOp" },
+
+ { 3, "IntFmt" },
+ { 3, "PushPop" },
+ { 5, "FindWindow" },
+ { 6, "SendMessage" },
+ { 3, "IsWindow" },
+ { 3, "GetDlgItem" },
+ { 3, "SerCtlColors" },
+ { 1, "SetBrandingImage" },
+ { 5, "CreateFont" },
+ { 2, "ShowWindow" },
+
+ { 4, "ShellExecute" },
+ { 3, "Execute" },
+ { 3, "GetFileTime" },
+ { 3, "GetDLLVersion" },
+ { 3, "RegisterDLL" },
+ { 5, "CreateShortCut" },
+ { 3, "CopyFiles" },
+ { 0, "Reboot" },
+ { 4, "WriteINIStr" },
+ { 4, "ReadINIStr" },
+
+ { 4, "DelReg" },
+ { 5, "WriteReg" },
+ { 5, "ReadRegStr" },
+ { 5, "RegEnum" },
+ { 1, "FileClose" },
+ { 4, "FileOpen" },
+ { 3, "FileWrite" },
+ { 4, "FileRead" },
+ { 4, "FileSeek" },
+ { 1, "FindClose" },
+
+ { 2, "FindNext" },
+ { 2, "FindFirst" },
+ { 3, "WriteUninstaller" },
+ { 2, "LogText" },
+ { 3, "Section?etText" },
+ { 3, "InstType?etFlags" },
+ { 6, "GetLabelAddr" },
+ { 2, "GetFunctionAddress" },
+ { 6, "LockWindow" }
+};
+
+#endif
+
+static const char *kShellStrings[] =
+{
+ "",
+ "",
+
+ "SMPROGRAMS",
+ "",
+ "PRINTERS",
+ "DOCUMENTS",
+ "FAVORITES",
+ "SMSTARTUP",
+ "RECENT",
+ "SENDTO",
+ "",
+ "STARTMENU",
+ "",
+ "MUSIC",
+ "VIDEO",
+ "",
+
+ "DESKTOP",
+ "",
+ "",
+ "NETHOOD",
+ "FONTS",
+ "TEMPLATES",
+ "COMMONSTARTMENU",
+ "COMMONFILES",
+ "COMMON_STARTUP",
+ "COMMON_DESKTOPDIRECTORY",
+ "QUICKLAUNCH",
+ "PRINTHOOD",
+ "LOCALAPPDATA",
+ "ALTSTARTUP",
+ "ALTSTARTUP",
+ "FAVORITES",
+
+ "INTERNET_CACHE",
+ "COOKIES",
+ "HISTORY",
+ "APPDATA",
+ "WINDIR",
+ "SYSDIR",
+ "PROGRAMFILES",
+ "PICTURES",
+ "PROFILE",
+ "",
+ "",
+ "COMMONFILES",
+ "",
+ "TEMPLATES",
+ "DOCUMENTS",
+ "ADMINTOOLS",
+
+ "ADMINTOOLS",
+ "",
+ "",
+ "",
+ "",
+ "MUSIC",
+ "PICTURES",
+ "VIDEO",
+ "RESOURCES",
+ "RESOURCES_LOCALIZED",
+ "",
+ "CDBURN_AREA"
+};
+
+static const int kNumShellStrings = sizeof(kShellStrings) / sizeof(kShellStrings[0]);
+
+/*
+# define CMDLINE 20 // everything before here doesn't have trailing slash removal
+# define INSTDIR 21
+# define OUTDIR 22
+# define EXEDIR 23
+# define LANGUAGE 24
+# define TEMP 25
+# define PLUGINSDIR 26
+# define HWNDPARENT 27
+# define _CLICK 28
+# define _OUTDIR 29
+*/
+
+static const char *kVarStrings[] =
+{
+ "CMDLINE",
+ "INSTDIR",
+ "OUTDIR",
+ "EXEDIR",
+ "LANGUAGE",
+ "TEMP",
+ "PLUGINSDIR",
+ "EXEPATH", // test it
+ "EXEFILE", // test it
+ "HWNDPARENT",
+ "_CLICK",
+ "_OUTDIR"
+};
+
+static const int kNumVarStrings = sizeof(kVarStrings) / sizeof(kVarStrings[0]);
+
+
+static AString GetVar(UInt32 index)
+{
+ AString res = "$";
+ if (index < 10)
+ res += UIntToString(index);
+ else if (index < 20)
+ {
+ res += "R";
+ res += UIntToString(index - 10);
+ }
+ else if (index < 20 + kNumVarStrings)
+ res += kVarStrings[index - 20];
+ else
+ {
+ res += "[";
+ res += UIntToString(index);
+ res += "]";
+ }
+ return res;
+}
+
+#define NS_SKIP_CODE 252
+#define NS_VAR_CODE 253
+#define NS_SHELL_CODE 254
+#define NS_LANG_CODE 255
+#define NS_CODES_START NS_SKIP_CODE
+
+static AString GetShellString(int index)
+{
+ AString res = "$";
+ if (index < kNumShellStrings)
+ {
+ const char *sz = kShellStrings[index];
+ if (sz[0] != 0)
+ return res + sz;
+ }
+ res += "SHELL[";
+ res += UIntToString(index);
+ res += "]";
+ return res;
+}
+
+// Based on Dave Laundon's simplified process_string
+AString GetNsisString(const AString &s)
+{
+ AString res;
+ for (int i = 0; i < s.Length();)
+ {
+ unsigned char nVarIdx = s[i++];
+ if (nVarIdx > NS_CODES_START && i + 2 <= s.Length())
+ {
+ int nData = s[i++] & 0x7F;
+ unsigned char c1 = s[i++];
+ nData |= (((int)(c1 & 0x7F)) << 7);
+
+ if (nVarIdx == NS_SHELL_CODE)
+ res += GetShellString(c1);
+ else if (nVarIdx == NS_VAR_CODE)
+ res += GetVar(nData);
+ else if (nVarIdx == NS_LANG_CODE)
+ res += "NS_LANG_CODE";
+ }
+ else if (nVarIdx == NS_SKIP_CODE)
+ {
+ if (i < s.Length())
+ res += s[i++];
+ }
+ else // Normal char
+ res += (char)nVarIdx;
+ }
+ return res;
+}
+
+UString GetNsisString(const UString &s)
+{
+ UString res;
+ for (int i = 0; i < s.Length();)
+ {
+ wchar_t nVarIdx = s[i++];
+ if (nVarIdx > NS_UN_CODES_START && nVarIdx <= NS_UN_CODES_END)
+ {
+ if (i == s.Length())
+ break;
+ int nData = s[i++] & 0x7FFF;
+
+ if (nVarIdx == NS_UN_SHELL_CODE)
+ res += GetUnicodeString(GetShellString(nData >> 8));
+ else if (nVarIdx == NS_UN_VAR_CODE)
+ res += GetUnicodeString(GetVar(nData));
+ else if (nVarIdx == NS_UN_LANG_CODE)
+ res += L"NS_LANG_CODE";
+ }
+ else if (nVarIdx == NS_UN_SKIP_CODE)
+ {
+ if (i == s.Length())
+ break;
+ res += s[i++];
+ }
+ else // Normal char
+ res += (char)nVarIdx;
+ }
+ return res;
+}
+
+AString CInArchive::ReadString2A(UInt32 pos) const
+{
+ return GetNsisString(ReadStringA(pos));
+}
+
+UString CInArchive::ReadString2U(UInt32 pos) const
+{
+ return GetNsisString(ReadStringU(pos));
+}
+
+AString CInArchive::ReadString2(UInt32 pos) const
+{
+ if (IsUnicode)
+ return UnicodeStringToMultiByte(ReadString2U(pos));
+ else
+ return ReadString2A(pos);
+}
+
+AString CInArchive::ReadString2Qw(UInt32 pos) const
+{
+ return "\"" + ReadString2(pos) + "\"";
+}
+
+#define DEL_DIR 1
+#define DEL_RECURSE 2
+#define DEL_REBOOT 4
+// #define DEL_SIMPLE 8
+
+static const int kNumEntryParams = 6;
+
+struct CEntry
+{
+ UInt32 Which;
+ UInt32 Params[kNumEntryParams];
+ AString GetParamsString(int numParams);
+ CEntry()
+ {
+ Which = 0;
+ for (UInt32 j = 0; j < kNumEntryParams; j++)
+ Params[j] = 0;
+ }
+};
+
+AString CEntry::GetParamsString(int numParams)
+{
+ AString s;
+ for (int i = 0; i < numParams; i++)
+ {
+ s += " ";
+ UInt32 v = Params[i];
+ if (v > 0xFFF00000)
+ s += IntToString((Int32)Params[i]);
+ else
+ s += UIntToString(Params[i]);
+ }
+ return s;
+}
+
+#ifdef NSIS_SCRIPT
+
+static AString GetRegRootID(UInt32 val)
+{
+ const char *s;
+ switch(val)
+ {
+ case 0: s = "SHCTX"; break;
+ case 0x80000000: s = "HKCR"; break;
+ case 0x80000001: s = "HKCU"; break;
+ case 0x80000002: s = "HKLM"; break;
+ case 0x80000003: s = "HKU"; break;
+ case 0x80000004: s = "HKPD"; break;
+ case 0x80000005: s = "HKCC"; break;
+ case 0x80000006: s = "HKDD"; break;
+ case 0x80000050: s = "HKPT"; break;
+ case 0x80000060: s = "HKPN"; break;
+ default:
+ return UIntToString(val); break;
+ }
+ return s;
+}
+
+#endif
+
+HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
+{
+ _posInData = bh.Offset + GetOffset();
+ AString prefixA;
+ UString prefixU;
+ for (UInt32 i = 0; i < bh.Num; i++)
+ {
+ CEntry e;
+ e.Which = ReadUInt32();
+ for (UInt32 j = 0; j < kNumEntryParams; j++)
+ e.Params[j] = ReadUInt32();
+ #ifdef NSIS_SCRIPT
+ if (e.Which != EW_PUSHPOP && e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0]))
+ {
+ const CCommandPair &pair = kCommandPairs[e.Which];
+ Script += pair.Name;
+ }
+ #endif
+
+ switch (e.Which)
+ {
+ case EW_CREATEDIR:
+ {
+ if (IsUnicode)
+ {
+ prefixU.Empty();
+ prefixU = ReadString2U(e.Params[0]);
+ }
+ else
+ {
+ prefixA.Empty();
+ prefixA = ReadString2A(e.Params[0]);
+ }
+ #ifdef NSIS_SCRIPT
+ Script += " ";
+ if (IsUnicode)
+ Script += UnicodeStringToMultiByte(prefixU);
+ else
+ Script += prefixA;
+ #endif
+ break;
+ }
+
+ case EW_EXTRACTFILE:
+ {
+ CItem item;
+ item.IsUnicode = IsUnicode;
+ if (IsUnicode)
+ {
+ item.PrefixU = prefixU;
+ item.NameU = ReadString2U(e.Params[1]);
+ }
+ else
+ {
+ item.PrefixA = prefixA;
+ item.NameA = ReadString2A(e.Params[1]);
+ }
+ /* UInt32 overwriteFlag = e.Params[0]; */
+ item.Pos = e.Params[2];
+ item.MTime.dwLowDateTime = e.Params[3];
+ item.MTime.dwHighDateTime = e.Params[4];
+ /* UInt32 allowIgnore = e.Params[5]; */
+ if (Items.Size() > 0)
+ {
+ /*
+ if (item.Pos == Items.Back().Pos)
+ continue;
+ */
+ }
+ Items.Add(item);
+ #ifdef NSIS_SCRIPT
+ Script += " ";
+
+ if (IsUnicode)
+ Script += UnicodeStringToMultiByte(item.NameU);
+ else
+ Script += item.NameA;
+ #endif
+ break;
+ }
+
+
+ #ifdef NSIS_SCRIPT
+ case EW_UPDATETEXT:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += UIntToString(e.Params[1]);
+ break;
+ }
+ case EW_SETFILEATTRIBUTES:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += UIntToString(e.Params[1]);
+ break;
+ }
+ case EW_IFFILEEXISTS:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += UIntToString(e.Params[1]);
+ Script += " ";
+ Script += UIntToString(e.Params[2]);
+ break;
+ }
+ case EW_RENAME:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += UIntToString(e.Params[2]);
+ break;
+ }
+ case EW_GETFULLPATHNAME:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += UIntToString(e.Params[2]);
+ break;
+ }
+ case EW_SEARCHPATH:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ break;
+ }
+ case EW_GETTEMPFILENAME:
+ {
+ AString s;
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ break;
+ }
+
+ case EW_DELETEFILE:
+ {
+ UInt64 flag = e.Params[1];
+ if (flag != 0)
+ {
+ Script += " ";
+ if (flag == DEL_REBOOT)
+ Script += "/REBOOTOK";
+ else
+ Script += UIntToString(e.Params[1]);
+ }
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ break;
+ }
+ case EW_RMDIR:
+ {
+ UInt64 flag = e.Params[1];
+ if (flag != 0)
+ {
+ if ((flag & DEL_REBOOT) != 0)
+ Script += " /REBOOTOK";
+ if ((flag & DEL_RECURSE) != 0)
+ Script += " /r";
+ }
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ break;
+ }
+ case EW_STRLEN:
+ {
+ Script += " ";
+ Script += GetVar(e.Params[0]);;
+ Script += " ";
+ Script += ReadString2Qw(e.Params[1]);
+ break;
+ }
+ case EW_ASSIGNVAR:
+ {
+ Script += " ";
+ Script += GetVar(e.Params[0]);;
+ Script += " ";
+ Script += ReadString2Qw(e.Params[1]);
+ AString maxLen, startOffset;
+ if (e.Params[2] != 0)
+ maxLen = ReadString2(e.Params[2]);
+ if (e.Params[3] != 0)
+ startOffset = ReadString2(e.Params[3]);
+ if (!maxLen.IsEmpty() || !startOffset.IsEmpty())
+ {
+ Script += " ";
+ if (maxLen.IsEmpty())
+ Script += "\"\"";
+ else
+ Script += maxLen;
+ if (!startOffset.IsEmpty())
+ {
+ Script += " ";
+ Script += startOffset;
+ }
+ }
+ break;
+ }
+ case EW_STRCMP:
+ {
+ Script += " ";
+
+ Script += " ";
+ Script += ReadString2Qw(e.Params[0]);
+
+ Script += " ";
+ Script += ReadString2Qw(e.Params[1]);
+
+ for (int j = 2; j < 5; j++)
+ {
+ Script += " ";
+ Script += UIntToString(e.Params[j]);
+ }
+ break;
+ }
+ case EW_INTCMP:
+ {
+ if (e.Params[5] != 0)
+ Script += "U";
+
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+
+ for (int i = 2; i < 5; i++)
+ {
+ Script += " ";
+ Script += UIntToString(e.Params[i]);
+ }
+ break;
+ }
+ case EW_INTOP:
+ {
+ Script += " ";
+ Script += GetVar(e.Params[0]);
+ Script += " ";
+ int numOps = 2;
+ AString op;
+ switch (e.Params[3])
+ {
+ case 0: op = '+'; break;
+ case 1: op = '-'; break;
+ case 2: op = '*'; break;
+ case 3: op = '/'; break;
+ case 4: op = '|'; break;
+ case 5: op = '&'; break;
+ case 6: op = '^'; break;
+ case 7: op = '~'; numOps = 1; break;
+ case 8: op = '!'; numOps = 1; break;
+ case 9: op = "||"; break;
+ case 10: op = "&&"; break;
+ case 11: op = '%'; break;
+ default: op = UIntToString(e.Params[3]);
+ }
+ AString p1 = ReadString2(e.Params[1]);
+ if (numOps == 1)
+ {
+ Script += op;
+ Script += p1;
+ }
+ else
+ {
+ Script += p1;
+ Script += " ";
+ Script += op;
+ Script += " ";
+ Script += ReadString2(e.Params[2]);
+ }
+ break;
+ }
+
+ case EW_PUSHPOP:
+ {
+ int isPop = (e.Params[1] != 0);
+ if (isPop)
+ {
+ Script += "Pop";
+ Script += " ";
+ Script += GetVar(e.Params[0]);;
+ }
+ else
+ {
+ int isExch = (e.Params[2] != 0);
+ if (isExch)
+ {
+ Script += "Exch";
+ }
+ else
+ {
+ Script += "Push";
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ }
+ }
+ break;
+ }
+
+ case EW_SENDMESSAGE:
+ {
+ // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2]
+ Script += " ";
+ // Script += ReadString2(e.Params[0]);
+ // Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += ReadString2(e.Params[2]);
+
+ Script += " ";
+ UInt32 spec = e.Params[5];
+ // if (spec & 1)
+ Script += IntToString(e.Params[3]);
+ // else
+ // Script += ReadString2(e.Params[3]);
+
+ Script += " ";
+ // if (spec & 2)
+ Script += IntToString(e.Params[4]);
+ // else
+ // Script += ReadString2(e.Params[4]);
+
+ if ((Int32)e.Params[0] >= 0)
+ {
+ Script += " ";
+ Script += GetVar(e.Params[1]);
+ }
+
+ spec >>= 2;
+ if (spec != 0)
+ {
+ Script += " /TIMEOUT=";
+ Script += IntToString(spec);
+ }
+ break;
+ }
+
+ case EW_GETDLGITEM:
+ {
+ Script += " ";
+ Script += GetVar(e.Params[0]);;
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += ReadString2(e.Params[2]);
+ break;
+ }
+
+
+ case EW_REGISTERDLL:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ Script += " ";
+ Script += ReadString2(e.Params[1]);
+ Script += " ";
+ Script += UIntToString(e.Params[2]);
+ break;
+ }
+
+ case EW_CREATESHORTCUT:
+ {
+ AString s;
+
+ Script += " ";
+ Script += ReadString2Qw(e.Params[0]);
+
+ Script += " ";
+ Script += ReadString2Qw(e.Params[1]);
+
+ for (int j = 2; j < 5; j++)
+ {
+ Script += " ";
+ Script += UIntToString(e.Params[j]);
+ }
+ break;
+ }
+
+ /*
+ case EW_DELREG:
+ {
+ AString keyName, valueName;
+ keyName = ReadString2(e.Params[1]);
+ bool isValue = (e.Params[2] != -1);
+ if (isValue)
+ {
+ valueName = ReadString2(e.Params[2]);
+ Script += "Key";
+ }
+ else
+ Script += "Value";
+ Script += " ";
+ Script += UIntToString(e.Params[0]);
+ Script += " ";
+ Script += keyName;
+ if (isValue)
+ {
+ Script += " ";
+ Script += valueName;
+ }
+ Script += " ";
+ Script += UIntToString(e.Params[3]);
+ break;
+ }
+ */
+
+ case EW_WRITEREG:
+ {
+ AString s;
+ switch(e.Params[4])
+ {
+ case 1: s = "Str"; break;
+ case 2: s = "ExpandStr"; break;
+ case 3: s = "Bin"; break;
+ case 4: s = "DWORD"; break;
+ default: s = "?" + UIntToString(e.Params[4]); break;
+ }
+ Script += s;
+ Script += " ";
+ Script += GetRegRootID(e.Params[0]);
+ Script += " ";
+
+ AString keyName, valueName;
+ keyName = ReadString2Qw(e.Params[1]);
+ Script += keyName;
+ Script += " ";
+
+ valueName = ReadString2Qw(e.Params[2]);
+ Script += valueName;
+ Script += " ";
+
+ valueName = ReadString2Qw(e.Params[3]);
+ Script += valueName;
+ Script += " ";
+
+ break;
+ }
+
+ case EW_WRITEUNINSTALLER:
+ {
+ Script += " ";
+ Script += ReadString2(e.Params[0]);
+ for (int j = 1; j < 3; j++)
+ {
+ Script += " ";
+ Script += UIntToString(e.Params[j]);
+ }
+ break;
+ }
+
+ default:
+ {
+ int numParams = kNumEntryParams;
+ if (e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0]))
+ {
+ const CCommandPair &pair = kCommandPairs[e.Which];
+ // Script += pair.Name;
+ numParams = pair.NumParams;
+ }
+ else
+ {
+ Script += "Unknown";
+ Script += UIntToString(e.Which);
+ }
+ Script += e.GetParamsString(numParams);
+ }
+ #endif
+ }
+ #ifdef NSIS_SCRIPT
+ Script += kCrLf;
+ #endif
+ }
+
+ {
+ Items.Sort(CompareItems, 0);
+ int i;
+ // if (IsSolid)
+ for (i = 0; i + 1 < Items.Size();)
+ {
+ bool sameName = IsUnicode ?
+ (Items[i].NameU == Items[i + 1].NameU) :
+ (Items[i].NameA == Items[i + 1].NameA);
+ if (Items[i].Pos == Items[i + 1].Pos && sameName)
+ Items.Delete(i + 1);
+ else
+ i++;
+ }
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ UInt32 curPos = item.Pos + 4;
+ for (int nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++)
+ {
+ UInt32 nextPos = Items[nextIndex].Pos;
+ if (curPos <= nextPos)
+ {
+ item.EstimatedSizeIsDefined = true;
+ item.EstimatedSize = nextPos - curPos;
+ break;
+ }
+ }
+ }
+ if (!IsSolid)
+ {
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ RINOK(_stream->Seek(GetPosOfNonSolidItem(i), STREAM_SEEK_SET, NULL));
+ const UInt32 kSigSize = 4 + 1 + 5;
+ BYTE sig[kSigSize];
+ size_t processedSize = kSigSize;
+ RINOK(ReadStream(_stream, sig, &processedSize));
+ if (processedSize < 4)
+ return S_FALSE;
+ UInt32 size = Get32(sig);
+ if ((size & 0x80000000) != 0)
+ {
+ item.IsCompressed = true;
+ // is compressed;
+ size &= ~0x80000000;
+ if (Method == NMethodType::kLZMA)
+ {
+ if (processedSize < 9)
+ return S_FALSE;
+ if (FilterFlag)
+ item.UseFilter = (sig[4] != 0);
+ item.DictionarySize = Get32(sig + 5 + (FilterFlag ? 1 : 0));
+ }
+ }
+ else
+ {
+ item.IsCompressed = false;
+ item.Size = size;
+ item.SizeIsDefined = true;
+ }
+ item.CompressedSize = size;
+ item.CompressedSizeIsDefined = true;
+ }
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::Parse()
+{
+ // UInt32 offset = ReadUInt32();
+ // ???? offset == FirstHeader.HeaderLength
+ /* UInt32 ehFlags = */ ReadUInt32();
+ CBlockHeader bhPages, bhSections, bhEntries, bhStrings, bhLangTables, bhCtlColors, bhData;
+ // CBlockHeader bgFont;
+ ReadBlockHeader(bhPages);
+ ReadBlockHeader(bhSections);
+ ReadBlockHeader(bhEntries);
+ ReadBlockHeader(bhStrings);
+ ReadBlockHeader(bhLangTables);
+ ReadBlockHeader(bhCtlColors);
+ // ReadBlockHeader(bgFont);
+ ReadBlockHeader(bhData);
+
+ _stringsPos = bhStrings.Offset;
+ UInt32 pos = GetOffset() + _stringsPos;
+ int numZeros0 = 0;
+ int numZeros1 = 0;
+ int i;
+ const int kBlockSize = 256;
+ for (i = 0; i < kBlockSize; i++)
+ {
+ if (pos >= _size || pos + 1 >= _size)
+ break;
+ char c0 = _data[pos++];
+ char c1 = _data[pos++];
+ wchar_t c = (c0 | ((wchar_t)c1 << 8));
+
+ if (c >= NS_UN_CODES_START && c < NS_UN_CODES_END)
+ {
+ if (pos >= _size || pos + 1 >= _size)
+ break;
+ pos += 2;
+ numZeros1++;
+ }
+ else
+ {
+ if (c0 == 0 && c1 != 0)
+ numZeros0++;
+ if (c1 == 0)
+ numZeros1++;
+ }
+ // printf("\nnumZeros0 = %2x %2x", _data[pos + 0], _data[pos + 1]);
+ }
+ IsUnicode = (numZeros1 > numZeros0 * 3 + kBlockSize / 16);
+ // printf("\nnumZeros0 = %3d numZeros1 = %3d", numZeros0, numZeros1);
+ return ReadEntries(bhEntries);
+}
+
+static bool IsLZMA(const Byte *p, UInt32 &dictionary)
+{
+ dictionary = Get32(p + 1);
+ return (p[0] == 0x5D && p[1] == 0x00 && p[2] == 0x00 && p[5] == 0x00);
+}
+
+static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag)
+{
+ if (IsLZMA(p, dictionary))
+ {
+ thereIsFlag = false;
+ return true;
+ }
+ if (IsLZMA(p + 1, dictionary))
+ {
+ thereIsFlag = true;
+ return true;
+ }
+ return false;
+}
+
+static bool IsBZip2(const Byte *p)
+{
+ return (p[0] == 0x31 && p[1] < 14);
+}
+
+HRESULT CInArchive::Open2(
+ DECL_EXTERNAL_CODECS_LOC_VARS2
+ )
+{
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &StreamOffset));
+
+ const UInt32 kSigSize = 4 + 1 + 5 + 1; // size, flag, lzma props, lzma first byte
+ BYTE sig[kSigSize];
+ RINOK(ReadStream_FALSE(_stream, sig, kSigSize));
+ UInt64 position;
+ RINOK(_stream->Seek(StreamOffset, STREAM_SEEK_SET, &position));
+
+ _headerIsCompressed = true;
+ IsSolid = true;
+ FilterFlag = false;
+ DictionarySize = 1;
+
+ UInt32 compressedHeaderSize = Get32(sig);
+
+ if (compressedHeaderSize == FirstHeader.HeaderLength)
+ {
+ _headerIsCompressed = false;
+ IsSolid = false;
+ Method = NMethodType::kCopy;
+ }
+ else if (IsLZMA(sig, DictionarySize, FilterFlag))
+ {
+ Method = NMethodType::kLZMA;
+ }
+ else if (IsLZMA(sig + 4, DictionarySize, FilterFlag))
+ {
+ IsSolid = false;
+ Method = NMethodType::kLZMA;
+ }
+ else if (sig[3] == 0x80)
+ {
+ IsSolid = false;
+ if (IsBZip2(sig + 4))
+ Method = NMethodType::kBZip2;
+ else
+ Method = NMethodType::kDeflate;
+ }
+ else if (IsBZip2(sig))
+ {
+ Method = NMethodType::kBZip2;
+ }
+ else
+ {
+ Method = NMethodType::kDeflate;
+ }
+
+ _posInData = 0;
+ if (!IsSolid)
+ {
+ _headerIsCompressed = ((compressedHeaderSize & 0x80000000) != 0);
+ if (_headerIsCompressed)
+ compressedHeaderSize &= ~0x80000000;
+ _nonSolidStartOffset = compressedHeaderSize;
+ RINOK(_stream->Seek(StreamOffset + 4, STREAM_SEEK_SET, NULL));
+ }
+ UInt32 unpackSize = FirstHeader.HeaderLength;
+ if (_headerIsCompressed)
+ {
+ // unpackSize = (1 << 23);
+ _data.SetCapacity(unpackSize);
+ RINOK(Decoder.Init(
+ EXTERNAL_CODECS_LOC_VARS
+ _stream, Method, FilterFlag, UseFilter));
+ size_t processedSize = unpackSize;
+ RINOK(Decoder.Read(_data, &processedSize));
+ if (processedSize != unpackSize)
+ return S_FALSE;
+ _size = processedSize;
+ if (IsSolid)
+ {
+ UInt32 size2 = ReadUInt32();
+ if (size2 < _size)
+ _size = size2;
+ }
+ }
+ else
+ {
+ _data.SetCapacity(unpackSize);
+ _size = (size_t)unpackSize;
+ RINOK(ReadStream_FALSE(_stream, (Byte *)_data, unpackSize));
+ }
+ return Parse();
+}
+
+/*
+NsisExe =
+{
+ ExeStub
+ Archive // must start from 512 * N
+ #ifndef NSIS_CONFIG_CRC_ANAL
+ {
+ Some additional data
+ }
+}
+
+Archive
+{
+ FirstHeader
+ Data
+ #ifdef NSIS_CONFIG_CRC_SUPPORT && FirstHeader.ThereIsCrc()
+ {
+ CRC
+ }
+}
+
+FirstHeader
+{
+ UInt32 Flags;
+ Byte Signature[16];
+ // points to the header+sections+entries+stringtable in the datablock
+ UInt32 HeaderLength;
+ UInt32 ArchiveSize;
+}
+*/
+
+HRESULT CInArchive::Open(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream, const UInt64 *maxCheckStartPosition)
+{
+ Clear();
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ UInt64 maxSize = ((maxCheckStartPosition != 0) ? *maxCheckStartPosition : 0);
+ const UInt32 kStep = 512;
+ Byte buffer[kStep];
+
+ UInt64 position = 0;
+ for (; position <= maxSize; position += kStep)
+ {
+ RINOK(ReadStream_FALSE(inStream, buffer, kStep));
+ if (memcmp(buffer + 4, kSignature, kSignatureSize) == 0)
+ break;
+ }
+ if (position > maxSize)
+ return S_FALSE;
+ const UInt32 kStartHeaderSize = 4 * 7;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &_archiveSize));
+ RINOK(inStream->Seek(position + kStartHeaderSize, STREAM_SEEK_SET, 0));
+ FirstHeader.Flags = Get32(buffer);
+ FirstHeader.HeaderLength = Get32(buffer + kSignatureSize + 4);
+ FirstHeader.ArchiveSize = Get32(buffer + kSignatureSize + 8);
+ if (_archiveSize - position < FirstHeader.ArchiveSize)
+ return S_FALSE;
+
+ try
+ {
+ _stream = inStream;
+ HRESULT res = Open2(EXTERNAL_CODECS_LOC_VARS2);
+ if (res != S_OK)
+ Clear();
+ _stream.Release();
+ return res;
+ }
+ catch(...) { Clear(); return S_FALSE; }
+}
+
+void CInArchive::Clear()
+{
+ #ifdef NSIS_SCRIPT
+ Script.Empty();
+ #endif
+ Items.Clear();
+ _stream.Release();
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisIn.h
new file mode 100644
index 000000000..87ae3f1ca
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisIn.h
@@ -0,0 +1,181 @@
+// NsisIn.h
+
+#ifndef __ARCHIVE_NSIS_IN_H
+#define __ARCHIVE_NSIS_IN_H
+
+#include "Common/Buffer.h"
+#include "Common/MyCom.h"
+#include "Common/StringConvert.h"
+
+#include "NsisDecode.h"
+
+// #define NSIS_SCRIPT
+
+namespace NArchive {
+namespace NNsis {
+
+const int kSignatureSize = 16;
+#define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 0x4E, 0x75, 0x6C, 0x6C, 0x73, 0x6F, 0x66, 0x74, 0x49, 0x6E, 0x73, 0x74}
+
+extern Byte kSignature[kSignatureSize];
+
+const UInt32 kFlagsMask = 0xF;
+namespace NFlags
+{
+ const UInt32 kUninstall = 1;
+ const UInt32 kSilent = 2;
+ const UInt32 kNoCrc = 4;
+ const UInt32 kForceCrc = 8;
+}
+
+struct CFirstHeader
+{
+ UInt32 Flags;
+ UInt32 HeaderLength;
+
+ UInt32 ArchiveSize;
+
+ bool ThereIsCrc() const
+ {
+ if ((Flags & NFlags::kForceCrc ) != 0)
+ return true;
+ return ((Flags & NFlags::kNoCrc) == 0);
+ }
+
+ UInt32 GetDataSize() const { return ArchiveSize - (ThereIsCrc() ? 4 : 0); }
+};
+
+
+struct CBlockHeader
+{
+ UInt32 Offset;
+ UInt32 Num;
+};
+
+struct CItem
+{
+ AString PrefixA;
+ UString PrefixU;
+ AString NameA;
+ UString NameU;
+ FILETIME MTime;
+ bool IsUnicode;
+ bool UseFilter;
+ bool IsCompressed;
+ bool SizeIsDefined;
+ bool CompressedSizeIsDefined;
+ bool EstimatedSizeIsDefined;
+ UInt32 Pos;
+ UInt32 Size;
+ UInt32 CompressedSize;
+ UInt32 EstimatedSize;
+ UInt32 DictionarySize;
+
+ CItem(): IsUnicode(false), UseFilter(false), IsCompressed(true), SizeIsDefined(false),
+ CompressedSizeIsDefined(false), EstimatedSizeIsDefined(false), Size(0), DictionarySize(1) {}
+
+ bool IsINSTDIR() const
+ {
+ return (PrefixA.Length() >= 3 || PrefixU.Length() >= 3);
+ }
+
+ UString GetReducedName(bool unicode) const
+ {
+ UString s;
+ if (unicode)
+ s = PrefixU;
+ else
+ s = MultiByteToUnicodeString(PrefixA);
+ if (s.Length() > 0)
+ if (s[s.Length() - 1] != L'\\')
+ s += L'\\';
+ if (unicode)
+ s += NameU;
+ else
+ s += MultiByteToUnicodeString(NameA);
+ const int len = 9;
+ if (s.Left(len).CompareNoCase(L"$INSTDIR\\") == 0)
+ s = s.Mid(len);
+ return s;
+ }
+};
+
+class CInArchive
+{
+ UInt64 _archiveSize;
+ CMyComPtr<IInStream> _stream;
+
+ Byte ReadByte();
+ UInt32 ReadUInt32();
+ HRESULT Open2(
+ DECL_EXTERNAL_CODECS_LOC_VARS2
+ );
+ void ReadBlockHeader(CBlockHeader &bh);
+ AString ReadStringA(UInt32 pos) const;
+ UString ReadStringU(UInt32 pos) const;
+ AString ReadString2A(UInt32 pos) const;
+ UString ReadString2U(UInt32 pos) const;
+ AString ReadString2(UInt32 pos) const;
+ AString ReadString2Qw(UInt32 pos) const;
+ HRESULT ReadEntries(const CBlockHeader &bh);
+ HRESULT Parse();
+
+ CByteBuffer _data;
+ UInt64 _size;
+
+ size_t _posInData;
+
+ UInt32 _stringsPos;
+
+
+ bool _headerIsCompressed;
+ UInt32 _nonSolidStartOffset;
+public:
+ HRESULT Open(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream, const UInt64 *maxCheckStartPosition);
+ void Clear();
+
+ UInt64 StreamOffset;
+ CDecoder Decoder;
+ CObjectVector<CItem> Items;
+ CFirstHeader FirstHeader;
+ NMethodType::EEnum Method;
+ UInt32 DictionarySize;
+ bool IsSolid;
+ bool UseFilter;
+ bool FilterFlag;
+ bool IsUnicode;
+
+ #ifdef NSIS_SCRIPT
+ AString Script;
+ #endif
+ UInt32 GetOffset() const { return IsSolid ? 4 : 0; }
+ UInt64 GetDataPos(int index)
+ {
+ const CItem &item = Items[index];
+ return GetOffset() + FirstHeader.HeaderLength + item.Pos;
+ }
+
+ UInt64 GetPosOfSolidItem(int index) const
+ {
+ const CItem &item = Items[index];
+ return 4 + FirstHeader.HeaderLength + item.Pos;
+ }
+
+ UInt64 GetPosOfNonSolidItem(int index) const
+ {
+ const CItem &item = Items[index];
+ return StreamOffset + _nonSolidStartOffset + 4 + item.Pos;
+ }
+
+ void Release()
+ {
+ Decoder.Release();
+ }
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisRegister.cpp
new file mode 100644
index 000000000..41dedb0d3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/NsisRegister.cpp
@@ -0,0 +1,13 @@
+// NsisRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "NsisHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NNsis::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Nsis", L"", 0, 0x9, NSIS_SIGNATURE, NArchive::NNsis::kSignatureSize, false, CreateArc, 0 };
+
+REGISTER_ARC(Nsis)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Nsis/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/StdAfx.h
new file mode 100644
index 000000000..2e4be10b2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Nsis/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp
new file mode 100644
index 000000000..505486fc5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/NtfsHandler.cpp
@@ -0,0 +1,1764 @@
+// NtfsHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+// #define SHOW_DEBUG_INFO2
+
+#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2)
+#include <stdio.h>
+#endif
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/DummyOutStream.h"
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#ifdef SHOW_DEBUG_INFO2
+#define PRF2(x) x
+#else
+#define PRF2(x)
+#endif
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(p, dest) dest = Get16(p);
+#define G32(p, dest) dest = Get32(p);
+#define G64(p, dest) dest = Get64(p);
+
+namespace NArchive {
+namespace Ntfs {
+
+static const UInt32 kNumSysRecs = 16;
+static const UInt32 kRecIndex_Volume = 3;
+static const UInt32 kRecIndex_BadClus = 8;
+
+struct CHeader
+{
+ Byte SectorSizeLog;
+ Byte ClusterSizeLog;
+ // Byte MediaType;
+ UInt32 NumHiddenSectors;
+ UInt64 NumClusters;
+ UInt64 MftCluster;
+ UInt64 SerialNumber;
+ UInt16 SectorsPerTrack;
+ UInt16 NumHeads;
+
+ UInt64 GetPhySize() const { return NumClusters << ClusterSizeLog; }
+ UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
+ bool Parse(const Byte *p);
+};
+
+static int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+
+ int codeOffset = 0;
+ switch (p[0])
+ {
+ case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break;
+ case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break;
+ default: return false;
+ }
+ Byte sectorsPerClusterLog;
+
+ if (memcmp(p + 3, "NTFS ", 8) != 0)
+ return false;
+ {
+ int s = GetLog(Get16(p + 11));
+ if (s < 9 || s > 12)
+ return false;
+ SectorSizeLog = (Byte)s;
+ s = GetLog(p[13]);
+ if (s < 0)
+ return false;
+ sectorsPerClusterLog = (Byte)s;
+ ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog;
+ }
+
+ for (int i = 14; i < 21; i++)
+ if (p[i] != 0)
+ return false;
+
+ // MediaType = p[21];
+ if (Get16(p + 22) != 0) // NumFatSectors
+ return false;
+ G16(p + 24, SectorsPerTrack);
+ G16(p + 26, NumHeads);
+ G32(p + 28, NumHiddenSectors);
+ if (Get32(p + 32) != 0) // NumSectors32
+ return false;
+
+ // DriveNumber = p[0x24];
+ if (p[0x25] != 0) // CurrentHead
+ return false;
+ /*
+ NTFS-HDD: p[0x26] = 0x80
+ NTFS-FLASH: p[0x26] = 0
+ */
+ if (p[0x26] != 0x80 && p[0x26] != 0) // ExtendedBootSig
+ return false;
+ if (p[0x27] != 0) // reserved
+ return false;
+ UInt64 numSectors = Get64(p + 0x28);
+ NumClusters = numSectors >> sectorsPerClusterLog;
+
+ G64(p + 0x30, MftCluster);
+ // G64(p + 0x38, Mft2Cluster);
+ G64(p + 0x48, SerialNumber);
+ UInt32 numClustersInMftRec;
+ UInt32 numClustersInIndexBlock;
+ G32(p + 0x40, numClustersInMftRec);
+ G32(p + 0x44, numClustersInIndexBlock);
+ return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256);
+}
+
+struct CMftRef
+{
+ UInt64 Val;
+ UInt64 GetIndex() const { return Val & (((UInt64)1 << 48) - 1); }
+ UInt16 GetNumber() const { return (UInt16)(Val >> 48); }
+ bool IsBaseItself() const { return Val == 0; }
+};
+
+#define ATNAME(n) ATTR_TYPE_ ## n
+#define DEF_ATTR_TYPE(v, n) ATNAME(n) = v
+
+enum
+{
+ DEF_ATTR_TYPE(0x00, UNUSED),
+ DEF_ATTR_TYPE(0x10, STANDARD_INFO),
+ DEF_ATTR_TYPE(0x20, ATTRIBUTE_LIST),
+ DEF_ATTR_TYPE(0x30, FILE_NAME),
+ DEF_ATTR_TYPE(0x40, OBJECT_ID),
+ DEF_ATTR_TYPE(0x50, SECURITY_DESCRIPTOR),
+ DEF_ATTR_TYPE(0x60, VOLUME_NAME),
+ DEF_ATTR_TYPE(0x70, VOLUME_INFO),
+ DEF_ATTR_TYPE(0x80, DATA),
+ DEF_ATTR_TYPE(0x90, INDEX_ROOT),
+ DEF_ATTR_TYPE(0xA0, INDEX_ALLOCATION),
+ DEF_ATTR_TYPE(0xB0, BITMAP),
+ DEF_ATTR_TYPE(0xC0, REPARSE_POINT),
+ DEF_ATTR_TYPE(0xD0, EA_INFO),
+ DEF_ATTR_TYPE(0xE0, EA),
+ DEF_ATTR_TYPE(0xF0, PROPERTY_SET),
+ DEF_ATTR_TYPE(0x100, LOGGED_UTILITY_STREAM),
+ DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE)
+};
+
+static const Byte kFileNameType_Posix = 0;
+static const Byte kFileNameType_Win32 = 1;
+static const Byte kFileNameType_Dos = 2;
+static const Byte kFileNameType_Win32Dos = 3;
+
+struct CFileNameAttr
+{
+ CMftRef ParentDirRef;
+ // UInt64 CTime;
+ // UInt64 MTime;
+ // UInt64 ThisRecMTime;
+ // UInt64 ATime;
+ // UInt64 AllocatedSize;
+ // UInt64 DataSize;
+ // UInt16 PackedEaSize;
+ UString Name;
+ UInt32 Attrib;
+ Byte NameType;
+
+ bool IsDos() const { return NameType == kFileNameType_Dos; }
+ bool Parse(const Byte *p, unsigned size);
+};
+
+static void GetString(const Byte *p, unsigned length, UString &res)
+{
+ wchar_t *s = res.GetBuffer(length);
+ for (unsigned i = 0; i < length; i++)
+ s[i] = Get16(p + i * 2);
+ s[length] = 0;
+ res.ReleaseBuffer();
+}
+
+bool CFileNameAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 0x42)
+ return false;
+ G64(p + 0x00, ParentDirRef.Val);
+ // G64(p + 0x08, CTime);
+ // G64(p + 0x10, MTime);
+ // G64(p + 0x18, ThisRecMTime);
+ // G64(p + 0x20, ATime);
+ // G64(p + 0x28, AllocatedSize);
+ // G64(p + 0x30, DataSize);
+ G32(p + 0x38, Attrib);
+ // G16(p + 0x3C, PackedEaSize);
+ NameType = p[0x41];
+ unsigned length = p[0x40];
+ if (0x42 + length > size)
+ return false;
+ GetString(p + 0x42, length, Name);
+ return true;
+}
+
+struct CSiAttr
+{
+ UInt64 CTime;
+ UInt64 MTime;
+ // UInt64 ThisRecMTime;
+ UInt64 ATime;
+ UInt32 Attrib;
+
+ /*
+ UInt32 MaxVersions;
+ UInt32 Version;
+ UInt32 ClassId;
+ UInt32 OwnerId;
+ UInt32 SecurityId;
+ UInt64 QuotaCharged;
+ */
+
+ bool Parse(const Byte *p, unsigned size);
+};
+
+bool CSiAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 0x24)
+ return false;
+ G64(p + 0x00, CTime);
+ G64(p + 0x08, MTime);
+ // G64(p + 0x10, ThisRecMTime);
+ G64(p + 0x18, ATime);
+ G32(p + 0x20, Attrib);
+ return true;
+}
+
+static const UInt64 kEmptyExtent = (UInt64)(Int64)-1;
+
+struct CExtent
+{
+ UInt64 Virt;
+ UInt64 Phy;
+
+ bool IsEmpty() const { return Phy == kEmptyExtent; }
+};
+
+struct CVolInfo
+{
+ Byte MajorVer;
+ Byte MinorVer;
+ // UInt16 Flags;
+
+ bool Parse(const Byte *p, unsigned size);
+};
+
+bool CVolInfo::Parse(const Byte *p, unsigned size)
+{
+ if (size < 12)
+ return false;
+ MajorVer = p[8];
+ MinorVer = p[9];
+ // Flags = Get16(p + 10);
+ return true;
+}
+
+struct CAttr
+{
+ UInt32 Type;
+ // UInt32 Length;
+ UString Name;
+ // UInt16 Flags;
+ // UInt16 Instance;
+ CByteBuffer Data;
+ Byte NonResident;
+
+ // Non-Resident
+ Byte CompressionUnit;
+ UInt64 LowVcn;
+ UInt64 HighVcn;
+ UInt64 AllocatedSize;
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt64 InitializedSize;
+
+ // Resident
+ // UInt16 ResidentFlags;
+
+ bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; }
+
+ UInt32 Parse(const Byte *p, unsigned size);
+ bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
+ bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
+ bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); }
+ bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const;
+ UInt64 GetSize() const { return NonResident ? Size : Data.GetCapacity(); }
+ UInt64 GetPackSize() const
+ {
+ if (!NonResident)
+ return Data.GetCapacity();
+ if (CompressionUnit != 0)
+ return PackSize;
+ return AllocatedSize;
+ }
+};
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+static int CompareAttr(void *const *elem1, void *const *elem2, void *)
+{
+ const CAttr &a1 = *(*((const CAttr **)elem1));
+ const CAttr &a2 = *(*((const CAttr **)elem2));
+ RINOZ(MyCompare(a1.Type, a2.Type));
+ RINOZ(MyCompare(a1.Name, a2.Name));
+ return MyCompare(a1.LowVcn, a2.LowVcn);
+}
+
+UInt32 CAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 4)
+ return 0;
+ G32(p, Type);
+ if (Type == 0xFFFFFFFF)
+ return 4;
+ if (size < 0x18)
+ return 0;
+ PRF(printf(" T=%2X", Type));
+
+ UInt32 length = Get32(p + 0x04);
+ PRF(printf(" L=%3d", length));
+ if (length > size)
+ return 0;
+ NonResident = p[0x08];
+ {
+ int nameLength = p[9];
+ UInt32 nameOffset = Get16(p + 0x0A);
+ if (nameLength != 0)
+ {
+ if (nameOffset + nameLength * 2 > length)
+ return 0;
+ GetString(p + nameOffset, nameLength, Name);
+ PRF(printf(" N=%S", Name));
+ }
+ }
+
+ // G16(p + 0x0C, Flags);
+ // G16(p + 0x0E, Instance);
+ // PRF(printf(" F=%4X", Flags));
+ // PRF(printf(" Inst=%d", Instance));
+
+ UInt32 dataSize;
+ UInt32 offs;
+ if (NonResident)
+ {
+ if (length < 0x40)
+ return 0;
+ PRF(printf(" NR"));
+ G64(p + 0x10, LowVcn);
+ G64(p + 0x18, HighVcn);
+ G64(p + 0x28, AllocatedSize);
+ G64(p + 0x30, Size);
+ G64(p + 0x38, InitializedSize);
+ G16(p + 0x20, offs);
+ CompressionUnit = p[0x22];
+
+ PackSize = Size;
+ if (CompressionUnit != 0)
+ {
+ if (length < 0x48)
+ return 0;
+ G64(p + 0x40, PackSize);
+ PRF(printf(" PS=%I64x", PackSize));
+ }
+
+ // PRF(printf("\n"));
+ PRF(printf(" ASize=%4I64d", AllocatedSize));
+ PRF(printf(" Size=%I64d", Size));
+ PRF(printf(" IS=%I64d", InitializedSize));
+ PRF(printf(" Low=%I64d", LowVcn));
+ PRF(printf(" High=%I64d", HighVcn));
+ PRF(printf(" CU=%d", (int)CompressionUnit));
+ dataSize = length - offs;
+ }
+ else
+ {
+ if (length < 0x18)
+ return 0;
+ PRF(printf(" RES"));
+ dataSize = Get32(p + 0x10);
+ PRF(printf(" dataSize=%3d", dataSize));
+ offs = Get16(p + 0x14);
+ // G16(p + 0x16, ResidentFlags);
+ // PRF(printf(" ResFlags=%4X", ResidentFlags));
+ }
+ if (offs > length || dataSize > length || length - dataSize < offs)
+ return 0;
+ Data.SetCapacity(dataSize);
+ memcpy(Data, p + offs, dataSize);
+ #ifdef SHOW_DEBUG_INFO
+ PRF(printf(" : "));
+ for (unsigned i = 0; i < Data.GetCapacity(); i++)
+ {
+ PRF(printf(" %02X", (int)Data[i]));
+ }
+ #endif
+ return length;
+}
+
+bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const
+{
+ const Byte *p = Data;
+ unsigned size = (unsigned)Data.GetCapacity();
+ UInt64 vcn = LowVcn;
+ UInt64 lcn = 0;
+ UInt64 highVcn1 = HighVcn + 1;
+ if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63)
+ return false;
+
+ extents.DeleteBack();
+
+ PRF2(printf("\n# ParseExtents # LowVcn = %4I64X # HighVcn = %4I64X", LowVcn, HighVcn));
+
+ while (size > 0)
+ {
+ Byte b = *p++;
+ size--;
+ if (b == 0)
+ break;
+ UInt32 num = b & 0xF;
+ if (num == 0 || num > 8 || num > size)
+ return false;
+
+ int i;
+ UInt64 vSize = p[num - 1];
+ for (i = (int)num - 2; i >= 0; i--)
+ vSize = (vSize << 8) | p[i];
+ if (vSize == 0)
+ return false;
+ p += num;
+ size -= num;
+ if ((highVcn1 - vcn) < vSize)
+ return false;
+
+ num = (b >> 4) & 0xF;
+ if (num > 8 || num > size)
+ return false;
+ CExtent e;
+ e.Virt = vcn;
+ if (num == 0)
+ {
+ if (compressionUnit == 0)
+ return false;
+ e.Phy = kEmptyExtent;
+ }
+ else
+ {
+ Int64 v = (signed char)p[num - 1];
+ for (i = (int)num - 2; i >= 0; i--)
+ v = (v << 8) | p[i];
+ p += num;
+ size -= num;
+ lcn += v;
+ if (lcn > numClustersMax)
+ return false;
+ e.Phy = lcn;
+ }
+ extents.Add(e);
+ vcn += vSize;
+ }
+ CExtent e;
+ e.Phy = kEmptyExtent;
+ e.Virt = vcn;
+ extents.Add(e);
+ return (highVcn1 == vcn);
+}
+
+static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
+
+static const int kNumCacheChunksLog = 1;
+static const UInt32 kNumCacheChunks = (1 << kNumCacheChunksLog);
+
+class CInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt64 _curRem;
+ bool _sparseMode;
+ size_t _compressedPos;
+
+ UInt64 _tags[kNumCacheChunks];
+ int _chunkSizeLog;
+ CByteBuffer _inBuf;
+ CByteBuffer _outBuf;
+public:
+ CMyComPtr<IInStream> Stream;
+ UInt64 Size;
+ UInt64 InitializedSize;
+ int BlockSizeLog;
+ int CompressionUnit;
+ bool InUse;
+ CRecordVector<CExtent> Extents;
+
+ HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
+
+ UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); }
+ HRESULT InitAndSeek(int compressionUnit)
+ {
+ CompressionUnit = compressionUnit;
+ if (compressionUnit != 0)
+ {
+ UInt32 cuSize = GetCuSize();
+ _inBuf.SetCapacity(cuSize);
+ _chunkSizeLog = BlockSizeLog + CompressionUnit;
+ _outBuf.SetCapacity(kNumCacheChunks << _chunkSizeLog);
+ }
+ for (int i = 0; i < kNumCacheChunks; i++)
+ _tags[i] = kEmptyTag;
+
+ _sparseMode = false;
+ _curRem = 0;
+ _virtPos = 0;
+ _physPos = 0;
+ const CExtent &e = Extents[0];
+ if (!e.IsEmpty())
+ _physPos = e.Phy << BlockSizeLog;
+ return SeekToPhys();
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen)
+{
+ size_t destSize = 0;
+ while (destSize < destLen)
+ {
+ if (srcLen < 2 || (destSize & 0xFFF) != 0)
+ break;
+ UInt32 v = Get16(src);
+ if (v == 0)
+ break;
+ src += 2;
+ srcLen -= 2;
+ UInt32 comprSize = (v & 0xFFF) + 1;
+ if (comprSize > srcLen)
+ break;
+ srcLen -= comprSize;
+ if ((v & 0x8000) == 0)
+ {
+ if (comprSize != (1 << 12))
+ break;
+ memcpy(dest + destSize, src, comprSize);
+ src += comprSize;
+ destSize += comprSize;
+ }
+ else
+ {
+ if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0)
+ return 0;
+ int numDistBits = 4;
+ UInt32 sbOffset = 0;
+ UInt32 pos = 0;
+
+ do
+ {
+ comprSize--;
+ for (UInt32 mask = src[pos++] | 0x100; mask > 1 && comprSize > 0; mask >>= 1)
+ {
+ if ((mask & 1) == 0)
+ {
+ if (sbOffset >= (1 << 12))
+ return 0;
+ dest[destSize++] = src[pos++];
+ sbOffset++;
+ comprSize--;
+ }
+ else
+ {
+ if (comprSize < 2)
+ return 0;
+ UInt32 v = Get16(src + pos);
+ pos += 2;
+ comprSize -= 2;
+
+ while (((sbOffset - 1) >> numDistBits) != 0)
+ numDistBits++;
+
+ UInt32 len = (v & (0xFFFF >> numDistBits)) + 3;
+ if (sbOffset + len > (1 << 12))
+ return 0;
+ UInt32 dist = (v >> (16 - numDistBits));
+ if (dist >= sbOffset)
+ return 0;
+ Int32 offs = -1 - dist;
+ Byte *p = dest + destSize;
+ for (UInt32 t = 0; t < len; t++)
+ p[t] = p[t + offs];
+ destSize += len;
+ sbOffset += len;
+ }
+ }
+ }
+ while (comprSize > 0);
+ src += pos;
+ }
+ }
+ return destSize;
+}
+
+STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return (Size == _virtPos) ? S_OK: E_FAIL;
+ if (size == 0)
+ return S_OK;
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (_virtPos >= InitializedSize)
+ {
+ memset((Byte *)data, 0, size);
+ _virtPos += size;
+ *processedSize = size;
+ return S_OK;
+ }
+ rem = InitializedSize - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+
+ while (_curRem == 0)
+ {
+ UInt64 cacheTag = _virtPos >> _chunkSizeLog;
+ UInt32 cacheIndex = (UInt32)cacheTag & (kNumCacheChunks - 1);
+ if (_tags[cacheIndex] == cacheTag)
+ {
+ UInt32 chunkSize = (UInt32)1 << _chunkSizeLog;
+ UInt32 offset = (UInt32)_virtPos & (chunkSize - 1);
+ UInt32 cur = MyMin(chunkSize - offset, size);
+ memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur);
+ *processedSize = cur;
+ _virtPos += cur;
+ return S_OK;
+ }
+
+ PRF2(printf("\nVirtPos = %6d", _virtPos));
+
+ UInt32 comprUnitSize = (UInt32)1 << CompressionUnit;
+ UInt64 virtBlock = _virtPos >> BlockSizeLog;
+ UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1);
+
+ int left = 0, right = Extents.Size();
+ for (;;)
+ {
+ int mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (virtBlock2 < Extents[mid].Virt)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ bool isCompressed = false;
+ UInt64 virtBlock2End = virtBlock2 + comprUnitSize;
+ if (CompressionUnit != 0)
+ for (int i = left; i < Extents.Size(); i++)
+ {
+ const CExtent &e = Extents[i];
+ if (e.Virt >= virtBlock2End)
+ break;
+ if (e.IsEmpty())
+ {
+ isCompressed = true;
+ break;
+ }
+ }
+
+ int i;
+ for (i = left; Extents[i + 1].Virt <= virtBlock; i++);
+
+ _sparseMode = false;
+ if (!isCompressed)
+ {
+ const CExtent &e = Extents[i];
+ UInt64 newPos = (e.Phy << BlockSizeLog) + _virtPos - (e.Virt << BlockSizeLog);
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+ UInt64 next = Extents[i + 1].Virt;
+ if (next > virtBlock2End)
+ next &= ~((UInt64)comprUnitSize - 1);
+ next <<= BlockSizeLog;
+ if (next > Size)
+ next = Size;
+ _curRem = next - _virtPos;
+ break;
+ }
+ bool thereArePhy = false;
+ for (int i2 = left; i2 < Extents.Size(); i2++)
+ {
+ const CExtent &e = Extents[i2];
+ if (e.Virt >= virtBlock2End)
+ break;
+ if (!e.IsEmpty())
+ {
+ thereArePhy = true;
+ break;
+ }
+ }
+ if (!thereArePhy)
+ {
+ _curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos;
+ _sparseMode = true;
+ break;
+ }
+
+ size_t offs = 0;
+ UInt64 curVirt = virtBlock2;
+ for (i = left; i < Extents.Size(); i++)
+ {
+ const CExtent &e = Extents[i];
+ if (e.IsEmpty())
+ break;
+ if (e.Virt >= virtBlock2End)
+ return S_FALSE;
+ UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+ UInt64 numChunks = Extents[i + 1].Virt - curVirt;
+ if (curVirt + numChunks > virtBlock2End)
+ numChunks = virtBlock2End - curVirt;
+ size_t compressed = (size_t)numChunks << BlockSizeLog;
+ RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed));
+ curVirt += numChunks;
+ _physPos += compressed;
+ offs += compressed;
+ }
+ size_t destLenMax = GetCuSize();
+ size_t destLen = destLenMax;
+ UInt64 rem = Size - (virtBlock2 << BlockSizeLog);
+ if (destLen > rem)
+ destLen = (size_t)rem;
+
+ Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog);
+ size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs);
+ _tags[cacheIndex] = cacheTag;
+
+ // some files in Vista have destSize > destLen
+ if (destSizeRes < destLen)
+ {
+ memset(dest, 0, destLenMax);
+ if (InUse)
+ return S_FALSE;
+ }
+ }
+ if (size > _curRem)
+ size = (UInt32)_curRem;
+ HRESULT res = S_OK;
+ if (_sparseMode)
+ memset(data, 0, size);
+ else
+ {
+ res = Stream->Read(data, size, &size);
+ _physPos += size;
+ }
+ if (processedSize != NULL)
+ *processedSize = size;
+ _virtPos += size;
+ _curRem -= size;
+ return res;
+}
+
+STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ UInt64 newVirtPos = offset;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: newVirtPos += _virtPos; break;
+ case STREAM_SEEK_END: newVirtPos += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (_virtPos != newVirtPos)
+ _curRem = 0;
+ _virtPos = newVirtPos;
+ if (newPosition)
+ *newPosition = newVirtPos;
+ return S_OK;
+}
+
+class CByteBufStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+public:
+ CByteBuffer Buf;
+ void Init() { _virtPos = 0; }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= Buf.GetCapacity())
+ return (_virtPos == Buf.GetCapacity()) ? S_OK: E_FAIL;
+ UInt64 rem = Buf.GetCapacity() - _virtPos;
+ if (rem < size)
+ size = (UInt32)rem;
+ memcpy(data, Buf + (size_t)_virtPos, size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ _virtPos += size;
+ return S_OK;
+}
+
+STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = Buf.GetCapacity() + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> &attrs,
+ int attrIndex, int attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents)
+{
+ CExtent e;
+ e.Virt = 0;
+ e.Phy = kEmptyExtent;
+ Extents.Add(e);
+ const CAttr &attr0 = attrs[attrIndex];
+
+ if (attr0.AllocatedSize < attr0.Size ||
+ (attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) ||
+ (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0)
+ return S_FALSE;
+
+ for (int i = attrIndex; i < attrIndexLim; i++)
+ if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit))
+ return S_FALSE;
+
+ UInt64 packSizeCalc = 0;
+ for (int k = 0; k < Extents.Size(); k++)
+ {
+ CExtent &e = Extents[k];
+ if (!e.IsEmpty())
+ packSizeCalc += (Extents[k + 1].Virt - e.Virt) << clusterSizeLog;
+ PRF2(printf("\nSize = %4I64X", Extents[k + 1].Virt - e.Virt));
+ PRF2(printf(" Pos = %4I64X", e.Phy));
+ }
+
+ if (attr0.CompressionUnit != 0)
+ {
+ if (packSizeCalc != attr0.PackSize)
+ return S_FALSE;
+ }
+ else
+ {
+ if (packSizeCalc != attr0.AllocatedSize)
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+struct CDataRef
+{
+ int Start;
+ int Num;
+};
+
+static const UInt32 kMagic_FILE = 0x454c4946;
+static const UInt32 kMagic_BAAD = 0x44414142;
+
+struct CMftRec
+{
+ UInt32 Magic;
+ // UInt64 Lsn;
+ UInt16 SeqNumber;
+ UInt16 Flags;
+ // UInt16 LinkCount;
+ // UInt16 NextAttrInstance;
+ CMftRef BaseMftRef;
+ // UInt32 ThisRecNumber;
+ UInt32 MyNumNameLinks;
+
+ CObjectVector<CAttr> DataAttrs;
+ CObjectVector<CFileNameAttr> FileNames;
+ CRecordVector<CDataRef> DataRefs;
+
+ CSiAttr SiAttr;
+
+ void MoveAttrsFrom(CMftRec &src)
+ {
+ DataAttrs += src.DataAttrs;
+ FileNames += src.FileNames;
+ src.DataAttrs.ClearAndFree();
+ src.FileNames.ClearAndFree();
+ }
+
+ UInt64 GetPackSize() const
+ {
+ UInt64 res = 0;
+ for (int i = 0; i < DataRefs.Size(); i++)
+ res += DataAttrs[DataRefs[i].Start].GetPackSize();
+ return res;
+ }
+
+ bool Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs);
+
+ bool IsEmpty() const { return (Magic <= 2); }
+ bool IsFILE() const { return (Magic == kMagic_FILE); }
+ bool IsBAAD() const { return (Magic == kMagic_BAAD); }
+
+ bool InUse() const { return (Flags & 1) != 0; }
+ bool IsDir() const { return (Flags & 2) != 0; }
+
+ void ParseDataNames();
+ HRESULT GetStream(IInStream *mainStream, int dataIndex,
+ int clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const;
+ int GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const;
+
+ UInt64 GetSize(int dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); }
+
+ CMftRec(): MyNumNameLinks(0) {}
+};
+
+void CMftRec::ParseDataNames()
+{
+ DataRefs.Clear();
+ DataAttrs.Sort(CompareAttr, 0);
+
+ for (int i = 0; i < DataAttrs.Size();)
+ {
+ CDataRef ref;
+ ref.Start = i;
+ for (i++; i < DataAttrs.Size(); i++)
+ if (DataAttrs[ref.Start].Name != DataAttrs[i].Name)
+ break;
+ ref.Num = i - ref.Start;
+ DataRefs.Add(ref);
+ }
+}
+
+HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
+ int clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const
+{
+ *destStream = 0;
+ CByteBufStream *streamSpec = new CByteBufStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+
+ if (dataIndex < 0)
+ return E_FAIL;
+
+ if (dataIndex < DataRefs.Size())
+ {
+ const CDataRef &ref = DataRefs[dataIndex];
+ int numNonResident = 0;
+ int i;
+ for (i = ref.Start; i < ref.Start + ref.Num; i++)
+ if (DataAttrs[i].NonResident)
+ numNonResident++;
+
+ const CAttr &attr0 = DataAttrs[ref.Start];
+
+ if (numNonResident != 0 || ref.Num != 1)
+ {
+ if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
+ return S_FALSE;
+ CInStream *streamSpec = new CInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ RINOK(DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, streamSpec->Extents));
+ streamSpec->Size = attr0.Size;
+ streamSpec->InitializedSize = attr0.InitializedSize;
+ streamSpec->Stream = mainStream;
+ streamSpec->BlockSizeLog = clusterSizeLog;
+ streamSpec->InUse = InUse();
+ RINOK(streamSpec->InitAndSeek(attr0.CompressionUnit));
+ *destStream = streamTemp.Detach();
+ return S_OK;
+ }
+ streamSpec->Buf = attr0.Data;
+ }
+ streamSpec->Init();
+ *destStream = streamTemp.Detach();
+ return S_OK;
+}
+
+int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const
+{
+ if (dataIndex < 0)
+ return 0;
+ {
+ const CDataRef &ref = DataRefs[dataIndex];
+ int numNonResident = 0;
+ int i;
+ for (i = ref.Start; i < ref.Start + ref.Num; i++)
+ if (DataAttrs[i].NonResident)
+ numNonResident++;
+
+ const CAttr &attr0 = DataAttrs[ref.Start];
+
+ if (numNonResident != 0 || ref.Num != 1)
+ {
+ if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
+ return 0; // error;
+ CRecordVector<CExtent> extents;
+ if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK)
+ return 0; // error;
+ return extents.Size() - 1;
+ }
+ // if (attr0.Data.GetCapacity() != 0)
+ // return 1;
+ return 0;
+ }
+}
+
+bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber,
+ CObjectVector<CAttr> *attrs)
+{
+ G32(p, Magic);
+ if (!IsFILE())
+ return IsEmpty() || IsBAAD();
+
+ UInt32 usaOffset;
+ UInt32 numUsaItems;
+ G16(p + 0x04, usaOffset);
+ G16(p + 0x06, numUsaItems);
+
+ if ((usaOffset & 1) != 0 || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2 ||
+ numUsaItems == 0 || numUsaItems - 1 != numSectors)
+ return false;
+
+ UInt16 usn = Get16(p + usaOffset);
+ // PRF(printf("\nusn = %d", usn));
+ for (UInt32 i = 1; i < numUsaItems; i++)
+ {
+ void *pp = p + (i << sectorSizeLog) - 2;
+ if (Get16(pp) != usn)
+ return false;
+ SetUi16(pp, Get16(p + usaOffset + i * 2));
+ }
+
+ // G64(p + 0x08, Lsn);
+ G16(p + 0x10, SeqNumber);
+ // G16(p + 0x12, LinkCount);
+ // PRF(printf(" L=%d", LinkCount));
+ UInt32 attrOffs = Get16(p + 0x14);
+ G16(p + 0x16, Flags);
+ PRF(printf(" F=%4X", Flags));
+
+ UInt32 bytesInUse = Get32(p + 0x18);
+ UInt32 bytesAlloc = Get32(p + 0x1C);
+ G64(p + 0x20, BaseMftRef.Val);
+ if (BaseMftRef.Val != 0)
+ {
+ PRF(printf(" BaseRef=%d", (int)BaseMftRef.Val));
+ // return false; // Check it;
+ }
+ // G16(p + 0x28, NextAttrInstance);
+ if (usaOffset >= 0x30)
+ if (Get32(p + 0x2C) != recNumber) // NTFS 3.1+
+ return false;
+
+ UInt32 limit = numSectors << sectorSizeLog;
+ if (attrOffs >= limit || (attrOffs & 7) != 0 || bytesInUse > limit
+ || bytesAlloc != limit)
+ return false;
+
+
+ for (UInt32 t = attrOffs; t < limit;)
+ {
+ CAttr attr;
+ // PRF(printf("\n %2d:", Attrs.Size()));
+ PRF(printf("\n"));
+ UInt32 length = attr.Parse(p + t, limit - t);
+ if (length == 0 || limit - t < length)
+ return false;
+ t += length;
+ if (attr.Type == 0xFFFFFFFF)
+ break;
+ switch(attr.Type)
+ {
+ case ATTR_TYPE_FILE_NAME:
+ {
+ CFileNameAttr fna;
+ if (!attr.ParseFileName(fna))
+ return false;
+ FileNames.Add(fna);
+ PRF(printf(" flags = %4x", (int)fna.NameType));
+ PRF(printf("\n %S", fna.Name));
+ break;
+ }
+ case ATTR_TYPE_STANDARD_INFO:
+ if (!attr.ParseSi(SiAttr))
+ return false;
+ break;
+ case ATTR_TYPE_DATA:
+ DataAttrs.Add(attr);
+ break;
+ default:
+ if (attrs)
+ attrs->Add(attr);
+ break;
+ }
+ }
+
+ return true;
+}
+
+struct CItem
+{
+ int RecIndex;
+ int DataIndex;
+ CMftRef ParentRef;
+ UString Name;
+ UInt32 Attrib;
+
+ bool IsDir() const { return (DataIndex < 0); }
+};
+
+struct CDatabase
+{
+ CHeader Header;
+ CObjectVector<CItem> Items;
+ CObjectVector<CMftRec> Recs;
+ CMyComPtr<IInStream> InStream;
+ IArchiveOpenCallback *OpenCallback;
+
+ CByteBuffer ByteBuf;
+
+ CObjectVector<CAttr> VolAttrs;
+
+ ~CDatabase() { ClearAndClose(); }
+
+ void Clear();
+ void ClearAndClose();
+
+ UString GetItemPath(Int32 index) const;
+ HRESULT Open();
+ HRESULT ReadDir(Int32 parent, UInt32 cluster, int level);
+
+ HRESULT SeekToCluster(UInt64 cluster);
+
+ int FindMtfRec(const CMftRef &ref) const
+ {
+ UInt64 val = ref.GetIndex();
+ int left = 0, right = Items.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ UInt64 midValue = Items[mid].RecIndex;
+ if (val == midValue)
+ return mid;
+ if (val < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+};
+
+HRESULT CDatabase::SeekToCluster(UInt64 cluster)
+{
+ return InStream->Seek(cluster << Header.ClusterSizeLog, STREAM_SEEK_SET, NULL);
+}
+
+void CDatabase::Clear()
+{
+ Items.Clear();
+ Recs.Clear();
+}
+
+void CDatabase::ClearAndClose()
+{
+ Clear();
+ InStream.Release();
+}
+
+#define MY_DIR_PREFIX(x) L"[" x L"]" WSTRING_PATH_SEPARATOR
+
+UString CDatabase::GetItemPath(Int32 index) const
+{
+ const CItem *item = &Items[index];
+ UString name = item->Name;
+ for (int j = 0; j < 256; j++)
+ {
+ CMftRef ref = item->ParentRef;
+ index = FindMtfRec(ref);
+ if (ref.GetIndex() == 5)
+ return name;
+ if (index < 0 || Recs[Items[index].RecIndex].SeqNumber != ref.GetNumber())
+ return MY_DIR_PREFIX(L"UNKNOWN") + name;
+ item = &Items[index];
+ name = item->Name + WCHAR_PATH_SEPARATOR + name;
+ }
+ return MY_DIR_PREFIX(L"BAD") + name;
+}
+
+HRESULT CDatabase::Open()
+{
+ Clear();
+
+ static const UInt32 kHeaderSize = 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
+ if (!Header.Parse(buf))
+ return S_FALSE;
+ UInt64 fileSize;
+ RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize));
+ if (fileSize < Header.GetPhySize())
+ return S_FALSE;
+
+ SeekToCluster(Header.MftCluster);
+
+ CMftRec mftRec;
+ UInt32 numSectorsInRec;
+ int recSizeLog;
+ CMyComPtr<IInStream> mftStream;
+ {
+ UInt32 blockSize = 1 << 12;
+ ByteBuf.SetCapacity(blockSize);
+ RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize));
+
+ UInt32 allocSize = Get32(ByteBuf + 0x1C);
+ recSizeLog = GetLog(allocSize);
+ if (recSizeLog < Header.SectorSizeLog)
+ return false;
+ numSectorsInRec = 1 << (recSizeLog - Header.SectorSizeLog);
+ if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, NULL, 0))
+ return S_FALSE;
+ if (!mftRec.IsFILE())
+ return S_FALSE;
+ mftRec.ParseDataNames();
+ if (mftRec.DataRefs.IsEmpty())
+ return S_FALSE;
+ RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream));
+ if (!mftStream)
+ return S_FALSE;
+ }
+
+ UInt64 mftSize = mftRec.DataAttrs[0].Size;
+ if ((mftSize >> 4) > Header.GetPhySize())
+ return S_FALSE;
+
+ UInt64 numFiles = mftSize >> recSizeLog;
+ if (numFiles > (1 << 30))
+ return S_FALSE;
+ if (OpenCallback)
+ {
+ RINOK(OpenCallback->SetTotal(&numFiles, &mftSize));
+ }
+ const UInt32 kBufSize = (1 << 15);
+ if (kBufSize < (1 << recSizeLog))
+ return S_FALSE;
+
+ ByteBuf.SetCapacity((size_t)kBufSize);
+ Recs.Reserve((int)numFiles);
+ for (UInt64 pos64 = 0;;)
+ {
+ if (OpenCallback)
+ {
+ UInt64 numFiles = Recs.Size();
+ if ((numFiles & 0x3FF) == 0)
+ {
+ RINOK(OpenCallback->SetCompleted(&numFiles, &pos64));
+ }
+ }
+ UInt32 readSize = kBufSize;
+ UInt64 rem = mftSize - pos64;
+ if (readSize > rem)
+ readSize = (UInt32)rem;
+ if (readSize < ((UInt32)1 << recSizeLog))
+ break;
+ RINOK(ReadStream_FALSE(mftStream, ByteBuf, (size_t)readSize));
+ pos64 += readSize;
+ for (int i = 0; ((UInt32)(i + 1) << recSizeLog) <= readSize; i++)
+ {
+ PRF(printf("\n---------------------"));
+ PRF(printf("\n%5d:", Recs.Size()));
+ Byte *p = ByteBuf + ((UInt32)i << recSizeLog);
+ CMftRec rec;
+ if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(),
+ (Recs.Size() == kRecIndex_Volume) ? &VolAttrs: NULL))
+ return S_FALSE;
+ Recs.Add(rec);
+ }
+ }
+
+ int i;
+ for (i = 0; i < Recs.Size(); i++)
+ {
+ CMftRec &rec = Recs[i];
+ if (!rec.BaseMftRef.IsBaseItself())
+ {
+ UInt64 refIndex = rec.BaseMftRef.GetIndex();
+ if (refIndex > (UInt32)Recs.Size())
+ return S_FALSE;
+ CMftRec &refRec = Recs[(int)refIndex];
+ bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself());
+ if (rec.InUse() && refRec.InUse())
+ {
+ if (!moveAttrs)
+ return S_FALSE;
+ }
+ else if (rec.InUse() || refRec.InUse())
+ moveAttrs = false;
+ if (moveAttrs)
+ refRec.MoveAttrsFrom(rec);
+ }
+ }
+
+ for (i = 0; i < Recs.Size(); i++)
+ Recs[i].ParseDataNames();
+
+ for (i = 0; i < Recs.Size(); i++)
+ {
+ CMftRec &rec = Recs[i];
+ if (!rec.IsFILE() || !rec.BaseMftRef.IsBaseItself())
+ continue;
+ int numNames = 0;
+ // printf("\n%4d: ", i);
+ for (int t = 0; t < rec.FileNames.Size(); t++)
+ {
+ const CFileNameAttr &fna = rec.FileNames[t];
+ // printf("%4d %S | ", (int)fna.NameType, fna.Name);
+ if (fna.IsDos())
+ continue;
+ int numDatas = rec.DataRefs.Size();
+
+ // For hard linked files we show substreams only for first Name.
+ if (numDatas > 1 && numNames > 0)
+ numDatas = 1;
+ numNames++;
+
+ if (rec.IsDir())
+ {
+ CItem item;
+ item.Name = fna.Name;
+ item.RecIndex = i;
+ item.DataIndex = -1;
+ item.ParentRef = fna.ParentDirRef;
+ item.Attrib = rec.SiAttr.Attrib | 0x10;
+ // item.Attrib = fna.Attrib;
+ Items.Add(item);
+ }
+ for (int di = 0; di < numDatas; di++)
+ {
+ CItem item;
+ item.Name = fna.Name;
+ item.Attrib = rec.SiAttr.Attrib;
+ const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
+ if (!subName.IsEmpty())
+ {
+ // $BadClus:$Bad is sparse file for all clusters. So we skip it.
+ if (i == kRecIndex_BadClus && subName == L"$Bad")
+ continue;
+ item.Name += L":";
+ item.Name += subName;
+ item.Attrib = fna.Attrib;
+ }
+
+ PRF(printf("\n%3d", i));
+ PRF(printf(" attrib=%2x", rec.SiAttr.Attrib));
+ PRF(printf(" %S", item.Name));
+
+ item.RecIndex = i;
+ item.DataIndex = di;
+ item.ParentRef = fna.ParentDirRef;
+
+ Items.Add(item);
+ rec.MyNumNameLinks++;
+ }
+ }
+ rec.FileNames.ClearAndFree();
+ }
+
+ return S_OK;
+}
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ CDatabase
+{
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ IInStream *stream2;
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+ HRESULT res = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &stream2);
+ *stream = (ISequentialInStream *)stream2;
+ return res;
+ COM_TRY_END
+}
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidLinks, VT_UI4},
+ { NULL, kpidNumBlocks, VT_UI4}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidVolumeName, VT_BSTR},
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+
+ { NULL, kpidSectorSize, VT_UI4},
+ { NULL, kpidId, VT_UI8}
+ // { NULL, kpidSectorsPerTrack, VT_UI4},
+ // { NULL, kpidNumHeads, VT_UI4},
+ // { NULL, kpidHiddenSectors, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void NtfsTimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)t;
+ ft.dwHighDateTime = (DWORD)(t >> 32);
+ prop = ft;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL);
+
+ switch(propID)
+ {
+ case kpidClusterSize: prop = Header.ClusterSize(); break;
+ case kpidPhySize: prop = Header.GetPhySize(); break;
+ /*
+ case kpidHeadersSize:
+ {
+ UInt64 val = 0;
+ for (int i = 0; i < kNumSysRecs; i++)
+ {
+ printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize());
+ if (i == 8)
+ i = i
+ val += Recs[i].GetPackSize();
+ }
+ prop = val;
+ break;
+ }
+ */
+ case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break;break;
+ case kpidVolumeName:
+ {
+ for (int i = 0; i < VolAttrs.Size(); i++)
+ {
+ const CAttr &attr = VolAttrs[i];
+ if (attr.Type == ATTR_TYPE_VOLUME_NAME)
+ {
+ UString name;
+ GetString(attr.Data, (int)attr.Data.GetCapacity() / 2, name);
+ prop = name;
+ break;
+ }
+ }
+ break;
+ }
+ case kpidFileSystem:
+ {
+ AString s = "NTFS";
+ for (int i = 0; i < VolAttrs.Size(); i++)
+ {
+ const CAttr &attr = VolAttrs[i];
+ if (attr.Type == ATTR_TYPE_VOLUME_INFO)
+ {
+ CVolInfo vi;
+ if (attr.ParseVolInfo(vi))
+ {
+ s += ' ';
+ char temp[16];
+ ConvertUInt32ToString(vi.MajorVer, temp);
+ s += temp;
+ s += '.';
+ ConvertUInt32ToString(vi.MinorVer, temp);
+ s += temp;
+ }
+ break;
+ }
+ }
+ prop = s;
+ break;
+ }
+ case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
+ case kpidId: prop = Header.SerialNumber; break;
+ // case kpidMediaType: prop = Header.MediaType; break;
+ // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
+ // case kpidNumHeads: prop = Header.NumHeads; break;
+ // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+
+ const CAttr *data= NULL;
+ if (item.DataIndex >= 0)
+ data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString name = GetItemPath(index);
+ const wchar_t *prefix = NULL;
+ if (!rec.InUse())
+ prefix = MY_DIR_PREFIX(L"DELETED");
+ else if (item.RecIndex < kNumSysRecs)
+ prefix = MY_DIR_PREFIX(L"SYSTEM");
+ if (prefix)
+ name = prefix + name;
+ prop = name;
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break;
+
+ case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break;
+ case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break;
+ case kpidAttrib:
+ prop = item.Attrib;
+ break;
+ case kpidLinks: prop = rec.MyNumNameLinks; break;
+ case kpidSize: if (data) prop = data->GetSize(); break;
+ case kpidPackSize: if (data) prop = data->GetPackSize(); break;
+ case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ OpenCallback = callback;
+ InStream = stream;
+ HRESULT res;
+ try
+ {
+ res = CDatabase::Open();
+ if (res == S_OK)
+ return S_OK;
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ Close();
+ return res;
+ }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ ClearAndClose();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = Items[allFilesMode ? i : indices[i]];
+ const CMftRec &rec = Recs[item.RecIndex];
+ if (!rec.IsDir())
+ totalSize += rec.GetSize(item.DataIndex);
+ }
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ CByteBuffer buf;
+ UInt32 clusterSize = Header.ClusterSize();
+ buf.SetCapacity(clusterSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ const CItem &item = Items[index];
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init();
+
+ const CMftRec &rec = Recs[item.RecIndex];
+ const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<IInStream> inStream;
+ HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream);
+ if (hres == S_FALSE)
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres != S_OK && hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ if (/* copyCoderSpec->TotalSize == item.GetSize() && */ hres == S_OK)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ }
+ totalPackSize += data.GetPackSize();
+ totalSize += data.GetSize();
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = Items.Size();
+ return S_OK;
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"NTFS", L"ntfs img", 0, 0xD9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }, 9, false, CreateArc, 0 };
+
+REGISTER_ARC(Fat)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp
new file mode 100644
index 000000000..c64067aa5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/PeHandler.cpp
@@ -0,0 +1,1752 @@
+// PeHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/DynamicBuffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariantUtils.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NPe {
+
+#define NUM_SCAN_SECTIONS_MAX (1 << 6)
+
+#define PE_SIG 0x00004550
+#define PE_OptHeader_Magic_32 0x10B
+#define PE_OptHeader_Magic_64 0x20B
+
+static AString GetDecString(UInt32 v)
+{
+ char sz[32];
+ ConvertUInt64ToString(v, sz);
+ return sz;
+}
+
+struct CVersion
+{
+ UInt16 Major;
+ UInt16 Minor;
+
+ void Parse(const Byte *buf);
+ AString GetString() const { return GetDecString(Major) + '.' + GetDecString(Minor); }
+};
+
+void CVersion::Parse(const Byte *p)
+{
+ Major = Get16(p);
+ Minor = Get16(p + 2);
+}
+
+static const UInt32 kHeaderSize = 4 + 20;
+
+struct CHeader
+{
+ UInt16 NumSections;
+ UInt32 Time;
+ UInt32 PointerToSymbolTable;
+ UInt32 NumSymbols;
+ UInt16 OptHeaderSize;
+ UInt16 Flags;
+ UInt16 Machine;
+
+ bool Parse(const Byte *buf);
+};
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (Get32(p) != PE_SIG)
+ return false;
+ p += 4;
+ Machine = Get16(p + 0);
+ NumSections = Get16(p + 2);
+ Time = Get32(p + 4);
+ PointerToSymbolTable = Get32(p + 8);
+ NumSymbols = Get32(p + 12);
+ OptHeaderSize = Get16(p + 16);
+ Flags = Get16(p + 18);
+ return true;
+}
+
+struct CDirLink
+{
+ UInt32 Va;
+ UInt32 Size;
+ void Parse(const Byte *p);
+};
+
+void CDirLink::Parse(const Byte *p)
+{
+ Va = Get32(p);
+ Size = Get32(p + 4);
+}
+
+enum
+{
+ kDirLink_Certificate = 4,
+ kDirLink_Debug = 6
+};
+
+struct CDebugEntry
+{
+ UInt32 Flags;
+ UInt32 Time;
+ CVersion Ver;
+ UInt32 Type;
+ UInt32 Size;
+ UInt32 Va;
+ UInt32 Pa;
+
+ void Parse(const Byte *p);
+};
+
+void CDebugEntry::Parse(const Byte *p)
+{
+ Flags = Get32(p);
+ Time = Get32(p + 4);
+ Ver.Parse(p + 8);
+ Type = Get32(p + 12);
+ Size = Get32(p + 16);
+ Va = Get32(p + 20);
+ Pa = Get32(p + 24);
+}
+
+static const UInt32 kNumDirItemsMax = 16;
+
+struct COptHeader
+{
+ UInt16 Magic;
+ Byte LinkerVerMajor;
+ Byte LinkerVerMinor;
+
+ UInt32 CodeSize;
+ UInt32 InitDataSize;
+ UInt32 UninitDataSize;
+
+ // UInt32 AddressOfEntryPoint;
+ // UInt32 BaseOfCode;
+ // UInt32 BaseOfData32;
+ UInt64 ImageBase;
+
+ UInt32 SectAlign;
+ UInt32 FileAlign;
+
+ CVersion OsVer;
+ CVersion ImageVer;
+ CVersion SubsysVer;
+
+ UInt32 ImageSize;
+ UInt32 HeadersSize;
+ UInt32 CheckSum;
+ UInt16 SubSystem;
+ UInt16 DllCharacts;
+
+ UInt64 StackReserve;
+ UInt64 StackCommit;
+ UInt64 HeapReserve;
+ UInt64 HeapCommit;
+
+ UInt32 NumDirItems;
+ CDirLink DirItems[kNumDirItemsMax];
+
+ bool Is64Bit() const { return Magic == PE_OptHeader_Magic_64; }
+ bool Parse(const Byte *p, UInt32 size);
+
+ int GetNumFileAlignBits() const
+ {
+ for (int i = 9; i <= 16; i++)
+ if (((UInt32)1 << i) == FileAlign)
+ return i;
+ return -1;
+ }
+};
+
+bool COptHeader::Parse(const Byte *p, UInt32 size)
+{
+ Magic = Get16(p);
+ switch (Magic)
+ {
+ case PE_OptHeader_Magic_32:
+ case PE_OptHeader_Magic_64:
+ break;
+ default:
+ return false;
+ }
+ LinkerVerMajor = p[2];
+ LinkerVerMinor = p[3];
+
+ bool hdr64 = Is64Bit();
+
+ CodeSize = Get32(p + 4);
+ InitDataSize = Get32(p + 8);
+ UninitDataSize = Get32(p + 12);
+
+ // AddressOfEntryPoint = Get32(p + 16);
+ // BaseOfCode = Get32(p + 20);
+ // BaseOfData32 = hdr64 ? 0: Get32(p + 24);
+ ImageBase = hdr64 ? GetUi64(p + 24) : Get32(p + 28);
+
+ SectAlign = Get32(p + 32);
+ FileAlign = Get32(p + 36);
+
+ OsVer.Parse(p + 40);
+ ImageVer.Parse(p + 44);
+ SubsysVer.Parse(p + 48);
+
+ // reserved = Get32(p + 52);
+
+ ImageSize = Get32(p + 56);
+ HeadersSize = Get32(p + 60);
+ CheckSum = Get32(p + 64);
+ SubSystem = Get16(p + 68);
+ DllCharacts = Get16(p + 70);
+
+ if (hdr64)
+ {
+ StackReserve = Get64(p + 72);
+ StackCommit = Get64(p + 80);
+ HeapReserve = Get64(p + 88);
+ HeapCommit = Get64(p + 96);
+ }
+ else
+ {
+ StackReserve = Get32(p + 72);
+ StackCommit = Get32(p + 76);
+ HeapReserve = Get32(p + 80);
+ HeapCommit = Get32(p + 84);
+ }
+ UInt32 pos = (hdr64 ? 108 : 92);
+ NumDirItems = Get32(p + pos);
+ pos += 4;
+ if (pos + 8 * NumDirItems != size)
+ return false;
+ for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++)
+ DirItems[i].Parse(p + pos + i * 8);
+ return true;
+}
+
+static const UInt32 kSectionSize = 40;
+
+struct CSection
+{
+ AString Name;
+
+ UInt32 VSize;
+ UInt32 Va;
+ UInt32 PSize;
+ UInt32 Pa;
+ UInt32 Flags;
+ UInt32 Time;
+ // UInt16 NumRelocs;
+ bool IsDebug;
+ bool IsRealSect;
+ bool IsAdditionalSection;
+
+ CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {}
+ UInt64 GetPackSize() const { return PSize; }
+
+ void UpdateTotalSize(UInt32 &totalSize)
+ {
+ UInt32 t = Pa + PSize;
+ if (t > totalSize)
+ totalSize = t;
+ }
+ void Parse(const Byte *p);
+};
+
+static bool operator <(const CSection &a1, const CSection &a2) { return (a1.Pa < a2.Pa) || ((a1.Pa == a2.Pa) && (a1.PSize < a2.PSize)) ; }
+static bool operator ==(const CSection &a1, const CSection &a2) { return (a1.Pa == a2.Pa) && (a1.PSize == a2.PSize); }
+
+static AString GetName(const Byte *name)
+{
+ const int kNameSize = 8;
+ AString res;
+ char *p = res.GetBuffer(kNameSize);
+ memcpy(p, name, kNameSize);
+ p[kNameSize] = 0;
+ res.ReleaseBuffer();
+ return res;
+}
+
+void CSection::Parse(const Byte *p)
+{
+ Name = GetName(p);
+ VSize = Get32(p + 8);
+ Va = Get32(p + 12);
+ PSize = Get32(p + 16);
+ Pa = Get32(p + 20);
+ // NumRelocs = Get16(p + 32);
+ Flags = Get32(p + 36);
+}
+
+static const CUInt32PCharPair g_HeaderCharacts[] =
+{
+ { 1, "Executable" },
+ { 13, "DLL" },
+ { 8, "32-bit" },
+ { 5, "LargeAddress" },
+ { 0, "NoRelocs" },
+ { 2, "NoLineNums" },
+ { 3, "NoLocalSyms" },
+ { 4, "AggressiveWsTrim" },
+ { 9, "NoDebugInfo" },
+ { 10, "RemovableRun" },
+ { 11, "NetRun" },
+ { 12, "System" },
+ { 14, "UniCPU" },
+ { 7, "Little-Endian" },
+ { 15, "Big-Endian" }
+};
+
+static const CUInt32PCharPair g_DllCharacts[] =
+{
+ { 6, "Relocated" },
+ { 7, "Integrity" },
+ { 8, "NX-Compatible" },
+ { 9, "NoIsolation" },
+ { 10, "NoSEH" },
+ { 11, "NoBind" },
+ { 13, "WDM" },
+ { 15, "TerminalServerAware" }
+};
+
+static const CUInt32PCharPair g_SectFlags[] =
+{
+ { 3, "NoPad" },
+ { 5, "Code" },
+ { 6, "InitializedData" },
+ { 7, "UninitializedData" },
+ { 9, "Comments" },
+ { 11, "Remove" },
+ { 12, "COMDAT" },
+ { 15, "GP" },
+ { 24, "ExtendedRelocations" },
+ { 25, "Discardable" },
+ { 26, "NotCached" },
+ { 27, "NotPaged" },
+ { 28, "Shared" },
+ { 29, "Execute" },
+ { 30, "Read" },
+ { 31, "Write" }
+};
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { 0x014C, "x86" },
+ { 0x0162, "MIPS-R3000" },
+ { 0x0166, "MIPS-R4000" },
+ { 0x0168, "MIPS-R10000" },
+ { 0x0169, "MIPS-V2" },
+ { 0x0184, "Alpha" },
+ { 0x01A2, "SH3" },
+ { 0x01A3, "SH3-DSP" },
+ { 0x01A4, "SH3E" },
+ { 0x01A6, "SH4" },
+ { 0x01A8, "SH5" },
+ { 0x01C0, "ARM" },
+ { 0x01C2, "ARM-Thumb" },
+ { 0x01F0, "PPC" },
+ { 0x01F1, "PPC-FP" },
+ { 0x0200, "IA-64" },
+ { 0x0284, "Alpha-64" },
+ { 0x0200, "IA-64" },
+ { 0x0366, "MIPSFPU" },
+ { 0x8664, "x64" },
+ { 0x0EBC, "EFI" }
+};
+
+static const CUInt32PCharPair g_SubSystems[] =
+{
+ { 0, "Unknown" },
+ { 1, "Native" },
+ { 2, "Windows GUI" },
+ { 3, "Windows CUI" },
+ { 7, "Posix" },
+ { 9, "Windows CE" },
+ { 10, "EFI" },
+ { 11, "EFI Boot" },
+ { 12, "EFI Runtime" },
+ { 13, "EFI ROM" },
+ { 14, "XBOX" }
+};
+
+static const wchar_t *g_ResTypes[] =
+{
+ NULL,
+ L"CURSOR",
+ L"BITMAP",
+ L"ICON",
+ L"MENU",
+ L"DIALOG",
+ L"STRING",
+ L"FONTDIR",
+ L"FONT",
+ L"ACCELERATOR",
+ L"RCDATA",
+ L"MESSAGETABLE",
+ L"GROUP_CURSOR",
+ NULL,
+ L"GROUP_ICON",
+ NULL,
+ L"VERSION",
+ L"DLGINCLUDE",
+ NULL,
+ L"PLUGPLAY",
+ L"VXD",
+ L"ANICURSOR",
+ L"ANIICON",
+ L"HTML",
+ L"MANIFEST"
+};
+
+const UInt32 kFlag = (UInt32)1 << 31;
+const UInt32 kMask = ~kFlag;
+
+struct CTableItem
+{
+ UInt32 Offset;
+ UInt32 ID;
+};
+
+
+const UInt32 kBmpHeaderSize = 14;
+const UInt32 kIconHeaderSize = 22;
+
+struct CResItem
+{
+ UInt32 Type;
+ UInt32 ID;
+ UInt32 Lang;
+
+ UInt32 Size;
+ UInt32 Offset;
+
+ UInt32 HeaderSize;
+ Byte Header[kIconHeaderSize]; // it must be enough for max size header.
+ bool Enabled;
+
+ bool IsNameEqual(const CResItem &item) const { return Lang == item.Lang; }
+ UInt32 GetSize() const { return Size + HeaderSize; }
+ bool IsBmp() const { return Type == 2; }
+ bool IsIcon() const { return Type == 3; }
+ bool IsString() const { return Type == 6; }
+ bool IsRcData() const { return Type == 10; }
+ bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; }
+};
+
+struct CStringItem
+{
+ UInt32 Lang;
+ UInt32 Size;
+ CByteDynamicBuffer Buf;
+
+ void AddChar(Byte c);
+ void AddWChar(UInt16 c);
+};
+
+void CStringItem::AddChar(Byte c)
+{
+ Buf.EnsureCapacity(Size + 2);
+ Buf[Size++] = c;
+ Buf[Size++] = 0;
+}
+
+void CStringItem::AddWChar(UInt16 c)
+{
+ if (c == '\n')
+ {
+ AddChar('\\');
+ c = 'n';
+ }
+ Buf.EnsureCapacity(Size + 2);
+ SetUi16(Buf + Size, c);
+ Size += 2;
+}
+
+struct CMixItem
+{
+ int SectionIndex;
+ int ResourceIndex;
+ int StringIndex;
+
+ bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0; };
+};
+
+struct CUsedBitmap
+{
+ CByteBuffer Buf;
+public:
+ void Alloc(size_t size)
+ {
+ size = (size + 7) / 8;
+ Buf.SetCapacity(size);
+ memset(Buf, 0, size);
+ }
+ void Free()
+ {
+ Buf.SetCapacity(0);
+ }
+ bool SetRange(size_t from, int size)
+ {
+ for (int i = 0; i < size; i++)
+ {
+ size_t pos = (from + i) >> 3;
+ Byte mask = (Byte)(1 << ((from + i) & 7));
+ Byte b = Buf[pos];
+ if ((b & mask) != 0)
+ return false;
+ Buf[pos] = b | mask;
+ }
+ return true;
+ }
+};
+
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CSection> _sections;
+ UInt32 _peOffset;
+ CHeader _header;
+ COptHeader _optHeader;
+ UInt32 _totalSize;
+ UInt32 _totalSizeLimited;
+ Int32 _mainSubfile;
+
+ CRecordVector<CResItem> _items;
+ CObjectVector<CStringItem> _strings;
+
+ CByteBuffer _buf;
+ bool _oneLang;
+ UString _resourceFileName;
+ CUsedBitmap _usedRes;
+ bool _parseResources;
+
+ CRecordVector<CMixItem> _mixItems;
+
+ HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ bool Parse(const Byte *buf, UInt32 size);
+
+ void AddResNameToString(UString &s, UInt32 id) const;
+ UString GetLangPrefix(UInt32 lang);
+ HRESULT ReadString(UInt32 offset, UString &dest) const;
+ HRESULT ReadTable(UInt32 offset, CRecordVector<CTableItem> &items);
+ bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size);
+ HRESULT OpenResources(int sectIndex, IInStream *stream, IArchiveOpenCallback *callback);
+ void CloseResources();
+
+
+ bool CheckItem(const CSection &sect, const CResItem &item, size_t offset) const
+ {
+ return item.Offset >= sect.Va && offset <= _buf.GetCapacity() && _buf.GetCapacity() - offset >= item.Size;
+ }
+
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+bool CHandler::Parse(const Byte *buf, UInt32 size)
+{
+ UInt32 i;
+ if (size < 512)
+ return false;
+ _peOffset = Get32(buf + 0x3C);
+ if (_peOffset >= 0x1000 || _peOffset + 512 > size || (_peOffset & 7) != 0)
+ return false;
+
+ UInt32 pos = _peOffset;
+ if (!_header.Parse(buf + pos))
+ return false;
+ if (_header.OptHeaderSize > 512 || _header.NumSections > NUM_SCAN_SECTIONS_MAX)
+ return false;
+ pos += kHeaderSize;
+
+ if (!_optHeader.Parse(buf + pos, _header.OptHeaderSize))
+ return false;
+
+ pos += _header.OptHeaderSize;
+ _totalSize = pos;
+
+ for (i = 0; i < _header.NumSections; i++, pos += kSectionSize)
+ {
+ CSection sect;
+ if (pos + kSectionSize > size)
+ return false;
+ sect.Parse(buf + pos);
+ sect.IsRealSect = true;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ return true;
+}
+
+enum
+{
+ kpidSectAlign = kpidUserDefined,
+ kpidFileAlign,
+ kpidLinkerVer,
+ kpidOsVer,
+ kpidImageVer,
+ kpidSubsysVer,
+ kpidCodeSize,
+ kpidImageSize,
+ kpidInitDataSize,
+ kpidUnInitDataSize,
+ kpidHeadersSizeUnInitDataSize,
+ kpidSubSystem,
+ kpidDllCharacts,
+ kpidStackReserve,
+ kpidStackCommit,
+ kpidHeapReserve,
+ kpidHeapCommit,
+ kpidImageBase
+ // kpidAddressOfEntryPoint,
+ // kpidBaseOfCode,
+ // kpidBaseOfData32,
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCpu, VT_BSTR},
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidPhySize, VT_UI4},
+ { NULL, kpidHeadersSize, VT_UI4},
+ { NULL, kpidChecksum, VT_UI4},
+ { L"Image Size", kpidImageSize, VT_UI4},
+ { L"Section Alignment", kpidSectAlign, VT_UI4},
+ { L"File Alignment", kpidFileAlign, VT_UI4},
+ { L"Code Size", kpidCodeSize, VT_UI4},
+ { L"Initialized Data Size", kpidInitDataSize, VT_UI4},
+ { L"Uninitialized Data Size", kpidUnInitDataSize, VT_UI4},
+ { L"Linker Version", kpidLinkerVer, VT_BSTR},
+ { L"OS Version", kpidOsVer, VT_BSTR},
+ { L"Image Version", kpidImageVer, VT_BSTR},
+ { L"Subsystem Version", kpidSubsysVer, VT_BSTR},
+ { L"Subsystem", kpidSubSystem, VT_BSTR},
+ { L"DLL Characteristics", kpidDllCharacts, VT_BSTR},
+ { L"Stack Reserve", kpidStackReserve, VT_UI8},
+ { L"Stack Commit", kpidStackCommit, VT_UI8},
+ { L"Heap Reserve", kpidHeapReserve, VT_UI8},
+ { L"Heap Commit", kpidHeapCommit, VT_UI8},
+ { L"Image Base", kpidImageBase, VT_UI8}
+ // { L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
+ // { L"Base Of Code", kpidBaseOfCode, VT_UI8},
+ // { L"Base Of Data", kpidBaseOfData32, VT_UI8},
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidVa, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void VerToProp(const CVersion &v, NCOM::CPropVariant &prop)
+{
+ StringToProp(v.GetString(), prop);
+}
+
+void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
+{
+ if (unixTime != 0)
+ {
+ FILETIME ft;
+ NTime::UnixTimeToFileTime(unixTime, ft);
+ prop = ft;
+ }
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSectAlign: prop = _optHeader.SectAlign; break;
+ case kpidFileAlign: prop = _optHeader.FileAlign; break;
+ case kpidLinkerVer:
+ {
+ CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor };
+ VerToProp(v, prop);
+ break;
+ }
+
+ case kpidOsVer: VerToProp(_optHeader.OsVer, prop); break;
+ case kpidImageVer: VerToProp(_optHeader.ImageVer, prop); break;
+ case kpidSubsysVer: VerToProp(_optHeader.SubsysVer, prop); break;
+ case kpidCodeSize: prop = _optHeader.CodeSize; break;
+ case kpidInitDataSize: prop = _optHeader.InitDataSize; break;
+ case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break;
+ case kpidImageSize: prop = _optHeader.ImageSize; break;
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _optHeader.HeadersSize; break;
+ case kpidChecksum: prop = _optHeader.CheckSum; break;
+
+ case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
+ case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break;
+ case kpidSubSystem: PAIR_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;
+
+ case kpidMTime:
+ case kpidCTime: TimeToProp(_header.Time, prop); break;
+ case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
+ case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break;
+ case kpidStackReserve: prop = _optHeader.StackReserve; break;
+ case kpidStackCommit: prop = _optHeader.StackCommit; break;
+ case kpidHeapReserve: prop = _optHeader.HeapReserve; break;
+ case kpidHeapCommit: prop = _optHeader.HeapCommit; break;
+
+ case kpidImageBase: prop = _optHeader.ImageBase; break;
+ // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
+ // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
+ // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break;
+
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::AddResNameToString(UString &s, UInt32 id) const
+{
+ if ((id & kFlag) != 0)
+ {
+ UString name;
+ if (ReadString(id & kMask, name) == S_OK)
+ {
+ if (name.IsEmpty())
+ s += L"[]";
+ else
+ {
+ if (name.Length() > 1 && name[0] == '"' && name.Back() == '"')
+ name = name.Mid(1, name.Length() - 2);
+ s += name;
+ }
+ return;
+ }
+ }
+ wchar_t sz[32];
+ ConvertUInt32ToString(id, sz);
+ s += sz;
+}
+
+UString CHandler::GetLangPrefix(UInt32 lang)
+{
+ UString s = _resourceFileName;
+ s += WCHAR_PATH_SEPARATOR;
+ if (!_oneLang)
+ {
+ AddResNameToString(s, lang);
+ s += WCHAR_PATH_SEPARATOR;
+ }
+ return s;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CMixItem &mixItem = _mixItems[index];
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ switch(propID)
+ {
+ case kpidPath: prop = GetLangPrefix(item.Lang) + L"string.txt"; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size; break;
+ }
+ }
+ else if (mixItem.ResourceIndex < 0)
+ {
+ const CSection &item = _sections[mixItem.SectionIndex];
+ switch(propID)
+ {
+ case kpidPath: StringToProp(item.Name, prop); break;
+ case kpidSize: prop = (UInt64)item.VSize; break;
+ case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
+ case kpidOffset: prop = item.Pa; break;
+ case kpidVa: if (item.IsRealSect) prop = item.Va; break;
+ case kpidMTime:
+ case kpidCTime:
+ TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break;
+ case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break;
+ }
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString s = GetLangPrefix(item.Lang);
+ {
+ const wchar_t *p = NULL;
+ if (item.Type < sizeof(g_ResTypes) / sizeof(g_ResTypes[0]))
+ p = g_ResTypes[item.Type];
+ if (p != 0)
+ s += p;
+ else
+ AddResNameToString(s, item.Type);
+ }
+ s += WCHAR_PATH_SEPARATOR;
+ AddResNameToString(s, item.ID);
+ if (item.HeaderSize != 0)
+ {
+ if (item.IsBmp())
+ s += L".bmp";
+ else if (item.IsIcon())
+ s += L".ico";
+ }
+ prop = s;
+ break;
+ }
+ case kpidSize: prop = (UInt64)item.GetSize(); break;
+ case kpidPackSize: prop = (UInt64)item.Size; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
+{
+ thereIsSection = false;
+ const CDirLink &debugLink = _optHeader.DirItems[kDirLink_Debug];
+ if (debugLink.Size == 0)
+ return S_OK;
+ const unsigned kEntrySize = 28;
+ UInt32 numItems = debugLink.Size / kEntrySize;
+ if (numItems * kEntrySize != debugLink.Size || numItems > 16)
+ return S_FALSE;
+
+ UInt64 pa = 0;
+ int i;
+ for (i = 0; i < _sections.Size(); i++)
+ {
+ const CSection &sect = _sections[i];
+ if (sect.Va < debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize)
+ {
+ pa = sect.Pa + (debugLink.Va - sect.Va);
+ break;
+ }
+ }
+ if (i == _sections.Size())
+ {
+ return S_OK;
+ // Exe for ARM requires S_OK
+ // return S_FALSE;
+ }
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(debugLink.Size);
+ Byte *buf = buffer;
+
+ RINOK(stream->Seek(pa, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(stream, buf, debugLink.Size));
+
+ for (i = 0; i < (int)numItems; i++)
+ {
+ CDebugEntry de;
+ de.Parse(buf);
+
+ if (de.Size == 0)
+ continue;
+
+ CSection sect;
+ sect.Name = ".debug" + GetDecString(i);
+
+ sect.IsDebug = true;
+ sect.Time = de.Time;
+ sect.Va = de.Va;
+ sect.Pa = de.Pa;
+ sect.PSize = sect.VSize = de.Size;
+ UInt32 totalSize = sect.Pa + sect.PSize;
+ if (totalSize > _totalSize)
+ {
+ _totalSize = totalSize;
+ _sections.Add(sect);
+ thereIsSection = true;
+ }
+ buf += kEntrySize;
+ }
+
+ return S_OK;
+}
+
+HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const
+{
+ if ((offset & 1) != 0 || offset >= _buf.GetCapacity())
+ return S_FALSE;
+ size_t rem = _buf.GetCapacity() - offset;
+ if (rem < 2)
+ return S_FALSE;
+ unsigned length = Get16(_buf + offset);
+ if ((rem - 2) / 2 < length)
+ return S_FALSE;
+ dest.Empty();
+ offset += 2;
+ for (unsigned i = 0; i < length; i++)
+ dest += (wchar_t)Get16(_buf + offset + i * 2);
+ return S_OK;
+}
+
+HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items)
+{
+ if ((offset & 3) != 0 || offset >= _buf.GetCapacity())
+ return S_FALSE;
+ size_t rem = _buf.GetCapacity() - offset;
+ if (rem < 16)
+ return S_FALSE;
+ items.Clear();
+ unsigned numNameItems = Get16(_buf + offset + 12);
+ unsigned numIdItems = Get16(_buf + offset + 14);
+ unsigned numItems = numNameItems + numIdItems;
+ if ((rem - 16) / 8 < numItems)
+ return S_FALSE;
+ if (!_usedRes.SetRange(offset, 16 + numItems * 8))
+ return S_FALSE;
+ offset += 16;
+ _oneLang = true;
+ unsigned i;
+ for (i = 0; i < numItems; i++)
+ {
+ CTableItem item;
+ const Byte *buf = _buf + offset;
+ offset += 8;
+ item.ID = Get32(buf + 0);
+ if (((item.ID & kFlag) != 0) != (i < numNameItems))
+ return S_FALSE;
+ item.Offset = Get32(buf + 4);
+ items.Add(item);
+ }
+ return S_OK;
+}
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 30;
+static const int kNumResItemsMax = (UInt32)1 << 23;
+static const int kNumStringLangsMax = 128;
+
+// BITMAPINFOHEADER
+struct CBitmapInfoHeader
+{
+ // UInt32 HeaderSize;
+ UInt32 XSize;
+ Int32 YSize;
+ UInt16 Planes;
+ UInt16 BitCount;
+ UInt32 Compression;
+ UInt32 SizeImage;
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+static const UInt32 kBitmapInfoHeader_Size = 0x28;
+
+bool CBitmapInfoHeader::Parse(const Byte *p, size_t size)
+{
+ if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size)
+ return false;
+ XSize = Get32(p + 4);
+ YSize = (Int32)Get32(p + 8);
+ Planes = Get16(p + 12);
+ BitCount = Get16(p + 14);
+ Compression = Get32(p + 16);
+ SizeImage = Get32(p + 20);
+ return true;
+}
+
+static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount)
+{
+ return ((xSize * bitCount + 7) / 8 + 3) / 4 * 4 * ySize;
+}
+
+static UInt32 SetBitmapHeader(Byte *dest, const Byte *src, UInt32 size)
+{
+ CBitmapInfoHeader h;
+ if (!h.Parse(src, size))
+ return 0;
+ if (h.YSize < 0)
+ h.YSize = -h.YSize;
+ if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 || h.BitCount > 32 ||
+ h.Compression != 0) // BI_RGB
+ return 0;
+ if (h.SizeImage == 0)
+ h.SizeImage = GetImageSize(h.XSize, h.YSize, h.BitCount);
+ UInt32 totalSize = kBmpHeaderSize + size;
+ UInt32 offBits = totalSize - h.SizeImage;
+ // BITMAPFILEHEADER
+ SetUi16(dest, 0x4D42);
+ SetUi32(dest + 2, totalSize);
+ SetUi32(dest + 6, 0);
+ SetUi32(dest + 10, offBits);
+ return kBmpHeaderSize;
+}
+
+static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size)
+{
+ CBitmapInfoHeader h;
+ if (!h.Parse(src, size))
+ return 0;
+ if (h.YSize < 0)
+ h.YSize = -h.YSize;
+ if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 ||
+ h.Compression != 0) // BI_RGB
+ return 0;
+
+ UInt32 numBitCount = h.BitCount;
+ if (numBitCount != 1 &&
+ numBitCount != 4 &&
+ numBitCount != 8 &&
+ numBitCount != 24 &&
+ numBitCount != 32)
+ return 0;
+
+ if ((h.YSize & 1) != 0)
+ return 0;
+ h.YSize /= 2;
+ if (h.XSize > 0x100 || h.YSize > 0x100)
+ return 0;
+
+ UInt32 imageSize;
+ // imageSize is not correct if AND mask array contains zeros
+ // in this case it is equal image1Size
+
+ // UInt32 imageSize = h.SizeImage;
+ // if (imageSize == 0)
+ // {
+ UInt32 image1Size = GetImageSize(h.XSize, h.YSize, h.BitCount);
+ UInt32 image2Size = GetImageSize(h.XSize, h.YSize, 1);
+ imageSize = image1Size + image2Size;
+ // }
+ UInt32 numColors = 0;
+ if (numBitCount < 16)
+ numColors = 1 << numBitCount;
+
+ SetUi16(dest, 0); // Reserved
+ SetUi16(dest + 2, 1); // RES_ICON
+ SetUi16(dest + 4, 1); // ResCount
+
+ dest[6] = (Byte)h.XSize; // Width
+ dest[7] = (Byte)h.YSize; // Height
+ dest[8] = (Byte)numColors; // ColorCount
+ dest[9] = 0; // Reserved
+
+ SetUi32(dest + 10, 0); // Reserved1 / Reserved2
+
+ UInt32 numQuadsBytes = numColors * 4;
+ UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize;
+ SetUi32(dest + 14, BytesInRes);
+ SetUi32(dest + 18, kIconHeaderSize);
+
+ /*
+ Description = DWORDToString(xSize) +
+ kDelimiterChar + DWORDToString(ySize) +
+ kDelimiterChar + DWORDToString(numBitCount);
+ */
+ return kIconHeaderSize;
+}
+
+bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size)
+{
+ if ((size & 1) != 0)
+ return false;
+
+ int i;
+ for (i = 0; i < _strings.Size(); i++)
+ if (_strings[i].Lang == lang)
+ break;
+ if (i == _strings.Size())
+ {
+ if (_strings.Size() >= kNumStringLangsMax)
+ return false;
+ CStringItem item;
+ item.Size = 0;
+ item.Lang = lang;
+ i = _strings.Add(item);
+ }
+
+ CStringItem &item = _strings[i];
+ id = (id - 1) << 4;
+ UInt32 pos = 0;
+ for (i = 0; i < 16; i++)
+ {
+ if (size - pos < 2)
+ return false;
+ UInt32 len = Get16(src + pos);
+ pos += 2;
+ if (len != 0)
+ {
+ if (size - pos < len * 2)
+ return false;
+ char temp[32];
+ ConvertUInt32ToString(id + i, temp);
+ size_t tempLen = strlen(temp);
+ size_t j;
+ for (j = 0; j < tempLen; j++)
+ item.AddChar(temp[j]);
+ item.AddChar('\t');
+ for (j = 0; j < len; j++, pos += 2)
+ item.AddWChar(Get16(src + pos));
+ item.AddChar(0x0D);
+ item.AddChar(0x0A);
+ }
+ }
+ return (size == pos);
+}
+
+HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpenCallback *callback)
+{
+ const CSection &sect = _sections[sectionIndex];
+ size_t fileSize = sect.PSize; // Maybe we need sect.VSize here !!!
+ if (fileSize > kFileSizeMax)
+ return S_FALSE;
+ {
+ UInt64 fileSize64 = fileSize;
+ if (callback)
+ RINOK(callback->SetTotal(NULL, &fileSize64));
+ RINOK(stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
+ _buf.SetCapacity(fileSize);
+ for (size_t pos = 0; pos < fileSize;)
+ {
+ UInt64 offset64 = pos;
+ if (callback)
+ RINOK(callback->SetCompleted(NULL, &offset64))
+ size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20));
+ RINOK(ReadStream_FALSE(stream, _buf + pos, rem));
+ pos += rem;
+ }
+ }
+
+ _usedRes.Alloc(fileSize);
+ CRecordVector<CTableItem> specItems;
+ RINOK(ReadTable(0, specItems));
+
+ _oneLang = true;
+ bool stringsOk = true;
+ size_t maxOffset = 0;
+ for (int i = 0; i < specItems.Size(); i++)
+ {
+ const CTableItem &item1 = specItems[i];
+ if ((item1.Offset & kFlag) == 0)
+ return S_FALSE;
+
+ CRecordVector<CTableItem> specItems2;
+ RINOK(ReadTable(item1.Offset & kMask, specItems2));
+
+ for (int j = 0; j < specItems2.Size(); j++)
+ {
+ const CTableItem &item2 = specItems2[j];
+ if ((item2.Offset & kFlag) == 0)
+ return S_FALSE;
+
+ CRecordVector<CTableItem> specItems3;
+ RINOK(ReadTable(item2.Offset & kMask, specItems3));
+
+ CResItem item;
+ item.Type = item1.ID;
+ item.ID = item2.ID;
+
+ for (int k = 0; k < specItems3.Size(); k++)
+ {
+ if (_items.Size() >= kNumResItemsMax)
+ return S_FALSE;
+ const CTableItem &item3 = specItems3[k];
+ if ((item3.Offset & kFlag) != 0)
+ return S_FALSE;
+ if (item3.Offset >= _buf.GetCapacity() || _buf.GetCapacity() - item3.Offset < 16)
+ return S_FALSE;
+ const Byte *buf = _buf + item3.Offset;
+ item.Lang = item3.ID;
+ item.Offset = Get32(buf + 0);
+ item.Size = Get32(buf + 4);
+ // UInt32 codePage = Get32(buf + 8);
+ if (Get32(buf + 12) != 0)
+ return S_FALSE;
+ if (!_items.IsEmpty() && _oneLang && !item.IsNameEqual(_items.Back()))
+ _oneLang = false;
+
+ item.HeaderSize = 0;
+
+ size_t offset = item.Offset - sect.Va;
+ if (offset > maxOffset)
+ maxOffset = offset;
+ if (offset + item.Size > maxOffset)
+ maxOffset = offset + item.Size;
+
+ if (CheckItem(sect, item, offset))
+ {
+ const Byte *data = _buf + offset;
+ if (item.IsBmp())
+ item.HeaderSize = SetBitmapHeader(item.Header, data, item.Size);
+ else if (item.IsIcon())
+ item.HeaderSize = SetIconHeader(item.Header, data, item.Size);
+ else if (item.IsString())
+ {
+ if (stringsOk)
+ stringsOk = ParseStringRes(item.ID, item.Lang, data, item.Size);
+ }
+ }
+
+ item.Enabled = true;
+ _items.Add(item);
+ }
+ }
+ }
+
+ if (stringsOk && !_strings.IsEmpty())
+ {
+ int i;
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CResItem &item = _items[i];
+ if (item.IsString())
+ item.Enabled = false;
+ }
+ for (i = 0; i < _strings.Size(); i++)
+ {
+ if (_strings[i].Size == 0)
+ continue;
+ CMixItem mixItem;
+ mixItem.ResourceIndex = -1;
+ mixItem.StringIndex = i;
+ mixItem.SectionIndex = sectionIndex;
+ _mixItems.Add(mixItem);
+ }
+ }
+
+ _usedRes.Free();
+
+ int numBits = _optHeader.GetNumFileAlignBits();
+ if (numBits >= 0)
+ {
+ UInt32 mask = (1 << numBits) - 1;
+ size_t end = ((maxOffset + mask) & ~mask);
+ if (end < sect.VSize && end <= sect.PSize)
+ {
+ CSection sect2;
+ sect2.Flags = 0;
+
+ // we skip Zeros to start of aligned block
+ size_t i;
+ for (i = maxOffset; i < end; i++)
+ if (_buf[i] != 0)
+ break;
+ if (i == end)
+ maxOffset = end;
+
+ sect2.Pa = sect.Pa + (UInt32)maxOffset;
+ sect2.Va = sect.Va + (UInt32)maxOffset;
+ sect2.PSize = sect.VSize - (UInt32)maxOffset;
+ sect2.VSize = sect2.PSize;
+ sect2.Name = ".rsrc_1";
+ sect2.Time = 0;
+ sect2.IsAdditionalSection = true;
+ _sections.Add(sect2);
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ const UInt32 kBufSize = 1 << 18;
+ const UInt32 kSigSize = 2;
+
+ _mainSubfile = -1;
+
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ size_t processed = kSigSize;
+ RINOK(ReadStream_FALSE(stream, buf, processed));
+ if (buf[0] != 'M' || buf[1] != 'Z')
+ return S_FALSE;
+ processed = kBufSize - kSigSize;
+ RINOK(ReadStream(stream, buf + kSigSize, &processed));
+ processed += kSigSize;
+ if (!Parse(buf, (UInt32)processed))
+ return S_FALSE;
+ bool thereISDebug;
+ RINOK(LoadDebugSections(stream, thereISDebug));
+
+ const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
+ if (certLink.Size != 0)
+ {
+ CSection sect;
+ sect.Name = "CERTIFICATE";
+ sect.Va = 0;
+ sect.Pa = certLink.Va;
+ sect.PSize = sect.VSize = certLink.Size;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ if (thereISDebug)
+ {
+ const UInt32 kAlign = 1 << 12;
+ UInt32 alignPos = _totalSize & (kAlign - 1);
+ if (alignPos != 0)
+ {
+ UInt32 size = kAlign - alignPos;
+ RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL));
+ buffer.Free();
+ buffer.SetCapacity(kAlign);
+ Byte *buf = buffer;
+ size_t processed = size;
+ RINOK(ReadStream(stream, buf, &processed));
+ size_t i;
+ for (i = 0; i < processed; i++)
+ {
+ if (buf[i] != 0)
+ break;
+ }
+ if (processed < size && processed < 100)
+ _totalSize += (UInt32)processed;
+ else if (((_totalSize + i) & 0x1FF) == 0 || processed < size)
+ _totalSize += (UInt32)i;
+ }
+ }
+
+ if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= 512)
+ {
+ if (_header.NumSymbols >= (1 << 24))
+ return S_FALSE;
+ CSection sect;
+ sect.Name = "COFF_SYMBOLS";
+ UInt32 size = _header.NumSymbols * 18;
+ RINOK(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL));
+ Byte buf[4];
+ RINOK(ReadStream_FALSE(stream, buf, 4));
+ UInt32 size2 = Get32(buf);
+ if (size2 >= (1 << 28))
+ return S_FALSE;
+ size += size2;
+
+ sect.Va = 0;
+ sect.Pa = _header.PointerToSymbolTable;
+ sect.PSize = sect.VSize = size;
+ sect.UpdateTotalSize(_totalSize);
+ _sections.Add(sect);
+ }
+
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ if (fileSize > _totalSize)
+ return S_FALSE;
+ _totalSizeLimited = (_totalSize < fileSize) ? _totalSize : (UInt32)fileSize;
+
+ {
+ CObjectVector<CSection> sections = _sections;
+ sections.Sort();
+ UInt32 limit = (1 << 12);
+ int num = 0;
+ int numSections = sections.Size();
+ for (int i = 0; i < numSections; i++)
+ {
+ const CSection &s = sections[i];
+ if (s.Pa > limit)
+ {
+ CSection s2;
+ s2.Pa = s2.Va = limit;
+ s2.PSize = s2.VSize = s.Pa - limit;
+ s2.IsAdditionalSection = true;
+ s2.Name = '[';
+ s2.Name += GetDecString(num++);
+ s2.Name += ']';
+ _sections.Add(s2);
+ limit = s.Pa;
+ }
+ UInt32 next = s.Pa + s.PSize;
+ if (next < s.Pa)
+ break;
+ if (next >= limit)
+ limit = next;
+ }
+ }
+
+ _parseResources = true;
+
+ UInt64 mainSize = 0, mainSize2 = 0;
+ int i;
+ for (i = 0; i < _sections.Size(); i++)
+ {
+ const CSection &sect = _sections[i];
+ CMixItem mixItem;
+ mixItem.SectionIndex = i;
+ if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty())
+ {
+ HRESULT res = OpenResources(i, stream, callback);
+ if (res == S_OK)
+ {
+ _resourceFileName = GetUnicodeString(sect.Name);
+ for (int j = 0; j < _items.Size(); j++)
+ {
+ const CResItem &item = _items[j];
+ if (item.Enabled)
+ {
+ mixItem.ResourceIndex = j;
+ mixItem.StringIndex = -1;
+ if (item.IsRcDataOrUnknown())
+ {
+ if (item.Size >= mainSize)
+ {
+ mainSize2 = mainSize;
+ mainSize = item.Size;
+ _mainSubfile = _mixItems.Size();
+ }
+ else if (item.Size >= mainSize2)
+ mainSize2 = item.Size;
+ }
+ _mixItems.Add(mixItem);
+ }
+ }
+ if (sect.PSize > sect.VSize)
+ {
+ int numBits = _optHeader.GetNumFileAlignBits();
+ if (numBits >= 0)
+ {
+ UInt32 mask = (1 << numBits) - 1;
+ UInt32 end = ((sect.VSize + mask) & ~mask);
+
+ if (sect.PSize > end)
+ {
+ CSection sect2;
+ sect2.Flags = 0;
+ sect2.Pa = sect.Pa + end;
+ sect2.Va = sect.Va + end;
+ sect2.PSize = sect.PSize - end;
+ sect2.VSize = sect2.PSize;
+ sect2.Name = ".rsrc_2";
+ sect2.Time = 0;
+ sect2.IsAdditionalSection = true;
+ _sections.Add(sect2);
+ }
+ }
+ }
+ continue;
+ }
+ if (res != S_FALSE)
+ return res;
+ CloseResources();
+ }
+ mixItem.StringIndex = -1;
+ mixItem.ResourceIndex = -1;
+ if (sect.IsAdditionalSection)
+ {
+ if (sect.PSize >= mainSize)
+ {
+ mainSize2 = mainSize;
+ mainSize = sect.PSize;
+ _mainSubfile = _mixItems.Size();
+ }
+ else
+ mainSize2 = sect.PSize;
+ }
+ _mixItems.Add(mixItem);
+ }
+
+ if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2)
+ _mainSubfile = -1;
+
+ for (i = 0; i < _mixItems.Size(); i++)
+ {
+ const CMixItem &mixItem = _mixItems[i];
+ if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_")
+ {
+ _mainSubfile = i;
+ break;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res)
+{
+ // size &= ~1;
+ const UInt32 kBufSize = 1 << 23;
+ CByteBuffer buffer;
+ buffer.SetCapacity(kBufSize);
+ Byte *buf = buffer;
+
+ UInt32 sum = 0;
+ UInt32 pos = 0;
+ for (;;)
+ {
+ UInt32 rem = size - pos;
+ if (rem > kBufSize)
+ rem = kBufSize;
+ if (rem == 0)
+ break;
+ size_t processed = rem;
+ RINOK(ReadStream(stream, buf, &processed));
+
+ /*
+ for (; processed < rem; processed++)
+ buf[processed] = 0;
+ */
+
+ if ((processed & 1) != 0)
+ buf[processed] = 0;
+
+ for (int j = 0; j < 4; j++)
+ {
+ UInt32 p = excludePos + j;
+ if (pos <= p && p < pos + processed)
+ buf[p - pos] = 0;
+ }
+
+ for (size_t i = 0; i < processed; i += 2)
+ {
+ sum += Get16(buf + i);
+ sum = (sum + (sum >> 16)) & 0xFFFF;
+ }
+ pos += (UInt32)processed;
+ if (rem != processed)
+ break;
+ }
+ sum += pos;
+ res = sum;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream, callback));
+ _stream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::CloseResources()
+{
+ _usedRes.Free();
+ _items.Clear();
+ _strings.Clear();
+ _buf.SetCapacity(0);
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ _sections.Clear();
+ _mixItems.Clear();
+ CloseResources();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _mixItems.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _mixItems.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]];
+ if (mixItem.StringIndex >= 0)
+ totalSize += _strings[mixItem.StringIndex].Size;
+ else if (mixItem.ResourceIndex < 0)
+ totalSize += _sections[mixItem.SectionIndex].GetPackSize();
+ else
+ totalSize += _items[mixItem.ResourceIndex].GetSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ bool checkSumOK = true;
+ if (_optHeader.CheckSum != 0 && (int)numItems == _mixItems.Size())
+ {
+ UInt32 checkSum = 0;
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ CalcCheckSum(_stream, _totalSizeLimited, _peOffset + kHeaderSize + 64, checkSum);
+ checkSumOK = (checkSum == _optHeader.CheckSum);
+ }
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ const CMixItem &mixItem = _mixItems[index];
+
+ const CSection &sect = _sections[mixItem.SectionIndex];
+ bool isOk = true;
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ currentItemSize = item.Size;
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (outStream)
+ RINOK(WriteStream(outStream, item.Buf, item.Size));
+ }
+ else if (mixItem.ResourceIndex < 0)
+ {
+ currentItemSize = sect.GetPackSize();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(_stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ isOk = (copyCoderSpec->TotalSize == currentItemSize);
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ currentItemSize = item.GetSize();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ size_t offset = item.Offset - sect.Va;
+ if (!CheckItem(sect, item, offset))
+ isOk = false;
+ else if (outStream)
+ {
+ if (item.HeaderSize != 0)
+ RINOK(WriteStream(outStream, item.Header, item.HeaderSize));
+ RINOK(WriteStream(outStream, _buf + offset, item.Size));
+ }
+ }
+
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(isOk ?
+ checkSumOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+
+ const CMixItem &mixItem = _mixItems[index];
+ const CSection &sect = _sections[mixItem.SectionIndex];
+ if (mixItem.IsSectionItem())
+ return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream);
+
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+ CReferenceBuf *referenceBuf = new CReferenceBuf;
+ CMyComPtr<IUnknown> ref = referenceBuf;
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ referenceBuf->Buf.SetCapacity(item.Size);
+ memcpy(referenceBuf->Buf, item.Buf, item.Size);
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ size_t offset = item.Offset - sect.Va;
+ if (!CheckItem(sect, item, offset))
+ return S_FALSE;
+ if (item.HeaderSize == 0)
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp2 = streamSpec;
+ streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this);
+ *stream = streamTemp2.Detach();
+ return S_OK;
+ }
+ referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size);
+ memcpy(referenceBuf->Buf, item.Header, item.HeaderSize);
+ memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size);
+ }
+ inStreamSpec->Init(referenceBuf);
+
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"PE", L"exe dll sys", 0, 0xDD, { 'P', 'E', 0, 0 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Pe)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/PpmdHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/PpmdHandler.cpp
new file mode 100644
index 000000000..9b2ef0482
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/PpmdHandler.cpp
@@ -0,0 +1,456 @@
+/* PpmdHandler.c -- PPMd format handler
+2010-03-10 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.H (2001) / var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/Alloc.h"
+#include "../../../C/Ppmd7.h"
+#include "../../../C/Ppmd8.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NPpmd {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static const UInt32 kBufSize = (1 << 20);
+
+struct CBuf
+{
+ Byte *Buf;
+
+ CBuf(): Buf(0) {}
+ ~CBuf() { ::MidFree(Buf); }
+ bool Alloc()
+ {
+ if (!Buf)
+ Buf = (Byte *)::MidAlloc(kBufSize);
+ return (Buf != 0);
+ }
+};
+
+static const UInt32 kHeaderSize = 16;
+static const UInt32 kSignature = 0x84ACAF8F;
+static const unsigned kNewHeaderVer = 8;
+
+struct CItem
+{
+ UInt32 Attrib;
+ UInt32 Time;
+ AString Name;
+
+ unsigned Order;
+ unsigned MemInMB;
+ unsigned Ver;
+ unsigned Restor;
+
+ HRESULT ReadHeader(ISequentialInStream *s, UInt32 &headerSize);
+ bool IsSupported() const { return Ver == 7 || (Ver == 8 && Restor <= 1); }
+};
+
+HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize)
+{
+ Byte h[kHeaderSize];
+ RINOK(ReadStream_FALSE(s, h, kHeaderSize));
+ if (GetUi32(h) != kSignature)
+ return S_FALSE;
+ Attrib = GetUi32(h + 4);
+ Time = GetUi32(h + 12);
+
+ unsigned info = GetUi16(h + 8);
+ Order = (info & 0xF) + 1;
+ MemInMB = ((info >> 4) & 0xFF) + 1;
+ Ver = info >> 12;
+
+ UInt32 nameLen = GetUi16(h + 10);
+ Restor = nameLen >> 14;
+ if (Restor > 2)
+ return S_FALSE;
+ if (Ver >= kNewHeaderVer)
+ nameLen &= 0x3FFF;
+ if (nameLen > (1 << 9))
+ return S_FALSE;
+ char *name = Name.GetBuffer(nameLen + 1);
+ HRESULT res = ReadStream_FALSE(s, name, nameLen);
+ name[nameLen] = 0;
+ headerSize = kHeaderSize + nameLen;
+ Name.ReleaseBuffer();
+ return res;
+}
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public CMyUnknownImp
+{
+ CItem _item;
+ UInt32 _headerSize;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<ISequentialInStream> _stream;
+
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+static void UIntToString(AString &s, const char *prefix, unsigned value)
+{
+ s += prefix;
+ char temp[16];
+ ::ConvertUInt32ToString((UInt32)value, temp);
+ s += temp;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPath: prop = MultiByteToUnicodeString(_item.Name, CP_ACP); break;
+ case kpidMTime:
+ {
+ FILETIME utc;
+ if (NTime::DosTimeToFileTime(_item.Time, utc))
+ prop = utc;
+ break;
+ }
+ case kpidAttrib: prop = _item.Attrib; break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidMethod:
+ {
+ AString s = "PPMd";
+ s += (char)('A' + _item.Ver);
+ UIntToString(s, ":o", _item.Order);
+ UIntToString(s, ":mem", _item.MemInMB);
+ s += 'm';
+ if (_item.Ver >= kNewHeaderVer && _item.Restor != 0)
+ UIntToString(s, ":r", _item.Restor);
+ prop = s;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
+{
+ return OpenSeq(stream);
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ Close();
+ res = _item.ReadHeader(stream, _headerSize);
+ }
+ catch(...) { res = S_FALSE; }
+ if (res == S_OK)
+ _stream = stream;
+ else
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _stream.Release();
+ return S_OK;
+}
+
+static const UInt32 kTopValue = (1 << 24);
+static const UInt32 kBot = (1 << 15);
+
+struct CRangeDecoder
+{
+ IPpmd7_RangeDec s;
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ CByteInBufWrap *Stream;
+
+public:
+ bool Init()
+ {
+ Code = 0;
+ Low = 0;
+ Range = 0xFFFFFFFF;
+ for (int i = 0; i < 4; i++)
+ Code = (Code << 8) | Stream->ReadByte();
+ return Code < 0xFFFFFFFF;
+ }
+
+ void Normalize()
+ {
+ while ((Low ^ (Low + Range)) < kTopValue ||
+ Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1))
+ {
+ Code = (Code << 8) | Stream->ReadByte();
+ Range <<= 8;
+ Low <<= 8;
+ }
+ }
+
+ CRangeDecoder();
+};
+
+
+extern "C" {
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ return p->Code / (p->Range /= total);
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ start *= p->Range;
+ p->Low += start;
+ p->Code -= start;
+ p->Range *= size;
+ p->Normalize();
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ if (p->Code / (p->Range >>= 14) < size0)
+ {
+ Range_Decode(p, 0, size0);
+ return 0;
+ }
+ else
+ {
+ Range_Decode(p, size0, (1 << 14) - size0);
+ return 1;
+ }
+}
+
+}
+
+CRangeDecoder::CRangeDecoder()
+{
+ s.GetThreshold = Range_GetThreshold;
+ s.Decode = Range_Decode;
+ s.DecodeBit = Range_DecodeBit;
+}
+
+struct CPpmdCpp
+{
+ unsigned Ver;
+ CRangeDecoder _rc;
+ CPpmd7 _ppmd7;
+ CPpmd8 _ppmd8;
+
+ CPpmdCpp(unsigned version)
+ {
+ Ver = version;
+ Ppmd7_Construct(&_ppmd7);
+ Ppmd8_Construct(&_ppmd8);
+ }
+
+ ~CPpmdCpp()
+ {
+ Ppmd7_Free(&_ppmd7, &g_BigAlloc);
+ Ppmd8_Free(&_ppmd8, &g_BigAlloc);
+ }
+
+ bool Alloc(UInt32 memInMB)
+ {
+ memInMB <<= 20;
+ if (Ver == 7)
+ return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0;
+ return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0;
+ }
+
+ void Init(unsigned order, unsigned restor)
+ {
+ if (Ver == 7)
+ Ppmd7_Init(&_ppmd7, order);
+ else
+ Ppmd8_Init(&_ppmd8, order, restor);;
+ }
+
+ bool InitRc(CByteInBufWrap *inStream)
+ {
+ if (Ver == 7)
+ {
+ _rc.Stream = inStream;
+ return _rc.Init();
+ }
+ else
+ {
+ _ppmd8.Stream.In = &inStream->p;
+ return Ppmd8_RangeDec_Init(&_ppmd8) != 0;
+ }
+ }
+
+ bool IsFinishedOK()
+ {
+ if (Ver == 7)
+ return Ppmd7z_RangeDec_IsFinishedOK(&_rc);
+ return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8);
+ }
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ // extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CByteInBufWrap inBuf;
+ if (!inBuf.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ inBuf.Stream = _stream;
+
+ CBuf outBuf;
+ if (!outBuf.Alloc())
+ return E_OUTOFMEMORY;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ CPpmdCpp ppmd(_item.Ver);
+ if (!ppmd.Alloc(_item.MemInMB))
+ return E_OUTOFMEMORY;
+ Int32 opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ if (_item.IsSupported())
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ ppmd.Init(_item.Order, _item.Restor);
+ inBuf.Init();
+ UInt64 outSize = 0;
+ if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK)
+ for (;;)
+ {
+ lps->InSize = _packSize = inBuf.GetProcessed();
+ lps->OutSize = outSize;
+ RINOK(lps->SetCur());
+
+ size_t i;
+ int sym = 0;
+
+ if (ppmd.Ver == 7)
+ {
+ for (i = 0; i < kBufSize; i++)
+ {
+ sym = Ppmd7_DecodeSymbol(&ppmd._ppmd7, &ppmd._rc.s);
+ if (inBuf.Extra || sym < 0)
+ break;
+ outBuf.Buf[i] = (Byte)sym;
+ }
+ }
+ else
+ {
+ for (i = 0; i < kBufSize; i++)
+ {
+ sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8);
+ if (inBuf.Extra || sym < 0)
+ break;
+ outBuf.Buf[i] = (Byte)sym;
+ }
+ }
+
+ outSize += i;
+ _packSize = _headerSize + inBuf.GetProcessed();
+ _packSizeDefined = true;
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, outBuf.Buf, i));
+ }
+ if (sym < 0)
+ {
+ if (sym == -1 && ppmd.IsFinishedOK())
+ opRes = NExtract::NOperationResult::kOK;
+ break;
+ }
+ }
+ RINOK(inBuf.Res);
+ }
+ realOutStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Ppmd", L"pmd", 0, 0xD, { 0x8F, 0xAF, 0xAC, 0x84 }, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Ppmd)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.cpp
new file mode 100644
index 000000000..5d072d34d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -0,0 +1,869 @@
+// RarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantUtils.h"
+#include "Windows/Time.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+#include "../../Common/MethodId.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../../Crypto/Rar20Crypto.h"
+#include "../../Crypto/RarAes.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "RarHandler.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NRar {
+
+static const wchar_t *kHostOS[] =
+{
+ L"MS DOS",
+ L"OS/2",
+ L"Win32",
+ L"Unix",
+ L"Mac OS",
+ L"BeOS"
+};
+
+static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
+
+static const wchar_t *kUnknownOS = L"Unknown";
+
+static const CUInt32PCharPair k_Flags[] =
+{
+ { 0, "Volume" },
+ { 1, "Comment" },
+ { 2, "Lock" },
+ { 3, "Solid" },
+ { 4, "NewVolName" }, // pack_comment in old versuons
+ { 5, "Authenticity" },
+ { 6, "Recovery" },
+ { 7, "BlockEncryption" },
+ { 8, "FirstVolume" },
+ { 9, "EncryptVer" }
+};
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+
+ { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidSolid, VT_BOOL},
+ { NULL, kpidCommented, VT_BOOL},
+ { NULL, kpidSplitBefore, VT_BOOL},
+ { NULL, kpidSplitAfter, VT_BOOL},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidUnpackVer, VT_UI1}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidSolid, VT_BOOL},
+ { NULL, kpidNumBlocks, VT_UI4},
+ // { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidIsVolume, VT_BOOL},
+ { NULL, kpidNumVolumes, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8}
+ // { NULL, kpidCommented, VT_BOOL}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+UInt64 CHandler::GetPackSize(int refIndex) const
+{
+ const CRefItem &refItem = _refItems[refIndex];
+ UInt64 totalPackSize = 0;
+ for (int i = 0; i < refItem.NumItems; i++)
+ totalPackSize += _items[refItem.ItemIndex + i].PackSize;
+ return totalPackSize;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSolid: prop = _archiveInfo.IsSolid(); break;
+ case kpidCharacts: FLAGS_TO_PROP(k_Flags, _archiveInfo.Flags, prop); break;
+ // case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names.
+ case kpidIsVolume: prop = _archiveInfo.IsVolume(); break;
+ case kpidNumVolumes: prop = (UInt32)_archives.Size(); break;
+ case kpidOffset: if (_archiveInfo.StartPosition != 0) prop = _archiveInfo.StartPosition; break;
+ // case kpidCommented: prop = _archiveInfo.IsCommented(); break;
+ case kpidNumBlocks:
+ {
+ UInt32 numBlocks = 0;
+ for (int i = 0; i < _refItems.Size(); i++)
+ if (!IsSolid(i))
+ numBlocks++;
+ prop = (UInt32)numBlocks;
+ break;
+ }
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _refItems.Size();
+ return S_OK;
+}
+
+static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result)
+{
+ if (!DosTimeToFileTime(rarTime.DosTime, result))
+ return false;
+ UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime;
+ value += (UInt64)rarTime.LowSecond * 10000000;
+ value += ((UInt64)rarTime.SubTime[2] << 16) +
+ ((UInt64)rarTime.SubTime[1] << 8) +
+ ((UInt64)rarTime.SubTime[0]);
+ result.dwLowDateTime = (DWORD)value;
+ result.dwHighDateTime = DWORD(value >> 32);
+ return true;
+}
+
+static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME localFileTime, utcFileTime;
+ if (RarTimeToFileTime(rarTime, localFileTime))
+ {
+ if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ }
+ else
+ utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
+ prop = utcFileTime;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CRefItem &refItem = _refItems[index];
+ const CItemEx &item = _items[refItem.ItemIndex];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ UString u;
+ if (item.HasUnicodeName() && !item.UnicodeName.IsEmpty())
+ u = item.UnicodeName;
+ else
+ u = MultiByteToUnicodeString(item.Name, CP_OEMCP);
+ prop = (const wchar_t *)NItemName::WinNameToOSName(u);
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = GetPackSize(index); break;
+ case kpidMTime: RarTimeToProp(item.MTime, prop); break;
+ case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break;
+ case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break;
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidSolid: prop = IsSolid(index); break;
+ case kpidCommented: prop = item.IsCommented(); break;
+ case kpidSplitBefore: prop = item.IsSplitBefore(); break;
+ case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break;
+ case kpidCRC:
+ {
+ const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
+ prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC);
+ break;
+ }
+ case kpidUnpackVer: prop = item.UnPackVersion; break;
+ case kpidMethod:
+ {
+ UString method;
+ if (item.Method >= Byte('0') && item.Method <= Byte('5'))
+ {
+ method = L"m";
+ wchar_t temp[32];
+ ConvertUInt64ToString(item.Method - Byte('0'), temp);
+ method += temp;
+ if (!item.IsDir())
+ {
+ method += L":";
+ ConvertUInt64ToString(16 + item.GetDictSize(), temp);
+ method += temp;
+ }
+ }
+ else
+ {
+ wchar_t temp[32];
+ ConvertUInt64ToString(item.Method, temp);
+ method += temp;
+ }
+ prop = method;
+ break;
+ }
+ case kpidHostOS: prop = (item.HostOS < kNumHostOSes) ? (kHostOS[item.HostOS]) : kUnknownOS; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CVolumeName
+{
+ bool _first;
+ bool _newStyle;
+ UString _unchangedPart;
+ UString _changedPart;
+ UString _afterPart;
+public:
+ CVolumeName(): _newStyle(true) {};
+
+ bool InitName(const UString &name, bool newStyle)
+ {
+ _first = true;
+ _newStyle = newStyle;
+ int dotPos = name.ReverseFind('.');
+ UString basePart = name;
+ if (dotPos >= 0)
+ {
+ UString ext = name.Mid(dotPos + 1);
+ if (ext.CompareNoCase(L"rar") == 0)
+ {
+ _afterPart = name.Mid(dotPos);
+ basePart = name.Left(dotPos);
+ }
+ else if (ext.CompareNoCase(L"exe") == 0)
+ {
+ _afterPart = L".rar";
+ basePart = name.Left(dotPos);
+ }
+ else if (!_newStyle)
+ {
+ if (ext.CompareNoCase(L"000") == 0 ||
+ ext.CompareNoCase(L"001") == 0 ||
+ ext.CompareNoCase(L"r00") == 0 ||
+ ext.CompareNoCase(L"r01") == 0)
+ {
+ _afterPart.Empty();
+ _first = false;
+ _changedPart = ext;
+ _unchangedPart = name.Left(dotPos + 1);
+ return true;
+ }
+ }
+ }
+
+ if (!_newStyle)
+ {
+ _afterPart.Empty();
+ _unchangedPart = basePart + UString(L".");
+ _changedPart = L"r00";
+ return true;
+ }
+
+ int numLetters = 1;
+ if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0")
+ {
+ while (numLetters < basePart.Length())
+ {
+ if (basePart[basePart.Length() - numLetters - 1] != '0')
+ break;
+ numLetters++;
+ }
+ }
+ else
+ return false;
+ _unchangedPart = basePart.Left(basePart.Length() - numLetters);
+ _changedPart = basePart.Right(numLetters);
+ return true;
+ }
+
+ UString GetNextName()
+ {
+ UString newName;
+ if (_newStyle || !_first)
+ {
+ int i;
+ int numLetters = _changedPart.Length();
+ for (i = numLetters - 1; i >= 0; i--)
+ {
+ wchar_t c = _changedPart[i];
+ if (c == L'9')
+ {
+ c = L'0';
+ newName = c + newName;
+ if (i == 0)
+ newName = UString(L'1') + newName;
+ continue;
+ }
+ c++;
+ newName = UString(c) + newName;
+ i--;
+ for (; i >= 0; i--)
+ newName = _changedPart[i] + newName;
+ break;
+ }
+ _changedPart = newName;
+ }
+ _first = false;
+ return _unchangedPart + _changedPart + _afterPart;
+ }
+};
+
+HRESULT CHandler::Open2(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback)
+{
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openCallback;
+
+ CVolumeName seqName;
+
+ UInt64 totalBytes = 0;
+ UInt64 curBytes = 0;
+
+ if (openCallback)
+ {
+ openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
+ openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ }
+
+ for (;;)
+ {
+ CMyComPtr<IInStream> inStream;
+ if (!_archives.IsEmpty())
+ {
+ if (!openVolumeCallback)
+ break;
+
+ if (_archives.Size() == 1)
+ {
+ if (!_archiveInfo.IsVolume())
+ break;
+ UString baseName;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
+ if (prop.vt != VT_BSTR)
+ break;
+ baseName = prop.bstrVal;
+ }
+ seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName());
+ }
+
+ UString fullName = seqName.GetNextName();
+ HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
+ if (result == S_FALSE)
+ break;
+ if (result != S_OK)
+ return result;
+ if (!stream)
+ break;
+ }
+ else
+ inStream = stream;
+
+ UInt64 endPos = 0;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ if (openCallback)
+ {
+ totalBytes += endPos;
+ RINOK(openCallback->SetTotal(NULL, &totalBytes));
+ }
+
+ NArchive::NRar::CInArchive archive;
+ RINOK(archive.Open(inStream, maxCheckStartPosition));
+
+ if (_archives.IsEmpty())
+ archive.GetArchiveInfo(_archiveInfo);
+
+ CItemEx item;
+ for (;;)
+ {
+ if (archive.m_Position > endPos)
+ {
+ AddErrorMessage("Unexpected end of archive");
+ break;
+ }
+ bool decryptionError;
+ AString errorMessageLoc;
+ HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError, errorMessageLoc);
+ if (errorMessageLoc)
+ AddErrorMessage(errorMessageLoc);
+ if (result == S_FALSE)
+ {
+ if (decryptionError && _items.IsEmpty())
+ return S_FALSE;
+ break;
+ }
+ RINOK(result);
+ if (item.IgnoreItem())
+ continue;
+
+ bool needAdd = true;
+ if (item.IsSplitBefore())
+ {
+ if (!_refItems.IsEmpty())
+ {
+ CRefItem &refItem = _refItems.Back();
+ refItem.NumItems++;
+ needAdd = false;
+ }
+ }
+ if (needAdd)
+ {
+ CRefItem refItem;
+ refItem.ItemIndex = _items.Size();
+ refItem.NumItems = 1;
+ refItem.VolumeIndex = _archives.Size();
+ _refItems.Add(refItem);
+ }
+ _items.Add(item);
+ if (openCallback && _items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = curBytes + item.Position;
+ RINOK(openCallback->SetCompleted(&numFiles, &numBytes));
+ }
+ }
+ curBytes += endPos;
+ _archives.Add(archive);
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback)
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ HRESULT res = Open2(stream, maxCheckStartPosition, openCallback);
+ if (res != S_OK)
+ Close();
+ return res;
+ }
+ catch(const CInArchiveException &) { Close(); return S_FALSE; }
+ catch(...) { Close(); throw; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ COM_TRY_BEGIN
+ _errorMessage.Empty();
+ _refItems.Clear();
+ _items.Clear();
+ _archives.Clear();
+ return S_OK;
+ COM_TRY_END
+}
+
+struct CMethodItem
+{
+ Byte RarUnPackVersion;
+ CMyComPtr<ICompressCoder> Coder;
+};
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ UInt64 censoredTotalUnPacked = 0,
+ // censoredTotalPacked = 0,
+ importantTotalUnPacked = 0;
+ // importantTotalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _refItems.Size();
+ if (numItems == 0)
+ return S_OK;
+ int lastIndex = 0;
+ CRecordVector<int> importantIndexes;
+ CRecordVector<bool> extractStatuses;
+
+ for (UInt32 t = 0; t < numItems; t++)
+ {
+ int index = allFilesMode ? t : indices[t];
+ const CRefItem &refItem = _refItems[index];
+ const CItemEx &item = _items[refItem.ItemIndex];
+ censoredTotalUnPacked += item.Size;
+ // censoredTotalPacked += item.PackSize;
+ int j;
+ for (j = lastIndex; j <= index; j++)
+ // if (!_items[_refItems[j].ItemIndex].IsSolid())
+ if (!IsSolid(j))
+ lastIndex = j;
+ for (j = lastIndex; j <= index; j++)
+ {
+ const CRefItem &refItem = _refItems[j];
+ const CItemEx &item = _items[refItem.ItemIndex];
+
+ // const CItemEx &item = _items[j];
+
+ importantTotalUnPacked += item.Size;
+ // importantTotalPacked += item.PackSize;
+ importantIndexes.Add(j);
+ extractStatuses.Add(j == index);
+ }
+ lastIndex = index + 1;
+ }
+
+ RINOK(extractCallback->SetTotal(importantTotalUnPacked));
+ UInt64 currentImportantTotalUnPacked = 0;
+ UInt64 currentImportantTotalPacked = 0;
+ UInt64 currentUnPackSize, currentPackSize;
+
+ CObjectVector<CMethodItem> methodItems;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CFilterCoder *filterStreamSpec = new CFilterCoder;
+ CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
+
+ NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL;
+ CMyComPtr<ICompressFilter> rar20CryptoDecoder;
+ NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL;
+ CMyComPtr<ICompressFilter> rar29CryptoDecoder;
+
+ CFolderInStream *folderInStreamSpec = NULL;
+ CMyComPtr<ISequentialInStream> folderInStream;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ bool solidStart = true;
+ for (int i = 0; i < importantIndexes.Size(); i++,
+ currentImportantTotalUnPacked += currentUnPackSize,
+ currentImportantTotalPacked += currentPackSize)
+ {
+ lps->InSize = currentImportantTotalPacked;
+ lps->OutSize = currentImportantTotalUnPacked;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+
+ Int32 askMode;
+ if (extractStatuses[i])
+ askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ else
+ askMode = NExtract::NAskMode::kSkip;
+
+ UInt32 index = importantIndexes[i];
+
+ const CRefItem &refItem = _refItems[index];
+ const CItemEx &item = _items[refItem.ItemIndex];
+
+ currentUnPackSize = item.Size;
+
+ currentPackSize = GetPackSize(index);
+
+ if (item.IgnoreItem())
+ continue;
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (!IsSolid(index))
+ solidStart = true;
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ bool mustBeProcessedAnywhere = false;
+ if (i < importantIndexes.Size() - 1)
+ {
+ // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];
+ // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex];
+ // mustBeProcessedAnywhere = nextItemInfo.IsSolid();
+ mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);
+ }
+
+ if (!mustBeProcessedAnywhere && !testMode && !realOutStream)
+ continue;
+
+ if (!realOutStream && !testMode)
+ askMode = NExtract::NAskMode::kSkip;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ /*
+ for (int partIndex = 0; partIndex < 1; partIndex++)
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+
+ // item redefinition
+ const CItemEx &item = _items[refItem.ItemIndex + partIndex];
+
+ NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex];
+
+ inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),
+ item.PackSize));
+ */
+ if (!folderInStream)
+ {
+ folderInStreamSpec = new CFolderInStream;
+ folderInStream = folderInStreamSpec;
+ }
+
+ folderInStreamSpec->Init(&_archives, &_items, refItem);
+
+ UInt64 packSize = currentPackSize;
+
+ // packedPos += item.PackSize;
+ // unpackedPos += 0;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ if (item.IsEncrypted())
+ {
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ if (item.UnPackVersion >= 29)
+ {
+ if (!rar29CryptoDecoder)
+ {
+ rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;
+ rar29CryptoDecoder = rar29CryptoDecoderSpec;
+ // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder));
+ }
+ rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
+ CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
+ RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
+ &cryptoProperties));
+ RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
+ filterStreamSpec->Filter = rar29CryptoDecoder;
+ }
+ else if (item.UnPackVersion >= 20)
+ {
+ if (!rar20CryptoDecoder)
+ {
+ rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;
+ rar20CryptoDecoder = rar20CryptoDecoderSpec;
+ // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder));
+ }
+ filterStreamSpec->Filter = rar20CryptoDecoder;
+ }
+ else
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword,
+ &cryptoSetPassword));
+
+ if (!getTextPassword)
+ extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password));
+ if (item.UnPackVersion >= 29)
+ {
+ CByteBuffer buffer;
+ UString unicodePassword(password);
+ const UInt32 sizeInBytes = unicodePassword.Length() * 2;
+ buffer.SetCapacity(sizeInBytes);
+ for (int i = 0; i < unicodePassword.Length(); i++)
+ {
+ wchar_t c = unicodePassword[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+ RINOK(cryptoSetPassword->CryptoSetPassword(
+ (const Byte *)buffer, sizeInBytes));
+ }
+ else
+ {
+ AString oemPassword = UnicodeStringToMultiByte(
+ (const wchar_t *)password, CP_OEMCP);
+ RINOK(cryptoSetPassword->CryptoSetPassword(
+ (const Byte *)(const char *)oemPassword, oemPassword.Length()));
+ }
+ }
+ else
+ {
+ RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
+ }
+ filterStreamSpec->SetInStream(folderInStream);
+ inStream = filterStream;
+ }
+ else
+ {
+ inStream = folderInStream;
+ }
+ CMyComPtr<ICompressCoder> commonCoder;
+ switch(item.Method)
+ {
+ case '0':
+ {
+ commonCoder = copyCoder;
+ break;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ {
+ /*
+ if (item.UnPackVersion >= 29)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ */
+ int m;
+ for (m = 0; m < methodItems.Size(); m++)
+ if (methodItems[m].RarUnPackVersion == item.UnPackVersion)
+ break;
+ if (m == methodItems.Size())
+ {
+ CMethodItem mi;
+ mi.RarUnPackVersion = item.UnPackVersion;
+
+ mi.Coder.Release();
+ if (item.UnPackVersion <= 30)
+ {
+ UInt32 methodID = 0x040300;
+ if (item.UnPackVersion < 20)
+ methodID += 1;
+ else if (item.UnPackVersion < 29)
+ methodID += 2;
+ else
+ methodID += 3;
+ RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, mi.Coder, false));
+ }
+
+ if (mi.Coder == 0)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+
+ m = methodItems.Add(mi);
+ }
+ CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder;
+
+ CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
+ RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,
+ &compressSetDecoderProperties));
+
+ Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
+ if (solidStart)
+ {
+ isSolid = false;
+ solidStart = false;
+ }
+
+
+ RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1));
+
+ commonCoder = decoder;
+ break;
+ }
+ default:
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ continue;
+ }
+ HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress);
+ if (item.IsEncrypted())
+ filterStreamSpec->ReleaseInStream();
+ if (result == S_FALSE)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
+ continue;
+ }
+ if (result != S_OK)
+ return result;
+
+ /*
+ if (refItem.NumItems == 1 &&
+ !item.IsSplitBefore() && !item.IsSplitAfter())
+ */
+ {
+ const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
+ bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(crcOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError));
+ }
+ /*
+ else
+ {
+ bool crcOK = true;
+ for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++)
+ {
+ const CItemEx &item = _items[refItem.ItemIndex + partIndex];
+ if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])
+ {
+ crcOK = false;
+ break;
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(crcOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError));
+ }
+ */
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.h
new file mode 100644
index 000000000..792668273
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHandler.h
@@ -0,0 +1,66 @@
+// Rar/Handler.h
+
+#ifndef __RAR_HANDLER_H
+#define __RAR_HANDLER_H
+
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "RarIn.h"
+#include "RarVolumeInStream.h"
+
+namespace NArchive {
+namespace NRar {
+
+class CHandler:
+ public IInArchive,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+ CRecordVector<CRefItem> _refItems;
+ CObjectVector<CItemEx> _items;
+ CObjectVector<CInArchive> _archives;
+ NArchive::NRar::CInArchiveInfo _archiveInfo;
+ AString _errorMessage;
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ UInt64 GetPackSize(int refIndex) const;
+
+ bool IsSolid(int refIndex)
+ {
+ const CItemEx &item = _items[_refItems[refIndex].ItemIndex];
+ if (item.UnPackVersion < 20)
+ {
+ if (_archiveInfo.IsSolid())
+ return (refIndex > 0);
+ return false;
+ }
+ return item.IsSolid();
+ }
+ void AddErrorMessage(const AString &s)
+ {
+ if (!_errorMessage.IsEmpty())
+ _errorMessage += '\n';
+ _errorMessage += s;
+ }
+
+ HRESULT Open2(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+
+ DECL_ISetCompressCodecsInfo
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.cpp
new file mode 100644
index 000000000..94481e025
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.cpp
@@ -0,0 +1,21 @@
+// Archive/Rar/Headers.cpp
+
+#include "StdAfx.h"
+
+#include "RarHeader.h"
+
+namespace NArchive{
+namespace NRar{
+namespace NHeader{
+
+Byte kMarker[kMarkerSize] = {0x52 + 1, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
+
+class CMarkerInitializer
+{
+public:
+ CMarkerInitializer() { kMarker[0]--; };
+};
+
+static CMarkerInitializer markerInitializer;
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.h
new file mode 100644
index 000000000..5c21a2ac0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarHeader.h
@@ -0,0 +1,205 @@
+// Archive/RarHeader.h
+
+#ifndef __ARCHIVE_RAR_HEADER_H
+#define __ARCHIVE_RAR_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NRar {
+namespace NHeader {
+
+const int kMarkerSize = 7;
+extern Byte kMarker[kMarkerSize];
+
+const int kArchiveSolid = 0x1;
+
+namespace NBlockType
+{
+ enum EBlockType
+ {
+ kMarker = 0x72,
+ kArchiveHeader,
+ kFileHeader,
+ kCommentHeader,
+ kOldAuthenticity,
+ kOldSubBlock,
+ kRecoveryRecord,
+ kAuthenticity,
+ kSubBlock,
+ kEndOfArchive
+ };
+}
+
+namespace NArchive
+{
+ const UInt16 kVolume = 1;
+ const UInt16 kComment = 2;
+ const UInt16 kLock = 4;
+ const UInt16 kSolid = 8;
+ const UInt16 kNewVolName = 0x10; // ('volname.partN.rar')
+ const UInt16 kAuthenticity = 0x20;
+ const UInt16 kRecovery = 0x40;
+ const UInt16 kBlockEncryption = 0x80;
+ const UInt16 kFirstVolume = 0x100; // (set only by RAR 3.0 and later)
+ const UInt16 kEncryptVer = 0x200; // RAR 3.6 there is EncryptVer Byte in End of MainHeader
+
+ const int kHeaderSizeMin = 7;
+
+ const int kArchiveHeaderSize = 13;
+
+ const int kBlockHeadersAreEncrypted = 0x80;
+
+}
+
+namespace NFile
+{
+ const int kSplitBefore = 1 << 0;
+ const int kSplitAfter = 1 << 1;
+ const int kEncrypted = 1 << 2;
+ const int kComment = 1 << 3;
+ const int kSolid = 1 << 4;
+
+ const int kDictBitStart = 5;
+ const int kNumDictBits = 3;
+ const int kDictMask = (1 << kNumDictBits) - 1;
+ const int kDictDirectoryValue = 0x7;
+
+ const int kSize64Bits = 1 << 8;
+ const int kUnicodeName = 1 << 9;
+ const int kSalt = 1 << 10;
+ const int kOldVersion = 1 << 11;
+ const int kExtTime = 1 << 12;
+ // const int kExtFlags = 1 << 13;
+ // const int kSkipIfUnknown = 1 << 14;
+
+ const int kLongBlock = 1 << 15;
+
+ /*
+ struct CBlock
+ {
+ // UInt16 HeadCRC;
+ // Byte Type;
+ // UInt16 Flags;
+ // UInt16 HeadSize;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ };
+ */
+
+ /*
+ struct CBlock32
+ {
+ UInt16 HeadCRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ UInt16 GetRealCRC(const void *aName, UInt32 aNameSize,
+ bool anExtraDataDefined = false, Byte *anExtraData = 0) const;
+ };
+ struct CBlock64
+ {
+ UInt16 HeadCRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 PackSizeLow;
+ UInt32 UnPackSizeLow;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ UInt32 PackSizeHigh;
+ UInt32 UnPackSizeHigh;
+ UInt16 GetRealCRC(const void *aName, UInt32 aNameSize) const;
+ };
+ */
+
+ const int kLabelFileAttribute = 0x08;
+ const int kWinFileDirectoryAttributeMask = 0x10;
+
+ enum CHostOS
+ {
+ kHostMSDOS = 0,
+ kHostOS2 = 1,
+ kHostWin32 = 2,
+ kHostUnix = 3,
+ kHostMacOS = 4,
+ kHostBeOS = 5
+ };
+}
+
+namespace NBlock
+{
+ const UInt16 kLongBlock = 1 << 15;
+ struct CBlock
+ {
+ UInt16 CRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ // UInt32 DataSize;
+ };
+}
+
+/*
+struct CSubBlock
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 DataSize;
+ UInt16 SubType;
+ Byte Level; // Reserved : Must be 0
+};
+
+struct CCommentBlock
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt16 UnpSize;
+ Byte UnpVer;
+ Byte Method;
+ UInt16 CommCRC;
+};
+
+
+struct CProtectHeader
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 DataSize;
+ Byte Version;
+ UInt16 RecSectors;
+ UInt32 TotalBlocks;
+ Byte Mark[8];
+};
+*/
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.cpp
new file mode 100644
index 000000000..e4c23752c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.cpp
@@ -0,0 +1,478 @@
+// Archive/RarIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "Common/StringConvert.h"
+#include "Common/UTFConvert.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/FindSignature.h"
+
+#include "RarIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NRar {
+
+static const char *k_UnexpectedEnd = "Unexpected end of archive";
+static const char *k_DecryptionError = "Decryption Error";
+
+void CInArchive::ThrowExceptionWithCode(
+ CInArchiveException::CCauseType cause)
+{
+ throw CInArchiveException(cause);
+}
+
+HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit)
+{
+ try
+ {
+ Close();
+ HRESULT res = Open2(inStream, searchHeaderSizeLimit);
+ if (res == S_OK)
+ return res;
+ Close();
+ return res;
+ }
+ catch(...) { Close(); throw; }
+}
+
+void CInArchive::Close()
+{
+ m_Stream.Release();
+}
+
+HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize)
+{
+ if (m_CryptoMode)
+ {
+ size_t size = *resSize;
+ *resSize = 0;
+ const Byte *bufData = m_DecryptedDataAligned;
+ UInt32 bufSize = m_DecryptedDataSize;
+ size_t i;
+ for (i = 0; i < size && m_CryptoPos < bufSize; i++)
+ ((Byte *)data)[i] = bufData[m_CryptoPos++];
+ *resSize = i;
+ return S_OK;
+ }
+ return ReadStream(m_Stream, data, resSize);
+}
+
+bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
+{
+ size_t processed = size;
+ if (ReadBytesSpec(data, &processed) != S_OK)
+ return false;
+ return processed == size;
+}
+
+HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ m_CryptoMode = false;
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition));
+ m_Position = m_StreamStartPosition;
+
+ UInt64 arcStartPos;
+ RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize,
+ searchHeaderSizeLimit, arcStartPos));
+ m_Position = arcStartPos + NHeader::kMarkerSize;
+ RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
+ Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1];
+
+ RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize));
+ AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize);
+
+
+ UInt32 blockSize = Get16(buf + 5);
+
+ _header.EncryptVersion = 0;
+ _header.Flags = Get16(buf + 3);
+
+ UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize;
+ if (_header.IsThereEncryptVer())
+ {
+ if (blockSize <= headerSize)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1));
+ AddToSeekValue(1);
+ _header.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize];
+ headerSize += 1;
+ }
+ if (blockSize < headerSize ||
+ buf[2] != NHeader::NBlockType::kArchiveHeader ||
+ (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF))
+ return S_FALSE;
+
+ size_t commentSize = blockSize - headerSize;
+ _comment.SetCapacity(commentSize);
+ RINOK(ReadStream_FALSE(stream, _comment, commentSize));
+ AddToSeekValue(commentSize);
+ m_Stream = stream;
+ _header.StartPosition = arcStartPos;
+ return S_OK;
+}
+
+void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const
+{
+ archiveInfo = _header;
+}
+
+static void DecodeUnicodeFileName(const char *name, const Byte *encName,
+ int encSize, wchar_t *unicodeName, int maxDecSize)
+{
+ int encPos = 0;
+ int decPos = 0;
+ int flagBits = 0;
+ Byte flags = 0;
+ Byte highByte = encName[encPos++];
+ while (encPos < encSize && decPos < maxDecSize)
+ {
+ if (flagBits == 0)
+ {
+ flags = encName[encPos++];
+ flagBits = 8;
+ }
+ switch(flags >> 6)
+ {
+ case 0:
+ unicodeName[decPos++] = encName[encPos++];
+ break;
+ case 1:
+ unicodeName[decPos++] = (wchar_t)(encName[encPos++] + (highByte << 8));
+ break;
+ case 2:
+ unicodeName[decPos++] = (wchar_t)(encName[encPos] + (encName[encPos + 1] << 8));
+ encPos += 2;
+ break;
+ case 3:
+ {
+ int length = encName[encPos++];
+ if (length & 0x80)
+ {
+ Byte correction = encName[encPos++];
+ for (length = (length & 0x7f) + 2;
+ length > 0 && decPos < maxDecSize; length--, decPos++)
+ unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8));
+ }
+ else
+ for (length += 2; length > 0 && decPos < maxDecSize; length--, decPos++)
+ unicodeName[decPos] = name[decPos];
+ }
+ break;
+ }
+ flags <<= 2;
+ flagBits -= 2;
+ }
+ unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0;
+}
+
+void CInArchive::ReadName(CItemEx &item, int nameSize)
+{
+ item.UnicodeName.Empty();
+ if (nameSize > 0)
+ {
+ m_NameBuffer.EnsureCapacity(nameSize + 1);
+ char *buffer = (char *)m_NameBuffer;
+
+ for (int i = 0; i < nameSize; i++)
+ buffer[i] = ReadByte();
+
+ int mainLen;
+ for (mainLen = 0; mainLen < nameSize; mainLen++)
+ if (buffer[mainLen] == '\0')
+ break;
+ buffer[mainLen] = '\0';
+ item.Name = buffer;
+
+ if(item.HasUnicodeName())
+ {
+ if(mainLen < nameSize)
+ {
+ int unicodeNameSizeMax = MyMin(nameSize, (0x400));
+ _unicodeNameBuffer.EnsureCapacity(unicodeNameSizeMax + 1);
+ DecodeUnicodeFileName(buffer, (const Byte *)buffer + mainLen + 1,
+ nameSize - (mainLen + 1), _unicodeNameBuffer, unicodeNameSizeMax);
+ item.UnicodeName = _unicodeNameBuffer;
+ }
+ else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName))
+ item.UnicodeName.Empty();
+ }
+ }
+ else
+ item.Name.Empty();
+}
+
+Byte CInArchive::ReadByte()
+{
+ if (m_CurPos >= m_PosLimit)
+ throw CInArchiveException(CInArchiveException::kIncorrectArchive);
+ return m_CurData[m_CurPos++];
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ UInt16 value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = ReadByte();
+ value |= (UInt16(b) << (8 * i));
+ }
+ return value;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ UInt32 value = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b = ReadByte();
+ value |= (UInt32(b) << (8 * i));
+ }
+ return value;
+}
+
+void CInArchive::ReadTime(Byte mask, CRarTime &rarTime)
+{
+ rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
+ int numDigits = (mask & 3);
+ rarTime.SubTime[0] = rarTime.SubTime[1] = rarTime.SubTime[2] = 0;
+ for (int i = 0; i < numDigits; i++)
+ rarTime.SubTime[3 - numDigits + i] = ReadByte();
+}
+
+void CInArchive::ReadHeaderReal(CItemEx &item)
+{
+ item.Flags = m_BlockHeader.Flags;
+ item.PackSize = ReadUInt32();
+ item.Size = ReadUInt32();
+ item.HostOS = ReadByte();
+ item.FileCRC = ReadUInt32();
+ item.MTime.DosTime = ReadUInt32();
+ item.UnPackVersion = ReadByte();
+ item.Method = ReadByte();
+ int nameSize = ReadUInt16();
+ item.Attrib = ReadUInt32();
+
+ item.MTime.LowSecond = 0;
+ item.MTime.SubTime[0] =
+ item.MTime.SubTime[1] =
+ item.MTime.SubTime[2] = 0;
+
+ if((item.Flags & NHeader::NFile::kSize64Bits) != 0)
+ {
+ item.PackSize |= ((UInt64)ReadUInt32() << 32);
+ item.Size |= ((UInt64)ReadUInt32() << 32);
+ }
+
+ ReadName(item, nameSize);
+
+ if (item.HasSalt())
+ for (int i = 0; i < sizeof(item.Salt); i++)
+ item.Salt[i] = ReadByte();
+
+ // some rar archives have HasExtTime flag without field.
+ if (m_CurPos < m_PosLimit && item.HasExtTime())
+ {
+ Byte accessMask = (Byte)(ReadByte() >> 4);
+ Byte b = ReadByte();
+ Byte modifMask = (Byte)(b >> 4);
+ Byte createMask = (Byte)(b & 0xF);
+ if ((modifMask & 8) != 0)
+ ReadTime(modifMask, item.MTime);
+ item.CTimeDefined = ((createMask & 8) != 0);
+ if (item.CTimeDefined)
+ {
+ item.CTime.DosTime = ReadUInt32();
+ ReadTime(createMask, item.CTime);
+ }
+ item.ATimeDefined = ((accessMask & 8) != 0);
+ if (item.ATimeDefined)
+ {
+ item.ATime.DosTime = ReadUInt32();
+ ReadTime(accessMask, item.ATime);
+ }
+ }
+
+ UInt16 fileHeaderWithNameSize = (UInt16)m_CurPos;
+
+ item.Position = m_Position;
+ item.MainPartSize = fileHeaderWithNameSize;
+ item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize);
+
+ if (m_CryptoMode)
+ item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF);
+ else
+ item.AlignSize = 0;
+ AddToSeekValue(m_BlockHeader.HeadSize);
+}
+
+void CInArchive::AddToSeekValue(UInt64 addValue)
+{
+ m_Position += addValue;
+}
+
+HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage)
+{
+ decryptionError = false;
+ for (;;)
+ {
+ SeekInArchive(m_Position);
+ if (!m_CryptoMode && (_header.Flags &
+ NHeader::NArchive::kBlockHeadersAreEncrypted) != 0)
+ {
+ m_CryptoMode = false;
+ if (getTextPassword == 0)
+ return S_FALSE;
+ if (!m_RarAES)
+ {
+ m_RarAESSpec = new NCrypto::NRar29::CDecoder;
+ m_RarAES = m_RarAESSpec;
+ }
+ m_RarAESSpec->SetRar350Mode(_header.IsEncryptOld());
+
+ // Salt
+ const UInt32 kSaltSize = 8;
+ Byte salt[kSaltSize];
+ if(!ReadBytesAndTestSize(salt, kSaltSize))
+ return S_FALSE;
+ m_Position += kSaltSize;
+ RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize))
+ // Password
+ CMyComBSTR password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password))
+ UString unicodePassword(password);
+
+ CByteBuffer buffer;
+ const UInt32 sizeInBytes = unicodePassword.Length() * 2;
+ buffer.SetCapacity(sizeInBytes);
+ for (int i = 0; i < unicodePassword.Length(); i++)
+ {
+ wchar_t c = unicodePassword[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+
+ RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
+
+ const UInt32 kDecryptedBufferSize = (1 << 12);
+ if (m_DecryptedData.GetCapacity() == 0)
+ {
+ const UInt32 kAlign = 16;
+ m_DecryptedData.SetCapacity(kDecryptedBufferSize + kAlign);
+ m_DecryptedDataAligned = (Byte *)((ptrdiff_t)((Byte *)m_DecryptedData + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
+ }
+ RINOK(m_RarAES->Init());
+ size_t decryptedDataSizeT = kDecryptedBufferSize;
+ RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT));
+ m_DecryptedDataSize = (UInt32)decryptedDataSizeT;
+ m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize);
+
+ m_CryptoMode = true;
+ m_CryptoPos = 0;
+ }
+
+ m_FileHeaderData.EnsureCapacity(7);
+ size_t processed = 7;
+ RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed));
+ if (processed != 7)
+ {
+ if (processed != 0)
+ errorMessage = k_UnexpectedEnd;
+ return S_FALSE;
+ }
+
+ m_CurData = (Byte *)m_FileHeaderData;
+ m_CurPos = 0;
+ m_PosLimit = 7;
+ m_BlockHeader.CRC = ReadUInt16();
+ m_BlockHeader.Type = ReadByte();
+ m_BlockHeader.Flags = ReadUInt16();
+ m_BlockHeader.HeadSize = ReadUInt16();
+
+ if (m_BlockHeader.HeadSize < 7)
+ ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive);
+
+ if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive)
+ return S_FALSE;
+
+ if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader)
+ {
+ m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize);
+ m_CurData = (Byte *)m_FileHeaderData;
+ m_PosLimit = m_BlockHeader.HeadSize;
+ if (!ReadBytesAndTestSize(m_CurData + m_CurPos, m_BlockHeader.HeadSize - 7))
+ {
+ errorMessage = k_UnexpectedEnd;
+ return S_FALSE;
+ }
+
+ ReadHeaderReal(item);
+ if ((CrcCalc(m_CurData + 2,
+ m_BlockHeader.HeadSize - item.CommentSize - 2) & 0xFFFF) != m_BlockHeader.CRC)
+ ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError);
+
+ FinishCryptoBlock();
+ m_CryptoMode = false;
+ SeekInArchive(m_Position); // Move Position to compressed Data;
+ AddToSeekValue(item.PackSize); // m_Position points to next header;
+ return S_OK;
+ }
+ if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10))
+ {
+ decryptionError = true;
+ errorMessage = k_DecryptionError;
+ return S_FALSE;
+ }
+ if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0)
+ {
+ m_FileHeaderData.EnsureCapacity(7 + 4);
+ m_CurData = (Byte *)m_FileHeaderData;
+ if (!ReadBytesAndTestSize(m_CurData + m_CurPos, 4))
+ {
+ errorMessage = k_UnexpectedEnd;
+ return S_FALSE;
+ }
+ m_PosLimit = 7 + 4;
+ UInt32 dataSize = ReadUInt32();
+ AddToSeekValue(dataSize);
+ if (m_CryptoMode && dataSize > (1 << 27))
+ {
+ decryptionError = true;
+ errorMessage = k_DecryptionError;
+ return S_FALSE;
+ }
+ m_CryptoPos = m_BlockHeader.HeadSize;
+ }
+ else
+ m_CryptoPos = 0;
+ AddToSeekValue(m_BlockHeader.HeadSize);
+ FinishCryptoBlock();
+ m_CryptoMode = false;
+ }
+}
+
+void CInArchive::SeekInArchive(UInt64 position)
+{
+ m_Stream->Seek(position, STREAM_SEEK_SET, NULL);
+}
+
+ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
+{
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ SeekInArchive(position);
+ streamSpec->SetStream(m_Stream);
+ streamSpec->Init(size);
+ return inStream.Detach();
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.h
new file mode 100644
index 000000000..a6998db26
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarIn.h
@@ -0,0 +1,123 @@
+// RarIn.h
+
+#ifndef __ARCHIVE_RAR_IN_H
+#define __ARCHIVE_RAR_IN_H
+
+#include "Common/DynamicBuffer.h"
+#include "Common/MyCom.h"
+
+#include "../../ICoder.h"
+#include "../../IStream.h"
+
+#include "../../Common/StreamObjects.h"
+
+#include "../../Crypto/RarAes.h"
+
+#include "RarHeader.h"
+#include "RarItem.h"
+
+namespace NArchive {
+namespace NRar {
+
+class CInArchiveException
+{
+public:
+ enum CCauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kArchiveHeaderCRCError,
+ kFileHeaderCRCError,
+ kIncorrectArchive
+ }
+ Cause;
+ CInArchiveException(CCauseType cause) : Cause(cause) {}
+};
+
+
+struct CInArchiveInfo
+{
+ UInt32 Flags;
+ Byte EncryptVersion;
+ UInt64 StartPosition;
+
+ bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; }
+ bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; }
+ bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; }
+ bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; }
+ bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; }
+ bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; }
+ bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); }
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+
+ UInt64 m_StreamStartPosition;
+
+ CInArchiveInfo _header;
+ CDynamicBuffer<char> m_NameBuffer;
+ CDynamicBuffer<wchar_t> _unicodeNameBuffer;
+
+ CByteBuffer _comment;
+
+ void ReadName(CItemEx &item, int nameSize);
+ void ReadHeaderReal(CItemEx &item);
+
+ HRESULT ReadBytesSpec(void *data, size_t *size);
+ bool ReadBytesAndTestSize(void *data, UInt32 size);
+
+ HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+
+ void ThrowExceptionWithCode(CInArchiveException::CCauseType cause);
+ void ThrowUnexpectedEndOfArchiveException();
+
+ void AddToSeekValue(UInt64 addValue);
+
+ CDynamicBuffer<Byte> m_FileHeaderData;
+
+ NHeader::NBlock::CBlock m_BlockHeader;
+
+ NCrypto::NRar29::CDecoder *m_RarAESSpec;
+ CMyComPtr<ICompressFilter> m_RarAES;
+
+ Byte *m_CurData; // it must point to start of Rar::Block
+ UInt32 m_CurPos;
+ UInt32 m_PosLimit;
+ Byte ReadByte();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ void ReadTime(Byte mask, CRarTime &rarTime);
+
+ CBuffer<Byte> m_DecryptedData;
+ Byte *m_DecryptedDataAligned;
+ UInt32 m_DecryptedDataSize;
+
+ bool m_CryptoMode;
+ UInt32 m_CryptoPos;
+ void FinishCryptoBlock()
+ {
+ if (m_CryptoMode)
+ while ((m_CryptoPos & 0xF) != 0)
+ {
+ m_CryptoPos++;
+ m_Position++;
+ }
+ }
+
+public:
+ UInt64 m_Position;
+
+ HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit);
+ void Close();
+ HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage);
+
+ void GetArchiveInfo(CInArchiveInfo &archiveInfo) const;
+
+ void SeekInArchive(UInt64 position);
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.cpp
new file mode 100644
index 000000000..9216ae57b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.cpp
@@ -0,0 +1,55 @@
+// RarItem.cpp
+
+#include "StdAfx.h"
+
+#include "RarItem.h"
+
+namespace NArchive{
+namespace NRar{
+
+bool CItem::IgnoreItem() const
+{
+ switch(HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0);
+ }
+ return false;
+}
+
+bool CItem::IsDir() const
+{
+ if (GetDictSize() == NHeader::NFile::kDictDirectoryValue)
+ return true;
+ switch(HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ return true;
+ }
+ return false;
+}
+
+UInt32 CItem::GetWinAttributes() const
+{
+ UInt32 winAttributes;
+ switch(HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ winAttributes = Attrib;
+ break;
+ default:
+ winAttributes = 0; // must be converted from unix value;
+ }
+ if (IsDir())
+ winAttributes |= NHeader::NFile::kWinFileDirectoryAttributeMask;
+ return winAttributes;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.h
new file mode 100644
index 000000000..4aa4d8667
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarItem.h
@@ -0,0 +1,79 @@
+// RarItem.h
+
+#ifndef __ARCHIVE_RAR_ITEM_H
+#define __ARCHIVE_RAR_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+
+#include "RarHeader.h"
+
+namespace NArchive{
+namespace NRar{
+
+struct CRarTime
+{
+ UInt32 DosTime;
+ Byte LowSecond;
+ Byte SubTime[3];
+};
+
+struct CItem
+{
+ UInt64 Size;
+ UInt64 PackSize;
+
+ CRarTime CTime;
+ CRarTime ATime;
+ CRarTime MTime;
+
+ UInt32 FileCRC;
+ UInt32 Attrib;
+
+ UInt16 Flags;
+ Byte HostOS;
+ Byte UnPackVersion;
+ Byte Method;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+
+ AString Name;
+ UString UnicodeName;
+
+ Byte Salt[8];
+
+ bool IsEncrypted() const { return (Flags & NHeader::NFile::kEncrypted) != 0; }
+ bool IsSolid() const { return (Flags & NHeader::NFile::kSolid) != 0; }
+ bool IsCommented() const { return (Flags & NHeader::NFile::kComment) != 0; }
+ bool IsSplitBefore() const { return (Flags & NHeader::NFile::kSplitBefore) != 0; }
+ bool IsSplitAfter() const { return (Flags & NHeader::NFile::kSplitAfter) != 0; }
+ bool HasSalt() const { return (Flags & NHeader::NFile::kSalt) != 0; }
+ bool HasExtTime() const { return (Flags & NHeader::NFile::kExtTime) != 0; }
+ bool HasUnicodeName()const { return (Flags & NHeader::NFile::kUnicodeName) != 0; }
+ bool IsOldVersion() const { return (Flags & NHeader::NFile::kOldVersion) != 0; }
+
+ UInt32 GetDictSize() const { return (Flags >> NHeader::NFile::kDictBitStart) & NHeader::NFile::kDictMask; }
+ bool IsDir() const;
+ bool IgnoreItem() const;
+ UInt32 GetWinAttributes() const;
+
+ CItem(): CTimeDefined(false), ATimeDefined(false) {}
+};
+
+class CItemEx: public CItem
+{
+public:
+ UInt64 Position;
+ UInt16 MainPartSize;
+ UInt16 CommentSize;
+ UInt16 AlignSize;
+ UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; };
+ // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; };
+ UInt64 GetCommentPosition() const { return Position + MainPartSize; };
+ UInt64 GetDataPosition() const { return GetCommentPosition() + CommentSize + AlignSize; };
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarRegister.cpp
new file mode 100644
index 000000000..2bcf569ef
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarRegister.cpp
@@ -0,0 +1,13 @@
+// RarRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "RarHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NRar::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Rar", L"rar r00", 0, 3, {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}, 7, false, CreateArc, 0, };
+
+REGISTER_ARC(Rar)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp
new file mode 100644
index 000000000..25194f915
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp
@@ -0,0 +1,78 @@
+// RarVolumeInStream.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "RarVolumeInStream.h"
+
+namespace NArchive {
+namespace NRar {
+
+void CFolderInStream::Init(
+ CObjectVector<CInArchive> *archives,
+ const CObjectVector<CItemEx> *items,
+ const CRefItem &refItem)
+{
+ _archives = archives;
+ _items = items;
+ _refItem = refItem;
+ _curIndex = 0;
+ CRCs.Clear();
+ _fileIsOpen = false;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+ while (_curIndex < _refItem.NumItems)
+ {
+ const CItemEx &item = (*_items)[_refItem.ItemIndex + _curIndex];
+ _stream.Attach((*_archives)[_refItem.VolumeIndex + _curIndex].
+ CreateLimitedStream(item.GetDataPosition(), item.PackSize));
+ _curIndex++;
+ _fileIsOpen = true;
+ _crc = CRC_INIT_VAL;
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT CFolderInStream::CloseStream()
+{
+ CRCs.Add(CRC_GET_DIGEST(_crc));
+ _stream.Release();
+ _fileIsOpen = false;
+ return S_OK;
+}
+
+STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 localProcessedSize;
+ RINOK(_stream->Read(
+ ((Byte *)data) + realProcessedSize, size, &localProcessedSize));
+ _crc = CrcUpdate(_crc, ((Byte *)data) + realProcessedSize, localProcessedSize);
+ if (localProcessedSize == 0)
+ {
+ RINOK(CloseStream());
+ continue;
+ }
+ realProcessedSize += localProcessedSize;
+ size -= localProcessedSize;
+ break;
+ }
+ else
+ {
+ RINOK(OpenStream());
+ }
+ }
+ if (processedSize != 0)
+ *processedSize = realProcessedSize;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.h
new file mode 100644
index 000000000..78d95b10f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/RarVolumeInStream.h
@@ -0,0 +1,49 @@
+// RarVolumeInStream.h
+
+#ifndef __RAR_VOLUME_IN_STREAM_H
+#define __RAR_VOLUME_IN_STREAM_H
+
+#include "../../IStream.h"
+#include "RarIn.h"
+
+namespace NArchive {
+namespace NRar {
+
+struct CRefItem
+{
+ int VolumeIndex;
+ int ItemIndex;
+ int NumItems;
+};
+
+class CFolderInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+private:
+ CObjectVector<CInArchive> *_archives;
+ const CObjectVector<CItemEx> *_items;
+ CRefItem _refItem;
+ int _curIndex;
+ UInt32 _crc;
+ bool _fileIsOpen;
+ CMyComPtr<ISequentialInStream> _stream;
+
+ HRESULT OpenStream();
+ HRESULT CloseStream();
+public:
+ void Init(CObjectVector<CInArchive> *archives,
+ const CObjectVector<CItemEx> *items,
+ const CRefItem &refItem);
+
+ CRecordVector<UInt32> CRCs;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.cpp
new file mode 100644
index 000000000..d0feea85c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.h
new file mode 100644
index 000000000..e7fb6986d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Rar/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/RpmHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/RpmHandler.cpp
new file mode 100644
index 000000000..1d31d4514
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/RpmHandler.cpp
@@ -0,0 +1,292 @@
+// RpmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+using namespace NWindows;
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+
+namespace NArchive {
+namespace NRpm {
+
+/* Reference: lib/signature.h of rpm package */
+#define RPMSIG_NONE 0 /* Do not change! */
+/* The following types are no longer generated */
+#define RPMSIG_PGP262_1024 1 /* No longer generated */ /* 256 byte */
+/* These are the new-style signatures. They are Header structures. */
+/* Inside them we can put any number of any type of signature we like. */
+
+#define RPMSIG_HEADERSIG 5 /* New Header style signature */
+
+const UInt32 kLeadSize = 96;
+struct CLead
+{
+ unsigned char Magic[4];
+ unsigned char Major; // not supported ver1, only support 2,3 and lator
+ unsigned char Minor;
+ UInt16 Type;
+ UInt16 ArchNum;
+ char Name[66];
+ UInt16 OSNum;
+ UInt16 SignatureType;
+ char Reserved[16]; // pad to 96 bytes -- 8 byte aligned
+ bool MagicCheck() const
+ { return Magic[0] == 0xed && Magic[1] == 0xab && Magic[2] == 0xee && Magic[3] == 0xdb; };
+};
+
+const UInt32 kEntryInfoSize = 16;
+/*
+struct CEntryInfo
+{
+ int Tag;
+ int Type;
+ int Offset; // Offset from beginning of data segment, only defined on disk
+ int Count;
+};
+*/
+
+// case: SignatureType == RPMSIG_HEADERSIG
+const UInt32 kCSigHeaderSigSize = 16;
+struct CSigHeaderSig
+{
+ unsigned char Magic[4];
+ UInt32 Reserved;
+ UInt32 IndexLen; // count of index entries
+ UInt32 DataLen; // number of bytes
+ bool MagicCheck()
+ { return Magic[0] == 0x8e && Magic[1] == 0xad && Magic[2] == 0xe8 && Magic[3] == 0x01; };
+ UInt32 GetLostHeaderLen()
+ { return IndexLen * kEntryInfoSize + DataLen; };
+};
+
+static HRESULT RedSigHeaderSig(IInStream *inStream, CSigHeaderSig &h)
+{
+ char dat[kCSigHeaderSigSize];
+ char *cur = dat;
+ RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize));
+ memcpy(h.Magic, cur, 4);
+ cur += 4;
+ cur += 4;
+ h.IndexLen = Get32(cur);
+ cur += 4;
+ h.DataLen = Get32(cur);
+ return S_OK;
+}
+
+HRESULT OpenArchive(IInStream *inStream)
+{
+ UInt64 pos;
+ char leadData[kLeadSize];
+ char *cur = leadData;
+ CLead lead;
+ RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize));
+ memcpy(lead.Magic, cur, 4);
+ cur += 4;
+ lead.Major = *cur++;
+ lead.Minor = *cur++;
+ lead.Type = Get16(cur);
+ cur += 2;
+ lead.ArchNum = Get16(cur);
+ cur += 2;
+ memcpy(lead.Name, cur, sizeof(lead.Name));
+ cur += sizeof(lead.Name);
+ lead.OSNum = Get16(cur);
+ cur += 2;
+ lead.SignatureType = Get16(cur);
+ cur += 2;
+
+ if (!lead.MagicCheck() || lead.Major < 3)
+ return S_FALSE;
+
+ CSigHeaderSig sigHeader, header;
+ if (lead.SignatureType == RPMSIG_NONE)
+ {
+ ;
+ }
+ else if (lead.SignatureType == RPMSIG_PGP262_1024)
+ {
+ UInt64 pos;
+ RINOK(inStream->Seek(256, STREAM_SEEK_CUR, &pos));
+ }
+ else if (lead.SignatureType == RPMSIG_HEADERSIG)
+ {
+ RINOK(RedSigHeaderSig(inStream, sigHeader));
+ if (!sigHeader.MagicCheck())
+ return S_FALSE;
+ UInt32 len = sigHeader.GetLostHeaderLen();
+ RINOK(inStream->Seek(len, STREAM_SEEK_CUR, &pos));
+ if ((pos % 8) != 0)
+ {
+ RINOK(inStream->Seek((pos / 8 + 1) * 8 - pos,
+ STREAM_SEEK_CUR, &pos));
+ }
+ }
+ else
+ return S_FALSE;
+
+ RINOK(RedSigHeaderSig(inStream, header));
+ if (!header.MagicCheck())
+ return S_FALSE;
+ int headerLen = header.GetLostHeaderLen();
+ if (headerLen == -1)
+ return S_FALSE;
+ RINOK(inStream->Seek(headerLen, STREAM_SEEK_CUR, &pos));
+ return S_OK;
+}
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ UInt64 _pos;
+ UInt64 _size;
+ Byte _sig[4];
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID) { case kpidMainSubfile: prop = (UInt32)0; break; }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ if (OpenArchive(inStream) != S_OK)
+ return S_FALSE;
+ RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_pos));
+ RINOK(ReadStream_FALSE(inStream, _sig, sizeof(_sig) / sizeof(_sig[0])));
+ UInt64 endPosition;
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPosition));
+ _size = endPosition - _pos;
+ _stream = inStream;
+ return S_OK;
+ }
+ catch(...) { return S_FALSE; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSize:
+ case kpidPackSize:
+ prop = _size;
+ break;
+ case kpidExtension:
+ {
+ char s[32];
+ MyStringCopy(s, "cpio.");
+ const char *ext;
+ if (_sig[0] == 0x1F && _sig[1] == 0x8B)
+ ext = "gz";
+ else if (_sig[0] == 'B' && _sig[1] == 'Z' && _sig[2] == 'h')
+ ext = "bz2";
+ else
+ ext = "lzma";
+ MyStringCopy(s + MyStringLen(s), ext);
+ prop = s;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ RINOK(extractCallback->SetTotal(_size));
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &outStream, askMode));
+ if (!testMode && !outStream)
+ return S_OK;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ RINOK(_stream->Seek(_pos, STREAM_SEEK_SET, NULL));
+ RINOK(copyCoder->Code(_stream, outStream, NULL, NULL, progress));
+ outStream.Release();
+ return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ return CreateLimitedInStream(_stream, _pos, _size, stream);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NRpm::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Rpm", L"rpm", 0, 0xEB, { 0xED, 0xAB, 0xEE, 0xDB}, 4, false, CreateArc, 0 };
+
+REGISTER_ARC(Rpm)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/SplitHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/SplitHandler.cpp
new file mode 100644
index 000000000..5d84de4ed
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/SplitHandler.cpp
@@ -0,0 +1,366 @@
+// SplitHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/MultiStream.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NSplit {
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidNumVolumes, VT_UI4}
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ UString _subName;
+ CObjectVector<CMyComPtr<IInStream> > _streams;
+ CRecordVector<UInt64> _sizes;
+ UInt64 _totalSize;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidNumVolumes: prop = (UInt32)_streams.Size(); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+struct CSeqName
+{
+ UString _unchangedPart;
+ UString _changedPart;
+ bool _splitStyle;
+
+ UString GetNextName()
+ {
+ UString newName;
+ if (_splitStyle)
+ {
+ int i;
+ int numLetters = _changedPart.Length();
+ for (i = numLetters - 1; i >= 0; i--)
+ {
+ wchar_t c = _changedPart[i];
+ if (c == 'z')
+ {
+ c = 'a';
+ newName = c + newName;
+ continue;
+ }
+ else if (c == 'Z')
+ {
+ c = 'A';
+ newName = c + newName;
+ continue;
+ }
+ c++;
+ if ((c == 'z' || c == 'Z') && i == 0)
+ {
+ _unchangedPart += c;
+ wchar_t newChar = (c == 'z') ? L'a' : L'A';
+ newName.Empty();
+ numLetters++;
+ for (int k = 0; k < numLetters; k++)
+ newName += newChar;
+ break;
+ }
+ newName = c + newName;
+ i--;
+ for (; i >= 0; i--)
+ newName = _changedPart[i] + newName;
+ break;
+ }
+ }
+ else
+ {
+ int i;
+ int numLetters = _changedPart.Length();
+ for (i = numLetters - 1; i >= 0; i--)
+ {
+ wchar_t c = _changedPart[i];
+ if (c == L'9')
+ {
+ c = L'0';
+ newName = c + newName;
+ if (i == 0)
+ newName = UString(L'1') + newName;
+ continue;
+ }
+ c++;
+ newName = c + newName;
+ i--;
+ for (; i >= 0; i--)
+ newName = _changedPart[i] + newName;
+ break;
+ }
+ }
+ _changedPart = newName;
+ return _unchangedPart + _changedPart;
+ }
+};
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ Close();
+ if (openArchiveCallback == 0)
+ return S_FALSE;
+ // try
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
+ if (openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback,
+ &openVolumeCallback) != S_OK)
+ return S_FALSE;
+
+ UString name;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
+ if (prop.vt != VT_BSTR)
+ return S_FALSE;
+ name = prop.bstrVal;
+ }
+
+ int dotPos = name.ReverseFind('.');
+ UString prefix, ext;
+ if (dotPos >= 0)
+ {
+ prefix = name.Left(dotPos + 1);
+ ext = name.Mid(dotPos + 1);
+ }
+ else
+ ext = name;
+ UString extBig = ext;
+ extBig.MakeUpper();
+
+ CSeqName seqName;
+
+ int numLetters = 2;
+ bool splitStyle = false;
+ if (extBig.Right(2) == L"AA")
+ {
+ splitStyle = true;
+ while (numLetters < extBig.Length())
+ {
+ if (extBig[extBig.Length() - numLetters - 1] != 'A')
+ break;
+ numLetters++;
+ }
+ }
+ else if (ext.Right(2) == L"01")
+ {
+ while (numLetters < extBig.Length())
+ {
+ if (extBig[extBig.Length() - numLetters - 1] != '0')
+ break;
+ numLetters++;
+ }
+ if (numLetters != ext.Length())
+ return S_FALSE;
+ }
+ else
+ return S_FALSE;
+
+ _streams.Add(stream);
+
+ seqName._unchangedPart = prefix + ext.Left(extBig.Length() - numLetters);
+ seqName._changedPart = ext.Right(numLetters);
+ seqName._splitStyle = splitStyle;
+
+ if (prefix.Length() < 1)
+ _subName = L"file";
+ else
+ _subName = prefix.Left(prefix.Length() - 1);
+
+ _totalSize = 0;
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ _totalSize += size;
+ _sizes.Add(size);
+
+ if (openArchiveCallback != NULL)
+ {
+ UInt64 numFiles = _streams.Size();
+ RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
+ }
+
+ for (;;)
+ {
+ UString fullName = seqName.GetNextName();
+ CMyComPtr<IInStream> nextStream;
+ HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
+ if (result == S_FALSE)
+ break;
+ if (result != S_OK)
+ return result;
+ if (!stream)
+ break;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ _totalSize += size;
+ _sizes.Add(size);
+ _streams.Add(nextStream);
+ if (openArchiveCallback != NULL)
+ {
+ UInt64 numFiles = _streams.Size();
+ RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
+ }
+ }
+ }
+ /*
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ */
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _sizes.Clear();
+ _streams.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _streams.IsEmpty() ? 0 : 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPath: prop = _subName; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = _totalSize;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ UInt64 currentTotalSize = 0;
+ RINOK(extractCallback->SetTotal(_totalSize));
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &outStream, askMode));
+ if (!testMode && !outStream)
+ return S_OK;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (int i = 0; i < _streams.Size(); i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ IInStream *inStream = _streams[i];
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ currentTotalSize += copyCoderSpec->TotalSize;
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ if (index != 0)
+ return E_INVALIDARG;
+ *stream = 0;
+ CMultiStream *streamSpec = new CMultiStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ for (int i = 0; i < _streams.Size(); i++)
+ {
+ CMultiStream::CSubStreamInfo subStreamInfo;
+ subStreamInfo.Stream = _streams[i];
+ subStreamInfo.Size = _sizes[i];
+ streamSpec->Streams.Add(subStreamInfo);
+ }
+ streamSpec->Init();
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+{ L"Split", L"001", 0, 0xEA, { 0 }, 0, false, CreateArc, 0 };
+
+REGISTER_ARC(Split)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/SquashfsHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/SquashfsHandler.cpp
new file mode 100644
index 000000000..2cc1219ad
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -0,0 +1,2155 @@
+// SquashfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariantUtils.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+#include "../Compress/LzmaDecoder.h"
+
+namespace NArchive {
+namespace NSquashfs {
+
+static const UInt32 kNumFilesMax = (1 << 28);
+static const unsigned kNumDirLevelsMax = (1 << 10);
+
+// Layout: Header, Data, inodes, Directories, Fragments, UIDs, GIDs
+
+/*
+#define Get16(p) (be ? GetBe16(p) : GetUi16(p))
+#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
+#define Get64(p) (be ? GetBe64(p) : GetUi64(p))
+*/
+
+UInt16 Get16b(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
+UInt32 Get32b(const Byte *p, bool be) { return be ? GetBe32(p) : GetUi32(p); }
+UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); }
+
+#define Get16(p) Get16b(p, be)
+#define Get32(p) Get32b(p, be)
+#define Get64(p) Get64b(p, be)
+
+#define LE_16(offs, dest) dest = GetUi16(p + (offs));
+#define LE_32(offs, dest) dest = GetUi32(p + (offs));
+#define LE_64(offs, dest) dest = GetUi64(p + (offs));
+
+#define GET_16(offs, dest) dest = Get16(p + (offs));
+#define GET_32(offs, dest) dest = Get32(p + (offs));
+#define GET_64(offs, dest) dest = Get64(p + (offs));
+
+static const UInt32 kSignatureSize = 4;
+#define SIGNATURE { 'h', 's', 'q', 's' }
+static const UInt32 kSignature32_LE = 0x73717368;
+static const UInt32 kSignature32_BE = 0x68737173;
+static const UInt32 kSignature32_LZ = 0x71736873;
+
+#define kMethod_ZLIB 1
+#define kMethod_LZMA 2
+#define kMethod_LZO 3
+
+static const char *k_Methods[] =
+{
+ "Unknown",
+ "ZLIB",
+ "LZMA",
+ "LZO"
+};
+
+static const UInt32 kMetadataBlockSizeLog = 13;
+static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog);
+
+#define MY_S_IFIFO 0x1000
+#define MY_S_IFCHR 0x2000
+#define MY_S_IFDIR 0x4000
+#define MY_S_IFBLK 0x6000
+#define MY_S_IFREG 0x8000
+#define MY_S_IFLNK 0xA000
+#define MY_S_IFSOCK 0xC000
+
+enum
+{
+ kType_IPC,
+ kType_DIR,
+ kType_FILE,
+ kType_LNK,
+ kType_BLK,
+ kType_CHR,
+ kType_FIFO,
+ kType_SOCK
+};
+
+static const UInt32 k_TypeToMode[] =
+{
+ 0,
+ MY_S_IFDIR, MY_S_IFREG, MY_S_IFLNK, MY_S_IFBLK, MY_S_IFCHR, MY_S_IFIFO, MY_S_IFSOCK,
+ MY_S_IFDIR, MY_S_IFREG, MY_S_IFLNK, MY_S_IFBLK, MY_S_IFCHR, MY_S_IFIFO, MY_S_IFSOCK
+};
+
+
+enum
+{
+ kFlag_UNC_INODES,
+ kFlag_UNC_DATA,
+ kFlag_CHECK,
+ kFlag_UNC_FRAGS,
+ kFlag_NO_FRAGS,
+ kFlag_ALWAYS_FRAG,
+ kFlag_DUPLICATE,
+ kFlag_EXPORT
+};
+
+static const CUInt32PCharPair k_Flags[] =
+{
+ { kFlag_UNC_INODES, "UNCOMPRESSED_INODES" },
+ { kFlag_UNC_DATA, "UNCOMPRESSED_DATA" },
+ { kFlag_CHECK, "CHECK" },
+ { kFlag_UNC_FRAGS, "UNCOMPRESSED_FRAGMENTS" },
+ { kFlag_NO_FRAGS, "NO_FRAGMENTS" },
+ { kFlag_ALWAYS_FRAG, "ALWAYS_FRAGMENTS" },
+ { kFlag_DUPLICATE, "DUPLICATES_REMOVED" },
+ { kFlag_EXPORT, "EXPORTABLE" }
+};
+
+static const UInt32 kNotCompressedBit16 = (1 << 15);
+static const UInt32 kNotCompressedBit32 = (1 << 24);
+
+#define GET_COMPRESSED_BLOCK_SIZE(size) ((size) & ~kNotCompressedBit32)
+#define IS_COMPRESSED_BLOCK(size) (((size) & kNotCompressedBit32) == 0)
+
+static const UInt32 kHeaderSize1 = 0x33;
+static const UInt32 kHeaderSize2 = 0x3F;
+static const UInt32 kHeaderSize3 = 0x77;
+static const UInt32 kHeaderSize4 = 0x60;
+
+struct CHeader
+{
+ bool be;
+ bool SeveralMethods;
+ Byte NumUids;
+ Byte NumGids;
+
+ UInt32 NumInodes;
+ UInt32 CTime;
+ UInt32 BlockSize;
+ UInt32 NumFrags;
+ UInt16 Method;
+ UInt16 BlockSizeLog;
+ UInt16 Flags;
+ UInt16 NumIDs;
+ UInt16 Major;
+ UInt16 Minor;
+ UInt64 RootInode;
+ UInt64 Size;
+ UInt64 UidTable;
+ UInt64 GidTable;
+ UInt64 XattrIdTable;
+ UInt64 InodeTable;
+ UInt64 DirTable;
+ UInt64 FragTable;
+ UInt64 LookupTable;
+
+ void Parse3(const Byte *p)
+ {
+ Method = kMethod_ZLIB;
+ GET_32 (0x08, Size);
+ GET_32 (0x0C, UidTable);
+ GET_32 (0x10, GidTable);
+ GET_32 (0x14, InodeTable);
+ GET_32 (0x18, DirTable);
+ GET_16 (0x20, BlockSize);
+ GET_16 (0x22, BlockSizeLog);
+ Flags = p[0x24];
+ NumUids = p[0x25];
+ NumGids = p[0x26];
+ GET_32 (0x27, CTime);
+ GET_64 (0x2B, RootInode);
+ NumFrags = 0;
+ FragTable = UidTable;
+
+ if (Major >= 2)
+ {
+ GET_32 (0x33, BlockSize);
+ GET_32 (0x37, NumFrags);
+ GET_32 (0x3B, FragTable);
+ if (Major == 3)
+ {
+ GET_64 (0x3F, Size);
+ GET_64 (0x47, UidTable);
+ GET_64 (0x4F, GidTable);
+ GET_64 (0x57, InodeTable);
+ GET_64 (0x5F, DirTable);
+ GET_64 (0x67, FragTable);
+ GET_64 (0x6F, LookupTable);
+ }
+ }
+ }
+
+ void Parse4(const Byte *p)
+ {
+ LE_32 (0x08, CTime);
+ LE_32 (0x0C, BlockSize);
+ LE_32 (0x10, NumFrags);
+ LE_16 (0x14, Method);
+ LE_16 (0x16, BlockSizeLog);
+ LE_16 (0x18, Flags);
+ LE_16 (0x1A, NumIDs);
+ LE_64 (0x20, RootInode);
+ LE_64 (0x28, Size);
+ LE_64 (0x30, UidTable);
+ LE_64 (0x38, XattrIdTable);
+ LE_64 (0x40, InodeTable);
+ LE_64 (0x48, DirTable);
+ LE_64 (0x50, FragTable);
+ LE_64 (0x58, LookupTable);
+ GidTable = 0;
+ }
+
+ bool Parse(const Byte *p)
+ {
+ be = false;
+ SeveralMethods = false;
+ switch (GetUi32(p))
+ {
+ case kSignature32_LE: break;
+ case kSignature32_BE: be = true; break;
+ case kSignature32_LZ: SeveralMethods = true; break;
+ default: return false;
+ }
+ GET_32 (4, NumInodes);
+ GET_16 (0x1C, Major);
+ GET_16 (0x1E, Minor);
+ if (Major <= 3)
+ Parse3(p);
+ else
+ {
+ if (be)
+ return false;
+ Parse4(p);
+ }
+ return
+ InodeTable < DirTable &&
+ DirTable <= FragTable &&
+ FragTable <= Size &&
+ UidTable <= Size &&
+ BlockSizeLog >= 12 &&
+ BlockSizeLog < 31 &&
+ BlockSize == ((UInt32)1 << BlockSizeLog);
+ }
+
+ bool IsSupported() const { return Major > 0 && Major <= 4 && BlockSizeLog <= 23; }
+ bool IsOldVersion() const { return Major < 4; }
+ bool NeedCheckData() const { return (Flags & (1 << kFlag_CHECK)) != 0; }
+ unsigned GetFileNameOffset() const { return Major <= 2 ? 3 : (Major == 3 ? 5 : 8); }
+ unsigned GetSymLinkOffset() const { return Major <= 1 ? 5: (Major <= 2 ? 6: (Major == 3 ? 18 : 24)); }
+ unsigned GetSpecGuidIndex() const { return Major <= 1 ? 0xF: 0xFF; }
+};
+
+static const UInt32 kFrag_Empty = (UInt32)(Int32)-1;
+// static const UInt32 kXattr_Empty = (UInt32)(Int32)-1;
+
+struct CNode
+{
+ UInt16 Type;
+ UInt16 Mode;
+ UInt16 Uid;
+ UInt16 Gid;
+ UInt32 Frag;
+ UInt32 Offset;
+ // UInt32 MTime;
+ // UInt32 Number;
+ // UInt32 NumLinks;
+ // UInt32 RDev;
+ // UInt32 Xattr;
+ // UInt32 Parent;
+
+ UInt64 FileSize;
+ UInt64 StartBlock;
+ // UInt64 Sparse;
+
+ UInt32 Parse1(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse2(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse3(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse4(const Byte *p, UInt32 size, const CHeader &_h);
+
+ bool IsDir() const { return (Type == kType_DIR || Type == kType_DIR + 7); }
+ bool IsLink() const { return (Type == kType_LNK || Type == kType_LNK + 7); }
+ UInt64 GetSize() const { return IsDir() ? 0 : FileSize; }
+
+ bool ThereAreFrags() const { return Frag != kFrag_Empty; }
+ UInt64 GetNumBlocks(const CHeader &_h) const
+ {
+ return (FileSize >> _h.BlockSizeLog) +
+ (!ThereAreFrags() && (FileSize & (_h.BlockSize - 1)) != 0);
+ }
+};
+
+UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ bool be = _h.be;
+ if (size < 4)
+ return 0;
+ UInt16 t = Get16(p);
+ if (be)
+ {
+ Type = t >> 12;
+ Mode = t & 0xFFF;
+ Uid = p[2] >> 4;
+ Gid = p[2] & 0xF;
+ }
+ else
+ {
+ Type = t & 0xF;
+ Mode = t >> 4;
+ Uid = p[2] & 0xF;
+ Gid = p[2] >> 4;
+ }
+
+ // Xattr = kXattr_Empty;
+ // MTime = 0;
+ FileSize = 0;
+ StartBlock = 0;
+ Frag = kFrag_Empty;
+
+ if (Type == 0)
+ {
+ Byte t = p[3];
+ if (be)
+ {
+ Type = t >> 4;
+ Offset = t & 0xF;
+ }
+ else
+ {
+ Type = t & 0xF;
+ Offset = t >> 4;
+ }
+ return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0;
+ }
+
+ Type--;
+ Uid += (Type / 5) * 16;
+ Type = (Type % 5) + 1;
+
+ if (Type == kType_FILE)
+ {
+ if (size < 15)
+ return 0;
+ // GET_32 (3, MTime);
+ GET_32 (7, StartBlock);
+ UInt32 t;
+ GET_32 (11, t);
+ FileSize = t;
+ UInt32 numBlocks = t >> _h.BlockSizeLog;
+ if ((t & (_h.BlockSize - 1)) != 0)
+ numBlocks++;
+ UInt32 pos = numBlocks * 2 + 15;
+ return (pos <= size) ? pos : 0;
+ }
+
+ if (Type == kType_DIR)
+ {
+ if (size < 14)
+ return 0;
+ UInt32 t = Get32(p + 3);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ // GET_32 (7, MTime);
+ GET_32 (10, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ return 14;
+ }
+
+ if (size < 5)
+ return 0;
+
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (3, len);
+ FileSize = len;
+ len += 5;
+ return (len <= size) ? len : 0;
+ }
+
+ // GET_32 (3, RDev);
+ return 5;
+}
+
+UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ bool be = _h.be;
+ if (size < 4)
+ return 0;
+ UInt16 t = Get16(p);
+ if (be)
+ {
+ Type = t >> 12;
+ Mode = t & 0xFFF;
+ }
+ else
+ {
+ Type = t & 0xF;
+ Mode = t >> 4;
+ }
+ Uid = p[2];
+ Gid = p[3];
+
+ // Xattr = kXattr_Empty;
+
+ if (Type == kType_FILE)
+ {
+ if (size < 24)
+ return 0;
+ // GET_32 (4, MTime);
+ GET_32 (8, StartBlock);
+ GET_32 (12, Frag);
+ GET_32 (16, Offset);
+ UInt32 t;
+ GET_32 (20, t);
+ FileSize = t;
+ UInt32 numBlocks = t >> _h.BlockSizeLog;
+ if (!ThereAreFrags() && (t & (_h.BlockSize - 1)) != 0)
+ numBlocks++;
+ UInt32 pos = numBlocks * 4 + 24;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ FileSize = 0;
+ // MTime = 0;
+ StartBlock = 0;
+ Frag = kFrag_Empty;
+
+ if (Type == kType_DIR)
+ {
+ if (size < 15)
+ return 0;
+ UInt32 t = Get32(p + 4);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ // GET_32 (8, MTime);
+ GET_32 (11, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ return 15;
+ }
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 18)
+ return 0;
+ UInt32 t = Get32(p + 4);
+ UInt32 t2 = Get16(p + 7);
+ if (be)
+ {
+ FileSize = t >> 5;
+ Offset = t2 & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFFFF;
+ Offset = t2 >> 3;
+ }
+ // GET_32 (9, MTime);
+ GET_32 (12, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ UInt32 iCount;
+ GET_16 (16, iCount);
+ UInt32 pos = 18;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // 27 bits: index
+ // 29 bits: startBlock
+ if (pos + 8 > size)
+ return 0;
+ pos += 8 + (UInt32)p[pos + 7] + 1; // nameSize
+ if (pos > size)
+ return 0;
+ }
+ return pos;
+ }
+
+ if (Type == kType_FIFO || Type == kType_SOCK)
+ return 4;
+
+ if (size < 6)
+ return 0;
+
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (4, len);
+ FileSize = len;
+ len += 6;
+ return (len <= size) ? len : 0;
+ }
+
+ if (Type == kType_BLK || Type == kType_CHR)
+ {
+ // GET_16 (4, RDev);
+ return 6;
+ }
+
+ return 0;
+}
+
+UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ bool be = _h.be;
+ if (size < 12)
+ return 0;
+ UInt16 t = Get16(p);
+ if (be)
+ {
+ Type = t >> 12;
+ Mode = t & 0xFFF;
+ }
+ else
+ {
+ Type = t & 0xF;
+ Mode = t >> 4;
+ }
+ Uid = p[2];
+ Gid = p[3];
+ // GET_32 (4, MTime);
+ // GET_32 (8, Number);
+ // Xattr = kXattr_Empty;
+ FileSize = 0;
+ StartBlock = 0;
+
+ if (Type == kType_FILE || Type == kType_FILE + 7)
+ {
+ UInt32 offset;
+ if (Type == kType_FILE)
+ {
+ if (size < 32)
+ return 0;
+ GET_64 (12, StartBlock);
+ GET_32 (20, Frag);
+ GET_32 (24, Offset);
+ GET_32 (28, FileSize);
+ offset = 32;
+ }
+ else
+ {
+ if (size < 40)
+ return 0;
+ // GET_32 (12, NumLinks);
+ GET_64 (16, StartBlock);
+ GET_32 (24, Frag);
+ GET_32 (28, Offset);
+ GET_64 (32, FileSize);
+ offset = 40;
+ }
+ UInt64 pos = GetNumBlocks(_h) * 4 + offset;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ if (size < 16)
+ return 0;
+ // GET_32 (12, NumLinks);
+
+ if (Type == kType_DIR)
+ {
+ if (size < 28)
+ return 0;
+ UInt32 t = Get32(p + 16);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ GET_32 (20, StartBlock);
+ // GET_32 (24, Parent);
+ return 28;
+ }
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 31)
+ return 0;
+ UInt32 t = Get32(p + 16);
+ UInt32 t2 = Get16(p + 19);
+ if (be)
+ {
+ FileSize = t >> 5;
+ Offset = t2 & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFFFF;
+ Offset = t2 >> 3;
+ }
+ GET_32 (21, StartBlock);
+ UInt32 iCount;
+ GET_16 (25, iCount);
+ // GET_32 (27, Parent);
+ UInt32 pos = 31;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // UInt32 index
+ // UInt32 startBlock
+ if (pos + 9 > size)
+ return 0;
+ pos += 9 + (unsigned)p[pos + 8] + 1; // nameSize
+ if (pos > size)
+ return 0;
+ }
+ return pos;
+ }
+
+ if (Type == kType_FIFO || Type == kType_SOCK)
+ return 16;
+
+ if (size < 18)
+ return 0;
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (16, len);
+ FileSize = len;
+ len += 18;
+ return (len <= size) ? len : 0;
+ }
+
+ if (Type == kType_BLK || Type == kType_CHR)
+ {
+ // GET_16 (16, RDev);
+ return 18;
+ }
+
+ return 0;
+}
+
+UInt32 CNode::Parse4(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ if (size < 20)
+ return 0;
+ LE_16 (0, Type);
+ LE_16 (2, Mode);
+ LE_16 (4, Uid);
+ LE_16 (6, Gid);
+ // LE_32 (8, MTime);
+ // LE_32 (12, Number);
+
+ // Xattr = kXattr_Empty;
+ FileSize = 0;
+ StartBlock = 0;
+
+ if (Type == kType_FILE || Type == kType_FILE + 7)
+ {
+ UInt32 offset;
+ if (Type == kType_FILE)
+ {
+ if (size < 32)
+ return 0;
+ LE_32 (16, StartBlock);
+ LE_32 (20, Frag);
+ LE_32 (24, Offset);
+ LE_32 (28, FileSize);
+ offset = 32;
+ }
+ else
+ {
+ if (size < 56)
+ return 0;
+ LE_64 (16, StartBlock);
+ LE_64 (24, FileSize);
+ // LE_64 (32, Sparse);
+ // LE_32 (40, NumLinks);
+ LE_32 (44, Frag);
+ LE_32 (48, Offset);
+ // LE_32 (52, Xattr);
+ offset = 56;
+ }
+ UInt64 pos = GetNumBlocks(_h) * 4 + offset;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ if (Type == kType_DIR)
+ {
+ if (size < 32)
+ return 0;
+ LE_32 (16, StartBlock);
+ // LE_32 (20, NumLinks);
+ LE_16 (24, FileSize);
+ LE_16 (26, Offset);
+ // LE_32 (28, Parent);
+ return 32;
+ }
+
+ // LE_32 (16, NumLinks);
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 40)
+ return 0;
+ LE_32 (20, FileSize);
+ LE_32 (24, StartBlock);
+ // LE_32 (28, Parent);
+ UInt32 iCount;
+ LE_16 (32, iCount);
+ LE_16 (34, Offset);
+ // LE_32 (36, Xattr);
+
+ UInt32 pos = 40;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // UInt32 index
+ // UInt32 startBlock
+ if (pos + 12 > size)
+ return 0;
+ UInt32 nameLen = GetUi32(p + pos + 8);
+ pos += 12 + nameLen + 1;
+ if (pos > size || nameLen > (1 << 10))
+ return 0;
+ }
+ return pos;
+ }
+
+ unsigned offset = 20;
+ switch(Type)
+ {
+ case kType_FIFO: case kType_FIFO + 7:
+ case kType_SOCK: case kType_SOCK + 7:
+ break;
+ case kType_LNK: case kType_LNK + 7:
+ {
+ if (size < 24)
+ return 0;
+ UInt32 len;
+ LE_32 (20, len);
+ FileSize = len;
+ offset = len + 24;
+ if (size < offset || len > (1 << 30))
+ return 0;
+ break;
+ }
+ case kType_BLK: case kType_BLK + 7:
+ case kType_CHR: case kType_CHR + 7:
+ if (size < 24)
+ return 0;
+ // LE_32 (20, RDev);
+ offset = 24;
+ break;
+ default:
+ return 0;
+ }
+
+ if (Type >= 8)
+ {
+ if (size < offset + 4)
+ return 0;
+ // LE_32 (offset, Xattr);
+ offset += 4;
+ }
+ return offset;
+}
+
+struct CItem
+{
+ int Node;
+ int Parent;
+ UInt32 Ptr;
+};
+
+struct CData
+{
+ CByteBuffer Data;
+ CRecordVector<UInt32> PackPos;
+ CRecordVector<UInt32> UnpackPos; // additional item at the end contains TotalUnpackSize
+
+ UInt32 GetNumBlocks() const { return PackPos.Size(); }
+ void Clear()
+ {
+ Data.Free();
+ PackPos.Clear();
+ UnpackPos.Clear();
+ }
+};
+
+struct CFrag
+{
+ UInt64 StartBlock;
+ UInt32 Size;
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CRecordVector<CItem> _items;
+ CRecordVector<CNode> _nodes;
+ CRecordVector<UInt32> _nodesPos;
+ CRecordVector<UInt32> _blockToNode;
+ CData _inodesData;
+ CData _dirs;
+ CRecordVector<CFrag> _frags;
+ // CByteBuffer _uids;
+ // CByteBuffer _gids;
+ CHeader _h;
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _sizeCalculated;
+
+ IArchiveOpenCallback *_openCallback;
+
+ int _nodeIndex;
+ CRecordVector<bool> _blockCompressed;
+ CRecordVector<UInt64> _blockOffsets;
+
+ CByteBuffer _cachedBlock;
+ UInt64 _cachedBlockStartPos;
+ UInt32 _cachedPackBlockSize;
+ UInt32 _cachedUnpackBlockSize;
+
+ CLimitedSequentialInStream *_limitedInStreamSpec;
+ CMyComPtr<ISequentialInStream> _limitedInStream;
+
+ CBufPtrSeqOutStream *_outStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outStream;
+
+ NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+ CMyComPtr<ICompressCoder> _lzmaDecoder;
+
+ NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+ CMyComPtr<ICompressCoder> _zlibDecoder;
+
+ CByteBuffer _inputBuffer;
+
+ CDynBufSeqOutStream *_dynOutStreamSpec;
+ CMyComPtr<ISequentialOutStream> _dynOutStream;
+
+ void ClearCache()
+ {
+ _cachedBlockStartPos = 0;
+ _cachedPackBlockSize = 0;
+ _cachedUnpackBlockSize = 0;
+ }
+
+ HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize,
+ UInt32 inSize, UInt32 outSizeMax);
+ HRESULT ReadMetadataBlock(UInt32 &packSize);
+ HRESULT ReadData(CData &data, UInt64 start, UInt64 end);
+
+ HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex);
+ HRESULT ScanInodes(UInt64 ptr);
+ // HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids);
+ HRESULT Open2(IInStream *inStream);
+ AString GetPath(int index) const;
+ bool GetPackSize(int index, UInt64 &res, bool fillOffsets);
+
+public:
+ CHandler();
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+};
+
+CHandler::CHandler()
+{
+ _limitedInStreamSpec = new CLimitedSequentialInStream;
+ _limitedInStream = _limitedInStreamSpec;
+
+ _outStreamSpec = new CBufPtrSeqOutStream();
+ _outStream = _outStreamSpec;
+
+ _dynOutStreamSpec = new CDynBufSeqOutStream;
+ _dynOutStream = _dynOutStreamSpec;
+}
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidPosixAttrib, VT_UI4}
+ // { NULL, kpidUser, VT_BSTR},
+ // { NULL, kpidGroup, VT_BSTR},
+ // { NULL, kpidLinks, VT_UI4},
+ // { NULL, kpidOffset, VT_UI4}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidBlock, VT_UI4},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidBigEndian, VT_BOOL},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidCharacts, VT_BSTR}
+ // { NULL, kpidNumBlocks, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
+{
+ SizeT destRem = *destLen;
+ SizeT srcRem = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ const Byte *destStart = dest;
+ const Byte *srcStart = src;
+ unsigned mode = 2;
+
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b = *src;
+ if (b > 17)
+ {
+ src++;
+ srcRem--;
+ b -= 17;
+ mode = (b < 4 ? 0 : 1);
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ do
+ *dest++ = *src++;
+ while (--b);
+ }
+ }
+
+ for (;;)
+ {
+ if (srcRem < 3)
+ return S_FALSE;
+ UInt32 b = *src++;
+ srcRem--;
+ UInt32 len, back;
+ if (b >= 64)
+ {
+ srcRem--;
+ back = ((b >> 2) & 7) + ((UInt32)*src++ << 3);
+ len = (b >> 5) + 1;
+ }
+ else if (b < 16)
+ {
+ if (mode == 2)
+ {
+ if (b == 0)
+ {
+ for (b = 15;; b += 255)
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b2 = *src++;
+ srcRem--;
+ if (b2 != 0)
+ {
+ b += b2;
+ break;
+ }
+ }
+ }
+ b += 3;
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ mode = 1;
+ do
+ *dest++ = *src++;
+ while (--b);
+ continue;
+ }
+ srcRem--;
+ back = (b >> 2) + (*src++ << 2);
+ len = 2;
+ if (mode == 1)
+ {
+ back += (1 << 11);
+ len = 3;
+ }
+ }
+ else
+ {
+ UInt32 bOld = b;
+ b = (b < 32 ? 7 : 31);
+ len = bOld & b;
+ if (len == 0)
+ {
+ for (len = b;; len += 255)
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b2 = *src++;
+ srcRem--;
+ if (b2 != 0)
+ {
+ len += b2;
+ break;
+ }
+ }
+ }
+ len += 2;
+ if (srcRem < 2)
+ return S_FALSE;
+ b = *src;
+ back = (b >> 2) + ((UInt32)src[1] << 6);
+ src += 2;
+ srcRem -= 2;
+ if (bOld < 32)
+ {
+ if (back == 0)
+ {
+ *destLen = dest - destStart;
+ *srcLen = src - srcStart;
+ return S_OK;
+ }
+ back += ((bOld & 8) << 11) + (1 << 14) - 1;
+ }
+ }
+ back++;
+ if (len > destRem || (size_t)(dest - destStart) < back)
+ return S_FALSE;
+ destRem -= len;
+ Byte *destTemp = dest - back;
+ dest += len;
+ do
+ {
+ *(destTemp + back) = *destTemp;
+ destTemp++;
+ }
+ while (--len);
+ b &= 3;
+ if (b == 0)
+ {
+ mode = 2;
+ continue;
+ }
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ mode = 0;
+ *dest++ = *src++;
+ if (b > 1)
+ {
+ *dest++ = *src++;
+ if (b > 2)
+ *dest++ = *src++;
+ }
+ }
+}
+
+HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, UInt32 inSize, UInt32 outSizeMax)
+{
+ if (outBuf)
+ {
+ *outBufWasWritten = false;
+ *outBufWasWrittenSize = 0;
+ }
+ UInt32 method = _h.Method;
+ if (_h.SeveralMethods)
+ {
+ Byte props[1];
+ RINOK(ReadStream_FALSE(_stream, props, 1));
+ method = (props[0] == 0x5D ? kMethod_LZMA : kMethod_ZLIB);
+ RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL));
+ }
+
+ if (method == kMethod_LZO)
+ {
+ if (_inputBuffer.GetCapacity() < inSize)
+ {
+ _inputBuffer.Free();
+ _inputBuffer.SetCapacity(inSize);
+ }
+ RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize));
+
+ Byte *dest = outBuf;
+ if (!outBuf)
+ {
+ dest = _dynOutStreamSpec->GetBufPtrForWriting(outSizeMax);
+ if (!dest)
+ return E_OUTOFMEMORY;
+ }
+ SizeT destLen = outSizeMax, srcLen = inSize;
+ RINOK(LzoDecode(dest, &destLen, _inputBuffer, &srcLen));
+ if (inSize != srcLen)
+ return S_FALSE;
+ if (outBuf)
+ {
+ *outBufWasWritten = true;
+ *outBufWasWrittenSize = (UInt32)destLen;
+ }
+ else
+ _dynOutStreamSpec->UpdateSize(destLen);
+ }
+ else if (method == kMethod_LZMA)
+ {
+ if (!_lzmaDecoder)
+ {
+ _lzmaDecoderSpec = new NCompress::NLzma::CDecoder();
+ _lzmaDecoderSpec->FinishStream = true;
+ _lzmaDecoder = _lzmaDecoderSpec;
+ }
+ const UInt32 kPropsSize = 5 + 8;
+ Byte props[kPropsSize];
+ ReadStream_FALSE(_limitedInStream, props, kPropsSize);
+ RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, 5));
+ UInt64 outSize = GetUi64(props + 5);
+ if (outSize > outSizeMax)
+ return S_FALSE;
+ RINOK(_lzmaDecoder->Code(_limitedInStream, outStream, NULL, &outSize, NULL));
+ if (inSize != kPropsSize + _lzmaDecoderSpec->GetInputProcessedSize())
+ return S_FALSE;
+ }
+ else
+ {
+ if (!_zlibDecoder)
+ {
+ _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+ _zlibDecoder = _zlibDecoderSpec;
+ }
+ RINOK(_zlibDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL));
+ if (inSize != _zlibDecoderSpec->GetInputProcessedSize())
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
+{
+ Byte temp[3];
+ unsigned offset = _h.NeedCheckData() ? 3 : 2;
+ if (offset > packSize)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(_stream, temp, offset));
+ // if (NeedCheckData && Major < 4) checkByte must be = 0xFF
+ bool be = _h.be;
+ UInt32 size = Get16(temp);
+ bool isCompressed = ((size & kNotCompressedBit16) == 0);
+ if (size != kNotCompressedBit16)
+ size &= ~kNotCompressedBit16;
+
+ if (size > kMetadataBlockSize || offset + size > packSize)
+ return S_FALSE;
+ packSize = offset + size;
+ if (isCompressed)
+ {
+ _limitedInStreamSpec->Init(size);
+ RINOK(Decompress(_dynOutStream, NULL, NULL, NULL, size, kMetadataBlockSize));
+ }
+ else
+ {
+ // size != 0 here
+ Byte *buf = _dynOutStreamSpec->GetBufPtrForWriting(size);
+ if (!buf)
+ return E_OUTOFMEMORY;
+ RINOK(ReadStream_FALSE(_stream, buf, size));
+ _dynOutStreamSpec->UpdateSize(size);
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end)
+{
+ if (end < start || end - start >= ((UInt64)1 << 32))
+ return S_FALSE;
+ UInt32 size = (UInt32)(end - start);
+ RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL));
+ _dynOutStreamSpec->Init();
+ UInt32 packPos = 0;
+ while (packPos != size)
+ {
+ data.PackPos.Add(packPos);
+ data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize());
+ if (packPos > size)
+ return S_FALSE;
+ UInt32 packSize = size - packPos;
+ RINOK(ReadMetadataBlock(packSize));
+ if (_dynOutStreamSpec->GetSize() >= ((UInt64)1 << 32))
+ return S_FALSE;
+ packPos += packSize;
+ }
+ data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize());
+ _dynOutStreamSpec->CopyToBuffer(data.Data);
+ return S_OK;
+}
+
+struct CTempItem
+{
+ UInt32 StartBlock;
+ // UInt32 iNodeNumber1;
+ UInt32 Offset;
+ // UInt16 iNodeNumber2;
+ UInt16 Type;
+};
+
+HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex)
+{
+ if (level > kNumDirLevelsMax)
+ return S_FALSE;
+
+ int blockIndex = _inodesData.PackPos.FindInSorted(startBlock);
+ if (blockIndex < 0)
+ return S_FALSE;
+ UInt32 unpackPos = _inodesData.UnpackPos[blockIndex] + offset;
+ if (unpackPos < offset)
+ return S_FALSE;
+
+ nodeIndex = _nodesPos.FindInSorted(unpackPos, _blockToNode[blockIndex], _blockToNode[blockIndex + 1]);
+ // nodeIndex = _nodesPos.FindInSorted(unpackPos);
+ if (nodeIndex < 0)
+ return S_FALSE;
+
+ const CNode &n = _nodes[nodeIndex];
+ if (!n.IsDir())
+ return S_OK;
+ blockIndex = _dirs.PackPos.FindInSorted((UInt32)n.StartBlock);
+ if (blockIndex < 0)
+ return S_FALSE;
+ unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset;
+ if (unpackPos < n.Offset || unpackPos > _dirs.Data.GetCapacity())
+ return S_FALSE;
+
+ UInt32 rem = (UInt32)_dirs.Data.GetCapacity() - unpackPos;
+ const Byte *p = _dirs.Data + unpackPos;
+ UInt32 fileSize = (UInt32)n.FileSize;
+
+ if (fileSize > rem)
+ return S_FALSE;
+ rem = fileSize;
+ if (_h.Major >= 3)
+ {
+ if (rem < 3)
+ return S_FALSE;
+ rem -= 3;
+ }
+
+ CRecordVector<CTempItem> tempItems;
+ while (rem != 0)
+ {
+ bool be = _h.be;
+ UInt32 count;
+ CTempItem tempItem;
+ if (_h.Major <= 2)
+ {
+ if (rem < 4)
+ return S_FALSE;
+ count = p[0];
+ tempItem.StartBlock = Get32(p);
+ if (be)
+ tempItem.StartBlock &= 0xFFFFFF;
+ else
+ tempItem.StartBlock >>= 8;
+ p += 4;
+ rem -= 4;
+ }
+ else
+ {
+ if (_h.Major == 3)
+ {
+ if (rem < 9)
+ return S_FALSE;
+ count = p[0];
+ p += 1;
+ rem -= 1;
+ }
+ else
+ {
+ if (rem < 12)
+ return S_FALSE;
+ count = GetUi32(p);
+ p += 4;
+ rem -= 4;
+ }
+ GET_32 (0, tempItem.StartBlock);
+ // GET_32 (4, tempItem.iNodeNumber1);
+ p += 8;
+ rem -= 8;
+ }
+ count++;
+
+ for (UInt32 i = 0; i < count; i++)
+ {
+ if (rem == 0)
+ return S_FALSE;
+
+ UInt32 nameOffset = _h.GetFileNameOffset();
+ if (rem < nameOffset)
+ return S_FALSE;
+
+ if ((UInt32)_items.Size() >= kNumFilesMax)
+ return S_FALSE;
+ if (_openCallback)
+ {
+ UInt64 numFiles = _items.Size();
+ if ((numFiles & 0xFFFF) == 0)
+ {
+ RINOK(_openCallback->SetCompleted(&numFiles, NULL));
+ }
+ }
+
+ CItem item;
+ item.Ptr = (UInt32)(p - _dirs.Data);
+
+ UInt32 size;
+ if (_h.IsOldVersion())
+ {
+ UInt32 t = Get16(p);
+ if (be)
+ {
+ tempItem.Offset = t >> 3;
+ tempItem.Type = (UInt16)(t & 0x7);
+ }
+ else
+ {
+ tempItem.Offset = t & 0x1FFF;
+ tempItem.Type = (UInt16)(t >> 13);
+ }
+ size = (UInt32)p[2];
+ /*
+ if (_h.Major > 2)
+ tempItem.iNodeNumber2 = Get16(p + 3);
+ */
+ }
+ else
+ {
+ GET_16 (0, tempItem.Offset);
+ // GET_16 (2, tempItem.iNodeNumber2);
+ GET_16 (4, tempItem.Type);
+ GET_16 (6, size);
+ }
+ p += nameOffset;
+ rem -= nameOffset;
+ size++;
+ if (rem < size)
+ return S_FALSE;
+ p += size;
+ rem -= size;
+ item.Parent = parent;
+ _items.Add(item);
+ tempItems.Add(tempItem);
+ }
+ }
+
+ int startItemIndex = _items.Size() - tempItems.Size();
+ for (int i = 0; i < tempItems.Size(); i++)
+ {
+ const CTempItem &tempItem = tempItems[i];
+ int index = startItemIndex + i;
+ CItem &item = _items[index];
+ RINOK(OpenDir(index, tempItem.StartBlock, tempItem.Offset, level + 1, item.Node));
+ }
+
+ return S_OK;
+}
+
+/*
+HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids)
+{
+ size_t size = num * 4;
+ ids.SetCapacity(size);
+ RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(_stream, ids, size);
+}
+*/
+
+HRESULT CHandler::Open2(IInStream *inStream)
+{
+ {
+ Byte buf[kHeaderSize3];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize3));
+ if (!_h.Parse(buf))
+ return S_FALSE;
+ if (!_h.IsSupported())
+ return E_NOTIMPL;
+
+ switch (_h.Method)
+ {
+ case kMethod_ZLIB:
+ case kMethod_LZMA:
+ case kMethod_LZO:
+ break;
+ default:
+ return E_NOTIMPL;
+ }
+ }
+
+ _stream = inStream;
+
+ if (_h.NumFrags != 0)
+ {
+ if (_h.NumFrags > kNumFilesMax)
+ return S_FALSE;
+ _frags.Reserve(_h.NumFrags);
+ CByteBuffer data;
+ unsigned bigFrag = (_h.Major > 2);
+
+ unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag);
+ UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog;
+ size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag);
+ data.SetCapacity(numBlocksBytes);
+ RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
+ bool be = _h.be;
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4);
+ RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
+ _dynOutStreamSpec->Init();
+ UInt32 packSize = kMetadataBlockSize + 3;
+ RINOK(ReadMetadataBlock(packSize));
+ UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
+ if (unpackSize != kMetadataBlockSize)
+ if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1)))
+ return S_FALSE;
+ const Byte *buf = _dynOutStreamSpec->GetBuffer();
+ for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;)
+ {
+ CFrag frag;
+ if (bigFrag)
+ {
+ frag.StartBlock = Get64(buf + j);
+ frag.Size = Get32(buf + j + 8);
+ // some archives contain nonzero in unused (buf + j + 12)
+ j += 16;
+ }
+ else
+ {
+ frag.StartBlock = Get32(buf + j);
+ frag.Size = Get32(buf + j + 4);
+ j += 8;
+ }
+ _frags.Add(frag);
+ }
+ }
+ if ((UInt32)_frags.Size() != _h.NumFrags)
+ return S_FALSE;
+ }
+
+ // RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL));
+
+ RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable));
+ RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable));
+
+ UInt64 absOffset = _h.RootInode >> 16;
+ if (absOffset >= ((UInt64)1 << 32))
+ return S_FALSE;
+ {
+ UInt32 pos = 0;
+ UInt32 totalSize = (UInt32)_inodesData.Data.GetCapacity();
+ _nodesPos.Reserve(_h.NumInodes);
+ _nodes.Reserve(_h.NumInodes);
+ // we use _blockToNode for binary search seed optimizations
+ _blockToNode.Reserve(_inodesData.GetNumBlocks() + 1);
+ int curBlock = 0;
+ for (UInt32 i = 0; i < _h.NumInodes; i++)
+ {
+ CNode n;
+ const Byte *p = _inodesData.Data + pos;
+ UInt32 size = totalSize - pos;
+
+ switch(_h.Major)
+ {
+ case 1: size = n.Parse1(p, size, _h); break;
+ case 2: size = n.Parse2(p, size, _h); break;
+ case 3: size = n.Parse3(p, size, _h); break;
+ default: size = n.Parse4(p, size, _h); break;
+ }
+ if (size == 0)
+ return S_FALSE;
+ while (pos >= _inodesData.UnpackPos[curBlock])
+ {
+ _blockToNode.Add(_nodesPos.Size());
+ curBlock++;
+ }
+ _nodesPos.Add(pos);
+ _nodes.Add(n);
+ pos += size;
+ }
+ _blockToNode.Add(_nodesPos.Size());
+ if (pos != totalSize)
+ return S_FALSE;
+ }
+ int rootNodeIndex;
+ RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex));
+
+ /*
+ if (_h.Major < 4)
+ {
+ RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids));
+ RINOK(ReadUids(_h.GidTable, _h.NumGids, _gids));
+ }
+ else
+ {
+ UInt32 size = _h.NumIDs * 4;
+ _uids.SetCapacity(size);
+
+ UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize;
+ UInt32 numBlocksBytes = numBlocks << 3;
+ CByteBuffer data;
+ data.SetCapacity(numBlocksBytes);
+ RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt64 offset = GetUi64(data + i * 8);
+ UInt32 unpackSize, packSize;
+ RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
+ RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
+ if (unpackSize != kMetadataBlockSize)
+ if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1)))
+ return S_FALSE;
+ }
+ }
+ */
+
+ {
+ const UInt32 alignSize = 1 << 12;
+ Byte buf[alignSize];
+ RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL));
+ UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1);
+ _sizeCalculated = _h.Size;
+ if (rem != 0)
+ {
+ if (ReadStream_FALSE(_stream, buf, rem) == S_OK)
+ {
+ size_t i;
+ for (i = 0; i < rem && buf[i] == 0; i++);
+ if (i == rem)
+ _sizeCalculated = _h.Size + rem;
+ }
+ }
+ }
+ return S_OK;
+}
+
+AString CHandler::GetPath(int index) const
+{
+ unsigned len = 0;
+ int indexMem = index;
+ bool be = _h.be;
+ do
+ {
+ const CItem &item = _items[index];
+ index = item.Parent;
+ const Byte *p = _dirs.Data + item.Ptr;
+ unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1;
+ p += _h.GetFileNameOffset();
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ len += i + 1;
+ }
+ while (index >= 0);
+ len--;
+
+ AString path;
+ char *dest = path.GetBuffer(len) + len;
+ index = indexMem;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ index = item.Parent;
+
+ const Byte *p = _dirs.Data + item.Ptr;
+ unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1;
+ p += _h.GetFileNameOffset();
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ dest -= i;
+ memcpy(dest, p, i);
+ if (index < 0)
+ break;
+ *(--dest) = CHAR_PATH_SEPARATOR;
+ }
+ path.ReleaseBuffer(len);
+ return path;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ _limitedInStreamSpec->SetStream(stream);
+ HRESULT res;
+ try
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ _openCallback = callback;
+ res = Open2(stream);
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ if (res != S_OK)
+ {
+ Close();
+ return res;
+ }
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _limitedInStreamSpec->ReleaseStream();
+ _stream.Release();
+
+ _items.Clear();
+ _nodes.Clear();
+ _nodesPos.Clear();
+ _blockToNode.Clear();
+ _frags.Clear();
+ _inodesData.Clear();
+ _dirs.Clear();
+
+ // _uids.Free();
+ // _gids.Free();;
+
+ _cachedBlock.Free();
+ ClearCache();
+
+ return S_OK;
+}
+
+bool CHandler::GetPackSize(int index, UInt64 &totalPack, bool fillOffsets)
+{
+ totalPack = 0;
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ UInt32 ptr = _nodesPos[item.Node];
+ const Byte *p = _inodesData.Data + ptr;
+ bool be = _h.be;
+
+ UInt32 type = node.Type;
+ UInt32 offset;
+ if (node.IsLink() || node.FileSize == 0)
+ {
+ totalPack = node.FileSize;
+ return true;
+ }
+
+ UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h);
+
+ if (fillOffsets)
+ {
+ _blockOffsets.Clear();
+ _blockCompressed.Clear();
+ _blockOffsets.Add(totalPack);
+ }
+
+ if (_h.Major <= 1)
+ {
+ offset = 15;
+ p += offset;
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt32 t = Get16(p + i * 2);
+ if (fillOffsets)
+ _blockCompressed.Add((t & kNotCompressedBit16) == 0);
+ if (t != kNotCompressedBit16)
+ t &= ~kNotCompressedBit16;
+ totalPack += t;
+ if (fillOffsets)
+ _blockOffsets.Add(totalPack);
+ }
+ }
+ else
+ {
+ if (_h.Major <= 2)
+ offset = 24;
+ else if (type == kType_FILE)
+ offset = 32;
+ else if (type == kType_FILE + 7)
+ offset = (_h.Major <= 3 ? 40 : 56);
+ else
+ return false;
+
+ p += offset;
+
+ for (UInt64 i = 0; i < numBlocks; i++)
+ {
+ UInt32 t = Get32(p + i * 4);
+ if (fillOffsets)
+ _blockCompressed.Add(IS_COMPRESSED_BLOCK(t));
+ UInt32 size = GET_COMPRESSED_BLOCK_SIZE(t);
+ if (size > _h.BlockSize)
+ return false;
+ totalPack += size;
+ if (fillOffsets)
+ _blockOffsets.Add(totalPack);
+ }
+
+ if (node.ThereAreFrags())
+ {
+ if (node.Frag >= (UInt32)_frags.Size())
+ return false;
+ const CFrag &frag = _frags[node.Frag];
+ if (node.Offset == 0)
+ {
+ UInt32 size = GET_COMPRESSED_BLOCK_SIZE(frag.Size);
+ if (size > _h.BlockSize)
+ return false;
+ totalPack += size;
+ }
+ }
+ }
+ return true;
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ const char *s;
+ if (_h.SeveralMethods)
+ s = "LZMA ZLIB";
+ else
+ {
+ s = k_Methods[0];
+ if (_h.Method < sizeof(k_Methods) / sizeof(k_Methods[0]))
+ s = k_Methods[_h.Method];
+ }
+ prop = s;
+ break;
+ }
+ case kpidFileSystem:
+ {
+ AString res = "SquashFS";
+ if (_h.SeveralMethods)
+ res += "-LZMA";
+ res += ' ';
+ char s[16];
+ ConvertUInt32ToString(_h.Major, s);
+ res += s;
+ res += '.';
+ ConvertUInt32ToString(_h.Minor, s);
+ res += s;
+ prop = res;
+ break;
+ }
+ case kpidBlock: prop = _h.BlockSize; break;
+ case kpidBigEndian: prop = _h.be; break;
+ case kpidCTime:
+ if (_h.CTime != 0)
+ {
+ FILETIME ft;
+ NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft);
+ prop = ft;
+ }
+ break;
+ case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
+ // case kpidNumBlocks: prop = _h.NumFrags; break;
+ case kpidPhySize: prop = _sizeCalculated; break;
+ case kpidHeadersSize:
+ if (_sizeCalculated >= _h.InodeTable)
+ prop = _sizeCalculated - _h.InodeTable;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ bool isDir = node.IsDir();
+ bool be = _h.be;
+
+ switch(propID)
+ {
+ case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
+ case kpidIsDir: prop = isDir; break;
+ // case kpidOffset: if (!node.IsLink()) prop = (UInt64)node.StartBlock; break;
+ case kpidSize: if (!isDir) prop = node.GetSize(); break;
+ case kpidPackSize:
+ if (!isDir)
+ {
+ UInt64 size;
+ if (GetPackSize(index, size, false))
+ prop = size;
+ }
+ break;
+ case kpidMTime:
+ {
+ UInt32 offset = 0;
+ switch(_h.Major)
+ {
+ case 1:
+ if (node.Type == kType_FILE)
+ offset = 3;
+ else if (node.Type == kType_DIR)
+ offset = 7;
+ break;
+ case 2:
+ if (node.Type == kType_FILE)
+ offset = 4;
+ else if (node.Type == kType_DIR)
+ offset = 8;
+ else if (node.Type == kType_DIR + 7)
+ offset = 9;
+ break;
+ case 3: offset = 4; break;
+ case 4: offset = 8; break;
+ }
+ if (offset != 0)
+ {
+ const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset;
+ FILETIME ft;
+ NWindows::NTime::UnixTimeToFileTime(Get32(p), ft);
+ prop = ft;
+ }
+ break;
+ }
+ case kpidPosixAttrib:
+ {
+ if (node.Type != 0 && node.Type < sizeof(k_TypeToMode) / sizeof(k_TypeToMode[0]))
+ prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
+ break;
+ }
+ /*
+ case kpidUser:
+ {
+ UInt32 offset = node.Uid * 4;
+ if (offset < _uids.GetCapacity())
+ prop = (UInt32)Get32(_uids + offset);
+ break;
+ }
+ case kpidGroup:
+ {
+ if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex())
+ {
+ UInt32 offset = node.Uid * 4;
+ if (offset < _uids.GetCapacity())
+ prop = (UInt32)Get32(_uids + offset);
+ }
+ else
+ {
+ UInt32 offset = node.Gid * 4;
+ if (offset < _gids.GetCapacity())
+ prop = (UInt32)Get32(_gids + offset);
+ }
+ break;
+ }
+ */
+ /*
+ case kpidLinks:
+ if (_h.Major >= 3 && node.Type != kType_FILE)
+ prop = node.NumLinks;
+ break;
+ */
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CSquashfsInStream: public CCachedInStream
+{
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+public:
+ CHandler *Handler;
+};
+
+HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ return Handler->ReadBlock(blockIndex, dest, blockSize);
+}
+
+HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ const CNode &node = _nodes[_nodeIndex];
+ UInt64 blockOffset;
+ UInt32 packBlockSize;
+ UInt32 offsetInBlock = 0;
+ bool compressed;
+ if (blockIndex < _blockCompressed.Size())
+ {
+ compressed = _blockCompressed[(int)blockIndex];
+ blockOffset = _blockOffsets[(int)blockIndex];
+ packBlockSize = (UInt32)(_blockOffsets[(int)blockIndex + 1] - blockOffset);
+ blockOffset += node.StartBlock;
+ }
+ else
+ {
+ if (!node.ThereAreFrags())
+ return S_FALSE;
+ const CFrag &frag = _frags[node.Frag];
+ offsetInBlock = node.Offset;
+ blockOffset = frag.StartBlock;
+ packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size);
+ compressed = IS_COMPRESSED_BLOCK(frag.Size);
+ }
+
+ if (packBlockSize == 0)
+ {
+ // sparse file ???
+ memset(dest, 0, blockSize);
+ return S_OK;
+ }
+
+ if (blockOffset != _cachedBlockStartPos ||
+ packBlockSize != _cachedPackBlockSize)
+ {
+ ClearCache();
+ RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL));
+ _limitedInStreamSpec->Init(packBlockSize);
+
+ if (compressed)
+ {
+ _outStreamSpec->Init((Byte *)_cachedBlock, _h.BlockSize);
+ bool outBufWasWritten;
+ UInt32 outBufWasWrittenSize;
+ HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize);
+ if (outBufWasWritten)
+ _cachedUnpackBlockSize = outBufWasWrittenSize;
+ else
+ _cachedUnpackBlockSize = (UInt32)_outStreamSpec->GetPos();
+ RINOK(res);
+ }
+ else
+ {
+ RINOK(ReadStream_FALSE(_limitedInStream, _cachedBlock, packBlockSize));
+ _cachedUnpackBlockSize = packBlockSize;
+ }
+ _cachedBlockStartPos = blockOffset;
+ _cachedPackBlockSize = packBlockSize;
+ }
+ if (offsetInBlock + blockSize > _cachedUnpackBlockSize)
+ return S_FALSE;
+ memcpy(dest, _cachedBlock + offsetInBlock, blockSize);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _items[allFilesMode ? i : indices[i]];
+ const CNode &node = _nodes[item.Node];
+ totalSize += node.GetSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ // const Byte *p = _data + item.Offset;
+
+ if (node.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ UInt64 unpackSize = node.GetSize();
+ totalSize += unpackSize;
+ UInt64 packSize;
+ if (GetPackSize(index, packSize, false))
+ totalPackSize += packSize;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ CMyComPtr<IInStream> inStream;
+ HRESULT hres = GetStream(index, &inSeqStream);
+ if (inSeqStream)
+ inSeqStream.QueryInterface(IID_IInStream, &inStream);
+ if (hres == S_FALSE || !inStream)
+ {
+ if (hres == E_OUTOFMEMORY)
+ return hres;
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ }
+ else
+ {
+ RINOK(hres);
+ if (inStream)
+ {
+ HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres != S_OK && hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ if (copyCoderSpec->TotalSize == unpackSize && hres == S_OK)
+ res = NExtract::NOperationResult::kOK;
+ else
+ {
+ res = res;
+ }
+ }
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(res));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+
+ if (node.IsDir())
+ return E_FAIL;
+
+ const Byte *p = _inodesData.Data + _nodesPos[item.Node];
+
+ if (node.FileSize == 0 || node.IsLink())
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ if (node.IsLink())
+ streamSpec->Init(p + _h.GetSymLinkOffset(), (size_t)node.FileSize);
+ else
+ streamSpec->Init(NULL, 0);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+
+ UInt64 packSize;
+ if (!GetPackSize(index, packSize, true))
+ return S_FALSE;
+
+ _nodeIndex = item.Node;
+
+ size_t cacheSize = _h.BlockSize;
+ if (_cachedBlock.GetCapacity() != cacheSize)
+ {
+ ClearCache();
+ _cachedBlock.SetCapacity(cacheSize);
+ }
+
+ CSquashfsInStream *streamSpec = new CSquashfsInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Handler = this;
+ unsigned cacheSizeLog = 22;
+ if (cacheSizeLog <= _h.BlockSizeLog)
+ cacheSizeLog = _h.BlockSizeLog + 1;
+ if (!streamSpec->Alloc(_h.BlockSizeLog, cacheSizeLog - _h.BlockSizeLog))
+ return E_OUTOFMEMORY;
+ streamSpec->Init(node.FileSize);
+ *stream = streamTemp.Detach();
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NSquashfs::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"SquashFS", L"squashfs", 0, 0xD2, SIGNATURE, kSignatureSize, false, CreateArc, 0 };
+
+REGISTER_ARC(Cramfs)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/StdAfx.h
new file mode 100644
index 000000000..ef555ec12
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/MyWindows.h"
+#include "../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/SwfHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/SwfHandler.cpp
new file mode 100644
index 000000000..dfc0326d1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/SwfHandler.cpp
@@ -0,0 +1,706 @@
+// SwfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+#include "../Compress/ZlibEncoder.h"
+
+#include "Common/DummyOutStream.h"
+
+#include "DeflateProps.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NSwfc {
+
+static const UInt32 kHeaderSize = 8;
+
+static const Byte SWF_UNCOMPRESSED = 'F';
+static const Byte SWF_COMPRESSED = 'C';
+static const Byte SWF_MIN_COMPRESSED_VER = 6;
+
+struct CItem
+{
+ Byte Buf[kHeaderSize];
+
+ UInt32 GetSize() const { return GetUi32(Buf + 4); }
+ bool IsSwf(Byte c) const { return (Buf[0] == c && Buf[1] == 'W' && Buf[2] == 'S' && Buf[3] < 32); }
+ bool IsUncompressed() const { return IsSwf(SWF_UNCOMPRESSED); }
+ bool IsCompressed() const { return IsSwf(SWF_COMPRESSED); }
+
+ void MakeUncompressed() { Buf[0] = SWF_UNCOMPRESSED; }
+ void MakeCompressed()
+ {
+ Buf[0] = SWF_COMPRESSED;
+ if (Buf[3] < SWF_MIN_COMPRESSED_VER)
+ Buf[3] = SWF_MIN_COMPRESSED_VER;
+ }
+
+ HRESULT ReadHeader(ISequentialInStream *stream) { return ReadStream_FALSE(stream, Buf, kHeaderSize); }
+ HRESULT WriteHeader(ISequentialOutStream *stream) { return WriteStream(stream, Buf, kHeaderSize); }
+};
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IOutArchive,
+ public ISetProperties,
+ public CMyUnknownImp
+{
+ CItem _item;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<ISequentialInStream> _seqStream;
+ CMyComPtr<IInStream> _stream;
+
+ CDeflateProps _method;
+
+public:
+ MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSize: prop = (UInt64)_item.GetSize(); break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
+{
+ RINOK(OpenSeq(stream));
+ _stream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ HRESULT res = _item.ReadHeader(stream);
+ if (res == S_OK)
+ if (_item.IsCompressed())
+ _seqStream = stream;
+ else
+ res = S_FALSE;
+ return res;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _packSizeDefined = false;
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_item.GetSize());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ NCompress::NZlib::CDecoder *_decoderSpec = new NCompress::NZlib::CDecoder;
+ CMyComPtr<ICompressCoder> _decoder = _decoderSpec;
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ lps->InSize = kHeaderSize;
+ lps->OutSize = outStreamSpec->GetSize();
+ RINOK(lps->SetCur());
+
+ CItem item = _item;
+ item.MakeUncompressed();
+ RINOK(item.WriteHeader(outStream));
+ if (_stream)
+ RINOK(_stream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL));
+ HRESULT result = _decoderSpec->Code(_seqStream, outStream, NULL, NULL, progress);
+ Int32 opRes = NExtract::NOperationResult::kDataError;
+ if (result == S_OK)
+ {
+ if (_item.GetSize() == outStreamSpec->GetSize())
+ {
+ _packSizeDefined = true;
+ _packSize = _decoderSpec->GetInputProcessedSize() + kHeaderSize;
+ opRes = NExtract::NOperationResult::kOK;
+ }
+ }
+ else if (result != S_FALSE)
+ return result;
+
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+static HRESULT UpdateArchive(ISequentialOutStream *outStream,
+ UInt64 size, CDeflateProps &deflateProps,
+ IArchiveUpdateCallback *updateCallback)
+{
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetTotal(size));
+ RINOK(updateCallback->SetCompleted(&complexity));
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+
+ CItem item;
+ HRESULT res = item.ReadHeader(fileInStream);
+ if (res == S_FALSE)
+ return E_INVALIDARG;
+ RINOK(res);
+ if (!item.IsUncompressed() || size != item.GetSize())
+ return E_INVALIDARG;
+
+ item.MakeCompressed();
+ item.WriteHeader(outStream);
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ NCompress::NZlib::CEncoder *encoderSpec = new NCompress::NZlib::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+ encoderSpec->Create();
+ RINOK(deflateProps.SetCoderProperties(encoderSpec->DeflateEncoderSpec));
+ RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress));
+ if (encoderSpec->GetInputProcessedSize() + kHeaderSize != size)
+ return E_INVALIDARG;
+ return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
+}
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
+ if (prop.vt == VT_BOOL)
+ {
+ if (prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ return UpdateArchive(outStream, size, _method, updateCallback);
+ }
+
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+
+ if (!_seqStream)
+ return E_NOTIMPL;
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+ else
+ _item.WriteHeader(outStream);
+ return NCompress::CopyStream(_seqStream, outStream, NULL);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ return _method.SetProperties(names, values, numProps);
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"SWFc", L"swf", L"~.swf", 0xD8, { 'C', 'W', 'S' }, 3, true, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Swfc)
+
+}
+
+namespace NSwf {
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 30;
+static const int kNumTagsMax = (UInt32)1 << 23;
+
+struct CTag
+{
+ UInt32 Type;
+ CByteBuffer Buf;
+};
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public CMyUnknownImp
+{
+ CObjectVector<CTag> _tags;
+ NSwfc::CItem _item;
+ UInt64 _packSize;
+
+ HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback);
+ HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback);
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq)
+ INTERFACE_IInArchive(;)
+
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidComment, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _tags.Size();
+ return S_OK;
+}
+
+static const char *g_TagDesc[92] =
+{
+ "End",
+ "ShowFrame",
+ "DefineShape",
+ NULL,
+ "PlaceObject",
+ "RemoveObject",
+ "DefineBits",
+ "DefineButton",
+ "JPEGTables",
+ "SetBackgroundColor",
+ "DefineFont",
+ "DefineText",
+ "DoAction",
+ "DefineFontInfo",
+ "DefineSound",
+ "StartSound",
+ NULL,
+ "DefineButtonSound",
+ "SoundStreamHead",
+ "SoundStreamBlock",
+ "DefineBitsLossless",
+ "DefineBitsJPEG2",
+ "DefineShape2",
+ "DefineButtonCxform",
+ "Protect",
+ NULL,
+ "PlaceObject2",
+ NULL,
+ "RemoveObject2",
+ NULL,
+ NULL,
+ NULL,
+ "DefineShape3",
+ "DefineText2",
+ "DefineButton2",
+ "DefineBitsJPEG3",
+ "DefineBitsLossless2",
+ "DefineEditText",
+ NULL,
+ "DefineSprite",
+ NULL,
+ "41",
+ NULL,
+ "FrameLabel",
+ NULL,
+ "SoundStreamHead2",
+ "DefineMorphShape",
+ NULL,
+ "DefineFont2",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ExportAssets",
+ "ImportAssets",
+ "EnableDebugger",
+ "DoInitAction",
+ "DefineVideoStream",
+ "VideoFrame",
+ "DefineFontInfo2",
+ NULL,
+ "EnableDebugger2",
+ "ScriptLimits",
+ "SetTabIndex",
+ NULL,
+ NULL,
+ "FileAttributes",
+ "PlaceObject3",
+ "ImportAssets2",
+ NULL,
+ "DefineFontAlignZones",
+ "CSMTextSettings",
+ "DefineFont3",
+ "SymbolClass",
+ "Metadata",
+ "DefineScalingGrid",
+ NULL,
+ NULL,
+ NULL,
+ "DoABC",
+ "DefineShape4",
+ "DefineMorphShape2",
+ NULL,
+ "DefineSceneAndFrameLabelData",
+ "DefineBinaryData",
+ "DefineFontName",
+ "StartSound2",
+ "DefineBitsJPEG4",
+ "DefineFont4"
+};
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ const CTag &tag = _tags[index];
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ char s[32];
+ ConvertUInt32ToString(index, s);
+ size_t i = strlen(s);
+ s[i++] = '.';
+ ConvertUInt32ToString(tag.Type, s + i);
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)tag.Buf.GetCapacity(); break;
+ case kpidComment:
+ if (tag.Type < sizeof(g_TagDesc) / sizeof(g_TagDesc[0]))
+ {
+ const char *s = g_TagDesc[tag.Type];
+ if (s != NULL)
+ prop = s;
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ return OpenSeq2(stream, callback);
+}
+
+static UInt16 Read16(CInBuffer &stream)
+{
+ UInt16 res = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b;
+ if (!stream.ReadByte(b))
+ throw 1;
+ res |= (UInt16)b << (i * 8);
+ }
+ return res;
+}
+
+static UInt32 Read32(CInBuffer &stream)
+{
+ UInt32 res = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b;
+ if (!stream.ReadByte(b))
+ throw 1;
+ res |= (UInt32)b << (i * 8);
+ }
+ return res;
+}
+
+struct CBitReader
+{
+ CInBuffer *stream;
+ unsigned NumBits;
+ Byte Val;
+
+ CBitReader(): NumBits(0), Val(0) {}
+
+ UInt32 ReadBits(unsigned numBits);
+};
+
+UInt32 CBitReader::ReadBits(unsigned numBits)
+{
+ UInt32 res = 0;
+ while (numBits > 0)
+ {
+ if (NumBits == 0)
+ {
+ Val = stream->ReadByte();
+ NumBits = 8;
+ }
+ if (numBits <= NumBits)
+ {
+ res <<= numBits;
+ NumBits -= numBits;
+ res |= (Val >> NumBits);
+ Val &= (1 << NumBits) - 1;
+ break;
+ }
+ else
+ {
+ res <<= NumBits;
+ res |= Val;
+ numBits -= NumBits;
+ NumBits = 0;
+ }
+ }
+ return res;
+}
+
+HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback)
+{
+ RINOK(_item.ReadHeader(stream))
+ if (!_item.IsUncompressed())
+ return S_FALSE;
+
+ CInBuffer s;
+ if (!s.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ s.SetStream(stream);
+ s.Init();
+ {
+ CBitReader br;
+ br.stream = &s;
+ unsigned numBits = br.ReadBits(5);
+ /* UInt32 xMin = */ br.ReadBits(numBits);
+ /* UInt32 xMax = */ br.ReadBits(numBits);
+ /* UInt32 yMin = */ br.ReadBits(numBits);
+ /* UInt32 yMax = */ br.ReadBits(numBits);
+ }
+ /* UInt32 frameDelay = */ Read16(s);
+ /* UInt32 numFrames = */ Read16(s);
+
+ _tags.Clear();
+ UInt64 offsetPrev = 0;
+ for (;;)
+ {
+ UInt32 pair = Read16(s);
+ UInt32 type = pair >> 6;
+ UInt32 length = pair & 0x3F;
+ if (length == 0x3F)
+ length = Read32(s);
+ if (type == 0)
+ break;
+ UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderSize + length;
+ if (offset > kFileSizeMax || _tags.Size() >= kNumTagsMax)
+ return S_FALSE;
+ _tags.Add(CTag());
+ CTag &tag = _tags.Back();
+ tag.Type = type;
+ tag.Buf.SetCapacity(length);
+ if (s.ReadBytes(tag.Buf, length) != length)
+ return S_FALSE;
+ if (callback && offset >= offsetPrev + (1 << 20))
+ {
+ UInt64 numItems = _tags.Size();
+ RINOK(callback->SetCompleted(&numItems, &offset));
+ offsetPrev = offset;
+ }
+ }
+ _packSize = s.GetProcessedSize() + NSwfc::kHeaderSize;
+ return S_OK;
+}
+
+HRESULT CHandler::OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback)
+{
+ HRESULT res;
+ try { res = OpenSeq3(stream, callback); }
+ catch(...) { res = S_FALSE; }
+ return res;
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ return OpenSeq2(stream, NULL);
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _tags.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _tags[allFilesMode ? i : indices[i]].Buf.GetCapacity();
+ extractCallback->SetTotal(totalSize);
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ totalSize = 0;
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+ const CByteBuffer &buf = _tags[index].Buf;
+ totalSize += buf.GetCapacity();
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode));
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ if (outStream)
+ RINOK(WriteStream(outStream, buf, buf.GetCapacity()));
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"SWF", L"swf", 0, 0xD7, { 'F', 'W', 'S' }, 3, true, CreateArc, 0 };
+
+REGISTER_ARC(Swf)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Tar/StdAfx.h
new file mode 100644
index 000000000..2e4be10b2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandler.cpp
new file mode 100644
index 000000000..4db0cae82
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -0,0 +1,386 @@
+// TarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "TarHandler.h"
+#include "TarIn.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NTar {
+
+static const char *kUnexpectedEnd = "Unexpected end of archive";
+
+static const STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidPosixAttrib, VT_UI4},
+ { NULL, kpidUser, VT_BSTR},
+ { NULL, kpidGroup, VT_BSTR},
+ { NULL, kpidLink, VT_BSTR}
+};
+
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
+ case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
+{
+ item.HeaderPos = _phySize;
+ RINOK(ReadItem(stream, filled, item, _errorMessage));
+ _phySize += item.HeaderSize;
+ _headersSize += item.HeaderSize;
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ UInt64 endPos = 0;
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+
+ _phySizeDefined = true;
+ for (;;)
+ {
+ CItemEx item;
+ bool filled;
+ RINOK(ReadItem2(stream, filled, item));
+ if (!filled)
+ break;
+ _items.Add(item);
+
+ RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize));
+ if (_phySize > endPos)
+ {
+ _errorMessage = kUnexpectedEnd;
+ break;
+ }
+ /*
+ if (_phySize == endPos)
+ {
+ _errorMessage = "There are no trailing zero-filled records";
+ break;
+ }
+ */
+ if (callback != NULL)
+ {
+ if (_items.Size() == 1)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos));
+ }
+ if (_items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ RINOK(callback->SetCompleted(&numFiles, &_phySize));
+ }
+ }
+ }
+
+ if (_items.Size() == 0)
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ if (!callback)
+ return S_FALSE;
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+ if (!openVolumeCallback)
+ return S_FALSE;
+ NCOM::CPropVariant prop;
+ if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK)
+ return S_FALSE;
+ if (prop.vt != VT_BSTR)
+ return S_FALSE;
+ UString baseName = prop.bstrVal;
+ baseName = baseName.Right(4);
+ if (baseName.CompareNoCase(L".tar") != 0)
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ RINOK(Open2(stream, openArchiveCallback));
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _errorMessage.Empty();
+ _phySizeDefined = false;
+ _phySize = 0;
+ _headersSize = 0;
+ _curIndex = 0;
+ _latestIsRead = false;
+ _items.Clear();
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1);
+ return S_OK;
+}
+
+CHandler::CHandler()
+{
+ copyCoderSpec = new NCompress::CCopyCoder();
+ copyCoder = copyCoderSpec;
+}
+
+HRESULT CHandler::SkipTo(UInt32 index)
+{
+ while (_curIndex < index || !_latestIsRead)
+ {
+ if (_latestIsRead)
+ {
+ UInt64 packSize = _latestItem.GetPackSize();
+ RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
+ _phySize += copyCoderSpec->TotalSize;
+ if (copyCoderSpec->TotalSize != packSize)
+ {
+ _errorMessage = kUnexpectedEnd;
+ return S_FALSE;
+ }
+ _latestIsRead = false;
+ _curIndex++;
+ }
+ else
+ {
+ bool filled;
+ RINOK(ReadItem2(_seqStream, filled, _latestItem));
+ if (!filled)
+ {
+ _phySizeDefined = true;
+ return E_INVALIDARG;
+ }
+ _latestIsRead = true;
+ }
+ }
+ return S_OK;
+}
+
+static UString TarStringToUnicode(const AString &s)
+{
+ return MultiByteToUnicodeString(s, CP_OEMCP);
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CItemEx *item;
+ if (_stream)
+ item = &_items[index];
+ else
+ {
+ if (index < _curIndex)
+ return E_INVALIDARG;
+ else
+ {
+ RINOK(SkipTo(index));
+ item = &_latestItem;
+ }
+ }
+
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
+ case kpidIsDir: prop = item->IsDir(); break;
+ case kpidSize: prop = item->GetUnpackSize(); break;
+ case kpidPackSize: prop = item->GetPackSize(); break;
+ case kpidMTime:
+ if (item->MTime != 0)
+ {
+ FILETIME ft;
+ NTime::UnixTimeToFileTime(item->MTime, ft);
+ prop = ft;
+ }
+ break;
+ case kpidPosixAttrib: prop = item->Mode; break;
+ case kpidUser: prop = TarStringToUnicode(item->User); break;
+ case kpidGroup: prop = TarStringToUnicode(item->Group); break;
+ case kpidLink: prop = TarStringToUnicode(item->LinkName); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ ISequentialInStream *stream = _seqStream;
+ bool seqMode = (_stream == NULL);
+ if (!seqMode)
+ stream = _stream;
+
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (_stream && numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize();
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(stream);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems || seqMode; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ const CItemEx *item;
+ if (seqMode)
+ {
+ HRESULT res = SkipTo(index);
+ if (res == E_INVALIDARG)
+ break;
+ RINOK(res);
+ item = &_latestItem;
+ }
+ else
+ item = &_items[index];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ UInt64 unpackSize = item->GetUnpackSize();
+ totalSize += unpackSize;
+ totalPackSize += item->GetPackSize();
+ if (item->IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ bool skipMode = false;
+ if (!testMode && !realOutStream)
+ {
+ if (!seqMode)
+ continue;
+ skipMode = true;
+ askMode = NExtract::NAskMode::kSkip;
+ }
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
+
+ if (item->IsLink())
+ {
+ RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
+ }
+ else
+ {
+ if (!seqMode)
+ {
+ RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
+ }
+ streamSpec->Init(item->GetPackSize());
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ }
+ if (seqMode)
+ {
+ _latestIsRead = false;
+ _curIndex++;
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(outStreamSpec->GetRem() == 0 ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ const CItemEx &item = _items[index];
+ if (item.IsLink())
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+ return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandler.h
new file mode 100644
index 000000000..b19670616
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandler.h
@@ -0,0 +1,61 @@
+// TarHandler.h
+
+#ifndef __TAR_HANDLER_H
+#define __TAR_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IInArchiveGetStream,
+ public IOutArchive,
+ public CMyUnknownImp
+{
+ CObjectVector<CItemEx> _items;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ UInt32 _curIndex;
+ bool _latestIsRead;
+ CItemEx _latestItem;
+
+ UInt64 _phySize;
+ UInt64 _headersSize;
+ bool _phySizeDefined;
+ AString _errorMessage;
+
+ NCompress::CCopyCoder *copyCoderSpec;
+ CMyComPtr<ICompressCoder> copyCoder;
+
+ HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ HRESULT SkipTo(UInt32 index);
+
+public:
+ MY_UNKNOWN_IMP4(
+ IInArchive,
+ IArchiveOpenSeq,
+ IInArchiveGetStream,
+ IOutArchive
+ )
+
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+
+ CHandler();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
new file mode 100644
index 000000000..ffdf2b136
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -0,0 +1,122 @@
+// TarHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "TarHandler.h"
+#include "TarUpdate.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NTar {
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
+{
+ *type = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res)
+{
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propId, &prop));
+ if (prop.vt == VT_BSTR)
+ res = UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP);
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback)
+{
+ COM_TRY_BEGIN
+ if ((_stream && !_errorMessage.IsEmpty()) || _seqStream)
+ return E_NOTIMPL;
+ CObjectVector<CUpdateItem> updateItems;
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData;
+ Int32 newProps;
+ UInt32 indexInArchive;
+ if (!callback)
+ return E_FAIL;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+ ui.NewProps = IntToBool(newProps);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArchive = indexInArchive;
+ ui.IndexInClient = i;
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Mode = 0777 | (ui.IsDir ? 0040000 : 0100000);
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Mode = prop.ulVal;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidMTime, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Time = 0;
+ else if (prop.vt != VT_FILETIME)
+ return E_INVALIDARG;
+ else if (!NTime::FileTimeToUnixTime(prop.filetime, ui.Time))
+ ui.Time = 0;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop));
+ if (prop.vt == VT_BSTR)
+ ui.Name = UnicodeStringToMultiByte(NItemName::MakeLegalName(prop.bstrVal), CP_OEMCP);
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ if (ui.IsDir)
+ ui.Name += '/';
+ }
+ RINOK(GetPropString(callback, i, kpidUser, ui.User));
+ RINOK(GetPropString(callback, i, kpidGroup, ui.Group));
+ }
+ if (IntToBool(newData))
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ ui.Size = prop.uhVal.QuadPart;
+ /*
+ // now we support GNU extension for big files
+ if (ui.Size >= ((UInt64)1 << 33))
+ return E_INVALIDARG;
+ */
+ }
+ updateItems.Add(ui);
+ }
+ return UpdateArchive(_stream, outStream, _items, updateItems, callback);
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHeader.cpp
new file mode 100644
index 000000000..3275b284c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHeader.cpp
@@ -0,0 +1,25 @@
+// Archive/Tar/Header.h
+
+#include "StdAfx.h"
+
+#include "TarHeader.h"
+
+namespace NArchive {
+namespace NTar {
+namespace NFileHeader {
+
+ // The checksum field is filled with this while the checksum is computed.
+ const char *kCheckSumBlanks = " "; // 8 blanks, no null
+
+ const char *kLongLink = "././@LongLink";
+ const char *kLongLink2 = "@LongLink";
+
+ // The magic field is filled with this if uname and gname are valid.
+ namespace NMagic
+ {
+ const char *kUsTar = "ustar"; // 5 chars
+ const char *kGNUTar = "GNUtar "; // 7 chars and a null
+ const char *kEmpty = "\0\0\0\0\0\0\0\0"; // 7 chars and a null
+ }
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHeader.h
new file mode 100644
index 000000000..0b78bdc26
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarHeader.h
@@ -0,0 +1,108 @@
+// Archive/Tar/Header.h
+
+#ifndef __ARCHIVE_TAR_HEADER_H
+#define __ARCHIVE_TAR_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NTar {
+
+namespace NFileHeader
+{
+ const int kRecordSize = 512;
+ const int kNameSize = 100;
+ const int kUserNameSize = 32;
+ const int kGroupNameSize = 32;
+ const int kPrefixSize = 155;
+
+ /*
+ struct CHeader
+ {
+ char Name[kNameSize];
+ char Mode[8];
+ char UID[8];
+ char GID[8];
+ char Size[12];
+ char ModificationTime[12];
+ char CheckSum[8];
+ char LinkFlag;
+ char LinkName[kNameSize];
+ char Magic[8];
+ char UserName[kUserNameSize];
+ char GroupName[kGroupNameSize];
+ char DeviceMajor[8];
+ char DeviceMinor[8];
+ char Prefix[155];
+ };
+ union CRecord
+ {
+ CHeader Header;
+ Byte Padding[kRecordSize];
+ };
+ */
+
+ namespace NMode
+ {
+ const int kSetUID = 04000; // Set UID on execution
+ const int kSetGID = 02000; // Set GID on execution
+ const int kSaveText = 01000; // Save text (sticky bit)
+ }
+
+ namespace NFilePermissions
+ {
+ const int kUserRead = 00400; // read by owner
+ const int kUserWrite = 00200; // write by owner
+ const int kUserExecute = 00100; // execute/search by owner
+ const int kGroupRead = 00040; // read by group
+ const int kGroupWrite = 00020; // write by group
+ const int kGroupExecute = 00010; // execute/search by group
+ const int kOtherRead = 00004; // read by other
+ const int kOtherWrite = 00002; // write by other
+ const int kOtherExecute = 00001; // execute/search by other
+ }
+
+
+ // The linkflag defines the type of file
+ namespace NLinkFlag
+ {
+ const char kOldNormal = '\0'; // Normal disk file, Unix compatible
+ const char kNormal = '0'; // Normal disk file
+ const char kLink = '1'; // Link to previously dumped file
+ const char kSymbolicLink = '2'; // Symbolic link
+ const char kCharacter = '3'; // Character special file
+ const char kBlock = '4'; // Block special file
+ const char kDirectory = '5'; // Directory
+ const char kFIFO = '6'; // FIFO special file
+ const char kContiguous = '7'; // Contiguous file
+
+ const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
+ data: list of files created by the --incremental (-G) option
+ Each file name is preceded by either
+ - 'Y' (file should be in this archive)
+ - 'N' (file is a directory, or is not stored in the archive.)
+ Each file name is terminated by a null + an additional null after
+ the last file name. */
+
+ }
+ // Further link types may be defined later.
+
+ // The checksum field is filled with this while the checksum is computed.
+ extern const char *kCheckSumBlanks;// = " "; // 8 blanks, no null
+
+ extern const char *kLongLink; // = "././@LongLink";
+ extern const char *kLongLink2; // = "@LongLink";
+
+ // The magic field is filled with this if uname and gname are valid.
+ namespace NMagic
+ {
+ extern const char *kUsTar; // = "ustar"; // 5 chars
+ extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null
+ extern const char *kEmpty; // = "GNUtar "; // 7 chars and a null
+ }
+
+}
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarIn.cpp
new file mode 100644
index 000000000..5ceaa509d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -0,0 +1,207 @@
+// TarIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/StringToInt.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "TarIn.h"
+
+namespace NArchive {
+namespace NTar {
+
+static void MyStrNCpy(char *dest, const char *src, int size)
+{
+ for (int i = 0; i < size; i++)
+ {
+ char c = src[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+}
+
+static bool OctalToNumber(const char *srcString, int size, UInt64 &res)
+{
+ char sz[32];
+ MyStrNCpy(sz, srcString, size);
+ sz[size] = 0;
+ const char *end;
+ int i;
+ for (i = 0; sz[i] == ' '; i++);
+ res = ConvertOctStringToUInt64(sz + i, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool OctalToNumber32(const char *srcString, int size, UInt32 &res)
+{
+ UInt64 res64;
+ if (!OctalToNumber(srcString, size, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+static bool IsRecordLast(const char *buf)
+{
+ for (int i = 0; i < NFileHeader::kRecordSize; i++)
+ if (buf[i] != 0)
+ return false;
+ return true;
+}
+
+static void ReadString(const char *s, int size, AString &result)
+{
+ char temp[NFileHeader::kRecordSize + 1];
+ MyStrNCpy(temp, s, size);
+ temp[size] = '\0';
+ result = temp;
+}
+
+static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
+{
+ char buf[NFileHeader::kRecordSize];
+ char *p = buf;
+
+ error.Empty();
+ filled = false;
+
+ bool thereAreEmptyRecords = false;
+ for (;;)
+ {
+ size_t processedSize = NFileHeader::kRecordSize;
+ RINOK(ReadStream(stream, buf, &processedSize));
+ if (processedSize == 0)
+ {
+ if (!thereAreEmptyRecords )
+ error = "There are no trailing zero-filled records";
+ return S_OK;
+ }
+ if (processedSize != NFileHeader::kRecordSize)
+ {
+ error = "There is no correct record at the end of archive";
+ return S_OK;
+ }
+ item.HeaderSize += NFileHeader::kRecordSize;
+ if (!IsRecordLast(buf))
+ break;
+ thereAreEmptyRecords = true;
+ }
+ if (thereAreEmptyRecords)
+ {
+ error = "There are data after end of archive";
+ return S_OK;
+ }
+
+ ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
+
+ RIF(OctalToNumber32(p, 8, item.Mode)); p += 8;
+
+ if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8;
+ if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8;
+
+ if (GetBe32(p) == (UInt32)1 << 31)
+ {
+ // GNU extension
+ item.Size = GetBe64(p + 4);
+ }
+ else
+ {
+ RIF(OctalToNumber(p, 12, item.Size));
+ }
+ p += 12;
+ RIF(OctalToNumber32(p, 12, item.MTime)); p += 12;
+
+ UInt32 checkSum;
+ RIF(OctalToNumber32(p, 8, checkSum));
+ memcpy(p, NFileHeader::kCheckSumBlanks, 8); p += 8;
+
+ item.LinkFlag = *p++;
+
+ ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize;
+
+ memcpy(item.Magic, p, 8); p += 8;
+
+ ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
+ ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
+
+ item.DeviceMajorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMajor)); p += 8;
+ item.DeviceMinorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMinor)); p += 8;
+
+ AString prefix;
+ ReadString(p, NFileHeader::kPrefixSize, prefix);
+ p += NFileHeader::kPrefixSize;
+ if (!prefix.IsEmpty() && item.IsMagic() &&
+ (item.LinkFlag != 'L' /* || prefix != "00000000000" */ ))
+ item.Name = prefix + AString('/') + item.Name;
+
+ if (item.LinkFlag == NFileHeader::NLinkFlag::kLink)
+ item.Size = 0;
+
+ UInt32 checkSumReal = 0;
+ for (int i = 0; i < NFileHeader::kRecordSize; i++)
+ checkSumReal += (Byte)buf[i];
+
+ if (checkSumReal != checkSum)
+ return S_FALSE;
+
+ filled = true;
+ return S_OK;
+}
+
+HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
+{
+ item.HeaderSize = 0;
+ bool flagL = false;
+ bool flagK = false;
+ AString nameL;
+ AString nameK;
+ for (;;)
+ {
+ RINOK(GetNextItemReal(stream, filled, item, error));
+ if (!filled)
+ return S_OK;
+ if (item.LinkFlag == 'L' || // NEXT file has a long name
+ item.LinkFlag == 'K') // NEXT file has a long linkname
+ {
+ AString *name;
+ if (item.LinkFlag == 'L')
+ { if (flagL) return S_FALSE; flagL = true; name = &nameL; }
+ else
+ { if (flagK) return S_FALSE; flagK = true; name = &nameK; }
+
+ if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
+ item.Name.Compare(NFileHeader::kLongLink2) != 0)
+ return S_FALSE;
+ if (item.Size > (1 << 14))
+ return S_FALSE;
+ int packSize = (int)item.GetPackSize();
+ char *buf = name->GetBuffer(packSize);
+ RINOK(ReadStream_FALSE(stream, buf, packSize));
+ item.HeaderSize += packSize;
+ buf[(size_t)item.Size] = '\0';
+ name->ReleaseBuffer();
+ continue;
+ }
+ if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
+ {
+ // pax Extended Header
+ }
+ else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
+ {
+ // GNU Extensions to the Archive Format
+ }
+ else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
+ return S_FALSE;
+ if (flagL) item.Name = nameL;
+ if (flagK) item.LinkName = nameK;
+ return S_OK;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarIn.h
new file mode 100644
index 000000000..a5491ebe4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarIn.h
@@ -0,0 +1,17 @@
+// TarIn.h
+
+#ifndef __ARCHIVE_TAR_IN_H
+#define __ARCHIVE_TAR_IN_H
+
+#include "../../IStream.h"
+
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarItem.h b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarItem.h
new file mode 100644
index 000000000..859e66dd8
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarItem.h
@@ -0,0 +1,72 @@
+// TarItem.h
+
+#ifndef __ARCHIVE_TAR_ITEM_H
+#define __ARCHIVE_TAR_ITEM_H
+
+#include "../Common/ItemNameUtils.h"
+
+#include "TarHeader.h"
+
+namespace NArchive {
+namespace NTar {
+
+struct CItem
+{
+ AString Name;
+ UInt64 Size;
+
+ UInt32 Mode;
+ UInt32 UID;
+ UInt32 GID;
+ UInt32 MTime;
+ UInt32 DeviceMajor;
+ UInt32 DeviceMinor;
+
+ AString LinkName;
+ AString User;
+ AString Group;
+
+ char Magic[8];
+ char LinkFlag;
+ bool DeviceMajorDefined;
+ bool DeviceMinorDefined;
+
+ bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
+ UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; }
+
+ bool IsDir() const
+ {
+ switch(LinkFlag)
+ {
+ case NFileHeader::NLinkFlag::kDirectory:
+ case NFileHeader::NLinkFlag::kDumpDir:
+ return true;
+ case NFileHeader::NLinkFlag::kOldNormal:
+ case NFileHeader::NLinkFlag::kNormal:
+ return NItemName::HasTailSlash(Name, CP_OEMCP);
+ }
+ return false;
+ }
+
+ bool IsMagic() const
+ {
+ for (int i = 0; i < 5; i++)
+ if (Magic[i] != NFileHeader::NMagic::kUsTar[i])
+ return false;
+ return true;
+ }
+
+ UInt64 GetPackSize() const { return (Size + 0x1FF) & (~((UInt64)0x1FF)); }
+};
+
+struct CItemEx: public CItem
+{
+ UInt64 HeaderPos;
+ unsigned HeaderSize;
+ UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
+ UInt64 GetFullSize() const { return HeaderSize + Size; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarOut.cpp
new file mode 100644
index 000000000..e542a3b2f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarOut.cpp
@@ -0,0 +1,187 @@
+// TarOut.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "TarOut.h"
+
+namespace NArchive {
+namespace NTar {
+
+HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size)
+{
+ return WriteStream(m_Stream, buffer, size);
+}
+
+void COutArchive::Create(ISequentialOutStream *outStream)
+{
+ m_Stream = outStream;
+}
+
+static AString MakeOctalString(UInt64 value)
+{
+ char s[32];
+ ConvertUInt64ToString(value, s, 8);
+ return AString(s) + ' ';
+}
+
+static void MyStrNCpy(char *dest, const char *src, int size)
+{
+ for (int i = 0; i < size; i++)
+ {
+ char c = src[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+}
+
+static bool MakeOctalString8(char *s, UInt32 value)
+{
+ AString tempString = MakeOctalString(value);
+
+ const int kMaxSize = 8;
+ if (tempString.Length() >= kMaxSize)
+ return false;
+ int numSpaces = kMaxSize - (tempString.Length() + 1);
+ for(int i = 0; i < numSpaces; i++)
+ s[i] = ' ';
+ MyStringCopy(s + numSpaces, (const char *)tempString);
+ return true;
+}
+
+static void MakeOctalString12(char *s, UInt64 value)
+{
+ AString tempString = MakeOctalString(value);
+ const int kMaxSize = 12;
+ if (tempString.Length() > kMaxSize)
+ {
+ // GNU extension;
+ s[0] = (char)(Byte)0x80;
+ s[1] = s[2] = s[3] = 0;
+ for (int i = 0; i < 8; i++, value <<= 8)
+ s[4 + i] = (char)(value >> 56);
+ return;
+ }
+ int numSpaces = kMaxSize - tempString.Length();
+ for(int i = 0; i < numSpaces; i++)
+ s[i] = ' ';
+ memmove(s + numSpaces, (const char *)tempString, tempString.Length());
+}
+
+static bool CopyString(char *dest, const AString &src, int maxSize)
+{
+ if (src.Length() >= maxSize)
+ return false;
+ MyStringCopy(dest, (const char *)src);
+ return true;
+}
+
+#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; }
+
+HRESULT COutArchive::WriteHeaderReal(const CItem &item)
+{
+ char record[NFileHeader::kRecordSize];
+ char *cur = record;
+ int i;
+ for (i = 0; i < NFileHeader::kRecordSize; i++)
+ record[i] = 0;
+
+ // RETURN_IF_NOT_TRUE(CopyString(header.Name, item.Name, NFileHeader::kNameSize));
+ if (item.Name.Length() > NFileHeader::kNameSize)
+ return E_FAIL;
+ MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
+ cur += NFileHeader::kNameSize;
+
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8;
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;
+
+ MakeOctalString12(cur, item.Size); cur += 12;
+ MakeOctalString12(cur, item.MTime); cur += 12;
+
+ memmove(cur, NFileHeader::kCheckSumBlanks, 8);
+ cur += 8;
+
+ *cur++ = item.LinkFlag;
+
+ RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));
+ cur += NFileHeader::kNameSize;
+
+ memmove(cur, item.Magic, 8);
+ cur += 8;
+
+ RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));
+ cur += NFileHeader::kUserNameSize;
+ RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize));
+ cur += NFileHeader::kGroupNameSize;
+
+
+ if (item.DeviceMajorDefined)
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor));
+ cur += 8;
+
+ if (item.DeviceMinorDefined)
+ RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMinor));
+ cur += 8;
+
+
+ UInt32 checkSumReal = 0;
+ for(i = 0; i < NFileHeader::kRecordSize; i++)
+ checkSumReal += Byte(record[i]);
+
+ RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal));
+
+ return WriteBytes(record, NFileHeader::kRecordSize);
+}
+
+HRESULT COutArchive::WriteHeader(const CItem &item)
+{
+ int nameSize = item.Name.Length();
+ if (nameSize < NFileHeader::kNameSize)
+ return WriteHeaderReal(item);
+
+ CItem modifiedItem = item;
+ int nameStreamSize = nameSize + 1;
+ modifiedItem.Size = nameStreamSize;
+ modifiedItem.LinkFlag = 'L';
+ modifiedItem.Name = NFileHeader::kLongLink;
+ modifiedItem.LinkName.Empty();
+ RINOK(WriteHeaderReal(modifiedItem));
+ RINOK(WriteBytes(item.Name, nameStreamSize));
+ RINOK(FillDataResidual(nameStreamSize));
+
+ modifiedItem = item;
+ modifiedItem.Name = item.Name.Left(NFileHeader::kNameSize - 1);
+ return WriteHeaderReal(modifiedItem);
+}
+
+HRESULT COutArchive::FillDataResidual(UInt64 dataSize)
+{
+ UInt32 lastRecordSize = UInt32(dataSize & (NFileHeader::kRecordSize - 1));
+ if (lastRecordSize == 0)
+ return S_OK;
+ UInt32 residualSize = NFileHeader::kRecordSize - lastRecordSize;
+ Byte residualBytes[NFileHeader::kRecordSize];
+ for (UInt32 i = 0; i < residualSize; i++)
+ residualBytes[i] = 0;
+ return WriteBytes(residualBytes, residualSize);
+}
+
+HRESULT COutArchive::WriteFinishHeader()
+{
+ Byte record[NFileHeader::kRecordSize];
+ int i;
+ for (i = 0; i < NFileHeader::kRecordSize; i++)
+ record[i] = 0;
+ for (i = 0; i < 2; i++)
+ {
+ RINOK(WriteBytes(record, NFileHeader::kRecordSize));
+ }
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarOut.h b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarOut.h
new file mode 100644
index 000000000..ef837869b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarOut.h
@@ -0,0 +1,28 @@
+// Archive/TarOut.h
+
+#ifndef __ARCHIVE_TAR_OUT_H
+#define __ARCHIVE_TAR_OUT_H
+
+#include "TarItem.h"
+
+#include "Common/MyCom.h"
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NTar {
+
+class COutArchive
+{
+ CMyComPtr<ISequentialOutStream> m_Stream;
+ HRESULT WriteBytes(const void *buffer, UInt32 size);
+public:
+ void Create(ISequentialOutStream *outStream);
+ HRESULT WriteHeaderReal(const CItem &item);
+ HRESULT WriteHeader(const CItem &item);
+ HRESULT FillDataResidual(UInt64 dataSize);
+ HRESULT WriteFinishHeader();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarRegister.cpp
new file mode 100644
index 000000000..e21c0aac4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarRegister.cpp
@@ -0,0 +1,18 @@
+// TarRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "TarHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NTar::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NTar::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+{ L"tar", L"tar", 0, 0xEE, { 'u', 's', 't', 'a', 'r' }, 5, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Tar)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarUpdate.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarUpdate.cpp
new file mode 100644
index 000000000..c16332189
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarUpdate.cpp
@@ -0,0 +1,139 @@
+// TarUpdate.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "TarOut.h"
+#include "TarUpdate.h"
+
+namespace NArchive {
+namespace NTar {
+
+HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
+ const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ COutArchive outArchive;
+ outArchive.Create(outStream);
+
+ UInt64 complexity = 0;
+
+ int i;
+ for(i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ complexity += ui.Size;
+ else
+ complexity += inputItems[ui.IndexInArchive].GetFullSize();
+ }
+
+ RINOK(updateCallback->SetTotal(complexity));
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
+ streamSpec->SetStream(inStream);
+
+ complexity = 0;
+
+ for(i = 0; i < updateItems.Size(); i++)
+ {
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur());
+
+ const CUpdateItem &ui = updateItems[i];
+ CItem item;
+ if (ui.NewProps)
+ {
+ item.Mode = ui.Mode;
+ item.Name = ui.Name;
+ item.User = ui.User;
+ item.Group = ui.Group;
+ if (ui.IsDir)
+ {
+ item.LinkFlag = NFileHeader::NLinkFlag::kDirectory;
+ item.Size = 0;
+ }
+ else
+ {
+ item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
+ item.Size = ui.Size;
+ }
+ item.MTime = ui.Time;
+ item.DeviceMajorDefined = false;
+ item.DeviceMinorDefined = false;
+ item.UID = 0;
+ item.GID = 0;
+ memmove(item.Magic, NFileHeader::NMagic::kEmpty, 8);
+ }
+ else
+ item = inputItems[ui.IndexInArchive];
+
+ if (ui.NewData)
+ {
+ item.Size = ui.Size;
+ if (item.Size == (UInt64)(Int64)-1)
+ return E_INVALIDARG;
+ }
+ else
+ item.Size = inputItems[ui.IndexInArchive].Size;
+
+ if (ui.NewData)
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res != S_FALSE)
+ {
+ RINOK(res);
+ RINOK(outArchive.WriteHeader(item));
+ if (!ui.IsDir)
+ {
+ RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != item.Size)
+ return E_FAIL;
+ RINOK(outArchive.FillDataResidual(item.Size));
+ }
+ }
+ complexity += ui.Size;
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+ else
+ {
+ const CItemEx &existItem = inputItems[ui.IndexInArchive];
+ UInt64 size;
+ if (ui.NewProps)
+ {
+ RINOK(outArchive.WriteHeader(item));
+ RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
+ size = existItem.Size;
+ }
+ else
+ {
+ RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL));
+ size = existItem.GetFullSize();
+ }
+ streamSpec->Init(size);
+
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
+ if (copyCoderSpec->TotalSize != size)
+ return E_FAIL;
+ RINOK(outArchive.FillDataResidual(existItem.Size));
+ complexity += size;
+ }
+ }
+ return outArchive.WriteFinishHeader();
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarUpdate.h b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarUpdate.h
new file mode 100644
index 000000000..fb217d196
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Tar/TarUpdate.h
@@ -0,0 +1,34 @@
+// TarUpdate.h
+
+#ifndef __TAR_UPDATE_H
+#define __TAR_UPDATE_H
+
+#include "../IArchive.h"
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+struct CUpdateItem
+{
+ int IndexInArchive;
+ int IndexInClient;
+ UInt32 Time;
+ UInt32 Mode;
+ UInt64 Size;
+ AString Name;
+ AString User;
+ AString Group;
+ bool NewData;
+ bool NewProps;
+ bool IsDir;
+};
+
+HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ IArchiveUpdateCallback *updateCallback);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Udf/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Udf/StdAfx.h
new file mode 100644
index 000000000..2e4be10b2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Udf/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfHandler.cpp
new file mode 100644
index 000000000..c70852728
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfHandler.cpp
@@ -0,0 +1,451 @@
+// UdfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "UdfHandler.h"
+
+namespace NArchive {
+namespace NUdf {
+
+void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop)
+{
+ UInt64 numSecs;
+ const Byte *d = t.Data;
+ if (!NWindows::NTime::GetSecondsSince1601(t.GetYear(), d[4], d[5], d[6], d[7], d[8], numSecs))
+ return;
+ if (t.IsLocal())
+ numSecs -= t.GetMinutesOffset() * 60;
+ FILETIME ft;
+ UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10;
+ ft.dwLowDateTime = (UInt32)v;
+ ft.dwHighDateTime = (UInt32)(v >> 32);
+ prop = ft;
+}
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME}
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidCTime, VT_FILETIME}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidComment:
+ {
+ UString comment = _archive.GetComment();
+ if (!comment.IsEmpty())
+ prop = comment;
+ break;
+ }
+
+ case kpidClusterSize:
+ if (_archive.LogVols.Size() > 0)
+ {
+ UInt32 blockSize = _archive.LogVols[0].BlockSize;
+ int i;
+ for (i = 1; i < _archive.LogVols.Size(); i++)
+ if (_archive.LogVols[i].BlockSize != blockSize)
+ break;
+ if (i == _archive.LogVols.Size())
+ prop = blockSize;
+ }
+ break;
+
+ case kpidCTime:
+ if (_archive.LogVols.Size() == 1)
+ {
+ const CLogVol &vol = _archive.LogVols[0];
+ if (vol.FileSets.Size() >= 1)
+ UdfTimeToFileTime(vol.FileSets[0].RecodringTime, prop);
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+ UInt64 _numFiles;
+ UInt64 _numBytes;
+public:
+ HRESULT SetTotal(UInt64 numBytes);
+ HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes);
+ HRESULT SetCompleted();
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback), _numFiles(0), _numBytes(0) {}
+};
+
+HRESULT CProgressImp::SetTotal(UInt64 numBytes)
+{
+ if (_callback)
+ return _callback->SetTotal(NULL, &numBytes);
+ return S_OK;
+}
+
+HRESULT CProgressImp::SetCompleted(UInt64 numFiles, UInt64 numBytes)
+{
+ _numFiles = numFiles;
+ _numBytes = numBytes;
+ return SetCompleted();
+}
+
+HRESULT CProgressImp::SetCompleted()
+{
+ if (_callback)
+ return _callback->SetCompleted(&_numFiles, &_numBytes);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ CProgressImp progressImp(callback);
+ RINOK(_archive.Open(stream, &progressImp));
+ bool showVolName = (_archive.LogVols.Size() > 1);
+ for (int volIndex = 0; volIndex < _archive.LogVols.Size(); volIndex++)
+ {
+ const CLogVol &vol = _archive.LogVols[volIndex];
+ bool showFileSetName = (vol.FileSets.Size() > 1);
+ for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++)
+ {
+ const CFileSet &fs = vol.FileSets[fsIndex];
+ for (int i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++)
+ {
+ CRef2 ref2;
+ ref2.Vol = volIndex;
+ ref2.Fs = fsIndex;
+ ref2.Ref = i;
+ _refs2.Add(ref2);
+ }
+ }
+ }
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _archive.Clear();
+ _refs2.Clear();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _refs2.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ {
+ const CRef2 &ref2 = _refs2[index];
+ const CLogVol &vol = _archive.LogVols[ref2.Vol];
+ const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ switch(propID)
+ {
+ case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref,
+ _archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: if (!item.IsDir()) prop = (UInt64)item.Size; break;
+ case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break;
+ case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break;
+ case kpidATime: UdfTimeToFileTime(item.ATime, prop); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+struct CSeekExtent
+{
+ UInt64 Phy;
+ UInt64 Virt;
+};
+
+class CExtentsStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _phyPos;
+ UInt64 _virtPos;
+ bool _needStartSeek;
+
+ HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); }
+
+public:
+ CMyComPtr<IInStream> Stream;
+ CRecordVector<CSeekExtent> Extents;
+
+ MY_UNKNOWN_IMP1(IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ void ReleaseStream() { Stream.Release(); }
+
+ void Init()
+ {
+ _virtPos = 0;
+ _phyPos = 0;
+ _needStartSeek = true;
+ }
+
+};
+
+
+STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size > 0)
+ {
+ UInt64 totalSize = Extents.Back().Virt;
+ if (_virtPos >= totalSize)
+ return (_virtPos == totalSize) ? S_OK : E_FAIL;
+ int left = 0, right = Extents.Size() - 1;
+ for (;;)
+ {
+ int mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (_virtPos < Extents[mid].Virt)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ const CSeekExtent &extent = Extents[left];
+ UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);
+ if (_needStartSeek || _phyPos != phyPos)
+ {
+ _needStartSeek = false;
+ _phyPos = phyPos;
+ RINOK(SeekToPhys());
+ }
+
+ UInt64 rem = Extents[left + 1].Virt - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+
+ HRESULT res = Stream->Read(data, size, &size);
+ _phyPos += size;
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return res;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = Extents.Back().Virt + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ *stream = 0;
+
+ const CRef2 &ref2 = _refs2[index];
+ const CLogVol &vol = _archive.LogVols[ref2.Vol];
+ const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ UInt64 size = item.Size;
+
+ if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || ! _archive.CheckItemExtents(ref2.Vol, item))
+ return E_NOTIMPL;
+
+ if (item.IsInline)
+ {
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ CReferenceBuf *referenceBuf = new CReferenceBuf;
+ CMyComPtr<IUnknown> ref = referenceBuf;
+ referenceBuf->Buf = item.InlineData;
+ inStreamSpec->Init(referenceBuf);
+ *stream = inStream.Detach();
+ return S_OK;
+ }
+
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ extentStreamSpec->Stream = _inStream;
+
+ UInt64 virtOffset = 0;
+ for (int extentIndex = 0; extentIndex < item.Extents.Size(); extentIndex++)
+ {
+ const CMyExtent &extent = item.Extents[extentIndex];
+ UInt32 len = extent.GetLen();
+ if (len == 0)
+ continue;
+ if (size < len)
+ return S_FALSE;
+
+ int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex;
+ UInt32 logBlockNumber = extent.Pos;
+ const CPartition &partition = _archive.Partitions[partitionIndex];
+ UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) +
+ (UInt64)logBlockNumber * vol.BlockSize;
+
+ CSeekExtent se;
+ se.Phy = offset;
+ se.Virt = virtOffset;
+ virtOffset += len;
+ extentStreamSpec->Extents.Add(se);
+
+ size -= len;
+ }
+ if (size != 0)
+ return S_FALSE;
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virtOffset;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _refs2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ const CRef2 &ref2 = _refs2[index];
+ const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ const CRef2 &ref2 = _refs2[index];
+ const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ currentTotalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(item.Size);
+ Int32 opRes;
+ CMyComPtr<ISequentialInStream> udfInStream;
+ HRESULT res = GetStream(index, &udfInStream);
+ if (res == E_NOTIMPL)
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ else if (res != S_OK)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(copyCoder->Code(udfInStream, outStream, NULL, NULL, progress));
+ opRes = outStreamSpec->IsFinishedOK() ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError;
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfHandler.h
new file mode 100644
index 000000000..f513727d7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfHandler.h
@@ -0,0 +1,37 @@
+// Udf/Handler.h
+
+#ifndef __UDF_HANDLER_H
+#define __UDF_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "../IArchive.h"
+
+#include "UdfIn.h"
+
+namespace NArchive {
+namespace NUdf {
+
+struct CRef2
+{
+ int Vol;
+ int Fs;
+ int Ref;
+};
+
+class CHandler:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _inStream;
+ CInArchive _archive;
+ CRecordVector<CRef2> _refs2;
+public:
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfIn.cpp
new file mode 100644
index 000000000..60d5fc2ad
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -0,0 +1,876 @@
+// Archive/UdfIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "UdfIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NUdf {
+
+const int kNumPartitionsMax = 64;
+const int kNumLogVolumesMax = 64;
+const int kNumRecureseLevelsMax = 1 << 10;
+const int kNumItemsMax = 1 << 27;
+const int kNumFilesMax = 1 << 28;
+const int kNumRefsMax = 1 << 28;
+const UInt32 kNumExtentsMax = (UInt32)1 << 30;
+const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33;
+const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33;
+
+void MY_FAST_CALL Crc16GenerateTable(void);
+
+#define CRC16_INIT_VAL 0
+#define CRC16_GET_DIGEST(crc) (crc)
+#define CRC16_UPDATE_BYTE(crc, b) (g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))
+
+#define kCrc16Poly 0x1021
+UInt16 g_Crc16Table[256];
+
+void MY_FAST_CALL Crc16GenerateTable(void)
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = (i << 8);
+ for (int j = 8; j > 0; j--)
+ r = ((r & 0x8000) ? ((r << 1) ^ kCrc16Poly) : (r << 1)) & 0xFFFF;
+ g_Crc16Table[i] = (UInt16)r;
+ }
+}
+
+UInt16 MY_FAST_CALL Crc16_Update(UInt16 v, const void *data, size_t size)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 ; size--, p++)
+ v = CRC16_UPDATE_BYTE(v, *p);
+ return v;
+}
+
+UInt16 MY_FAST_CALL Crc16Calc(const void *data, size_t size)
+{
+ return Crc16_Update(CRC16_INIT_VAL, data, size);
+}
+
+struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit;
+
+void CDString128::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
+
+void CDString::Parse(const Byte *p, unsigned size)
+{
+ Data.SetCapacity(size);
+ memcpy(Data, p, size);
+}
+
+static UString ParseDString(const Byte *data, int size)
+{
+ UString res;
+ wchar_t *p;
+ if (size > 0)
+ {
+ Byte type = data[0];
+ if (type == 8)
+ {
+ p = res.GetBuffer((int)size + 1);
+ for (int i = 1; i < size; i++)
+ {
+ wchar_t c = data[i];
+ if (c == 0)
+ break;
+ *p++ = c;
+ }
+ }
+ else if (type == 16)
+ {
+ p = res.GetBuffer((int)size / 2 + 1);
+ for (int i = 1; i + 2 <= size; i += 2)
+ {
+ wchar_t c = ((wchar_t)data[i] << 8) | data[i + 1];
+ if (c == 0)
+ break;
+ *p++ = c;
+ }
+ }
+ else
+ return L"[unknow]";
+ *p++ = 0;
+ res.ReleaseBuffer();
+ }
+ return res;
+}
+
+UString CDString:: GetString() const { return ParseDString(Data, (int)Data.GetCapacity()); }
+UString CDString128::GetString() const
+{
+ int size = Data[sizeof(Data) - 1];
+ return ParseDString(Data, MyMin(size, (int)(sizeof(Data) - 1)));
+}
+
+void CTime::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
+
+/*
+void CRegId::Parse(const Byte *buf)
+{
+ Flags = buf[0];
+ memcpy(Id, buf + 1, sizeof(Id));
+ memcpy(Suffix, buf + 24, sizeof(Suffix));
+}
+*/
+
+// ECMA 3/7.1
+
+struct CExtent
+{
+ UInt32 Len;
+ UInt32 Pos;
+
+ void Parse(const Byte *buf);
+};
+
+void CExtent::Parse(const Byte *buf)
+{
+ Len = Get32(buf);
+ Pos = Get32(buf + 4);
+}
+
+// ECMA 3/7.2
+
+struct CTag
+{
+ UInt16 Id;
+ UInt16 Version;
+ // Byte Checksum;
+ // UInt16 SerialNumber;
+ // UInt16 Crc;
+ // UInt16 CrcLen;
+ // UInt32 TagLocation;
+
+ HRESULT Parse(const Byte *buf, size_t size);
+};
+
+HRESULT CTag::Parse(const Byte *buf, size_t size)
+{
+ if (size < 16)
+ return S_FALSE;
+ Byte sum = 0;
+ int i;
+ for (i = 0; i < 4; i++) sum = sum + buf[i];
+ for (i = 5; i < 16; i++) sum = sum + buf[i];
+ if (sum != buf[4] || buf[5] != 0) return S_FALSE;
+
+ Id = Get16(buf);
+ Version = Get16(buf + 2);
+ // SerialNumber = Get16(buf + 6);
+ UInt16 crc = Get16(buf + 8);
+ UInt16 crcLen = Get16(buf + 10);
+ // TagLocation = Get32(buf + 12);
+
+ if (size >= 16 + (size_t)crcLen)
+ if (crc == Crc16Calc(buf + 16, crcLen))
+ return S_OK;
+ return S_FALSE;
+}
+
+// ECMA 3/7.2.1
+
+enum EDescriptorType
+{
+ DESC_TYPE_SpoaringTable = 0, // UDF
+ DESC_TYPE_PrimVol = 1,
+ DESC_TYPE_AnchorVolPtr = 2,
+ DESC_TYPE_VolPtr = 3,
+ DESC_TYPE_ImplUseVol = 4,
+ DESC_TYPE_Partition = 5,
+ DESC_TYPE_LogicalVol = 6,
+ DESC_TYPE_UnallocSpace = 7,
+ DESC_TYPE_Terminating = 8,
+ DESC_TYPE_LogicalVolIntegrity = 9,
+ DESC_TYPE_FileSet = 256,
+ DESC_TYPE_FileId = 257,
+ DESC_TYPE_AllocationExtent = 258,
+ DESC_TYPE_Indirect = 259,
+ DESC_TYPE_Terminal = 260,
+ DESC_TYPE_File = 261,
+ DESC_TYPE_ExtendedAttrHeader = 262,
+ DESC_TYPE_UnallocatedSpace = 263,
+ DESC_TYPE_SpaceBitmap = 264,
+ DESC_TYPE_PartitionIntegrity = 265,
+ DESC_TYPE_ExtendedFile = 266
+};
+
+
+void CLogBlockAddr::Parse(const Byte *buf)
+{
+ Pos = Get32(buf);
+ PartitionRef = Get16(buf + 4);
+}
+
+void CShortAllocDesc::Parse(const Byte *buf)
+{
+ Len = Get32(buf);
+ Pos = Get32(buf + 4);
+}
+
+/*
+void CADImpUse::Parse(const Byte *buf)
+{
+ Flags = Get16(buf);
+ UdfUniqueId = Get32(buf + 2);
+}
+*/
+
+void CLongAllocDesc::Parse(const Byte *buf)
+{
+ Len = Get32(buf);
+ Location.Parse(buf + 4);
+ // memcpy(ImplUse, buf + 10, sizeof(ImplUse));
+ // adImpUse.Parse(ImplUse);
+}
+
+bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const
+{
+ const CLogVol &vol = LogVols[volIndex];
+ const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
+ UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize;
+ return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize);
+}
+
+bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const
+{
+ for (int i = 0; i < item.Extents.Size(); i++)
+ {
+ const CMyExtent &e = item.Extents[i];
+ if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen()))
+ return false;
+ }
+ return true;
+}
+
+HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf)
+{
+ if (!CheckExtent(volIndex, partitionRef, blockPos, len))
+ return S_FALSE;
+ const CLogVol &vol = LogVols[volIndex];
+ const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
+ RINOK(_stream->Seek(((UInt64)partition.Pos << SecLogSize) +
+ (UInt64)blockPos * vol.BlockSize, STREAM_SEEK_SET, NULL));
+ return ReadStream_FALSE(_stream, buf, len);
+}
+
+HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf)
+{
+ return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf);
+}
+
+HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf)
+{
+ if (item.Size >= (UInt32)1 << 30)
+ return S_FALSE;
+ if (item.IsInline)
+ {
+ buf = item.InlineData;
+ return S_OK;
+ }
+ buf.SetCapacity((size_t)item.Size);
+ size_t pos = 0;
+ for (int i = 0; i < item.Extents.Size(); i++)
+ {
+ const CMyExtent &e = item.Extents[i];
+ UInt32 len = e.GetLen();
+ RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos));
+ pos += len;
+ }
+ return S_OK;
+}
+
+
+void CIcbTag::Parse(const Byte *p)
+{
+ // PriorDirectNum = Get32(p);
+ // StrategyType = Get16(p + 4);
+ // StrategyParam = Get16(p + 6);
+ // MaxNumOfEntries = Get16(p + 8);
+ FileType = p[11];
+ // ParentIcb.Parse(p + 12);
+ Flags = Get16(p + 18);
+}
+
+void CItem::Parse(const Byte *p)
+{
+ // Uid = Get32(p + 36);
+ // Gid = Get32(p + 40);
+ // Permissions = Get32(p + 44);
+ // FileLinkCount = Get16(p + 48);
+ // RecordFormat = p[50];
+ // RecordDisplayAttr = p[51];
+ // RecordLen = Get32(p + 52);
+ Size = Get64(p + 56);
+ NumLogBlockRecorded = Get64(p + 64);
+ ATime.Parse(p + 72);
+ MTime.Parse(p + 84);
+ // AttrtTime.Parse(p + 96);
+ // CheckPoint = Get32(p + 108);
+ // ExtendedAttrIcb.Parse(p + 112);
+ // ImplId.Parse(p + 128);
+ // UniqueId = Get64(p + 160);
+}
+
+// 4/14.4
+struct CFileId
+{
+ // UInt16 FileVersion;
+ Byte FileCharacteristics;
+ // CByteBuffer ImplUse;
+ CDString Id;
+ CLongAllocDesc Icb;
+
+ bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; }
+ HRESULT Parse(const Byte *p, size_t size, size_t &processed);
+};
+
+HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed)
+{
+ processed = 0;
+ if (size < 38)
+ return S_FALSE;
+ CTag tag;
+ RINOK(tag.Parse(p, size));
+ if (tag.Id != DESC_TYPE_FileId)
+ return S_FALSE;
+ // FileVersion = Get16(p + 16);
+ FileCharacteristics = p[18];
+ unsigned idLen = p[19];
+ Icb.Parse(p + 20);
+ unsigned impLen = Get16(p + 36);
+ if (size < 38 + idLen + impLen)
+ return S_FALSE;
+ // ImplUse.SetCapacity(impLen);
+ processed = 38;
+ // memcpy(ImplUse, p + processed, impLen);
+ processed += impLen;
+ Id.Parse(p + processed, idLen);
+ processed += idLen;
+ for (;(processed & 3) != 0; processed++)
+ if (p[processed] != 0)
+ return S_FALSE;
+ return (processed <= size) ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)
+{
+ if (Files.Size() % 100 == 0)
+ RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes));
+ if (numRecurseAllowed-- == 0)
+ return S_FALSE;
+ CFile &file = Files.Back();
+ const CLogVol &vol = LogVols[volIndex];
+ CPartition &partition = Partitions[vol.PartitionMaps[lad.Location.PartitionRef].PartitionIndex];
+
+ UInt32 key = lad.Location.Pos;
+ UInt32 value;
+ const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1;
+ if (partition.Map.Find(key, value))
+ {
+ if (value == kRecursedErrorValue)
+ return S_FALSE;
+ file.ItemIndex = value;
+ }
+ else
+ {
+ value = Items.Size();
+ file.ItemIndex = (int)value;
+ if (partition.Map.Set(key, kRecursedErrorValue))
+ return S_FALSE;
+ RINOK(ReadItem(volIndex, fsIndex, lad, numRecurseAllowed));
+ if (!partition.Map.Set(key, value))
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed)
+{
+ if (Items.Size() > kNumItemsMax)
+ return S_FALSE;
+ Items.Add(CItem());
+ CItem &item = Items.Back();
+
+ const CLogVol &vol = LogVols[volIndex];
+
+ if (lad.GetLen() != vol.BlockSize)
+ return S_FALSE;
+
+ CByteBuffer buf;
+ size_t size = lad.GetLen();
+ buf.SetCapacity(size);
+ RINOK(Read(volIndex, lad, buf));
+
+ CTag tag;
+ const Byte *p = buf;
+ RINOK(tag.Parse(p, size));
+ if (tag.Id != DESC_TYPE_File)
+ return S_FALSE;
+
+ item.IcbTag.Parse(p + 16);
+ if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR &&
+ item.IcbTag.FileType != ICB_FILE_TYPE_FILE)
+ return S_FALSE;
+
+ item.Parse(p);
+
+ _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size;
+
+ UInt32 extendedAttrLen = Get32(p + 168);
+ UInt32 allocDescriptorsLen = Get32(p + 172);
+
+ if ((extendedAttrLen & 3) != 0)
+ return S_FALSE;
+ int pos = 176;
+ if (extendedAttrLen > size - pos)
+ return S_FALSE;
+ /*
+ if (extendedAttrLen != 16)
+ {
+ if (extendedAttrLen < 24)
+ return S_FALSE;
+ CTag attrTag;
+ RINOK(attrTag.Parse(p + pos, size));
+ if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader)
+ return S_FALSE;
+ // UInt32 implAttrLocation = Get32(p + pos + 16);
+ // UInt32 applicationlAttrLocation = Get32(p + pos + 20);
+ }
+ */
+ pos += extendedAttrLen;
+
+ int desctType = item.IcbTag.GetDescriptorType();
+ if (allocDescriptorsLen > size - pos)
+ return S_FALSE;
+ if (desctType == ICB_DESC_TYPE_INLINE)
+ {
+ item.IsInline = true;
+ item.InlineData.SetCapacity(allocDescriptorsLen);
+ memcpy(item.InlineData, p + pos, allocDescriptorsLen);
+ }
+ else
+ {
+ item.IsInline = false;
+ if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG)
+ return S_FALSE;
+ for (UInt32 i = 0; i < allocDescriptorsLen;)
+ {
+ CMyExtent e;
+ if (desctType == ICB_DESC_TYPE_SHORT)
+ {
+ if (i + 8 > allocDescriptorsLen)
+ return S_FALSE;
+ CShortAllocDesc sad;
+ sad.Parse(p + pos + i);
+ e.Pos = sad.Pos;
+ e.Len = sad.Len;
+ e.PartitionRef = lad.Location.PartitionRef;
+ i += 8;
+ }
+ else
+ {
+ if (i + 16 > allocDescriptorsLen)
+ return S_FALSE;
+ CLongAllocDesc ladNew;
+ ladNew.Parse(p + pos + i);
+ e.Pos = ladNew.Location.Pos;
+ e.PartitionRef = ladNew.Location.PartitionRef;
+ e.Len = ladNew.Len;
+ i += 16;
+ }
+ item.Extents.Add(e);
+ }
+ }
+
+ if (item.IcbTag.IsDir())
+ {
+ if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
+ return S_FALSE;
+ CByteBuffer buf;
+ RINOK(ReadFromFile(volIndex, item, buf));
+ item.Size = 0;
+ item.Extents.ClearAndFree();
+ item.InlineData.Free();
+
+ const Byte *p = buf;
+ size = buf.GetCapacity();
+ size_t processedTotal = 0;
+ for (; processedTotal < size;)
+ {
+ size_t processedCur;
+ CFileId fileId;
+ RINOK(fileId.Parse(p + processedTotal, size - processedTotal, processedCur));
+ if (!fileId.IsItLinkParent())
+ {
+ CFile file;
+ // file.FileVersion = fileId.FileVersion;
+ // file.FileCharacteristics = fileId.FileCharacteristics;
+ // file.ImplUse = fileId.ImplUse;
+ file.Id = fileId.Id;
+
+ _fileNameLengthTotal += file.Id.Data.GetCapacity();
+ if (_fileNameLengthTotal > kFileNameLengthTotalMax)
+ return S_FALSE;
+
+ item.SubFiles.Add(Files.Size());
+ if (Files.Size() > kNumFilesMax)
+ return S_FALSE;
+ Files.Add(file);
+ RINOK(ReadFileItem(volIndex, fsIndex, fileId.Icb, numRecurseAllowed));
+ }
+ processedTotal += processedCur;
+ }
+ }
+ else
+ {
+ if ((UInt32)item.Extents.Size() > kNumExtentsMax - _numExtents)
+ return S_FALSE;
+ _numExtents += item.Extents.Size();
+
+ if (item.InlineData.GetCapacity() > kInlineExtentsSizeMax - _inlineExtentsSize)
+ return S_FALSE;
+ _inlineExtentsSize += item.InlineData.GetCapacity();
+ }
+
+ return S_OK;
+}
+
+HRESULT CInArchive::FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed)
+{
+ if (_numRefs % 10000 == 0)
+ {
+ RINOK(_progress->SetCompleted());
+ }
+ if (numRecurseAllowed-- == 0)
+ return S_FALSE;
+ if (_numRefs >= kNumRefsMax)
+ return S_FALSE;
+ _numRefs++;
+ CRef ref;
+ ref.FileIndex = fileIndex;
+ ref.Parent = parent;
+ parent = fs.Refs.Size();
+ fs.Refs.Add(ref);
+ const CItem &item = Items[Files[fileIndex].ItemIndex];
+ for (int i = 0; i < item.SubFiles.Size(); i++)
+ {
+ RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed));
+ }
+ return S_OK;
+}
+
+HRESULT CInArchive::Open2()
+{
+ Clear();
+
+ UInt64 fileSize;
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize));
+
+ // Some UDFs contain additional 2 KB of zeros, so we also check 12, corrected to 11.
+ const int kSecLogSizeMax = 12;
+ Byte buf[1 << kSecLogSizeMax];
+ Byte kSizesLog[] = { 11, 8, 12 };
+
+ for (int i = 0;; i++)
+ {
+ if (i == sizeof(kSizesLog) / sizeof(kSizesLog[0]))
+ return S_FALSE;
+ SecLogSize = kSizesLog[i];
+ Int32 bufSize = 1 << SecLogSize;
+ if (bufSize > fileSize)
+ return S_FALSE;
+ RINOK(_stream->Seek(-bufSize, STREAM_SEEK_END, NULL));
+ RINOK(ReadStream_FALSE(_stream, buf, bufSize));
+ CTag tag;
+ if (tag.Parse(buf, bufSize) == S_OK)
+ if (tag.Id == DESC_TYPE_AnchorVolPtr)
+ break;
+ }
+ if (SecLogSize == 12)
+ SecLogSize = 11;
+
+ CExtent extentVDS;
+ extentVDS.Parse(buf + 16);
+
+ for (UInt32 location = extentVDS.Pos; ; location++)
+ {
+ size_t bufSize = 1 << SecLogSize;
+ size_t pos = 0;
+ RINOK(_stream->Seek((UInt64)location << SecLogSize, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(_stream, buf, bufSize));
+ CTag tag;
+ RINOK(tag.Parse(buf + pos, bufSize - pos));
+ if (tag.Id == DESC_TYPE_Terminating)
+ break;
+ if (tag.Id == DESC_TYPE_Partition)
+ {
+ if (Partitions.Size() >= kNumPartitionsMax)
+ return S_FALSE;
+ CPartition partition;
+ // UInt32 volDescSeqNumer = Get32(buf + 16);
+ // partition.Flags = Get16(buf + 20);
+ partition.Number = Get16(buf + 22);
+ // partition.ContentsId.Parse(buf + 24);
+
+ // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse));
+ // ContentsUse is Partition Header Description.
+
+ // partition.AccessType = Get32(buf + 184);
+ partition.Pos = Get32(buf + 188);
+ partition.Len = Get32(buf + 192);
+ // partition.ImplId.Parse(buf + 196);
+ // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse));
+
+ Partitions.Add(partition);
+ }
+ else if (tag.Id == DESC_TYPE_LogicalVol)
+ {
+ if (LogVols.Size() >= kNumLogVolumesMax)
+ return S_FALSE;
+ CLogVol vol;
+ vol.Id.Parse(buf + 84);
+ vol.BlockSize = Get32(buf + 212);
+ // vol.DomainId.Parse(buf + 216);
+
+ if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30))
+ return S_FALSE;
+
+ // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse));
+ vol.FileSetLocation.Parse(buf + 248);
+
+ // UInt32 mapTableLength = Get32(buf + 264);
+ UInt32 numPartitionMaps = Get32(buf + 268);
+ if (numPartitionMaps > kNumPartitionsMax)
+ return S_FALSE;
+ // vol.ImplId.Parse(buf + 272);
+ // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse));
+ size_t pos = 440;
+ for (UInt32 i = 0; i < numPartitionMaps; i++)
+ {
+ if (pos + 2 > bufSize)
+ return S_FALSE;
+ CPartitionMap pm;
+ pm.Type = buf[pos];
+ // pm.Length = buf[pos + 1];
+ Byte len = buf[pos + 1];
+
+ if (pos + len > bufSize)
+ return S_FALSE;
+
+ // memcpy(pm.Data, buf + pos + 2, pm.Length - 2);
+ if (pm.Type == 1)
+ {
+ if (pos + 6 > bufSize)
+ return S_FALSE;
+ // pm.VolSeqNumber = Get16(buf + pos + 2);
+ pm.PartitionNumber = Get16(buf + pos + 4);
+ }
+ else
+ return S_FALSE;
+ pos += len;
+ vol.PartitionMaps.Add(pm);
+ }
+ LogVols.Add(vol);
+ }
+ }
+
+ UInt64 totalSize = 0;
+
+ int volIndex;
+ for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
+ {
+ CLogVol &vol = LogVols[volIndex];
+ for (int pmIndex = 0; pmIndex < vol.PartitionMaps.Size(); pmIndex++)
+ {
+ CPartitionMap &pm = vol.PartitionMaps[pmIndex];
+ int i;
+ for (i = 0; i < Partitions.Size(); i++)
+ {
+ CPartition &part = Partitions[i];
+ if (part.Number == pm.PartitionNumber)
+ {
+ if (part.VolIndex >= 0)
+ return S_FALSE;
+ pm.PartitionIndex = i;
+ part.VolIndex = volIndex;
+
+ totalSize += (UInt64)part.Len << SecLogSize;
+ break;
+ }
+ }
+ if (i == Partitions.Size())
+ return S_FALSE;
+ }
+ }
+
+ RINOK(_progress->SetTotal(totalSize));
+
+ for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
+ {
+ CLogVol &vol = LogVols[volIndex];
+
+ CLongAllocDesc nextExtent = vol.FileSetLocation;
+ // while (nextExtent.ExtentLen != 0)
+ // for (int i = 0; i < 1; i++)
+ {
+ if (nextExtent.GetLen() < 512)
+ return S_FALSE;
+ CByteBuffer buf;
+ buf.SetCapacity(nextExtent.GetLen());
+ RINOK(Read(volIndex, nextExtent, buf));
+ const Byte *p = buf;
+ size_t size = nextExtent.GetLen();
+
+ CTag tag;
+ RINOK(tag.Parse(p, size));
+ if (tag.Id != DESC_TYPE_FileSet)
+ return S_FALSE;
+
+ CFileSet fs;
+ fs.RecodringTime.Parse(p + 16);
+ // fs.InterchangeLevel = Get16(p + 18);
+ // fs.MaxInterchangeLevel = Get16(p + 20);
+ // fs.FileSetNumber = Get32(p + 40);
+ // fs.FileSetDescNumber = Get32(p + 44);
+
+ // fs.Id.Parse(p + 304);
+ // fs.CopyrightId.Parse(p + 336);
+ // fs.AbstractId.Parse(p + 368);
+
+ fs.RootDirICB.Parse(p + 400);
+ // fs.DomainId.Parse(p + 416);
+
+ // fs.SystemStreamDirICB.Parse(p + 464);
+
+ vol.FileSets.Add(fs);
+
+ // nextExtent.Parse(p + 448);
+ }
+
+ for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++)
+ {
+ CFileSet &fs = vol.FileSets[fsIndex];
+ int fileIndex = Files.Size();
+ Files.Add(CFile());
+ RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecureseLevelsMax));
+ RINOK(FillRefs(fs, fileIndex, -1, kNumRecureseLevelsMax));
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress)
+{
+ _progress = progress;
+ _stream = inStream;
+ HRESULT res;
+ try { res = Open2(); }
+ catch(...) { Clear(); res = S_FALSE; }
+ _stream.Release();
+ return res;
+}
+
+void CInArchive::Clear()
+{
+ Partitions.Clear();
+ LogVols.Clear();
+ Items.Clear();
+ Files.Clear();
+ _fileNameLengthTotal = 0;
+ _numRefs = 0;
+ _numExtents = 0;
+ _inlineExtentsSize = 0;
+ _processedProgressBytes = 0;
+}
+
+UString CInArchive::GetComment() const
+{
+ UString res;
+ for (int i = 0; i < LogVols.Size(); i++)
+ {
+ if (i > 0)
+ res += L" ";
+ res += LogVols[i].GetName();
+ }
+ return res;
+}
+
+static UString GetSpecName(const UString &name)
+{
+ UString name2 = name;
+ name2.Trim();
+ if (name2.IsEmpty())
+ {
+ /*
+ wchar_t s[32];
+ ConvertUInt64ToString(id, s);
+ return L"[" + (UString)s + L"]";
+ */
+ return L"[]";
+ }
+ return name;
+}
+
+static void UpdateWithName(UString &res, const UString &addString)
+{
+ if (res.IsEmpty())
+ res = addString;
+ else
+ res = addString + WCHAR_PATH_SEPARATOR + res;
+}
+
+UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex,
+ bool showVolName, bool showFsName) const
+{
+ // showVolName = true;
+ const CLogVol &vol = LogVols[volIndex];
+ const CFileSet &fs = vol.FileSets[fsIndex];
+
+ UString name;
+
+ for (;;)
+ {
+ const CRef &ref = fs.Refs[refIndex];
+ refIndex = ref.Parent;
+ if (refIndex < 0)
+ break;
+ UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName()));
+ }
+
+ if (showFsName)
+ {
+ wchar_t s[32];
+ ConvertUInt64ToString(fsIndex, s);
+ UString newName = L"File Set ";
+ newName += s;
+ UpdateWithName(name, newName);
+ }
+
+ if (showVolName)
+ {
+ wchar_t s[32];
+ ConvertUInt64ToString(volIndex, s);
+ UString newName = s;
+ UString newName2 = vol.GetName();
+ if (newName2.IsEmpty())
+ newName2 = L"Volume";
+ newName += L'-';
+ newName += newName2;
+ UpdateWithName(name, newName);
+ }
+ return name;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfIn.h
new file mode 100644
index 000000000..46b9a7e85
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfIn.h
@@ -0,0 +1,375 @@
+// Archive/UdfIn.h -- UDF / ECMA-167
+
+#ifndef __ARCHIVE_UDF_IN_H
+#define __ARCHIVE_UDF_IN_H
+
+#include "Common/MyCom.h"
+#include "Common/IntToString.h"
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+#include "Common/MyMap.h"
+
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NUdf {
+
+// ---------- ECMA Part 1 ----------
+
+// ECMA 1/7.2.12
+
+/*
+struct CDString32
+{
+ Byte Data[32];
+ void Parse(const Byte *buf);
+ // UString GetString() const;
+};
+*/
+
+struct CDString128
+{
+ Byte Data[128];
+ void Parse(const Byte *buf);
+ UString GetString() const;
+};
+
+struct CDString
+{
+ CByteBuffer Data;
+ void Parse(const Byte *p, unsigned size);
+ UString GetString() const;
+};
+
+
+// ECMA 1/7.3
+
+struct CTime
+{
+ Byte Data[12];
+
+ unsigned GetType() const { return Data[1] >> 4; }
+ bool IsLocal() const { return GetType() == 1; }
+ int GetMinutesOffset() const
+ {
+ int t = (Data[0] | ((UInt16)Data[1] << 8)) & 0xFFF;
+ if ((t >> 11) != 0)
+ t -= (1 << 12);
+ return (t > (60 * 24) || t < -(60 * 24)) ? 0 : t;
+ }
+ unsigned GetYear() const { return (Data[2] | ((UInt16)Data[3] << 8)); }
+ void Parse(const Byte *buf);
+};
+
+
+// ECMA 1/7.4
+
+/*
+struct CRegId
+{
+ Byte Flags;
+ char Id[23];
+ char Suffix[8];
+
+ void Parse(const Byte *buf);
+};
+*/
+
+// ---------- ECMA Part 3: Volume Structure ----------
+
+// ECMA 3/10.5
+
+struct CPartition
+{
+ // UInt16 Flags;
+ UInt16 Number;
+ // CRegId ContentsId;
+ // Byte ContentsUse[128];
+ // UInt32 AccessType;
+
+ UInt32 Pos;
+ UInt32 Len;
+
+ // CRegId ImplId;
+ // Byte ImplUse[128];
+
+ int VolIndex;
+ CMap32 Map;
+
+ CPartition(): VolIndex(-1) {}
+
+ // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); }
+ // bool IsAllocated() const { return ((Flags & 1) != 0); }
+};
+
+struct CLogBlockAddr
+{
+ UInt32 Pos;
+ UInt16 PartitionRef;
+
+ void Parse(const Byte *buf);
+};
+
+enum EShortAllocDescType
+{
+ SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0,
+ SHORT_ALLOC_DESC_TYPE_NotRecordedButAllocated = 1,
+ SHORT_ALLOC_DESC_TYPE_NotRecordedAndNotAllocated = 2,
+ SHORT_ALLOC_DESC_TYPE_NextExtent = 3
+};
+
+struct CShortAllocDesc
+{
+ UInt32 Len;
+ UInt32 Pos;
+
+ // 4/14.14.1
+ // UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ // UInt32 GetType() const { return Len >> 30; }
+ // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+ void Parse(const Byte *buf);
+};
+
+/*
+struct CADImpUse
+{
+ UInt16 Flags;
+ UInt32 UdfUniqueId;
+ void Parse(const Byte *buf);
+};
+*/
+
+struct CLongAllocDesc
+{
+ UInt32 Len;
+ CLogBlockAddr Location;
+
+ // Byte ImplUse[6];
+ // CADImpUse adImpUse; // UDF
+
+ UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ UInt32 GetType() const { return Len >> 30; }
+ bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+ void Parse(const Byte *buf);
+};
+
+struct CPartitionMap
+{
+ Byte Type;
+ // Byte Len;
+
+ // Type - 1
+ // UInt16 VolSeqNumber;
+ UInt16 PartitionNumber;
+
+ // Byte Data[256];
+
+ int PartitionIndex;
+};
+
+// ECMA 4/14.6
+
+enum EIcbFileType
+{
+ ICB_FILE_TYPE_DIR = 4,
+ ICB_FILE_TYPE_FILE = 5
+};
+
+enum EIcbDescriptorType
+{
+ ICB_DESC_TYPE_SHORT = 0,
+ ICB_DESC_TYPE_LONG = 1,
+ ICB_DESC_TYPE_EXTENDED = 2,
+ ICB_DESC_TYPE_INLINE = 3
+};
+
+struct CIcbTag
+{
+ // UInt32 PriorDirectNum;
+ // UInt16 StrategyType;
+ // UInt16 StrategyParam;
+ // UInt16 MaxNumOfEntries;
+ Byte FileType;
+ // CLogBlockAddr ParentIcb;
+ UInt16 Flags;
+
+ bool IsDir() const { return FileType == ICB_FILE_TYPE_DIR; }
+ int GetDescriptorType() const { return Flags & 3; }
+ void Parse(const Byte *p);
+};
+
+// const Byte FILEID_CHARACS_Existance = (1 << 0);
+const Byte FILEID_CHARACS_Parent = (1 << 3);
+
+struct CFile
+{
+ // UInt16 FileVersion;
+ // Byte FileCharacteristics;
+ // CByteBuffer ImplUse;
+ CDString Id;
+
+ CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {}
+ int ItemIndex;
+ UString GetName() const { return Id.GetString(); }
+};
+
+struct CMyExtent
+{
+ UInt32 Pos;
+ UInt32 Len;
+ int PartitionRef;
+
+ UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ UInt32 GetType() const { return Len >> 30; }
+ bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+};
+
+struct CItem
+{
+ CIcbTag IcbTag;
+
+ // UInt32 Uid;
+ // UInt32 Gid;
+ // UInt32 Permissions;
+ // UInt16 FileLinkCount;
+ // Byte RecordFormat;
+ // Byte RecordDisplayAttr;
+ // UInt32 RecordLen;
+ UInt64 Size;
+ UInt64 NumLogBlockRecorded;
+ CTime ATime;
+ CTime MTime;
+ // CTime AttrtTime;
+ // UInt32 CheckPoint;
+ // CLongAllocDesc ExtendedAttrIcb;
+ // CRegId ImplId;
+ // UInt64 UniqueId;
+
+ bool IsInline;
+ CByteBuffer InlineData;
+ CRecordVector<CMyExtent> Extents;
+ CRecordVector<int> SubFiles;
+
+ void Parse(const Byte *buf);
+
+ bool IsRecAndAlloc() const
+ {
+ for (int i = 0; i < Extents.Size(); i++)
+ if (!Extents[i].IsRecAndAlloc())
+ return false;
+ return true;
+ }
+
+ UInt64 GetChunksSumSize() const
+ {
+ if (IsInline)
+ return InlineData.GetCapacity();
+ UInt64 size = 0;
+ for (int i = 0; i < Extents.Size(); i++)
+ size += Extents[i].GetLen();
+ return size;
+ }
+
+ bool CheckChunkSizes() const { return GetChunksSumSize() == Size; }
+
+ bool IsDir() const { return IcbTag.IsDir(); }
+};
+
+struct CRef
+{
+ int Parent;
+ int FileIndex;
+};
+
+
+// ECMA 4 / 14.1
+struct CFileSet
+{
+ CTime RecodringTime;
+ // UInt16 InterchangeLevel;
+ // UInt16 MaxInterchangeLevel;
+ // UInt32 FileSetNumber;
+ // UInt32 FileSetDescNumber;
+ // CDString32 Id;
+ // CDString32 CopyrightId;
+ // CDString32 AbstractId;
+
+ CLongAllocDesc RootDirICB;
+ // CRegId DomainId;
+ // CLongAllocDesc SystemStreamDirICB;
+
+ CRecordVector<CRef> Refs;
+};
+
+
+// ECMA 3/10.6
+
+struct CLogVol
+{
+ CDString128 Id;
+ UInt32 BlockSize;
+ // CRegId DomainId;
+
+ // Byte ContentsUse[16];
+ CLongAllocDesc FileSetLocation; // UDF
+
+ // CRegId ImplId;
+ // Byte ImplUse[128];
+
+ CObjectVector<CPartitionMap> PartitionMaps;
+ CObjectVector<CFileSet> FileSets;
+
+ UString GetName() const { return Id.GetString(); }
+};
+
+struct CProgressVirt
+{
+ virtual HRESULT SetTotal(UInt64 numBytes) PURE;
+ virtual HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) PURE;
+ virtual HRESULT SetCompleted() PURE;
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> _stream;
+ CProgressVirt *_progress;
+
+ HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf);
+ HRESULT Read(int volIndex, const CLongAllocDesc &lad, Byte *buf);
+ HRESULT ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf);
+
+ HRESULT ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed);
+ HRESULT ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed);
+
+ HRESULT Open2();
+ HRESULT FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed);
+
+ UInt64 _processedProgressBytes;
+
+ UInt64 _fileNameLengthTotal;
+ int _numRefs;
+ UInt32 _numExtents;
+ UInt64 _inlineExtentsSize;
+ bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const;
+public:
+ HRESULT Open(IInStream *inStream, CProgressVirt *progress);
+ void Clear();
+
+ CObjectVector<CPartition> Partitions;
+ CObjectVector<CLogVol> LogVols;
+
+ CObjectVector<CItem> Items;
+ CObjectVector<CFile> Files;
+
+ int SecLogSize;
+
+ UString GetComment() const;
+ UString GetItemPath(int volIndex, int fsIndex, int refIndex,
+ bool showVolName, bool showFsName) const;
+
+ bool CheckItemExtents(int volIndex, const CItem &item) const;
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfRegister.cpp
new file mode 100644
index 000000000..1b08d120b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Udf/UdfRegister.cpp
@@ -0,0 +1,13 @@
+// UdfRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "UdfHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NUdf::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Udf", L"iso img", 0, 0xE0, { 0, 'N', 'S', 'R', '0' }, 5, false, CreateArc, 0 };
+
+REGISTER_ARC(Udf)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp
new file mode 100644
index 000000000..9d1c928e6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/VhdHandler.cpp
@@ -0,0 +1,734 @@
+// VhdHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/Buffer.h"
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+#define G32(p, dest) dest = Get32(p);
+#define G64(p, dest) dest = Get64(p);
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NVhd {
+
+static const UInt32 kUnusedBlock = 0xFFFFFFFF;
+
+static const UInt32 kDiskType_Fixed = 2;
+static const UInt32 kDiskType_Dynamic = 3;
+static const UInt32 kDiskType_Diff = 4;
+
+static const char *kDiskTypes[] =
+{
+ "0",
+ "1",
+ "Fixed",
+ "Dynamic",
+ "Differencing"
+};
+
+struct CFooter
+{
+ // UInt32 Features;
+ // UInt32 FormatVersion;
+ UInt64 DataOffset;
+ UInt32 CTime;
+ UInt32 CreatorApp;
+ UInt32 CreatorVersion;
+ UInt32 CreatorHostOS;
+ // UInt64 OriginalSize;
+ UInt64 CurrentSize;
+ UInt32 DiskGeometry;
+ UInt32 Type;
+ Byte Id[16];
+ Byte SavedState;
+
+ bool IsFixed() const { return Type == kDiskType_Fixed; }
+ bool ThereIsDynamic() const { return Type == kDiskType_Dynamic || Type == kDiskType_Diff; }
+ // bool IsSupported() const { return Type == kDiskType_Fixed || Type == kDiskType_Dynamic || Type == kDiskType_Diff; }
+ UInt32 NumCyls() const { return DiskGeometry >> 16; }
+ UInt32 NumHeads() const { return (DiskGeometry >> 8) & 0xFF; }
+ UInt32 NumSectorsPerTrack() const { return DiskGeometry & 0xFF; }
+ AString GetTypeString() const;
+ bool Parse(const Byte *p);
+};
+
+AString CFooter::GetTypeString() const
+{
+ if (Type < sizeof(kDiskTypes) / sizeof(kDiskTypes[0]))
+ return kDiskTypes[Type];
+ char s[16];
+ ConvertUInt32ToString(Type, s);
+ return s;
+}
+
+static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, unsigned zeroOffset)
+{
+ UInt32 sum = 0;
+ unsigned i;
+ for (i = 0; i < checkSumOffset; i++)
+ sum += p[i];
+ for (i = checkSumOffset + 4; i < size; i++)
+ sum += p[i];
+ if (~sum != Get32(p + checkSumOffset))
+ return false;
+ for (i = zeroOffset; i < size; i++)
+ if (p[i] != 0)
+ return false;
+ return true;
+}
+
+bool CFooter::Parse(const Byte *p)
+{
+ if (memcmp(p, "conectix", 8) != 0)
+ return false;
+ // G32(p + 0x08, Features);
+ // G32(p + 0x0C, FormatVersion);
+ G64(p + 0x10, DataOffset);
+ G32(p + 0x18, CTime);
+ G32(p + 0x1C, CreatorApp);
+ G32(p + 0x20, CreatorVersion);
+ G32(p + 0x24, CreatorHostOS);
+ // G64(p + 0x28, OriginalSize);
+ G64(p + 0x30, CurrentSize);
+ G32(p + 0x38, DiskGeometry);
+ G32(p + 0x3C, Type);
+ memcpy(Id, p + 0x44, 16);
+ SavedState = p[0x54];
+ return CheckBlock(p, 512, 0x40, 0x55);
+}
+
+/*
+struct CParentLocatorEntry
+{
+ UInt32 Code;
+ UInt32 DataSpace;
+ UInt32 DataLen;
+ UInt64 DataOffset;
+
+ bool Parse(const Byte *p);
+};
+bool CParentLocatorEntry::Parse(const Byte *p)
+{
+ G32(p + 0x00, Code);
+ G32(p + 0x04, DataSpace);
+ G32(p + 0x08, DataLen);
+ G32(p + 0x10, DataOffset);
+ return (Get32(p + 0x0C) == 0); // Resrved
+}
+*/
+
+struct CDynHeader
+{
+ // UInt64 DataOffset;
+ UInt64 TableOffset;
+ // UInt32 HeaderVersion;
+ UInt32 NumBlocks;
+ int BlockSizeLog;
+ UInt32 ParentTime;
+ Byte ParentId[16];
+ UString ParentName;
+ // CParentLocatorEntry ParentLocators[8];
+
+ bool Parse(const Byte *p);
+ UInt32 NumBitMapSectors() const
+ {
+ UInt32 numSectorsInBlock = (1 << (BlockSizeLog - 9));
+ return (numSectorsInBlock + 512 * 8 - 1) / (512 * 8);
+ }
+};
+
+static int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+bool CDynHeader::Parse(const Byte *p)
+{
+ if (memcmp(p, "cxsparse", 8) != 0)
+ return false;
+ // G64(p + 0x08, DataOffset);
+ G64(p + 0x10, TableOffset);
+ // G32(p + 0x18, HeaderVersion);
+ G32(p + 0x1C, NumBlocks);
+ BlockSizeLog = GetLog(Get32(p + 0x20));
+ if (BlockSizeLog < 9 || BlockSizeLog > 30)
+ return false;
+ G32(p + 0x38, ParentTime);
+ if (Get32(p + 0x3C) != 0) // reserved
+ return false;
+ memcpy(ParentId, p + 0x28, 16);
+ {
+ const int kNameLength = 256;
+ wchar_t *s = ParentName.GetBuffer(kNameLength);
+ for (unsigned i = 0; i < kNameLength; i++)
+ s[i] = Get16(p + 0x40 + i * 2);
+ s[kNameLength] = 0;
+ ParentName.ReleaseBuffer();
+ }
+ /*
+ for (int i = 0; i < 8; i++)
+ if (!ParentLocators[i].Parse(p + 0x240 + i * 24))
+ return false;
+ */
+ return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24);
+}
+
+class CHandler:
+ public IInStream,
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ UInt64 _phyPos;
+ UInt64 _phyLimit;
+
+ CFooter Footer;
+ CDynHeader Dyn;
+ CRecordVector<UInt32> Bat;
+ CByteBuffer BitMap;
+ UInt32 BitMapTag;
+ UInt32 NumUsedBlocks;
+ CMyComPtr<IInStream> Stream;
+ CMyComPtr<IInStream> ParentStream;
+ CHandler *Parent;
+
+ HRESULT Seek(UInt64 offset);
+ HRESULT InitAndSeek();
+ HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size);
+
+ bool NeedParent() const { return Footer.Type == kDiskType_Diff; }
+ UInt64 GetPackSize() const
+ { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; }
+
+ UString GetParentName() const
+ {
+ const CHandler *p = this;
+ UString res;
+ while (p && p->NeedParent())
+ {
+ if (!res.IsEmpty())
+ res += L" -> ";
+ res += p->Dyn.ParentName;
+ p = p->Parent;
+ }
+ return res;
+ }
+
+ bool IsOK() const
+ {
+ const CHandler *p = this;
+ while (p->NeedParent())
+ {
+ p = p->Parent;
+ if (p == 0)
+ return false;
+ }
+ return true;
+ }
+
+ HRESULT Open3();
+ HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level);
+
+public:
+ MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
+
+ INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(offset, STREAM_SEEK_SET, NULL); }
+
+HRESULT CHandler::InitAndSeek()
+{
+ if (ParentStream)
+ {
+ RINOK(Parent->InitAndSeek());
+ }
+ _virtPos = _phyPos = 0;
+ BitMapTag = kUnusedBlock;
+ BitMap.SetCapacity(Dyn.NumBitMapSectors() << 9);
+ return Seek(0);
+}
+
+HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size)
+{
+ if (offset + size > _phyLimit)
+ return S_FALSE;
+ if (offset != _phyPos)
+ {
+ _phyPos = offset;
+ RINOK(Seek(offset));
+ }
+ HRESULT res = ReadStream_FALSE(Stream, data, size);
+ _phyPos += size;
+ return res;
+}
+
+HRESULT CHandler::Open3()
+{
+ RINOK(Stream->Seek(0, STREAM_SEEK_END, &_phyPos));
+ if (_phyPos < 512)
+ return S_FALSE;
+ const UInt32 kDynSize = 1024;
+ Byte buf[kDynSize];
+
+ _phyLimit = _phyPos;
+ RINOK(ReadPhy(_phyLimit - 512, buf, 512));
+ if (!Footer.Parse(buf))
+ return S_FALSE;
+ _phyLimit -= 512;
+
+ if (!Footer.ThereIsDynamic())
+ return S_OK;
+
+ RINOK(ReadPhy(0, buf + 512, 512));
+ if (memcmp(buf, buf + 512, 512) != 0)
+ return S_FALSE;
+
+ RINOK(ReadPhy(Footer.DataOffset, buf, kDynSize));
+ if (!Dyn.Parse(buf))
+ return S_FALSE;
+
+ if (Dyn.NumBlocks >= (UInt32)1 << 31)
+ return S_FALSE;
+ if (Footer.CurrentSize == 0)
+ {
+ if (Dyn.NumBlocks != 0)
+ return S_FALSE;
+ }
+ else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks)
+ return S_FALSE;
+
+ Bat.Reserve(Dyn.NumBlocks);
+ while ((UInt32)Bat.Size() < Dyn.NumBlocks)
+ {
+ RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, 512));
+ for (UInt32 j = 0; j < 512; j += 4)
+ {
+ UInt32 v = Get32(buf + j);
+ if (v != kUnusedBlock)
+ NumUsedBlocks++;
+ Bat.Add(v);
+ if ((UInt32)Bat.Size() >= Dyn.NumBlocks)
+ break;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= Footer.CurrentSize)
+ return (Footer.CurrentSize == _virtPos) ? S_OK: E_FAIL;
+ UInt64 rem = Footer.CurrentSize - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (size == 0)
+ return S_OK;
+ UInt32 blockIndex = (UInt32)(_virtPos >> Dyn.BlockSizeLog);
+ UInt32 blockSectIndex = Bat[blockIndex];
+ UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog;
+ UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ size = MyMin(blockSize - offsetInBlock, size);
+
+ HRESULT res = S_OK;
+ if (blockSectIndex == kUnusedBlock)
+ {
+ if (ParentStream)
+ {
+ RINOK(ParentStream->Seek(_virtPos, STREAM_SEEK_SET, NULL));
+ res = ParentStream->Read(data, size, &size);
+ }
+ else
+ memset(data, 0, size);
+ }
+ else
+ {
+ UInt64 newPos = (UInt64)blockSectIndex << 9;
+ if (BitMapTag != blockIndex)
+ {
+ RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.GetCapacity()));
+ BitMapTag = blockIndex;
+ }
+ RINOK(ReadPhy(newPos + BitMap.GetCapacity() + offsetInBlock, data, size));
+ for (UInt32 cur = 0; cur < size;)
+ {
+ UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur);
+ UInt32 bmi = offsetInBlock >> 9;
+ if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0)
+ {
+ if (ParentStream)
+ {
+ RINOK(ParentStream->Seek(_virtPos + cur, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(ParentStream, (Byte *)data + cur, rem));
+ }
+ else
+ {
+ const Byte *p = (const Byte *)data + cur;
+ for (UInt32 i = 0; i < rem; i++)
+ if (p[i] != 0)
+ return S_FALSE;
+ }
+ }
+ offsetInBlock += rem;
+ cur += rem;
+ }
+ }
+ if (processedSize != NULL)
+ *processedSize = size;
+ _virtPos += size;
+ return res;
+}
+
+STDMETHODIMP CHandler::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = Footer.CurrentSize + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+enum
+{
+ kpidParent = kpidUserDefined,
+ kpidSavedState
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidClusterSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR},
+ { L"Parent", kpidParent, VT_BSTR},
+ { NULL, kpidCreatorApp, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR},
+ { L"Saved State", kpidSavedState, VT_BOOL},
+ { NULL, kpidId, VT_BSTR}
+ };
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME}
+
+ /*
+ { NULL, kpidNumCyls, VT_UI4},
+ { NULL, kpidNumHeads, VT_UI4},
+ { NULL, kpidSectorsPerTrack, VT_UI4}
+ */
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+// VHD start time: 2000-01-01
+static const UInt64 kVhdTimeStartValue = (UInt64)3600 * 24 * (399 * 365 + 24 * 4);
+
+static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop)
+{
+ FILETIME ft, utc;
+ UInt64 v = (kVhdTimeStartValue + vhdTime) * 10000000;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+ // specification says that it's UTC time, but Virtual PC 6 writes local time. Why?
+ LocalFileTimeToFileTime(&ft, &utc);
+ prop = utc;
+}
+
+static void StringToAString(char *dest, UInt32 s)
+{
+ for (int i = 24; i >= 0; i -= 8)
+ {
+ Byte b = (Byte)((s >> i) & 0xFF);
+ if (b < 0x20 || b > 0x7F)
+ break;
+ *dest++ = b;
+ }
+ *dest = 0;
+}
+
+static void ConvertByteToHex(unsigned value, char *s)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ unsigned t = value & 0xF;
+ value >>= 4;
+ s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break;
+ case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break;
+ case kpidMethod:
+ {
+ AString s = Footer.GetTypeString();
+ if (NeedParent())
+ {
+ s += " -> ";
+ const CHandler *p = this;
+ while (p != 0 && p->NeedParent())
+ p = p->Parent;
+ if (p == 0)
+ s += '?';
+ else
+ s += p->Footer.GetTypeString();
+ }
+ prop = s;
+ break;
+ }
+ case kpidCreatorApp:
+ {
+ char s[16];
+ StringToAString(s, Footer.CreatorApp);
+ AString res = s;
+ res.Trim();
+ ConvertUInt32ToString(Footer.CreatorVersion >> 16, s);
+ res += ' ';
+ res += s;
+ res += '.';
+ ConvertUInt32ToString(Footer.CreatorVersion & 0xFFFF, s);
+ res += s;
+ prop = res;
+ break;
+ }
+ case kpidHostOS:
+ {
+ if (Footer.CreatorHostOS == 0x5769326b)
+ prop = "Windows";
+ else
+ {
+ char s[16];
+ StringToAString(s, Footer.CreatorHostOS);
+ prop = s;
+ }
+ break;
+ }
+ case kpidId:
+ {
+ char s[32 + 4];
+ for (int i = 0; i < 16; i++)
+ ConvertByteToHex(Footer.Id[i], s + i * 2);
+ s[32] = 0;
+ prop = s;
+ break;
+ }
+ case kpidSavedState: prop = Footer.SavedState ? true : false; break;
+ case kpidParent: if (NeedParent()) prop = GetParentName(); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level)
+{
+ Close();
+ Stream = stream;
+ if (level > 32)
+ return S_FALSE;
+ RINOK(Open3());
+ if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0)
+ return S_FALSE;
+ if (Footer.Type != kDiskType_Diff)
+ return S_OK;
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ if (openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback) != S_OK)
+ return S_FALSE;
+ CMyComPtr<IInStream> nextStream;
+ HRESULT res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream);
+ if (res == S_FALSE)
+ return S_OK;
+ RINOK(res);
+
+ Parent = new CHandler;
+ ParentStream = Parent;
+ return Parent->Open2(nextStream, this, openArchiveCallback, level + 1);
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ {
+ HRESULT res;
+ try
+ {
+ res = Open2(stream, NULL, openArchiveCallback, 0);
+ if (res == S_OK)
+ return S_OK;
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ Close();
+ return res;
+ }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ Bat.Clear();
+ NumUsedBlocks = 0;
+ Parent = 0;
+ Stream.Release();
+ ParentStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ switch(propID)
+ {
+ case kpidSize: prop = Footer.CurrentSize; break;
+ case kpidPackSize: prop = GetPackSize(); break;
+ case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break;
+ /*
+ case kpidNumCyls: prop = Footer.NumCyls(); break;
+ case kpidNumHeads: prop = Footer.NumHeads(); break;
+ case kpidSectorsPerTrack: prop = Footer.NumSectorsPerTrack(); break;
+ */
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ RINOK(extractCallback->SetTotal(Footer.CurrentSize));
+ CMyComPtr<ISequentialOutStream> outStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &outStream, askMode));
+ if (!testMode && !outStream)
+ return S_OK;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ int res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(0, &inStream);
+ if (hres == S_FALSE)
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ RINOK(hres);
+ HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres == S_OK)
+ {
+ if (copyCoderSpec->TotalSize == Footer.CurrentSize)
+ res = NExtract::NOperationResult::kOK;
+ }
+ else
+ {
+ if (hres != S_FALSE)
+ {
+ RINOK(hres);
+ }
+ }
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(res);
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+ *stream = 0;
+ if (Footer.IsFixed())
+ {
+ CLimitedInStream *streamSpec = new CLimitedInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->SetStream(Stream);
+ streamSpec->InitAndSeek(0, Footer.CurrentSize);
+ RINOK(streamSpec->SeekToStart());
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+ if (!Footer.ThereIsDynamic() || !IsOK())
+ return S_FALSE;
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ RINOK(InitAndSeek());
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"VHD", L"vhd", L".mbr", 0xDC, { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }, 10, false, CreateArc, 0 };
+
+REGISTER_ARC(Vhd)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Wim/StdAfx.h
new file mode 100644
index 000000000..e7fb6986d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Wim/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandler.cpp
new file mode 100644
index 000000000..eaad1e7ca
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -0,0 +1,660 @@
+// WimHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+#include "Common/StringToInt.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "WimHandler.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NWim {
+
+#define WIM_DETAILS
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidShortName, VT_BSTR}
+
+ #ifdef WIM_DETAILS
+ , { NULL, kpidVolume, VT_UI4}
+ , { NULL, kpidOffset, VT_UI8}
+ , { NULL, kpidLinks, VT_UI4}
+ #endif
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidUnpackVer, VT_BSTR},
+ { NULL, kpidIsVolume, VT_BOOL},
+ { NULL, kpidVolume, VT_UI4},
+ { NULL, kpidNumVolumes, VT_UI4}
+};
+
+static bool ParseNumber64(const AString &s, UInt64 &res)
+{
+ const char *end;
+ if (s.Left(2) == "0x")
+ {
+ if (s.Length() == 2)
+ return false;
+ res = ConvertHexStringToUInt64((const char *)s + 2, &end);
+ }
+ else
+ {
+ if (s.IsEmpty())
+ return false;
+ res = ConvertStringToUInt64(s, &end);
+ }
+ return *end == 0;
+}
+
+static bool ParseNumber32(const AString &s, UInt32 &res)
+{
+ UInt64 res64;
+ if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32))
+ return false;
+ res = (UInt32)res64;
+ return true;
+}
+
+bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag)
+{
+ int index = item.FindSubTag(tag);
+ if (index >= 0)
+ {
+ const CXmlItem &timeItem = item.SubItems[index];
+ UInt32 low = 0, high = 0;
+ if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) &&
+ ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high))
+ {
+ ft.dwLowDateTime = low;
+ ft.dwHighDateTime = high;
+ return true;
+ }
+ }
+ return false;
+}
+
+void CImageInfo::Parse(const CXmlItem &item)
+{
+ CTimeDefined = ParseTime(item, CTime, "CREATIONTIME");
+ MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME");
+ NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name);
+ // IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index);
+}
+
+void CXml::ToUnicode(UString &s)
+{
+ size_t size = Data.GetCapacity();
+ if (size < 2 || (size & 1) != 0 || size > (1 << 24))
+ return;
+ const Byte *p = Data;
+ if (Get16(p) != 0xFEFF)
+ return;
+ wchar_t *chars = s.GetBuffer((int)size / 2);
+ for (size_t i = 2; i < size; i += 2)
+ *chars++ = (wchar_t)Get16(p + i);
+ *chars = 0;
+ s.ReleaseBuffer();
+}
+
+void CXml::Parse()
+{
+ UString s;
+ ToUnicode(s);
+ AString utf;
+ if (!ConvertUnicodeToUTF8(s, utf))
+ return;
+ ::CXml xml;
+ if (!xml.Parse(utf))
+ return;
+ if (xml.Root.Name != "WIM")
+ return;
+
+ for (int i = 0; i < xml.Root.SubItems.Size(); i++)
+ {
+ const CXmlItem &item = xml.Root.SubItems[i];
+ if (item.IsTagged("IMAGE"))
+ {
+ CImageInfo imageInfo;
+ imageInfo.Parse(item);
+ Images.Add(imageInfo);
+ }
+ }
+}
+
+static const char *kMethodLZX = "LZX";
+static const char *kMethodXpress = "XPress";
+static const char *kMethodCopy = "Copy";
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CImageInfo *image = NULL;
+ if (_xmls.Size() == 1)
+ {
+ const CXml &xml = _xmls[0];
+ if (xml.Images.Size() == 1)
+ image = &xml.Images[0];
+ }
+
+ switch(propID)
+ {
+ case kpidSize: prop = _db.GetUnpackSize(); break;
+ case kpidPackSize: prop = _db.GetPackSize(); break;
+
+ case kpidCTime:
+ if (_xmls.Size() == 1)
+ {
+ const CXml &xml = _xmls[0];
+ int index = -1;
+ for (int i = 0; i < xml.Images.Size(); i++)
+ {
+ const CImageInfo &image = xml.Images[i];
+ if (image.CTimeDefined)
+ if (index < 0 || ::CompareFileTime(&image.CTime, &xml.Images[index].CTime) < 0)
+ index = i;
+ }
+ if (index >= 0)
+ prop = xml.Images[index].CTime;
+ }
+ break;
+
+ case kpidMTime:
+ if (_xmls.Size() == 1)
+ {
+ const CXml &xml = _xmls[0];
+ int index = -1;
+ for (int i = 0; i < xml.Images.Size(); i++)
+ {
+ const CImageInfo &image = xml.Images[i];
+ if (image.MTimeDefined)
+ if (index < 0 || ::CompareFileTime(&image.MTime, &xml.Images[index].MTime) > 0)
+ index = i;
+ }
+ if (index >= 0)
+ prop = xml.Images[index].MTime;
+ }
+ break;
+
+ case kpidComment:
+ if (image != NULL)
+ {
+ if (_xmlInComments)
+ {
+ UString s;
+ _xmls[0].ToUnicode(s);
+ prop = s;
+ }
+ else if (image->NameDefined)
+ prop = image->Name;
+ }
+ break;
+
+ case kpidUnpackVer:
+ {
+ UInt32 ver1 = _version >> 16;
+ UInt32 ver2 = (_version >> 8) & 0xFF;
+ UInt32 ver3 = (_version) & 0xFF;
+
+ char s[16];
+ ConvertUInt32ToString(ver1, s);
+ AString res = s;
+ res += '.';
+ ConvertUInt32ToString(ver2, s);
+ res += s;
+ if (ver3 != 0)
+ {
+ res += '.';
+ ConvertUInt32ToString(ver3, s);
+ res += s;
+ }
+ prop = res;
+ break;
+ }
+
+ case kpidIsVolume:
+ if (_xmls.Size() > 0)
+ {
+ UInt16 volIndex = _xmls[0].VolIndex;
+ if (volIndex < _volumes.Size())
+ prop = (_volumes[volIndex].Header.NumParts > 1);
+ }
+ break;
+ case kpidVolume:
+ if (_xmls.Size() > 0)
+ {
+ UInt16 volIndex = _xmls[0].VolIndex;
+ if (volIndex < _volumes.Size())
+ prop = (UInt32)_volumes[volIndex].Header.PartNumber;
+ }
+ break;
+ case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break;
+ case kpidMethod:
+ {
+ bool lzx = false, xpress = false, copy = false;
+ for (int i = 0; i < _xmls.Size(); i++)
+ {
+ const CHeader &header = _volumes[_xmls[i].VolIndex].Header;
+ if (header.IsCompressed())
+ if (header.IsLzxMode())
+ lzx = true;
+ else
+ xpress = true;
+ else
+ copy = true;
+ }
+ AString res;
+ if (lzx)
+ res = kMethodLZX;
+ if (xpress)
+ {
+ if (!res.IsEmpty())
+ res += ' ';
+ res += kMethodXpress;
+ }
+ if (copy)
+ {
+ if (!res.IsEmpty())
+ res += ' ';
+ res += kMethodCopy;
+ }
+ prop = res;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ if (index < (UInt32)_db.SortedItems.Size())
+ {
+ int realIndex = _db.SortedItems[index];
+ const CItem &item = _db.Items[realIndex];
+ const CStreamInfo *si = NULL;
+ const CVolume *vol = NULL;
+ if (item.StreamIndex >= 0)
+ {
+ si = &_db.Streams[item.StreamIndex];
+ vol = &_volumes[si->PartNumber];
+ }
+
+ switch(propID)
+ {
+ case kpidPath:
+ if (item.HasMetadata)
+ prop = _db.GetItemPath(realIndex);
+ else
+ {
+ char sz[16];
+ ConvertUInt32ToString(item.StreamIndex, sz);
+ AString s = sz;
+ while (s.Length() < _nameLenForStreams)
+ s = '0' + s;
+ /*
+ if (si->Resource.IsFree())
+ prefix = "[Free]";
+ */
+ s = "[Files]" STRING_PATH_SEPARATOR + s;
+ prop = s;
+ }
+ break;
+ case kpidShortName: if (item.HasMetadata) prop = item.ShortName; break;
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidAttrib: if (item.HasMetadata) prop = item.Attrib; break;
+ case kpidCTime: if (item.HasMetadata) prop = item.CTime; break;
+ case kpidATime: if (item.HasMetadata) prop = item.ATime; break;
+ case kpidMTime: if (item.HasMetadata) prop = item.MTime; break;
+ case kpidPackSize: prop = si ? si->Resource.PackSize : (UInt64)0; break;
+ case kpidSize: prop = si ? si->Resource.UnpackSize : (UInt64)0; break;
+ case kpidMethod: if (si) prop = si->Resource.IsCompressed() ?
+ (vol->Header.IsLzxMode() ? kMethodLZX : kMethodXpress) : kMethodCopy; break;
+ #ifdef WIM_DETAILS
+ case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break;
+ case kpidOffset: if (si) prop = (UInt64)si->Resource.Offset; break;
+ case kpidLinks: prop = si ? (UInt32)si->RefCount : (UInt32)0; break;
+ #endif
+ }
+ }
+ else
+ {
+ index -= _db.SortedItems.Size();
+ {
+ switch(propID)
+ {
+ case kpidPath:
+ {
+ char sz[16];
+ ConvertUInt32ToString(_xmls[index].VolIndex, sz);
+ prop = (AString)"[" + (AString)sz + "].xml";
+ break;
+ }
+ case kpidIsDir: prop = false; break;
+ case kpidPackSize:
+ case kpidSize: prop = (UInt64)_xmls[index].Data.GetCapacity(); break;
+ case kpidMethod: prop = kMethodCopy; break;
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CVolumeName
+{
+ // UInt32 _volIndex;
+ UString _before;
+ UString _after;
+public:
+ CVolumeName() {};
+
+ void InitName(const UString &name)
+ {
+ // _volIndex = 1;
+ int dotPos = name.ReverseFind('.');
+ if (dotPos < 0)
+ dotPos = name.Length();
+ _before = name.Left(dotPos);
+ _after = name.Mid(dotPos);
+ }
+
+ UString GetNextName(UInt32 index)
+ {
+ wchar_t s[16];
+ ConvertUInt32ToString(index, s);
+ return _before + (UString)s + _after;
+ }
+};
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ COM_TRY_BEGIN
+ Close();
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+
+ CVolumeName seqName;
+ if (openArchiveCallback != NULL)
+ openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+
+ UInt32 numVolumes = 1;
+ int firstVolumeIndex = -1;
+ for (UInt32 i = 1; i <= numVolumes; i++)
+ {
+ CMyComPtr<IInStream> curStream;
+ if (i != 1)
+ {
+ UString fullName = seqName.GetNextName(i);
+ HRESULT result = openVolumeCallback->GetStream(fullName, &curStream);
+ if (result == S_FALSE)
+ continue;
+ if (result != S_OK)
+ return result;
+ if (!curStream)
+ break;
+ }
+ else
+ curStream = inStream;
+ CHeader header;
+ HRESULT res = NWim::ReadHeader(curStream, header);
+ if (res != S_OK)
+ {
+ if (i == 1)
+ return res;
+ if (res == S_FALSE)
+ continue;
+ return res;
+ }
+ _version = header.Version;
+ _isOldVersion = header.IsOldVersion();
+ if (firstVolumeIndex >= 0)
+ if (!header.AreFromOnArchive(_volumes[firstVolumeIndex].Header))
+ break;
+ if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream)
+ break;
+ CXml xml;
+ xml.VolIndex = header.PartNumber;
+ res = _db.Open(curStream, header, xml.Data, openArchiveCallback);
+ if (res != S_OK)
+ {
+ if (i == 1)
+ return res;
+ if (res == S_FALSE)
+ continue;
+ return res;
+ }
+
+ while (_volumes.Size() <= header.PartNumber)
+ _volumes.Add(CVolume());
+ CVolume &volume = _volumes[header.PartNumber];
+ volume.Header = header;
+ volume.Stream = curStream;
+
+ firstVolumeIndex = header.PartNumber;
+
+ bool needAddXml = true;
+ if (_xmls.Size() != 0)
+ if (xml.Data == _xmls[0].Data)
+ needAddXml = false;
+ if (needAddXml)
+ {
+ xml.Parse();
+ _xmls.Add(xml);
+ }
+
+ if (i == 1)
+ {
+ if (header.PartNumber != 1)
+ break;
+ if (!openVolumeCallback)
+ break;
+ numVolumes = header.NumParts;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
+ if (prop.vt != VT_BSTR)
+ break;
+ seqName.InitName(prop.bstrVal);
+ }
+ }
+ }
+
+ _db.DetectPathMode();
+ RINOK(_db.Sort(_db.SkipRoot));
+
+ wchar_t sz[16];
+ ConvertUInt32ToString(_db.Streams.Size(), sz);
+ _nameLenForStreams = MyStringLen(sz);
+
+ _xmlInComments = (_xmls.Size() == 1 && !_db.ShowImageNumber);
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _db.Clear();
+ _volumes.Clear();
+ _xmls.Clear();
+ _nameLenForStreams = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+
+ if (allFilesMode)
+ numItems = _db.SortedItems.Size() + _xmls.Size();
+ if (numItems == 0)
+ return S_OK;
+
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = allFilesMode ? i : indices[i];
+ if (index < (UInt32)_db.SortedItems.Size())
+ {
+ int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex;
+ if (streamIndex >= 0)
+ {
+ const CStreamInfo &si = _db.Streams[streamIndex];
+ totalSize += si.Resource.UnpackSize;
+ }
+ }
+ else
+ totalSize += _xmls[index - (UInt32)_db.SortedItems.Size()].Data.GetCapacity();
+ }
+
+ RINOK(extractCallback->SetTotal(totalSize));
+
+ UInt64 currentTotalPacked = 0;
+ UInt64 currentTotalUnPacked = 0;
+ UInt64 currentItemUnPacked, currentItemPacked;
+
+ int prevSuccessStreamIndex = -1;
+
+ CUnpacker unpacker;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; currentTotalUnPacked += currentItemUnPacked,
+ currentTotalPacked += currentItemPacked)
+ {
+ currentItemUnPacked = 0;
+ currentItemPacked = 0;
+
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = currentTotalUnPacked;
+
+ RINOK(lps->SetCur());
+ UInt32 index = allFilesMode ? i : indices[i];
+ i++;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+ if (index >= (UInt32)_db.SortedItems.Size())
+ {
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ const CByteBuffer &data = _xmls[index - (UInt32)_db.SortedItems.Size()].Data;
+ currentItemUnPacked = data.GetCapacity();
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetCapacity()));
+ realOutStream.Release();
+ }
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ const CItem &item = _db.Items[_db.SortedItems[index]];
+ int streamIndex = item.StreamIndex;
+ if (streamIndex < 0)
+ {
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(item.HasStream() ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK));
+ continue;
+ }
+
+ const CStreamInfo &si = _db.Streams[streamIndex];
+ currentItemUnPacked = si.Resource.UnpackSize;
+ currentItemPacked = si.Resource.PackSize;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ if (streamIndex != prevSuccessStreamIndex || realOutStream)
+ {
+ Byte digest[20];
+ const CVolume &vol = _volumes[si.PartNumber];
+ HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(),
+ realOutStream, progress, digest);
+ if (res == S_OK)
+ {
+ if (memcmp(digest, si.Hash, kHashSize) == 0)
+ prevSuccessStreamIndex = streamIndex;
+ else
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ else if (res == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ return res;
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _db.SortedItems.Size();
+ if (!_xmlInComments)
+ *numItems += _xmls.Size();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandler.h
new file mode 100644
index 000000000..aa92069a5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandler.h
@@ -0,0 +1,77 @@
+// WimHandler.h
+
+#ifndef __ARCHIVE_WIM_HANDLER_H
+#define __ARCHIVE_WIM_HANDLER_H
+
+#include "Common/MyCom.h"
+#include "Common/MyXml.h"
+
+#include "WimIn.h"
+
+namespace NArchive {
+namespace NWim {
+
+struct CVolume
+{
+ CHeader Header;
+ CMyComPtr<IInStream> Stream;
+};
+
+struct CImageInfo
+{
+ bool CTimeDefined;
+ bool MTimeDefined;
+ bool NameDefined;
+ // bool IndexDefined;
+
+ FILETIME CTime;
+ FILETIME MTime;
+ UString Name;
+ // UInt32 Index;
+
+ CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false)
+ // , IndexDefined(false)
+ {}
+ void Parse(const CXmlItem &item);
+};
+
+struct CXml
+{
+ CByteBuffer Data;
+ UInt16 VolIndex;
+ CObjectVector<CImageInfo> Images;
+
+ void ToUnicode(UString &s);
+ void Parse();
+};
+
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CDatabase _db;
+ UInt32 _version;
+ bool _isOldVersion;
+ CObjectVector<CVolume> _volumes;
+ CObjectVector<CXml> _xmls;
+ int _nameLenForStreams;
+ bool _xmlInComments;
+
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+class COutHandler:
+ public IOutArchive,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(IOutArchive)
+ INTERFACE_IOutArchive(;)
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
new file mode 100644
index 000000000..50b879e79
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
@@ -0,0 +1,639 @@
+// WimHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Crypto/RandGen.h"
+#include "../../Crypto/Sha1.h"
+
+#include "WimHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NWim {
+
+struct CSha1Hash
+{
+ Byte Hash[kHashSize];
+};
+
+struct CHashList
+{
+ CRecordVector<CSha1Hash> Digests;
+ CIntVector Sorted;
+
+ int AddUnique(const CSha1Hash &h);
+};
+
+int CHashList::AddUnique(const CSha1Hash &h)
+{
+ int left = 0, right = Sorted.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ int index = Sorted[mid];
+ UInt32 i;
+ const Byte *hash2 = Digests[index].Hash;
+ for (i = 0; i < kHashSize; i++)
+ if (h.Hash[i] != hash2[i])
+ break;
+ if (i == kHashSize)
+ return index;
+ if (h.Hash[i] < hash2[i])
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Sorted.Insert(left, Digests.Add(h));
+ return -1;
+}
+
+struct CUpdateItem
+{
+ UString Name;
+ UInt64 Size;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ UInt32 Attrib;
+ bool IsDir;
+ int HashIndex;
+
+ CUpdateItem(): HashIndex(-1) {}
+};
+
+struct CDir
+{
+ int Index;
+ UString Name;
+ CObjectVector<CDir> Dirs;
+ CIntVector Files;
+
+ CDir(): Index(-1) {}
+ bool IsLeaf() const { return Index >= 0; }
+ UInt64 GetNumDirs() const;
+ UInt64 GetNumFiles() const;
+ CDir* AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index);
+};
+
+UInt64 CDir::GetNumDirs() const
+{
+ UInt64 num = Dirs.Size();
+ for (int i = 0; i < Dirs.Size(); i++)
+ num += Dirs[i].GetNumDirs();
+ return num;
+}
+
+UInt64 CDir::GetNumFiles() const
+{
+ UInt64 num = Files.Size();
+ for (int i = 0; i < Dirs.Size(); i++)
+ num += Dirs[i].GetNumFiles();
+ return num;
+}
+
+CDir* CDir::AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index)
+{
+ int left = 0, right = Dirs.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ CDir &d = Dirs[mid];
+ int compare = name.CompareNoCase(d.IsLeaf() ? items[Dirs[mid].Index].Name : d.Name);
+ if (compare == 0)
+ {
+ if (index >= 0)
+ d.Index = index;
+ return &d;
+ }
+ if (compare < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Dirs.Insert(left, CDir());
+ CDir &d = Dirs[left];
+ d.Index = index;
+ if (index < 0)
+ d.Name = name;
+ return &d;
+}
+
+
+STDMETHODIMP COutHandler::GetFileTimeType(UInt32 *type)
+{
+ *type = NFileTimeType::kWindows;
+ return S_OK;
+}
+
+static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &ft)
+{
+ ft.dwLowDateTime = ft.dwHighDateTime = 0;
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ ft = prop.filetime;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+#define Set16(p, d) SetUi16(p, d)
+#define Set32(p, d) SetUi32(p, d)
+#define Set64(p, d) SetUi64(p, d)
+
+void CResource::WriteTo(Byte *p) const
+{
+ Set64(p, PackSize);
+ p[7] = Flags;
+ Set64(p + 8, Offset);
+ Set64(p + 16, UnpackSize);
+}
+
+void CHeader::WriteTo(Byte *p) const
+{
+ memcpy(p, kSignature, kSignatureSize);
+ Set32(p + 8, kHeaderSizeMax);
+ Set32(p + 0xC, Version);
+ Set32(p + 0x10, Flags);
+ Set32(p + 0x14, ChunkSize);
+ memcpy(p + 0x18, Guid, 16);
+ Set16(p + 0x28, PartNumber);
+ Set16(p + 0x2A, NumParts);
+ Set32(p + 0x2C, NumImages);
+ OffsetResource.WriteTo(p + 0x30);
+ XmlResource.WriteTo(p + 0x48);
+ MetadataResource.WriteTo(p + 0x60);
+ IntegrityResource.WriteTo(p + 0x7C);
+ Set32(p + 0x78, BootIndex);
+ memset(p + 0x94, 0, 60);
+}
+
+void CStreamInfo::WriteTo(Byte *p) const
+{
+ Resource.WriteTo(p);
+ Set16(p + 0x18, PartNumber);
+ Set32(p + 0x1A, RefCount);
+ memcpy(p + 0x1E, Hash, kHashSize);
+}
+
+class CInStreamWithSha1:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ NCrypto::NSha1::CContext _sha;
+public:
+ MY_UNKNOWN_IMP1(IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ _sha.Init();
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt64 GetSize() const { return _size; }
+ void Final(Byte *digest) { _sha.Final(digest); }
+};
+
+STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ _sha.Update((const Byte *)data, realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+static void SetFileTimeToMem(Byte *p, const FILETIME &ft)
+{
+ Set32(p, ft.dwLowDateTime);
+ Set32(p + 4, ft.dwHighDateTime);
+}
+
+static size_t WriteItem(const CUpdateItem &item, Byte *p, const Byte *hash)
+{
+ int fileNameLen = item.Name.Length() * 2;
+ int fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+
+ size_t totalLen = ((kDirRecordSize + fileNameLen2 + 6) & ~7);
+ if (p)
+ {
+ memset(p, 0, totalLen);
+ Set64(p, totalLen);
+ Set64(p + 8, item.Attrib);
+ Set32(p + 0xC, (UInt32)(Int32)-1); // item.SecurityId
+ // Set64(p + 0x10, 0); // subdirOffset
+ SetFileTimeToMem(p + 0x28, item.CTime);
+ SetFileTimeToMem(p + 0x30, item.ATime);
+ SetFileTimeToMem(p + 0x38, item.MTime);
+ if (hash)
+ memcpy(p + 0x40, hash, kHashSize);
+ /*
+ else
+ memset(p + 0x40, 0, kHashSize);
+ */
+ // Set16(p + 98, 0); // shortNameLen
+ Set16(p + 100, (UInt16)fileNameLen);
+ for (int i = 0; i * 2 < fileNameLen; i++)
+ Set16(p + kDirRecordSize + i * 2, item.Name[i]);
+ }
+ return totalLen;
+}
+
+static void WriteTree(const CDir &tree, CRecordVector<CSha1Hash> &digests,
+ CUpdateItem &defaultDirItem,
+ CObjectVector<CUpdateItem> &updateItems, Byte *dest, size_t &pos)
+{
+ int i;
+ for (i = 0; i < tree.Files.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[tree.Files[i]];
+ pos += WriteItem(ui, dest ? dest + pos : NULL,
+ ui.HashIndex >= 0 ? digests[ui.HashIndex].Hash : NULL);
+ }
+
+ size_t posStart = pos;
+ for (i = 0; i < tree.Dirs.Size(); i++)
+ {
+ const CDir &subfolder = tree.Dirs[i];
+ CUpdateItem *item = &defaultDirItem;
+ if (subfolder.IsLeaf())
+ item = &updateItems[subfolder.Index];
+ else
+ defaultDirItem.Name = subfolder.Name;
+ pos += WriteItem(*item, NULL, NULL);
+ }
+
+ if (dest)
+ Set64(dest + pos, 0);
+
+ pos += 8;
+
+ for (i = 0; i < tree.Dirs.Size(); i++)
+ {
+ const CDir &subfolder = tree.Dirs[i];
+ if (dest)
+ {
+ CUpdateItem *item = &defaultDirItem;
+ if (subfolder.IsLeaf())
+ item = &updateItems[subfolder.Index];
+ else
+ defaultDirItem.Name = subfolder.Name;
+ size_t len = WriteItem(*item, dest + posStart, NULL);
+ Set64(dest + posStart + 0x10, pos);
+ posStart += len;
+ }
+ WriteTree(subfolder, digests, defaultDirItem, updateItems, dest, pos);
+ }
+}
+
+static void AddTag(AString &s, const char *name, const AString &value)
+{
+ s += "<";
+ s += name;
+ s += ">";
+ s += value;
+ s += "</";
+ s += name;
+ s += ">";
+}
+
+static void AddTagUInt64(AString &s, const char *name, UInt64 value)
+{
+ char temp[32];
+ ConvertUInt64ToString(value, temp);
+ AddTag(s, name, temp);
+}
+
+static AString TimeToXml(FILETIME &ft)
+{
+ AString res;
+ char temp[16] = { '0', 'x' };
+ ConvertUInt32ToHexWithZeros(ft.dwHighDateTime, temp + 2);
+ AddTag(res, "HIGHPART", temp);
+ ConvertUInt32ToHexWithZeros(ft.dwLowDateTime, temp + 2);
+ AddTag(res, "LOWPART", temp);
+ return res;
+}
+
+void CHeader::SetDefaultFields(bool useLZX)
+{
+ Version = kWimVersion;
+ Flags = NHeaderFlags::kRpFix;
+ ChunkSize = 0;
+ if (useLZX)
+ {
+ Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX;
+ ChunkSize = kChunkSize;
+ }
+ g_RandomGenerator.Generate(Guid, 16);
+ PartNumber = 1;
+ NumParts = 1;
+ NumImages = 1;
+ BootIndex = 0;
+ OffsetResource.Clear();
+ XmlResource.Clear();
+ MetadataResource.Clear();
+ IntegrityResource.Clear();
+}
+
+static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream,
+ CDir &rootFolder,
+ CObjectVector<CUpdateItem> &updateItems,
+ IArchiveUpdateCallback *callback)
+{
+ CMyComPtr<IOutStream> outStream;
+ RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
+ if (!outStream)
+ return E_NOTIMPL;
+
+ UInt64 complexity = 0;
+
+ int i;
+ for (i = 0; i < updateItems.Size(); i++)
+ complexity += updateItems[i].Size;
+
+ RINOK(callback->SetTotal(complexity));
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(callback, true);
+
+ complexity = 0;
+
+ bool useCompression = false;
+
+ CHeader header;
+ header.SetDefaultFields(useCompression);
+ Byte buf[kHeaderSizeMax];
+ header.WriteTo(buf);
+ RINOK(WriteStream(outStream, buf, kHeaderSizeMax));
+
+ CHashList hashes;
+ CObjectVector<CStreamInfo> streams;
+
+ UInt64 curPos = kHeaderSizeMax;
+ UInt64 unpackTotalSize = 0;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur());
+
+ CUpdateItem &ui = updateItems[i];
+ if (ui.IsDir || ui.Size == 0)
+ continue;
+
+ CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1;
+ CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec;
+
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = callback->GetStream(i, &fileInStream);
+ if (res != S_FALSE)
+ {
+ RINOK(res);
+ inShaStreamSpec->SetStream(fileInStream);
+ fileInStream.Release();
+ inShaStreamSpec->Init();
+ UInt64 offsetBlockSize = 0;
+ if (useCompression)
+ {
+ for (UInt64 t = kChunkSize; t < ui.Size; t += kChunkSize)
+ {
+ Byte buf[8];
+ SetUi32(buf, (UInt32)t);
+ RINOK(WriteStream(outStream, buf, 4));
+ offsetBlockSize += 4;
+ }
+ }
+
+ RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress));
+ ui.Size = copyCoderSpec->TotalSize;
+
+ CSha1Hash hash;
+ unpackTotalSize += ui.Size;
+ UInt64 packSize = offsetBlockSize + ui.Size;
+ inShaStreamSpec->Final(hash.Hash);
+ int index = hashes.AddUnique(hash);
+ if (index >= 0)
+ {
+ ui.HashIndex = index;
+ streams[index].RefCount++;
+ outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos);
+ outStream->SetSize(curPos);
+ }
+ else
+ {
+ ui.HashIndex = hashes.Digests.Size() - 1;
+ CStreamInfo s;
+ s.Resource.PackSize = packSize;
+ s.Resource.Offset = curPos;
+ s.Resource.UnpackSize = ui.Size;
+ s.Resource.Flags = 0;
+ if (useCompression)
+ s.Resource.Flags = NResourceFlags::Compressed;
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, hash.Hash, kHashSize);
+ streams.Add(s);
+ curPos += packSize;
+ }
+ }
+ fileInStream.Release();
+ complexity += ui.Size;
+ RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+ }
+
+
+ CUpdateItem ri;
+ FILETIME ft;
+ NTime::GetCurUtcFileTime(ft);
+ ri.MTime = ri.ATime = ri.CTime = ft;
+ ri.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+
+ const UInt32 kSecuritySize = 8;
+ size_t pos = kSecuritySize;
+ WriteTree(rootFolder, hashes.Digests, ri, updateItems, NULL, pos);
+
+ CByteBuffer meta;
+ meta.SetCapacity(pos);
+
+ // we can write 0 here only if there is no security data, imageX does it,
+ // but some programs expect size = 8
+ Set32((Byte *)meta, 8); // size of security data
+ Set32((Byte *)meta + 4, 0); // num security entries
+
+ pos = kSecuritySize;
+ WriteTree(rootFolder, hashes.Digests, ri, updateItems, (Byte *)meta, pos);
+
+ {
+ NCrypto::NSha1::CContext sha;
+ sha.Init();
+ sha.Update((const Byte *)meta, pos);
+ CSha1Hash digest;
+ sha.Final(digest.Hash);
+
+ CStreamInfo s;
+ s.Resource.PackSize = pos;
+ s.Resource.Offset = curPos;
+ s.Resource.UnpackSize = pos;
+ s.Resource.Flags = NResourceFlags::kMetadata;
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, digest.Hash, kHashSize);
+ streams.Add(s);
+ RINOK(WriteStream(outStream, (const Byte *)meta, pos));
+ meta.Free();
+ curPos += pos;
+ }
+
+
+ header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize;
+ header.OffsetResource.Offset = curPos;
+ header.OffsetResource.Flags = NResourceFlags::kMetadata;
+
+ for (i = 0; i < streams.Size(); i++)
+ {
+ Byte buf[kStreamInfoSize];
+ streams[i].WriteTo(buf);
+ RINOK(WriteStream(outStream, buf, kStreamInfoSize));
+ curPos += kStreamInfoSize;
+ }
+
+ AString xml = "<WIM>";
+ AddTagUInt64(xml, "TOTALBYTES", curPos);
+ xml += "<IMAGE INDEX=\"1\"><NAME>1</NAME>";
+ AddTagUInt64(xml, "DIRCOUNT", rootFolder.GetNumDirs());
+ AddTagUInt64(xml, "FILECOUNT", rootFolder.GetNumFiles());
+ AddTagUInt64(xml, "TOTALBYTES", unpackTotalSize);
+ NTime::GetCurUtcFileTime(ft);
+ AddTag(xml, "CREATIONTIME", TimeToXml(ft));
+ AddTag(xml, "LASTMODIFICATIONTIME", TimeToXml(ft));
+ xml += "</IMAGE></WIM>";
+
+ size_t xmlSize = (xml.Length() + 1) * 2;
+ meta.SetCapacity(xmlSize);
+ Set16((Byte *)meta, 0xFEFF);
+ for (i = 0; i < xml.Length(); i++)
+ Set16((Byte *)meta + 2 + i * 2, xml[i]);
+ RINOK(WriteStream(outStream, (const Byte *)meta, xmlSize));
+ meta.Free();
+
+ header.XmlResource.UnpackSize = header.XmlResource.PackSize = xmlSize;
+ header.XmlResource.Offset = curPos;
+ header.XmlResource.Flags = NResourceFlags::kMetadata;
+
+ outStream->Seek(0, STREAM_SEEK_SET, NULL);
+ header.WriteTo(buf);
+ return WriteStream(outStream, buf, kHeaderSizeMax);
+}
+
+STDMETHODIMP COutHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback)
+{
+ COM_TRY_BEGIN
+ CObjectVector<CUpdateItem> updateItems;
+ CDir tree;
+ tree.Dirs.Add(CDir());
+ CDir &rootFolder = tree.Dirs.Back();
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!callback)
+ return E_FAIL;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Attrib = (ui.IsDir ? FILE_ATTRIBUTE_DIRECTORY : 0);
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Attrib = prop.ulVal;
+ }
+
+ RINOK(GetTime(callback, i, kpidCTime, ui.CTime));
+ RINOK(GetTime(callback, i, kpidATime, ui.ATime));
+ RINOK(GetTime(callback, i, kpidMTime, ui.MTime));
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ ui.Size = prop.uhVal.QuadPart;
+ }
+
+ UString path;
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop));
+ if (prop.vt == VT_BSTR)
+ path = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+
+ CDir *curItem = &rootFolder;
+ int len = path.Length();
+ UString fileName;
+ for (int j = 0; j < len; j++)
+ {
+ wchar_t c = path[j];
+ if (c == WCHAR_PATH_SEPARATOR || c == L'/')
+ {
+ curItem = curItem->AddDir(updateItems, fileName, -1);
+ fileName.Empty();
+ }
+ else
+ fileName += c;
+ }
+
+ ui.Name = fileName;
+ updateItems.Add(ui);
+ if (ui.IsDir)
+ curItem->AddDir(updateItems, fileName, (int)i);
+ else
+ curItem->Files.Add(i);
+ }
+ return UpdateArchive(outStream, tree, updateItems, callback);
+ COM_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp
new file mode 100644
index 000000000..c210804df
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -0,0 +1,855 @@
+// Archive/WimIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/IntToString.h"
+
+#include "../../Common/StreamUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/LimitedStreams.h"
+
+#include "../Common/OutStreamWithSha1.h"
+
+#include "WimIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NWim {
+
+namespace NXpress {
+
+class CDecoderFlusher
+{
+ CDecoder *m_Decoder;
+public:
+ bool NeedFlush;
+ CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ m_Decoder->Flush();
+ m_Decoder->ReleaseStreams();
+ }
+};
+
+HRESULT CDecoder::CodeSpec(UInt32 outSize)
+{
+ {
+ Byte levels[kMainTableSize];
+ for (unsigned i = 0; i < kMainTableSize; i += 2)
+ {
+ Byte b = m_InBitStream.DirectReadByte();
+ levels[i] = b & 0xF;
+ levels[i + 1] = b >> 4;
+ }
+ if (!m_MainDecoder.SetCodeLengths(levels))
+ return S_FALSE;
+ }
+
+ while (outSize > 0)
+ {
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < 256)
+ {
+ m_OutWindowStream.PutByte((Byte)number);
+ outSize--;
+ }
+ else
+ {
+ if (number >= kMainTableSize)
+ return S_FALSE;
+ UInt32 posLenSlot = number - 256;
+ UInt32 posSlot = posLenSlot / kNumLenSlots;
+ UInt32 len = posLenSlot % kNumLenSlots;
+ UInt32 distance = (1 << posSlot) - 1 + m_InBitStream.ReadBits(posSlot);
+
+ if (len == kNumLenSlots - 1)
+ {
+ len = m_InBitStream.DirectReadByte();
+ if (len == 0xFF)
+ {
+ len = m_InBitStream.DirectReadByte();
+ len |= (UInt32)m_InBitStream.DirectReadByte() << 8;
+ }
+ else
+ len += kNumLenSlots - 1;
+ }
+
+ len += kMatchMinLen;
+ UInt32 locLen = (len <= outSize ? len : outSize);
+
+ if (!m_OutWindowStream.CopyBlock(distance, locLen))
+ return S_FALSE;
+
+ len -= locLen;
+ outSize -= locLen;
+ if (len != 0)
+ return S_FALSE;
+ }
+ }
+ return S_OK;
+}
+
+const UInt32 kDictSize = (1 << kNumPosSlots);
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize)
+{
+ if (!m_OutWindowStream.Create(kDictSize) || !m_InBitStream.Create(1 << 16))
+ return E_OUTOFMEMORY;
+
+ CDecoderFlusher flusher(this);
+
+ m_InBitStream.SetStream(inStream);
+ m_OutWindowStream.SetStream(outStream);
+ m_InBitStream.Init();
+ m_OutWindowStream.Init(false);
+
+ RINOK(CodeSpec(outSize));
+
+ flusher.NeedFlush = false;
+ return Flush();
+}
+
+HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize)
+{
+ try { return CodeReal(inStream, outStream, outSize); }
+ catch(const CInBufferException &e) { return e.ErrorCode; } \
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}
+
+HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL));
+
+ CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream();
+ CMyComPtr<ISequentialInStream> limitedStream = limitedStreamSpec;
+ limitedStreamSpec->SetStream(inStream);
+
+ if (!copyCoder)
+ {
+ copyCoderSpec = new NCompress::CCopyCoder;
+ copyCoder = copyCoderSpec;
+ }
+ if (!resource.IsCompressed())
+ {
+ if (resource.PackSize != resource.UnpackSize)
+ return S_FALSE;
+ limitedStreamSpec->Init(resource.PackSize);
+ return copyCoder->Code(limitedStreamSpec, outStream, NULL, NULL, progress);
+ }
+ if (resource.UnpackSize == 0)
+ return S_OK;
+ UInt64 numChunks = (resource.UnpackSize + kChunkSize - 1) >> kChunkSizeBits;
+ unsigned entrySize = ((resource.UnpackSize > (UInt64)1 << 32) ? 8 : 4);
+ UInt64 sizesBufSize64 = entrySize * (numChunks - 1);
+ size_t sizesBufSize = (size_t)sizesBufSize64;
+ if (sizesBufSize != sizesBufSize64)
+ return E_OUTOFMEMORY;
+ if (sizesBufSize > sizesBuf.GetCapacity())
+ {
+ sizesBuf.Free();
+ sizesBuf.SetCapacity(sizesBufSize);
+ }
+ RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize));
+ const Byte *p = (const Byte *)sizesBuf;
+
+ if (lzxMode && !lzxDecoder)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder(true);
+ lzxDecoder = lzxDecoderSpec;
+ RINOK(lzxDecoderSpec->SetParams(kChunkSizeBits));
+ }
+
+ UInt64 baseOffset = resource.Offset + sizesBufSize64;
+ UInt64 outProcessed = 0;
+ for (UInt32 i = 0; i < (UInt32)numChunks; i++)
+ {
+ UInt64 offset = 0;
+ if (i > 0)
+ {
+ offset = (entrySize == 4) ? Get32(p): Get64(p);
+ p += entrySize;
+ }
+ UInt64 nextOffset = resource.PackSize - sizesBufSize64;
+ if (i + 1 < (UInt32)numChunks)
+ nextOffset = (entrySize == 4) ? Get32(p): Get64(p);
+ if (nextOffset < offset)
+ return S_FALSE;
+
+ RINOK(inStream->Seek(baseOffset + offset, STREAM_SEEK_SET, NULL));
+ UInt64 inSize = nextOffset - offset;
+ limitedStreamSpec->Init(inSize);
+
+ if (progress)
+ {
+ RINOK(progress->SetRatioInfo(&offset, &outProcessed));
+ }
+
+ UInt32 outSize = kChunkSize;
+ if (outProcessed + outSize > resource.UnpackSize)
+ outSize = (UInt32)(resource.UnpackSize - outProcessed);
+ UInt64 outSize64 = outSize;
+ if (inSize == outSize)
+ {
+ RINOK(copyCoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
+ }
+ else
+ {
+ if (lzxMode)
+ {
+ lzxDecoderSpec->SetKeepHistory(false);
+ RINOK(lzxDecoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
+ }
+ else
+ {
+ RINOK(xpressDecoder.Code(limitedStreamSpec, outStream, outSize));
+ }
+ }
+ outProcessed += outSize;
+ }
+ return S_OK;
+}
+
+HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest)
+{
+ COutStreamWithSha1 *shaStreamSpec = new COutStreamWithSha1();
+ CMyComPtr<ISequentialOutStream> shaStream = shaStreamSpec;
+ shaStreamSpec->SetStream(outStream);
+ shaStreamSpec->Init(digest != NULL);
+ HRESULT result = Unpack(inStream, resource, lzxMode, shaStream, progress);
+ if (digest)
+ shaStreamSpec->Final(digest);
+ return result;
+}
+
+static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool lzxMode, CByteBuffer &buf, Byte *digest)
+{
+ size_t size = (size_t)resource.UnpackSize;
+ if (size != resource.UnpackSize)
+ return E_OUTOFMEMORY;
+ buf.Free();
+ buf.SetCapacity(size);
+
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream();
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->Init((Byte *)buf, size);
+
+ CUnpacker unpacker;
+ return unpacker.Unpack(inStream, resource, lzxMode, outStream, NULL, digest);
+}
+
+void CResource::Parse(const Byte *p)
+{
+ Flags = p[7];
+ PackSize = Get64(p) & (((UInt64)1 << 56) - 1);
+ Offset = Get64(p + 8);
+ UnpackSize = Get64(p + 16);
+}
+
+#define GetResource(p, res) res.Parse(p)
+
+static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s)
+{
+ s.Resource.Parse(p);
+ if (oldVersion)
+ {
+ s.PartNumber = 1;
+ s.Id = Get32(p + 24);
+ s.RefCount = Get32(p + 28);
+ memcpy(s.Hash, p + 32, kHashSize);
+ }
+ else
+ {
+ s.PartNumber = Get16(p + 24);
+ s.RefCount = Get32(p + 26);
+ memcpy(s.Hash, p + 30, kHashSize);
+ }
+}
+
+static const wchar_t *kLongPath = L"[LongPath]";
+
+UString CDatabase::GetItemPath(const int index1) const
+{
+ int size = 0;
+ int index = index1;
+ int newLevel;
+ for (newLevel = 0;; newLevel = 1)
+ {
+ const CItem &item = Items[index];
+ index = item.Parent;
+ if (index >= 0 || !SkipRoot)
+ size += item.Name.Length() + newLevel;
+ if (index < 0)
+ break;
+ if ((UInt32)size >= ((UInt32)1 << 16))
+ return kLongPath;
+ }
+
+ wchar_t temp[16];
+ int imageLen = 0;
+ if (ShowImageNumber)
+ {
+ ConvertUInt32ToString(-1 - index, temp);
+ imageLen = MyStringLen(temp);
+ size += imageLen + 1;
+ }
+ if ((UInt32)size >= ((UInt32)1 << 16))
+ return kLongPath;
+
+ UString path;
+ wchar_t *s = path.GetBuffer(size);
+ s[size] = 0;
+ if (ShowImageNumber)
+ {
+ memcpy(s, temp, imageLen * sizeof(wchar_t));
+ s[imageLen] = WCHAR_PATH_SEPARATOR;
+ }
+
+ index = index1;
+
+ for (newLevel = 0;; newLevel = 1)
+ {
+ const CItem &item = Items[index];
+ index = item.Parent;
+ if (index >= 0 || !SkipRoot)
+ {
+ if (newLevel)
+ s[--size] = WCHAR_PATH_SEPARATOR;
+ size -= item.Name.Length();
+ memcpy(s + size, item.Name, sizeof(wchar_t) * item.Name.Length());
+ }
+ if (index < 0)
+ {
+ path.ReleaseBuffer();
+ return path;
+ }
+ }
+}
+
+static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
+{
+ ft->dwLowDateTime = Get32(p);
+ ft->dwHighDateTime = Get32(p + 4);
+}
+
+static HRESULT ReadName(const Byte *p, int size, UString &dest)
+{
+ if (size == 0)
+ return S_OK;
+ if (Get16(p + size) != 0)
+ return S_FALSE;
+ wchar_t *s = dest.GetBuffer(size / 2);
+ for (int i = 0; i <= size; i += 2)
+ *s++ = Get16(p + i);
+ dest.ReleaseBuffer();
+ return S_OK;
+}
+
+HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
+{
+ if ((pos & 7) != 0)
+ return S_FALSE;
+
+ int prevIndex = -1;
+ for (int numItems = 0;; numItems++)
+ {
+ if (OpenCallback)
+ {
+ UInt64 numFiles = Items.Size();
+ if ((numFiles & 0x3FF) == 0)
+ {
+ RINOK(OpenCallback->SetCompleted(&numFiles, NULL));
+ }
+ }
+ size_t rem = DirSize - pos;
+ if (pos < DirStartOffset || pos > DirSize || rem < 8)
+ return S_FALSE;
+ const Byte *p = DirData + pos;
+ UInt64 len = Get64(p);
+ if (len == 0)
+ {
+ if (parent < 0 && numItems != 1)
+ SkipRoot = false;
+ DirProcessed += 8;
+ return S_OK;
+ }
+ if ((len & 7) != 0 || rem < len)
+ return S_FALSE;
+ if (!IsOldVersion)
+ if (len < 0x28)
+ return S_FALSE;
+ DirProcessed += (size_t)len;
+ if (DirProcessed > DirSize)
+ return S_FALSE;
+ int extraOffset = 0;
+ if (IsOldVersion)
+ {
+ if (len < 0x40 || (/* Get32(p + 12) == 0 && */ Get32(p + 0x14) != 0))
+ {
+ extraOffset = 0x10;
+ }
+ }
+ else if (Get64(p + 8) == 0)
+ extraOffset = 0x24;
+ if (extraOffset)
+ {
+ if (prevIndex == -1)
+ return S_FALSE;
+ UInt32 fileNameLen = Get16(p + extraOffset);
+ if ((fileNameLen & 1) != 0)
+ return S_FALSE;
+ /* Probably different versions of ImageX can use different number of
+ additional ZEROs. So we don't use exact check. */
+ UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+ if (((extraOffset + 2 + fileNameLen2 + 6) & ~7) > len)
+ return S_FALSE;
+
+ UString name;
+ RINOK(ReadName(p + extraOffset + 2, fileNameLen, name));
+
+ CItem &prevItem = Items[prevIndex];
+ if (name.IsEmpty() && !prevItem.HasStream())
+ {
+ if (IsOldVersion)
+ prevItem.Id = Get32(p + 8);
+ else
+ memcpy(prevItem.Hash, p + 0x10, kHashSize);
+ }
+ else
+ {
+ CItem item;
+ item.Name = prevItem.Name + L':' + name;
+ item.CTime = prevItem.CTime;
+ item.ATime = prevItem.ATime;
+ item.MTime = prevItem.MTime;
+ if (IsOldVersion)
+ {
+ item.Id = Get32(p + 8);
+ memset(item.Hash, 0, kHashSize);
+ }
+ else
+ memcpy(item.Hash, p + 0x10, kHashSize);
+ item.Attrib = 0;
+ item.Order = Order++;
+ item.Parent = parent;
+ Items.Add(item);
+ }
+ pos += (size_t)len;
+ continue;
+ }
+
+ UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize;
+ if (len < dirRecordSize)
+ return S_FALSE;
+
+ CItem item;
+ item.Attrib = Get32(p + 8);
+ // item.SecurityId = Get32(p + 0xC);
+ UInt64 subdirOffset = Get64(p + 0x10);
+ UInt32 timeOffset = IsOldVersion ? 0x18: 0x28;
+ GetFileTimeFromMem(p + timeOffset, &item.CTime);
+ GetFileTimeFromMem(p + timeOffset + 8, &item.ATime);
+ GetFileTimeFromMem(p + timeOffset + 16, &item.MTime);
+ if (IsOldVersion)
+ {
+ item.Id = Get32(p + 0x10);
+ memset(item.Hash, 0, kHashSize);
+ }
+ else
+ {
+ memcpy(item.Hash, p + 0x40, kHashSize);
+ }
+ // UInt32 numStreams = Get16(p + dirRecordSize - 6);
+ UInt32 shortNameLen = Get16(p + dirRecordSize - 4);
+ UInt32 fileNameLen = Get16(p + dirRecordSize - 2);
+
+ if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0)
+ return S_FALSE;
+
+ UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2);
+ UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+
+ if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len)
+ return S_FALSE;
+ p += dirRecordSize;
+
+ RINOK(ReadName(p, fileNameLen, item.Name));
+ RINOK(ReadName(p + fileNameLen2, shortNameLen, item.ShortName));
+
+ if (parent < 0 && (shortNameLen || fileNameLen || !item.IsDir()))
+ SkipRoot = false;
+
+ /*
+ // there are some extra data for some files.
+ p -= dirRecordSize;
+ p += ((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7);
+ if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len)
+ p = p;
+ */
+
+ /*
+ if (parent >= 0)
+ {
+ UString s = GetItemPath(parent) + L"\\" + item.Name;
+ printf("\n%s %8x %S", item.IsDir() ? "D" : " ", (int)subdirOffset, (const wchar_t *)s);
+ }
+ */
+
+ if (fileNameLen == 0 && item.IsDir() && !item.HasStream())
+ item.Attrib = 0x10; // some swm archives have system/hidden attributes for root
+
+ item.Parent = parent;
+ prevIndex = Items.Add(item);
+ if (item.IsDir() && subdirOffset != 0)
+ {
+ RINOK(ParseDirItem((size_t)subdirOffset, prevIndex));
+ }
+ Items[prevIndex].Order = Order++;
+ pos += (size_t)len;
+ }
+}
+
+HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent)
+{
+ DirData = buf;
+ DirSize = buf.GetCapacity();
+
+ size_t pos = 0;
+ if (DirSize < 8)
+ return S_FALSE;
+ const Byte *p = DirData;
+ UInt32 totalLength = Get32(p);
+ if (IsOldVersion)
+ {
+ for (pos = 4;; pos += 8)
+ {
+ if (pos + 4 > DirSize)
+ return S_FALSE;
+ UInt32 n = Get32(p + pos);
+ if (n == 0)
+ break;
+ if (pos + 8 > DirSize)
+ return S_FALSE;
+ totalLength += Get32(p + pos + 4);
+ if (totalLength > DirSize)
+ return S_FALSE;
+ }
+ pos += totalLength + 4;
+ pos = (pos + 7) & ~(size_t)7;
+ if (pos > DirSize)
+ return S_FALSE;
+ }
+ else
+ {
+
+ // UInt32 numEntries = Get32(p + 4);
+ pos += 8;
+ {
+ /*
+ CRecordVector<UInt64> entryLens;
+ UInt64 sum = 0;
+ for (UInt32 i = 0; i < numEntries; i++)
+ {
+ if (pos + 8 > DirSize)
+ return S_FALSE;
+ UInt64 len = Get64(p + pos);
+ entryLens.Add(len);
+ sum += len;
+ pos += 8;
+ }
+ pos += (size_t)sum; // skip security descriptors
+ while ((pos & 7) != 0)
+ pos++;
+ if (pos != totalLength)
+ return S_FALSE;
+ */
+ if (totalLength == 0)
+ pos = 8;
+ else if (totalLength < 8)
+ return S_FALSE;
+ else
+ pos = totalLength;
+ }
+ }
+ DirStartOffset = DirProcessed = pos;
+ RINOK(ParseDirItem(pos, parent));
+ if (DirProcessed == DirSize)
+ return S_OK;
+ /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), but
+ reference to that folder is empty */
+ if (DirProcessed == DirSize - 8 && DirProcessed - DirStartOffset == 112 &&
+ Get64(p + DirSize - 8) == 0)
+ return S_OK;
+ return S_FALSE;
+}
+
+HRESULT CHeader::Parse(const Byte *p)
+{
+ UInt32 headerSize = Get32(p + 8);
+ Version = Get32(p + 0x0C);
+ Flags = Get32(p + 0x10);
+ if (!IsSupported())
+ return S_FALSE;
+ ChunkSize = Get32(p + 0x14);
+ if (ChunkSize != kChunkSize && ChunkSize != 0)
+ return S_FALSE;
+ int offset;
+ if (IsOldVersion())
+ {
+ if (headerSize != 0x60)
+ return S_FALSE;
+ memset(Guid, 0, 16);
+ offset = 0x18;
+ PartNumber = 1;
+ NumParts = 1;
+ }
+ else
+ {
+ if (headerSize < 0x74)
+ return S_FALSE;
+ memcpy(Guid, p + 0x18, 16);
+ PartNumber = Get16(p + 0x28);
+ NumParts = Get16(p + 0x2A);
+ offset = 0x2C;
+ if (IsNewVersion())
+ {
+ NumImages = Get32(p + offset);
+ offset += 4;
+ }
+ }
+ GetResource(p + offset, OffsetResource);
+ GetResource(p + offset + 0x18, XmlResource);
+ GetResource(p + offset + 0x30, MetadataResource);
+ if (IsNewVersion())
+ {
+ if (headerSize < 0xD0)
+ return S_FALSE;
+ BootIndex = Get32(p + 0x48);
+ IntegrityResource.Parse(p + offset + 0x4C);
+ }
+ return S_OK;
+}
+
+const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 };
+
+HRESULT ReadHeader(IInStream *inStream, CHeader &h)
+{
+ Byte p[kHeaderSizeMax];
+ RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax));
+ if (memcmp(p, kSignature, kSignatureSize) != 0)
+ return S_FALSE;
+ return h.Parse(p);
+}
+
+static HRESULT ReadStreams(bool oldVersion, IInStream *inStream, const CHeader &h, CDatabase &db)
+{
+ CByteBuffer offsetBuf;
+ RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL));
+ size_t i;
+ size_t streamInfoSize = oldVersion ? kStreamInfoSize + 2 : kStreamInfoSize;
+ for (i = 0; offsetBuf.GetCapacity() - i >= streamInfoSize; i += streamInfoSize)
+ {
+ CStreamInfo s;
+ GetStream(oldVersion, (const Byte *)offsetBuf + i, s);
+ if (s.PartNumber == h.PartNumber)
+ db.Streams.Add(s);
+ }
+ return (i == offsetBuf.GetCapacity()) ? S_OK : S_FALSE;
+}
+
+static bool IsEmptySha(const Byte *data)
+{
+ for (int i = 0; i < kHashSize; i++)
+ if (data[i] != 0)
+ return false;
+ return true;
+}
+
+HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback)
+{
+ OpenCallback = openCallback;
+ IsOldVersion = h.IsOldVersion();
+ RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL));
+ RINOK(ReadStreams(h.IsOldVersion(), inStream, h, *this));
+ bool needBootMetadata = !h.MetadataResource.IsEmpty();
+ Order = 0;
+ if (h.PartNumber == 1)
+ {
+ int imageIndex = 1;
+ for (int i = 0; i < Streams.Size(); i++)
+ {
+ // if (imageIndex > 1) break;
+ const CStreamInfo &si = Streams[i];
+ if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber)
+ continue;
+ Byte hash[kHashSize];
+ CByteBuffer metadata;
+ RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash));
+ if (memcmp(hash, si.Hash, kHashSize) != 0 &&
+ !(h.IsOldVersion() && IsEmptySha(si.Hash)))
+ return S_FALSE;
+ NumImages++;
+ RINOK(ParseImageDirs(metadata, -(int)(++imageIndex)));
+ if (needBootMetadata)
+ if (h.MetadataResource.Offset == si.Resource.Offset)
+ needBootMetadata = false;
+ }
+ }
+
+ if (needBootMetadata)
+ {
+ CByteBuffer metadata;
+ RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL));
+ RINOK(ParseImageDirs(metadata, -1));
+ NumImages++;
+ }
+ return S_OK;
+}
+
+
+static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */)
+{
+ int res = MyCompare(p1->PartNumber, p2->PartNumber);
+ if (res != 0)
+ return res;
+ return MyCompare(p1->Resource.Offset, p2->Resource.Offset);
+}
+
+static int CompareIDs(const int *p1, const int *p2, void *param)
+{
+ const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
+ return MyCompare(streams[*p1].Id, streams[*p2].Id);
+}
+
+static int CompareHashRefs(const int *p1, const int *p2, void *param)
+{
+ const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
+ return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize);
+}
+
+static int FindId(const CRecordVector<CStreamInfo> &streams,
+ const CIntVector &sortedByHash, UInt32 id)
+{
+ int left = 0, right = streams.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ int streamIndex = sortedByHash[mid];
+ UInt32 id2 = streams[streamIndex].Id;
+ if (id == id2)
+ return streamIndex;
+ if (id < id2)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+static int FindHash(const CRecordVector<CStreamInfo> &streams,
+ const CIntVector &sortedByHash, const Byte *hash)
+{
+ int left = 0, right = streams.Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ int streamIndex = sortedByHash[mid];
+ UInt32 i;
+ const Byte *hash2 = streams[streamIndex].Hash;
+ for (i = 0; i < kHashSize; i++)
+ if (hash[i] != hash2[i])
+ break;
+ if (i == kHashSize)
+ return streamIndex;
+ if (hash[i] < hash2[i])
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+static int CompareItems(const int *a1, const int *a2, void *param)
+{
+ const CObjectVector<CItem> &items = ((CDatabase *)param)->Items;
+ const CItem &i1 = items[*a1];
+ const CItem &i2 = items[*a2];
+
+ if (i1.IsDir() != i2.IsDir())
+ return i1.IsDir() ? 1 : -1;
+ int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
+ if (res != 0)
+ return res;
+ return MyCompare(i1.Order, i2.Order);
+}
+
+HRESULT CDatabase::Sort(bool skipRootDir)
+{
+ Streams.Sort(CompareStreamsByPos, NULL);
+
+ {
+ CIntVector sortedByHash;
+ {
+ for (int i = 0; i < Streams.Size(); i++)
+ sortedByHash.Add(i);
+ if (IsOldVersion)
+ sortedByHash.Sort(CompareIDs, &Streams);
+ else
+ sortedByHash.Sort(CompareHashRefs, &Streams);
+ }
+
+ for (int i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ item.StreamIndex = -1;
+ if (item.HasStream())
+ if (IsOldVersion)
+ item.StreamIndex = FindId(Streams, sortedByHash, item.Id);
+ else
+ item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash);
+ }
+ }
+
+ {
+ CRecordVector<bool> used;
+ int i;
+ for (i = 0; i < Streams.Size(); i++)
+ {
+ const CStreamInfo &s = Streams[i];
+ used.Add(s.Resource.IsMetadata() && s.PartNumber == 1);
+ // used.Add(false);
+ }
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ if (item.StreamIndex >= 0)
+ used[item.StreamIndex] = true;
+ }
+ for (i = 0; i < Streams.Size(); i++)
+ if (!used[i])
+ {
+ CItem item;
+ item.StreamIndex = i;
+ item.HasMetadata = false;
+ Items.Add(item);
+ }
+ }
+
+ SortedItems.Reserve(Items.Size());
+ for (int i = (skipRootDir ? 1 : 0); i < Items.Size(); i++)
+ SortedItems.Add(i);
+ SortedItems.Sort(CompareItems, this);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.h
new file mode 100644
index 000000000..da3e28a56
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimIn.h
@@ -0,0 +1,297 @@
+// Archive/WimIn.h
+
+#ifndef __ARCHIVE_WIM_IN_H
+#define __ARCHIVE_WIM_IN_H
+
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/LzxDecoder.h"
+
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace NWim {
+
+namespace NXpress {
+
+class CBitStream
+{
+ CInBuffer m_Stream;
+ UInt32 m_Value;
+ unsigned m_BitPos;
+public:
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); }
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+
+ void Init() { m_Stream.Init(); m_BitPos = 0; }
+ // UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - m_BitPos / 8; }
+ Byte DirectReadByte() { return m_Stream.ReadByte(); }
+
+ void Normalize()
+ {
+ if (m_BitPos < 16)
+ {
+ Byte b0 = m_Stream.ReadByte();
+ Byte b1 = m_Stream.ReadByte();
+ m_Value = (m_Value << 8) | b1;
+ m_Value = (m_Value << 8) | b0;
+ m_BitPos += 16;
+ }
+ }
+
+ UInt32 GetValue(unsigned numBits)
+ {
+ Normalize();
+ return (m_Value >> (m_BitPos - numBits)) & ((1 << numBits) - 1);
+ }
+
+ void MovePos(unsigned numBits) { m_BitPos -= numBits; }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ m_BitPos -= numBits;
+ return res;
+ }
+};
+
+const unsigned kNumHuffmanBits = 16;
+const UInt32 kMatchMinLen = 3;
+const UInt32 kNumLenSlots = 16;
+const UInt32 kNumPosSlots = 16;
+const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
+const UInt32 kMainTableSize = 256 + kNumPosLenSlots;
+
+class CDecoder
+{
+ CBitStream m_InBitStream;
+ CLzOutWindow m_OutWindowStream;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+
+ HRESULT CodeSpec(UInt32 size);
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
+public:
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+ HRESULT Flush() { return m_OutWindowStream.Flush(); }
+ HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
+};
+
+}
+
+namespace NResourceFlags
+{
+ const Byte kFree = 1;
+ const Byte kMetadata = 2;
+ const Byte Compressed = 4;
+ const Byte Spanned = 4;
+}
+
+struct CResource
+{
+ UInt64 PackSize;
+ UInt64 Offset;
+ UInt64 UnpackSize;
+ Byte Flags;
+
+ void Clear()
+ {
+ PackSize = 0;
+ Offset = 0;
+ UnpackSize = 0;
+ Flags = 0;
+ }
+ void Parse(const Byte *p);
+ void WriteTo(Byte *p) const;
+ bool IsFree() const { return (Flags & NResourceFlags::kFree) != 0; }
+ bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; }
+ bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; }
+ bool IsEmpty() const { return (UnpackSize == 0); }
+};
+
+namespace NHeaderFlags
+{
+ const UInt32 kCompression = 2;
+ const UInt32 kSpanned = 8;
+ const UInt32 kRpFix = 0x80;
+ const UInt32 kXPRESS = 0x20000;
+ const UInt32 kLZX = 0x40000;
+}
+
+const UInt32 kWimVersion = 0x010D00;
+const UInt32 kHeaderSizeMax = 0xD0;
+const UInt32 kSignatureSize = 8;
+extern const Byte kSignature[kSignatureSize];
+const unsigned kChunkSizeBits = 15;
+const UInt32 kChunkSize = (1 << kChunkSizeBits);
+
+struct CHeader
+{
+ UInt32 Version;
+ UInt32 Flags;
+ UInt32 ChunkSize;
+ Byte Guid[16];
+ UInt16 PartNumber;
+ UInt16 NumParts;
+ UInt32 NumImages;
+
+ CResource OffsetResource;
+ CResource XmlResource;
+ CResource MetadataResource;
+ CResource IntegrityResource;
+ UInt32 BootIndex;
+
+ void SetDefaultFields(bool useLZX);
+
+ void WriteTo(Byte *p) const;
+ HRESULT Parse(const Byte *p);
+ bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; }
+ bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0 || (Flags & NHeaderFlags::kXPRESS) != 0 ) ; }
+ bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; }
+ bool IsSpanned() const { return (!IsCompressed() || (Flags & NHeaderFlags::kSpanned) != 0); }
+ bool IsOldVersion() const { return (Version <= 0x010A00); }
+ bool IsNewVersion() const { return (Version > 0x010C00); }
+
+ bool AreFromOnArchive(const CHeader &h)
+ {
+ return (memcmp(Guid, h.Guid, sizeof(Guid)) == 0) && (h.NumParts == NumParts);
+ }
+};
+
+const UInt32 kHashSize = 20;
+const UInt32 kStreamInfoSize = 24 + 2 + 4 + kHashSize;
+
+struct CStreamInfo
+{
+ CResource Resource;
+ UInt16 PartNumber;
+ UInt32 RefCount;
+ UInt32 Id;
+ BYTE Hash[kHashSize];
+
+ void WriteTo(Byte *p) const;
+};
+
+const UInt32 kDirRecordSizeOld = 62;
+const UInt32 kDirRecordSize = 102;
+
+struct CItem
+{
+ UString Name;
+ UString ShortName;
+ UInt32 Attrib;
+ // UInt32 SecurityId;
+ BYTE Hash[kHashSize];
+ UInt32 Id;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ // UInt32 ReparseTag;
+ // UInt64 HardLink;
+ // UInt16 NumStreams;
+ int StreamIndex;
+ int Parent;
+ unsigned Order;
+ bool HasMetadata;
+ CItem(): HasMetadata(true), StreamIndex(-1), Id(0) {}
+ bool IsDir() const { return HasMetadata && ((Attrib & 0x10) != 0); }
+ bool HasStream() const
+ {
+ for (unsigned i = 0; i < kHashSize; i++)
+ if (Hash[i] != 0)
+ return true;
+ return Id != 0;
+ }
+};
+
+class CDatabase
+{
+ const Byte *DirData;
+ size_t DirSize;
+ size_t DirProcessed;
+ size_t DirStartOffset;
+ int Order;
+ IArchiveOpenCallback *OpenCallback;
+
+ HRESULT ParseDirItem(size_t pos, int parent);
+ HRESULT ParseImageDirs(const CByteBuffer &buf, int parent);
+
+public:
+ CRecordVector<CStreamInfo> Streams;
+ CObjectVector<CItem> Items;
+ CIntVector SortedItems;
+ int NumImages;
+ bool SkipRoot;
+ bool ShowImageNumber;
+
+ bool IsOldVersion;
+
+ UInt64 GetUnpackSize() const
+ {
+ UInt64 res = 0;
+ for (int i = 0; i < Streams.Size(); i++)
+ res += Streams[i].Resource.UnpackSize;
+ return res;
+ }
+
+ UInt64 GetPackSize() const
+ {
+ UInt64 res = 0;
+ for (int i = 0; i < Streams.Size(); i++)
+ res += Streams[i].Resource.PackSize;
+ return res;
+ }
+
+ void Clear()
+ {
+ Streams.Clear();
+ Items.Clear();
+ SortedItems.Clear();
+ NumImages = 0;
+
+ SkipRoot = true;
+ ShowImageNumber = true;
+ IsOldVersion = false;
+ }
+
+ UString GetItemPath(int index) const;
+
+ HRESULT Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback);
+
+ void DetectPathMode()
+ {
+ ShowImageNumber = (NumImages != 1);
+ }
+
+ HRESULT Sort(bool skipRootDir);
+};
+
+HRESULT ReadHeader(IInStream *inStream, CHeader &header);
+
+class CUnpacker
+{
+ NCompress::CCopyCoder *copyCoderSpec;
+ CMyComPtr<ICompressCoder> copyCoder;
+
+ NCompress::NLzx::CDecoder *lzxDecoderSpec;
+ CMyComPtr<ICompressCoder> lzxDecoder;
+
+ NXpress::CDecoder xpressDecoder;
+
+ CByteBuffer sizesBuf;
+ HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+public:
+ HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimRegister.cpp
new file mode 100644
index 000000000..8da914360
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Wim/WimRegister.cpp
@@ -0,0 +1,18 @@
+// WimRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "WimHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NWim::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NWim::COutHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Wim)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/XarHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/XarHandler.cpp
new file mode 100644
index 000000000..e7d88b6c7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/XarHandler.cpp
@@ -0,0 +1,588 @@
+// XarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/ComTry.h"
+#include "Common/MyXml.h"
+#include "Common/StringToInt.h"
+#include "Common/UTFConvert.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BZip2Decoder.h"
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+#include "Common/OutStreamWithSha1.h"
+
+#define XAR_SHOW_RAW
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+namespace NArchive {
+namespace NXar {
+
+struct CFile
+{
+ AString Name;
+ AString Method;
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt64 Offset;
+
+ // UInt32 mode;
+ UInt64 CTime;
+ UInt64 MTime;
+ UInt64 ATime;
+
+ bool IsDir;
+ bool HasData;
+
+ bool Sha1IsDefined;
+ Byte Sha1[20];
+ // bool packSha1IsDefined;
+ // Byte packSha1[20];
+
+ int Parent;
+
+ CFile(): IsDir(false), HasData(false), Sha1IsDefined(false),
+ /* packSha1IsDefined(false), */
+ Parent(-1), Size(0), PackSize(0), CTime(0), MTime(0), ATime(0) {}
+};
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ UInt64 _dataStartPos;
+ CMyComPtr<IInStream> _inStream;
+ AString _xml;
+ CObjectVector<CFile> _files;
+
+ HRESULT Open2(IInStream *stream);
+ HRESULT Extract(IInStream *stream);
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14);
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+static bool ParseNumber(const char *s, int size, UInt32 &res)
+{
+ const char *end;
+ res = (UInt32)ConvertStringToUInt64(s, &end);
+ return (end - s == size);
+}
+
+static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res)
+{
+ AString s = item.GetSubStringForTag(name);
+ const char *end;
+ res = ConvertStringToUInt64(s, &end);
+ return (end - (const char *)s == s.Length());
+}
+
+static UInt64 ParseTime(const CXmlItem &item, const char *name)
+{
+ AString s = item.GetSubStringForTag(name);
+ if (s.Length() < 20)
+ return 0;
+ const char *p = s;
+ if (p[ 4] != '-' || p[ 7] != '-' || p[10] != 'T' ||
+ p[13] != ':' || p[16] != ':' || p[19] != 'Z')
+ return 0;
+ UInt32 year, month, day, hour, min, sec;
+ if (!ParseNumber(p, 4, year )) return 0;
+ if (!ParseNumber(p + 5, 2, month)) return 0;
+ if (!ParseNumber(p + 8, 2, day )) return 0;
+ if (!ParseNumber(p + 11, 2, hour )) return 0;
+ if (!ParseNumber(p + 14, 2, min )) return 0;
+ if (!ParseNumber(p + 17, 2, sec )) return 0;
+
+ UInt64 numSecs;
+ if (!NWindows::NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
+ return 0;
+ return numSecs * 10000000;
+}
+
+static bool HexToByte(char c, Byte &res)
+{
+ if (c >= '0' && c <= '9') res = c - '0';
+ else if (c >= 'A' && c <= 'F') res = c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f') res = c - 'a' + 10;
+ else return false;
+ return true;
+}
+
+#define METHOD_NAME_ZLIB "zlib"
+
+static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest)
+{
+ int index = item.FindSubTag(name);
+ if (index < 0)
+ return false;
+ const CXmlItem &checkItem = item.SubItems[index];
+ AString style = checkItem.GetPropertyValue("style");
+ if (style == "SHA1")
+ {
+ AString s = checkItem.GetSubString();
+ if (s.Length() != 40)
+ return false;
+ for (int i = 0; i < s.Length(); i += 2)
+ {
+ Byte b0, b1;
+ if (!HexToByte(s[i], b0) || !HexToByte(s[i + 1], b1))
+ return false;
+ digest[i / 2] = (b0 << 4) | b1;
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int parent)
+{
+ if (!item.IsTag)
+ return true;
+ if (item.Name == "file")
+ {
+ CFile file;
+ file.Parent = parent;
+ parent = files.Size();
+ file.Name = item.GetSubStringForTag("name");
+ AString type = item.GetSubStringForTag("type");
+ if (type == "directory")
+ file.IsDir = true;
+ else if (type == "file")
+ file.IsDir = false;
+ else
+ return false;
+
+ int dataIndex = item.FindSubTag("data");
+ if (dataIndex >= 0 && !file.IsDir)
+ {
+ file.HasData = true;
+ const CXmlItem &dataItem = item.SubItems[dataIndex];
+ if (!ParseUInt64(dataItem, "size", file.Size))
+ return false;
+ if (!ParseUInt64(dataItem, "length", file.PackSize))
+ return false;
+ if (!ParseUInt64(dataItem, "offset", file.Offset))
+ return false;
+ file.Sha1IsDefined = ParseSha1(dataItem, "extracted-checksum", file.Sha1);
+ // file.packSha1IsDefined = ParseSha1(dataItem, "archived-checksum", file.packSha1);
+ int encodingIndex = dataItem.FindSubTag("encoding");
+ if (encodingIndex >= 0)
+ {
+ const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex];
+ if (encodingItem.IsTag)
+ {
+ AString s = encodingItem.GetPropertyValue("style");
+ if (s.Length() >= 0)
+ {
+ AString appl = "application/";
+ if (s.Left(appl.Length()) == appl)
+ {
+ s = s.Mid(appl.Length());
+ AString xx = "x-";
+ if (s.Left(xx.Length()) == xx)
+ {
+ s = s.Mid(xx.Length());
+ if (s == "gzip")
+ s = METHOD_NAME_ZLIB;
+ }
+ }
+ file.Method = s;
+ }
+ }
+ }
+ }
+
+ file.CTime = ParseTime(item, "ctime");
+ file.MTime = ParseTime(item, "mtime");
+ file.ATime = ParseTime(item, "atime");
+ files.Add(file);
+ }
+ for (int i = 0; i < item.SubItems.Size(); i++)
+ if (!AddItem(item.SubItems[i], files, parent))
+ return false;
+ return true;
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ UInt64 archiveStartPos;
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, &archiveStartPos));
+
+ const UInt32 kHeaderSize = 0x1C;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
+
+ UInt32 size = Get16(buf + 4);
+ // UInt32 ver = Get16(buf + 6); // == 0
+ if (Get32(buf) != 0x78617221 || size != kHeaderSize)
+ return S_FALSE;
+
+ UInt64 packSize = Get64(buf + 8);
+ UInt64 unpackSize = Get64(buf + 0x10);
+ // UInt32 checkSumAlogo = Get32(buf + 0x18);
+
+ if (unpackSize >= kXmlSizeMax)
+ return S_FALSE;
+
+ _dataStartPos = archiveStartPos + kHeaderSize + packSize;
+
+ char *ss = _xml.GetBuffer((int)unpackSize + 1);
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStreamLim(inStreamLimSpec);
+ inStreamLimSpec->SetStream(stream);
+ inStreamLimSpec->Init(packSize);
+
+ CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec);
+ outStreamLimSpec->Init((Byte *)ss, (size_t)unpackSize);
+
+ RINOK(zlibCoder->Code(inStreamLim, outStreamLim, NULL, NULL, NULL));
+
+ if (outStreamLimSpec->GetPos() != (size_t)unpackSize)
+ return S_FALSE;
+
+ ss[(size_t)unpackSize] = 0;
+ _xml.ReleaseBuffer();
+
+ CXml xml;
+ if (!xml.Parse(_xml))
+ return S_FALSE;
+
+ if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1)
+ return S_FALSE;
+ const CXmlItem &toc = xml.Root.SubItems[0];
+ if (!toc.IsTagged("toc"))
+ return S_FALSE;
+ if (!AddItem(toc, _files, -1))
+ return S_FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ if (Open2(stream) != S_OK)
+ return S_FALSE;
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _inStream.Release();
+ _files.Clear();
+ _xml.Empty();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = _files.Size()
+ #ifdef XAR_SHOW_RAW
+ + 1
+ #endif
+ ;
+ return S_OK;
+}
+
+static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
+{
+ if (t != 0)
+ {
+ FILETIME ft;
+ ft.dwLowDateTime = (UInt32)(t);
+ ft.dwHighDateTime = (UInt32)(t >> 32);
+ prop = ft;
+ }
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ #ifdef XAR_SHOW_RAW
+ if ((int)index == _files.Size())
+ {
+ switch(propID)
+ {
+ case kpidPath: prop = L"[TOC].xml"; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)_xml.Length(); break;
+ }
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ switch(propID)
+ {
+ case kpidMethod:
+ {
+ UString name;
+ if (!item.Method.IsEmpty() && ConvertUTF8ToUnicode(item.Method, name))
+ prop = name;
+ break;
+ }
+ case kpidPath:
+ {
+ AString path;
+ int cur = index;
+ do
+ {
+ const CFile &item = _files[cur];
+ AString s = item.Name;
+ if (s.IsEmpty())
+ s = "unknown";
+ if (path.IsEmpty())
+ path = s;
+ else
+ path = s + CHAR_PATH_SEPARATOR + path;
+ cur = item.Parent;
+ }
+ while (cur >= 0);
+
+ UString name;
+ if (ConvertUTF8ToUnicode(path, name))
+ prop = name;
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidSize: if (!item.IsDir) prop = item.Size; break;
+ case kpidPackSize: if (!item.IsDir) prop = item.PackSize; break;
+
+ case kpidMTime: TimeToProp(item.MTime, prop); break;
+ case kpidCTime: TimeToProp(item.CTime, prop); break;
+ case kpidATime: TimeToProp(item.ATime, prop); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = _files.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ int index = (int)(allFilesMode ? i : indices[i]);
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ totalSize += _xml.Length();
+ else
+ #endif
+ totalSize += _files[index].Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentPackTotal = 0;
+ UInt64 currentUnpTotal = 0;
+ UInt64 currentPackSize = 0;
+ UInt64 currentUnpSize = 0;
+
+ const UInt32 kZeroBufSize = (1 << 14);
+ CByteBuffer zeroBuf;
+ zeroBuf.SetCapacity(kZeroBufSize);
+ memset(zeroBuf, 0, kZeroBufSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+ CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
+
+ NCompress::NDeflate::NDecoder::CCOMCoder *deflateCoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
+ CMyComPtr<ICompressCoder> deflateCoder = deflateCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
+ inStreamSpec->SetStream(_inStream);
+
+
+ CLimitedSequentialOutStream *outStreamLimSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamLimSpec);
+
+ COutStreamWithSha1 *outStreamSha1Spec = new COutStreamWithSha1;
+ {
+ CMyComPtr<ISequentialOutStream> outStreamSha1(outStreamSha1Spec);
+ outStreamLimSpec->SetStream(outStreamSha1);
+ }
+
+ for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
+ {
+ lps->InSize = currentPackTotal;
+ lps->OutSize = currentUnpTotal;
+ currentPackSize = 0;
+ currentUnpSize = 0;
+ RINOK(lps->SetCur());
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ if (index < _files.Size())
+ {
+ const CFile &item = _files[index];
+ if (item.IsDir)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ continue;
+ }
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ outStreamSha1Spec->SetStream(realOutStream);
+ realOutStream.Release();
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ {
+ outStreamSha1Spec->Init(false);
+ outStreamLimSpec->Init(_xml.Length());
+ RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
+ currentPackSize = currentUnpSize = _xml.Length();
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ if (item.HasData)
+ {
+ currentPackSize = item.PackSize;
+ currentUnpSize = item.Size;
+
+ RINOK(_inStream->Seek(_dataStartPos + item.Offset, STREAM_SEEK_SET, NULL));
+ inStreamSpec->Init(item.PackSize);
+ outStreamSha1Spec->Init(item.Sha1IsDefined);
+ outStreamLimSpec->Init(item.Size);
+ HRESULT res = S_OK;
+
+ ICompressCoder *coder = NULL;
+ if (item.Method.IsEmpty() || item.Method == "octet-stream")
+ if (item.PackSize == item.Size)
+ coder = copyCoder;
+ else
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ else if (item.Method == METHOD_NAME_ZLIB)
+ coder = zlibCoder;
+ else if (item.Method == "bzip2")
+ coder = bzip2Coder;
+ else
+ opRes = NExtract::NOperationResult::kUnSupportedMethod;
+
+ if (coder)
+ res = coder->Code(inStream, outStream, NULL, NULL, progress);
+
+ if (res != S_OK)
+ {
+ if (!outStreamLimSpec->IsFinishedOK())
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (res != S_FALSE)
+ return res;
+ if (opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ if (outStreamLimSpec->IsFinishedOK() &&
+ outStreamSha1Spec->GetSize() == item.Size)
+ {
+ if (!outStreamLimSpec->IsFinishedOK())
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ else if (item.Sha1IsDefined)
+ {
+ Byte digest[NCrypto::NSha1::kDigestSize];
+ outStreamSha1Spec->Final(digest);
+ if (memcmp(digest, item.Sha1, NCrypto::NSha1::kDigestSize) != 0)
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ }
+ else
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ }
+ }
+ outStreamSha1Spec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new NArchive::NXar::CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Xar", L"xar", 0, 0xE1, { 'x', 'a', 'r', '!', 0, 0x1C }, 6, false, CreateArc, 0 };
+
+REGISTER_ARC(Xar)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/XzHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/XzHandler.cpp
new file mode 100644
index 000000000..64b7a5863
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/XzHandler.cpp
@@ -0,0 +1,707 @@
+// XzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/XzCrc64.h"
+#include "../../../C/XzEnc.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+
+#include "../ICoder.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "IArchive.h"
+
+#include "Common/HandlerOut.h"
+
+using namespace NWindows;
+
+namespace NCompress {
+namespace NLzma2 {
+
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);
+
+}}
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+namespace NArchive {
+namespace NXz {
+
+struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit;
+
+class CHandler:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ #ifndef EXTRACT_ONLY
+ public IOutArchive,
+ public ISetProperties,
+ public COutHandler,
+ #endif
+ public CMyUnknownImp
+{
+ Int64 _startPosition;
+ UInt64 _packSize;
+ UInt64 _unpackSize;
+ UInt64 _numBlocks;
+ AString _methodsString;
+ bool _useSeq;
+ UInt64 _unpackSizeDefined;
+ UInt64 _packSizeDefined;
+
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ UInt32 _crcSize;
+
+ void Init()
+ {
+ _crcSize = 4;
+ COutHandler::Init();
+ }
+
+ HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
+ #ifndef EXTRACT_ONLY
+ MY_QUERYINTERFACE_ENTRY(IOutArchive)
+ MY_QUERYINTERFACE_ENTRY(ISetProperties)
+ #endif
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+ STDMETHOD(OpenSeq)(ISequentialInStream *stream);
+
+ #ifndef EXTRACT_ONLY
+ INTERFACE_IOutArchive(;)
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
+ #endif
+
+ CHandler();
+};
+
+CHandler::CHandler()
+{
+ Init();
+}
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR}
+};
+
+STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidNumBlocks, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+static inline void AddHexToString(AString &res, Byte value)
+{
+ res += GetHex((Byte)(value >> 4));
+ res += GetHex((Byte)(value & 0xF));
+}
+
+static AString ConvertUInt32ToString(UInt32 value)
+{
+ char temp[32];
+ ::ConvertUInt32ToString(value, temp);
+ return temp;
+}
+
+static AString Lzma2PropToString(int prop)
+{
+ if ((prop & 1) == 0)
+ return ConvertUInt32ToString(prop / 2 + 12);
+ AString res;
+ char c;
+
+ UInt32 size = (2 | ((prop) & 1)) << ((prop) / 2 + 1);
+
+ if (prop > 17)
+ {
+ res = ConvertUInt32ToString(size >> 10);
+ c = 'm';
+ }
+ else
+ {
+ res = ConvertUInt32ToString(size);
+ c = 'k';
+ }
+ return res + c;
+}
+
+struct CMethodNamePair
+{
+ UInt32 Id;
+ const char *Name;
+};
+
+static CMethodNamePair g_NamePairs[] =
+{
+ { XZ_ID_Subblock, "SB" },
+ { XZ_ID_Delta, "Delta" },
+ { XZ_ID_X86, "x86" },
+ { XZ_ID_PPC, "PPC" },
+ { XZ_ID_IA64, "IA64" },
+ { XZ_ID_ARM, "ARM" },
+ { XZ_ID_ARMT, "ARMT" },
+ { XZ_ID_SPARC, "SPARC" },
+ { XZ_ID_LZMA2, "LZMA2" }
+};
+
+static AString GetMethodString(const CXzFilter &f)
+{
+ AString s;
+
+ for (int i = 0; i < sizeof(g_NamePairs) / sizeof(g_NamePairs[i]); i++)
+ if (g_NamePairs[i].Id == f.id)
+ s = g_NamePairs[i].Name;
+ if (s.IsEmpty())
+ {
+ char temp[32];
+ ::ConvertUInt64ToString(f.id, temp);
+ s = temp;
+ }
+
+ if (f.propsSize > 0)
+ {
+ s += ':';
+ if (f.id == XZ_ID_LZMA2 && f.propsSize == 1)
+ s += Lzma2PropToString(f.props[0]);
+ else if (f.id == XZ_ID_Delta && f.propsSize == 1)
+ s += ConvertUInt32ToString((UInt32)f.props[0] + 1);
+ else
+ {
+ s += '[';
+ for (UInt32 bi = 0; bi < f.propsSize; bi++)
+ AddHexToString(s, f.props[bi]);
+ s += ']';
+ }
+ }
+ return s;
+}
+
+static void AddString(AString &dest, const AString &src)
+{
+ if (!dest.IsEmpty())
+ dest += ' ';
+ dest += src;
+}
+
+static const char *kChecks[] =
+{
+ "NoCheck",
+ "CRC32",
+ NULL,
+ NULL,
+ "CRC64",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SHA256",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static AString GetCheckString(const CXzs &xzs)
+{
+ size_t i;
+ UInt32 mask = 0;
+ for (i = 0; i < xzs.num; i++)
+ mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags));
+ AString s;
+ for (i = 0; i <= XZ_CHECK_MASK; i++)
+ if (((mask >> i) & 1) != 0)
+ {
+ AString s2;
+ if (kChecks[i])
+ s2 = kChecks[i];
+ else
+ s2 = "Check-" + ConvertUInt32ToString((UInt32)i);
+ AddString(s, s2);
+ }
+ return s;
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidNumBlocks: if (!_useSeq) prop = _numBlocks; break;
+ case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidSize: if (_unpackSizeDefined) prop = _unpackSize; break;
+ case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
+ case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+struct COpenCallbackWrap
+{
+ ICompressProgress p;
+ IArchiveOpenCallback *OpenCallback;
+ HRESULT Res;
+ COpenCallbackWrap(IArchiveOpenCallback *progress);
+};
+
+static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */)
+{
+ COpenCallbackWrap *p = (COpenCallbackWrap *)pp;
+ p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
+ return (SRes)p->Res;
+}
+
+COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback)
+{
+ p.Progress = OpenCallbackProgress;
+ OpenCallback = callback;
+ Res = SZ_OK;
+}
+
+struct CXzsCPP
+{
+ CXzs p;
+ CXzsCPP() { Xzs_Construct(&p); }
+ ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
+};
+
+HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback)
+{
+ CSeekInStreamWrap inStreamImp(inStream);
+
+ CLookToRead lookStream;
+ LookToRead_CreateVTable(&lookStream, True);
+ lookStream.realStream = &inStreamImp.p;
+ LookToRead_Init(&lookStream);
+
+ COpenCallbackWrap openWrap(callback);
+ RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize));
+ RINOK(callback->SetTotal(NULL, &_packSize));
+
+ CXzsCPP xzs;
+ SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &_startPosition, &openWrap.p, &g_Alloc);
+ if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0)
+ res = SZ_OK;
+ if (res == SZ_OK)
+ {
+ _packSize -= _startPosition;
+ _unpackSize = Xzs_GetUnpackSize(&xzs.p);
+ _unpackSizeDefined = _packSizeDefined = true;
+ _numBlocks = (UInt64)Xzs_GetNumBlocks(&xzs.p);
+
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ CXzStreamFlags st;
+ CSeqInStreamWrap inStreamWrap(inStream);
+ SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p);
+
+ if (res2 == SZ_OK)
+ {
+ CXzBlock block;
+ Bool isIndex;
+ UInt32 headerSizeRes;
+ res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes);
+ if (res2 == SZ_OK && !isIndex)
+ {
+ int numFilters = XzBlock_GetNumFilters(&block);
+ for (int i = 0; i < numFilters; i++)
+ AddString(_methodsString, GetMethodString(block.filters[i]));
+ }
+ }
+ AddString(_methodsString, GetCheckString(xzs.p));
+ }
+
+ if (res != SZ_OK || _startPosition != 0)
+ {
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ CXzStreamFlags st;
+ CSeqInStreamWrap inStreamWrap(inStream);
+ SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p);
+ if (res2 == SZ_OK)
+ {
+ res = res2;
+ _startPosition = 0;
+ _useSeq = True;
+ _unpackSizeDefined = _packSizeDefined = false;
+ }
+ }
+ if (res == SZ_ERROR_NO_ARCHIVE)
+ return S_FALSE;
+ RINOK(SResToHRESULT(res));
+ _stream = inStream;
+ _seqStream = inStream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ return Open2(inStream, callback);
+ }
+ catch(...) { return S_FALSE; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
+{
+ Close();
+ _seqStream = stream;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _numBlocks = 0;
+ _useSeq = true;
+ _unpackSizeDefined = _packSizeDefined = false;
+ _methodsString.Empty();
+ _stream.Release();
+ _seqStream.Release();
+ return S_OK;
+}
+
+class CSeekToSeqStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+public:
+ CMyComPtr<ISequentialInStream> Stream;
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ return Stream->Read(data, size, processedSize);
+}
+
+STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; }
+
+struct CXzUnpackerCPP
+{
+ Byte *InBuf;
+ Byte *OutBuf;
+ CXzUnpacker p;
+ CXzUnpackerCPP(): InBuf(0), OutBuf(0) {}
+ ~CXzUnpackerCPP()
+ {
+ XzUnpacker_Free(&p);
+ MyFree(InBuf);
+ MyFree(OutBuf);
+ }
+};
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ if (_stream)
+ {
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ }
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ CCompressProgressWrap progressWrap(progress);
+
+ SRes res;
+
+ const UInt32 kInBufSize = 1 << 15;
+ const UInt32 kOutBufSize = 1 << 21;
+
+ UInt32 inPos = 0;
+ UInt32 inSize = 0;
+ UInt32 outPos = 0;
+ CXzUnpackerCPP xzu;
+ res = XzUnpacker_Create(&xzu.p, &g_Alloc);
+ if (res == SZ_OK)
+ {
+ xzu.InBuf = (Byte *)MyAlloc(kInBufSize);
+ xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize);
+ if (xzu.InBuf == 0 || xzu.OutBuf == 0)
+ res = SZ_ERROR_MEM;
+ }
+ if (res == SZ_OK)
+ for (;;)
+ {
+ if (inPos == inSize)
+ {
+ inPos = inSize = 0;
+ RINOK(_seqStream->Read(xzu.InBuf, kInBufSize, &inSize));
+ }
+
+ SizeT inLen = inSize - inPos;
+ SizeT outLen = kOutBufSize - outPos;
+ ECoderStatus status;
+ res = XzUnpacker_Code(&xzu.p,
+ xzu.OutBuf + outPos, &outLen,
+ xzu.InBuf + inPos, &inLen,
+ (inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status);
+
+ // printf("\n_inPos = %6d inLen = %5d, outLen = %5d", inPos, inLen, outLen);
+
+ inPos += (UInt32)inLen;
+ outPos += (UInt32)outLen;
+ lps->InSize += inLen;
+ lps->OutSize += outLen;
+
+ bool finished = (((inLen == 0) && (outLen == 0)) || res != SZ_OK);
+
+ if (outPos == kOutBufSize || finished)
+ {
+ if (realOutStream && outPos > 0)
+ {
+ RINOK(WriteStream(realOutStream, xzu.OutBuf, outPos));
+ }
+ outPos = 0;
+ }
+ if (finished)
+ {
+ _packSize = lps->InSize;
+ _unpackSize = lps->OutSize;
+ _packSizeDefined = _unpackSizeDefined = true;
+ if (res == SZ_OK)
+ {
+ if (status == CODER_STATUS_NEEDS_MORE_INPUT)
+ {
+ if (XzUnpacker_IsStreamWasFinished(&xzu.p))
+ _packSize -= xzu.p.padSize;
+ else
+ res = SZ_ERROR_DATA;
+ }
+ else
+ res = SZ_ERROR_DATA;
+ }
+ break;
+ }
+ RINOK(lps->SetCur());
+ }
+
+ Int32 opRes;
+ switch(res)
+ {
+ case SZ_OK:
+ opRes = NExtract::NOperationResult::kOK; break;
+ case SZ_ERROR_UNSUPPORTED:
+ opRes = NExtract::NOperationResult::kUnSupportedMethod; break;
+ case SZ_ERROR_CRC:
+ opRes = NExtract::NOperationResult::kCRCError; break;
+ case SZ_ERROR_DATA:
+ case SZ_ERROR_ARCHIVE:
+ case SZ_ERROR_NO_ARCHIVE:
+ opRes = NExtract::NOperationResult::kDataError; break;
+ default:
+ return SResToHRESULT(res);
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes));
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifndef EXTRACT_ONLY
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CSeqOutStreamWrap seqOutStream(outStream);
+
+ if (numItems == 0)
+ {
+ SRes res = Xz_EncodeEmpty(&seqOutStream.p);
+ return SResToHRESULT(res);
+ }
+
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
+ if (prop.vt != VT_EMPTY)
+ if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ {
+ UInt64 size;
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ RINOK(updateCallback->SetTotal(size));
+ }
+
+ CLzma2EncProps lzma2Props;
+ Lzma2EncProps_Init(&lzma2Props);
+
+ lzma2Props.lzmaProps.level = _level;
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream));
+
+ CSeqInStreamWrap seqInStream(fileInStream);
+
+ for (int i = 0; i < _methods.Size(); i++)
+ {
+ COneMethodInfo &m = _methods[i];
+ SetCompressionMethod2(m
+ #ifndef _7ZIP_ST
+ , _numThreads
+ #endif
+ );
+ if (m.IsLzma())
+ {
+ for (int j = 0; j < m.Props.Size(); j++)
+ {
+ const CProp &prop = m.Props[j];
+ RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props));
+ }
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ lzma2Props.numTotalThreads = _numThreads;
+ #endif
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CCompressProgressWrap progressWrap(progress);
+ SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &lzma2Props, False, &progressWrap.p);
+ if (res == SZ_OK)
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+ return SResToHRESULT(res);
+ }
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+ if (_stream)
+ RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
+ return NCompress::CopyStream(_stream, outStream, 0);
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
+{
+ COM_TRY_BEGIN
+ BeforeSetProperty();
+ for (int i = 0; i < numProps; i++)
+ {
+ RINOK(SetProperty(names[i], values[i]));
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+#endif
+
+static IInArchive *CreateArc() { return new NArchive::NXz::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NXz::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"xz", L"xz txz", L"* .tar", 0xC, {0xFD, '7' , 'z', 'X', 'Z', '\0'}, 6, true, CreateArc, CreateArcOut };
+
+REGISTER_ARC(xz)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ZHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ZHandler.cpp
new file mode 100644
index 000000000..49b76a116
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/ZHandler.cpp
@@ -0,0 +1,161 @@
+// ZHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/ZDecoder.h"
+
+#include "Common/DummyOutStream.h"
+
+namespace NArchive {
+namespace NZ {
+
+class CHandler:
+ public IInArchive,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ UInt64 _streamStartPosition;
+ UInt64 _packSize;
+ Byte _properties;
+public:
+ MY_UNKNOWN_IMP1(IInArchive)
+ INTERFACE_IInArchive(;)
+};
+
+STATPROPSTG kProps[] =
+{
+ { NULL, kpidPackSize, VT_UI8}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidPackSize: prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+static const int kSignatureSize = 3;
+
+STDMETHODIMP CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */)
+{
+ COM_TRY_BEGIN
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_streamStartPosition));
+ Byte buffer[kSignatureSize];
+ RINOK(ReadStream_FALSE(stream, buffer, kSignatureSize));
+ if (buffer[0] != 0x1F || buffer[1] != 0x9D)
+ return S_FALSE;
+ _properties = buffer[2];
+
+ UInt64 endPosition;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition));
+ _packSize = endPosition - _streamStartPosition - kSignatureSize;
+
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ _stream.Release();
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_packSize);
+
+ UInt64 currentTotalPacked = 0;
+
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
+
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ RINOK(_stream->Seek(_streamStartPosition + kSignatureSize, STREAM_SEEK_SET, NULL));
+
+ CMyComPtr<ICompressCoder> decoder;
+ NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder;
+ decoder = decoderSpec;
+
+ HRESULT result = decoderSpec->SetDecoderProperties2(&_properties, 1);
+
+ int opResult;
+ if (result != S_OK)
+ opResult = NExtract::NOperationResult::kUnSupportedMethod;
+ else
+ {
+ result = decoder->Code(_stream, outStream, NULL, NULL, progress);
+ if (result == S_FALSE)
+ opResult = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(result);
+ opResult = NExtract::NOperationResult::kOK;
+ }
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(opResult);
+ COM_TRY_END
+}
+
+static IInArchive *CreateArc() { return new CHandler; }
+
+static CArcInfo g_ArcInfo =
+ { L"Z", L"z taz", L"* .tar", 5, { 0x1F, 0x9D }, 2, false, CreateArc, 0 };
+
+REGISTER_ARC(Z)
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/StdAfx.h
new file mode 100644
index 000000000..e7fb6986d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
new file mode 100644
index 000000000..4c5fd38d1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
@@ -0,0 +1,379 @@
+// ZipAddCommon.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../ICoder.h"
+#include "../../IPassword.h"
+#include "../../MyVersion.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/LzmaEncoder.h"
+#include "../../Compress/PpmdZip.h"
+
+#include "../Common/InStreamWithCRC.h"
+
+#include "ZipAddCommon.h"
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+static const CMethodId kMethodId_ZipBase = 0x040100;
+static const CMethodId kMethodId_BZip2 = 0x040202;
+
+static const UInt32 kLzmaPropsSize = 5;
+static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize;
+
+class CLzmaEncoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ NCompress::NLzma::CEncoder *EncoderSpec;
+ CMyComPtr<ICompressCoder> Encoder;
+ Byte Header[kLzmaHeaderSize];
+public:
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+
+ MY_UNKNOWN_IMP
+};
+
+HRESULT CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ if (!Encoder)
+ {
+ EncoderSpec = new NCompress::NLzma::CEncoder;
+ Encoder = EncoderSpec;
+ }
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init(Header + 4, kLzmaPropsSize);
+ RINOK(EncoderSpec->SetCoderProperties(propIDs, props, numProps));
+ RINOK(EncoderSpec->WriteCoderProperties(outStream));
+ if (outStreamSpec->GetPos() != kLzmaPropsSize)
+ return E_FAIL;
+ Header[0] = MY_VER_MAJOR;
+ Header[1] = MY_VER_MINOR;
+ Header[2] = kLzmaPropsSize;
+ Header[3] = 0;
+ return S_OK;
+}
+
+HRESULT CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ RINOK(WriteStream(outStream, Header, kLzmaHeaderSize));
+ return Encoder->Code(inStream, outStream, inSize, outSize, progress);
+}
+
+
+CAddCommon::CAddCommon(const CCompressionMethodMode &options):
+ _options(options),
+ _copyCoderSpec(NULL),
+ _cryptoStreamSpec(0)
+ {}
+
+static HRESULT GetStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC)
+{
+ UInt32 crc = CRC_INIT_VAL;
+ const UInt32 kBufferSize = (1 << 14);
+ Byte buffer[kBufferSize];
+ for (;;)
+ {
+ UInt32 realProcessedSize;
+ RINOK(inStream->Read(buffer, kBufferSize, &realProcessedSize));
+ if (realProcessedSize == 0)
+ {
+ resultCRC = CRC_GET_DIGEST(crc);
+ return S_OK;
+ }
+ crc = CrcUpdate(crc, buffer, (size_t)realProcessedSize);
+ }
+}
+
+HRESULT CAddCommon::Compress(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream, IOutStream *outStream,
+ ICompressProgressInfo *progress, CCompressingResult &opRes)
+{
+ CSequentialInStreamWithCRC *inSecCrcStreamSpec = 0;
+ CInStreamWithCRC *inCrcStreamSpec = 0;
+ CMyComPtr<ISequentialInStream> inCrcStream;
+ {
+ CMyComPtr<IInStream> inStream2;
+ // we don't support stdin, since stream from stdin can require 64-bit size header
+ RINOK(inStream->QueryInterface(IID_IInStream, (void **)&inStream2));
+ if (inStream2)
+ {
+ inCrcStreamSpec = new CInStreamWithCRC;
+ inCrcStream = inCrcStreamSpec;
+ inCrcStreamSpec->SetStream(inStream2);
+ inCrcStreamSpec->Init();
+ }
+ else
+ {
+ inSecCrcStreamSpec = new CSequentialInStreamWithCRC;
+ inCrcStream = inSecCrcStreamSpec;
+ inSecCrcStreamSpec->SetStream(inStream);
+ inSecCrcStreamSpec->Init();
+ }
+ }
+
+ int numTestMethods = _options.MethodSequence.Size();
+ if (numTestMethods > 1 || _options.PasswordIsDefined)
+ {
+ if (inCrcStreamSpec == 0)
+ {
+ if (_options.PasswordIsDefined)
+ return E_NOTIMPL;
+ numTestMethods = 1;
+ }
+ }
+ Byte method = 0;
+ COutStreamReleaser outStreamReleaser;
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
+ for (int i = 0; i < numTestMethods; i++)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default;
+ if (inCrcStreamSpec != 0)
+ RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(outStream->SetSize(0));
+ RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL));
+ if (_options.PasswordIsDefined)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_ZipCrypto;
+
+ if (!_cryptoStream)
+ {
+ _cryptoStreamSpec = new CFilterCoder;
+ _cryptoStream = _cryptoStreamSpec;
+ }
+ if (_options.IsAesMode)
+ {
+ opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Aes;
+ if (!_cryptoStreamSpec->Filter)
+ {
+ _cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder;
+ _filterAesSpec->SetKeyMode(_options.AesKeyMode);
+ RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length()));
+ }
+ RINOK(_filterAesSpec->WriteHeader(outStream));
+ }
+ else
+ {
+ if (!_cryptoStreamSpec->Filter)
+ {
+ _cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder;
+ _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length());
+ }
+ UInt32 crc = 0;
+ RINOK(GetStreamCRC(inStream, crc));
+ RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(_filterSpec->WriteHeader(outStream, crc));
+ }
+ RINOK(_cryptoStreamSpec->SetOutStream(outStream));
+ outStreamReleaser.FilterCoder = _cryptoStreamSpec;
+ }
+
+ method = _options.MethodSequence[i];
+ switch(method)
+ {
+ case NFileHeader::NCompressionMethod::kStored:
+ {
+ if (_copyCoderSpec == NULL)
+ {
+ _copyCoderSpec = new NCompress::CCopyCoder;
+ _copyCoder = _copyCoderSpec;
+ }
+ CMyComPtr<ISequentialOutStream> outStreamNew;
+ if (_options.PasswordIsDefined)
+ outStreamNew = _cryptoStream;
+ else
+ outStreamNew = outStream;
+ RINOK(_copyCoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
+ break;
+ }
+ default:
+ {
+ if (!_compressEncoder)
+ {
+ if (method == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_LZMA;
+ CLzmaEncoder *_lzmaEncoder = new CLzmaEncoder();
+ _compressEncoder = _lzmaEncoder;
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ #ifndef _7ZIP_ST
+ _options.NumThreads,
+ #endif
+ _options.Algo,
+ _options.DicSize,
+ _options.NumFastBytes,
+ const_cast<BSTR>((const wchar_t *)_options.MatchFinder),
+ _options.NumMatchFinderCycles
+ };
+ PROPID propIDs[] =
+ {
+ #ifndef _7ZIP_ST
+ NCoderPropID::kNumThreads,
+ #endif
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinder,
+ NCoderPropID::kMatchFinderCycles
+ };
+ int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ if (!_options.NumMatchFinderCyclesDefined)
+ numProps--;
+ RINOK(_lzmaEncoder->SetCoderProperties(propIDs, props, numProps));
+ }
+ else if (method == NFileHeader::NCompressionMethod::kPPMd)
+ {
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_PPMd;
+ NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder();
+ _compressEncoder = encoder;
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.Algo,
+ _options.MemSize,
+ _options.Order
+
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kUsedMemorySize,
+ NCoderPropID::kOrder
+ };
+ RINOK(encoder->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0])));
+ }
+ else
+ {
+ CMethodId methodId;
+ switch(method)
+ {
+ case NFileHeader::NCompressionMethod::kBZip2:
+ methodId = kMethodId_BZip2;
+ _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_BZip2;
+ break;
+ default:
+ _compressExtractVersion = ((method == NFileHeader::NCompressionMethod::kDeflated64) ?
+ NFileHeader::NCompressionMethod::kExtractVersion_Deflate64 :
+ NFileHeader::NCompressionMethod::kExtractVersion_Deflate);
+ methodId = kMethodId_ZipBase + method;
+ break;
+ }
+ RINOK(CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId, _compressEncoder, true));
+ if (!_compressEncoder)
+ return E_NOTIMPL;
+
+ if (method == NFileHeader::NCompressionMethod::kDeflated ||
+ method == NFileHeader::NCompressionMethod::kDeflated64)
+ {
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.Algo,
+ _options.NumPasses,
+ _options.NumFastBytes,
+ _options.NumMatchFinderCycles
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumPasses,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinderCycles
+ };
+ int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ if (!_options.NumMatchFinderCyclesDefined)
+ numProps--;
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties);
+ if (setCoderProperties)
+ {
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, numProps));
+ }
+ }
+ else if (method == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ NWindows::NCOM::CPropVariant props[] =
+ {
+ _options.DicSize,
+ _options.NumPasses
+ #ifndef _7ZIP_ST
+ , _options.NumThreads
+ #endif
+ };
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumPasses
+ #ifndef _7ZIP_ST
+ , NCoderPropID::kNumThreads
+ #endif
+ };
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties);
+ if (setCoderProperties)
+ {
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0])));
+ }
+ }
+ }
+ }
+ CMyComPtr<ISequentialOutStream> outStreamNew;
+ if (_options.PasswordIsDefined)
+ outStreamNew = _cryptoStream;
+ else
+ outStreamNew = outStream;
+ if (_compressExtractVersion > opRes.ExtractVersion)
+ opRes.ExtractVersion = _compressExtractVersion;
+ RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress));
+ break;
+ }
+ }
+
+ RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
+
+ if (inCrcStreamSpec != 0)
+ {
+ opRes.CRC = inCrcStreamSpec->GetCRC();
+ opRes.UnpackSize = inCrcStreamSpec->GetSize();
+ }
+ else
+ {
+ opRes.CRC = inSecCrcStreamSpec->GetCRC();
+ opRes.UnpackSize = inSecCrcStreamSpec->GetSize();
+ }
+
+ if (_options.PasswordIsDefined)
+ {
+ if (opRes.PackSize < opRes.UnpackSize +
+ (_options.IsAesMode ? _filterAesSpec->GetHeaderSize() : NCrypto::NZip::kHeaderSize))
+ break;
+ }
+ else if (opRes.PackSize < opRes.UnpackSize)
+ break;
+ }
+ if (_options.IsAesMode)
+ {
+ RINOK(_filterAesSpec->WriteFooter(outStream));
+ RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize));
+ }
+ opRes.Method = method;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.h
new file mode 100644
index 000000000..e4c02db3f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipAddCommon.h
@@ -0,0 +1,56 @@
+// ZipAddCommon.h
+
+#ifndef __ZIP_ADD_COMMON_H
+#define __ZIP_ADD_COMMON_H
+
+#include "../../ICoder.h"
+#include "../../IProgress.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../../Crypto/ZipCrypto.h"
+#include "../../Crypto/WzAes.h"
+
+#include "ZipCompressionMode.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CCompressingResult
+{
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt32 CRC;
+ UInt16 Method;
+ Byte ExtractVersion;
+};
+
+class CAddCommon
+{
+ CCompressionMethodMode _options;
+ NCompress::CCopyCoder *_copyCoderSpec;
+ CMyComPtr<ICompressCoder> _copyCoder;
+
+ CMyComPtr<ICompressCoder> _compressEncoder;
+ Byte _compressExtractVersion;
+
+ CFilterCoder *_cryptoStreamSpec;
+ CMyComPtr<ISequentialOutStream> _cryptoStream;
+
+ NCrypto::NZip::CEncoder *_filterSpec;
+ NCrypto::NWzAes::CEncoder *_filterAesSpec;
+
+public:
+ CAddCommon(const CCompressionMethodMode &options);
+ HRESULT Compress(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream, IOutStream *outStream,
+ ICompressProgressInfo *progress, CCompressingResult &operationResult);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipCompressionMode.h
new file mode 100644
index 000000000..7ef7cfb28
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipCompressionMode.h
@@ -0,0 +1,42 @@
+// CompressionMode.h
+
+#ifndef __ZIP_COMPRESSION_MODE_H
+#define __ZIP_COMPRESSION_MODE_H
+
+#include "Common/MyString.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CCompressionMethodMode
+{
+ CRecordVector<Byte> MethodSequence;
+ UString MatchFinder;
+ UInt32 Algo;
+ UInt32 NumPasses;
+ UInt32 NumFastBytes;
+ bool NumMatchFinderCyclesDefined;
+ UInt32 NumMatchFinderCycles;
+ UInt32 DicSize;
+ UInt32 MemSize;
+ UInt32 Order;
+
+ #ifndef _7ZIP_ST
+ UInt32 NumThreads;
+ #endif
+ bool PasswordIsDefined;
+ AString Password;
+ bool IsAesMode;
+ Byte AesKeyMode;
+
+ CCompressionMethodMode():
+ NumMatchFinderCyclesDefined(false),
+ PasswordIsDefined(false),
+ IsAesMode(false),
+ AesKeyMode(3)
+ {}
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.cpp
new file mode 100644
index 000000000..bd1563226
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -0,0 +1,822 @@
+// ZipHandler.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/IntToString.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/FilterCoder.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/LzmaDecoder.h"
+#include "../../Compress/ImplodeDecoder.h"
+#include "../../Compress/PpmdZip.h"
+#include "../../Compress/ShrinkDecoder.h"
+
+#include "../../Crypto/WzAes.h"
+#include "../../Crypto/ZipCrypto.h"
+#include "../../Crypto/ZipStrong.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "ZipHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NZip {
+
+static const CMethodId kMethodId_ZipBase = 0x040100;
+static const CMethodId kMethodId_BZip2 = 0x040202;
+
+static const char *kHostOS[] =
+{
+ "FAT",
+ "AMIGA",
+ "VMS",
+ "Unix",
+ "VM/CMS",
+ "Atari",
+ "HPFS",
+ "Macintosh",
+ "Z-System",
+ "CP/M",
+ "TOPS-20",
+ "NTFS",
+ "SMS/QDOS",
+ "Acorn",
+ "VFAT",
+ "MVS",
+ "BeOS",
+ "Tandem",
+ "OS/400",
+ "OS/X"
+};
+
+static const char *kUnknownOS = "Unknown";
+
+static const char *kMethods[] =
+{
+ "Store",
+ "Shrink",
+ "Reduced1",
+ "Reduced2",
+ "Reduced3",
+ "Reduced4",
+ "Implode",
+ "Tokenizing",
+ "Deflate",
+ "Deflate64",
+ "PKImploding"
+};
+
+static const char *kBZip2Method = "BZip2";
+static const char *kLZMAMethod = "LZMA";
+static const char *kJpegMethod = "Jpeg";
+static const char *kWavPackMethod = "WavPack";
+static const char *kPPMdMethod = "PPMd";
+static const char *kAESMethod = "AES";
+static const char *kZipCryptoMethod = "ZipCrypto";
+static const char *kStrongCryptoMethod = "StrongCrypto";
+
+static struct CStrongCryptoPair
+{
+ UInt16 Id;
+ const char *Name;
+} g_StrongCryptoPairs[] =
+{
+ { NStrongCryptoFlags::kDES, "DES" },
+ { NStrongCryptoFlags::kRC2old, "RC2a" },
+ { NStrongCryptoFlags::k3DES168, "3DES-168" },
+ { NStrongCryptoFlags::k3DES112, "3DES-112" },
+ { NStrongCryptoFlags::kAES128, "pkAES-128" },
+ { NStrongCryptoFlags::kAES192, "pkAES-192" },
+ { NStrongCryptoFlags::kAES256, "pkAES-256" },
+ { NStrongCryptoFlags::kRC2, "RC2" },
+ { NStrongCryptoFlags::kBlowfish, "Blowfish" },
+ { NStrongCryptoFlags::kTwofish, "Twofish" },
+ { NStrongCryptoFlags::kRC4, "RC4" }
+};
+
+static STATPROPSTG kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidEncrypted, VT_BOOL},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidCRC, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR},
+ { NULL, kpidUnpackVer, VT_UI4}
+};
+
+static STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidOffset, VT_UI8}
+};
+
+CHandler::CHandler()
+{
+ InitMethodProperties();
+}
+
+static AString BytesToString(const CByteBuffer &data)
+{
+ AString s;
+ int size = (int)data.GetCapacity();
+ if (size > 0)
+ {
+ char *p = s.GetBuffer(size + 1);
+ memcpy(p, (const Byte *)data, size);
+ p[size] = '\0';
+ s.ReleaseBuffer();
+ }
+ return s;
+}
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch(propID)
+ {
+ case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break;
+ case kpidComment: prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break;
+ case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break;
+ case kpidOffset: if (m_Archive.ArcInfo.StartPosition != 0) prop = m_Archive.ArcInfo.StartPosition; break;
+ }
+ prop.Detach(value);
+ COM_TRY_END
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
+{
+ *numItems = m_Items.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItemEx &item = m_Items[index];
+ switch(propID)
+ {
+ case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.UnPackSize; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidTimeType:
+ {
+ FILETIME ft;
+ UInt32 unixTime;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
+ prop = (UInt32)NFileTimeType::kWindows;
+ else if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime))
+ prop = (UInt32)NFileTimeType::kUnix;
+ else
+ prop = (UInt32)NFileTimeType::kDOS;
+ break;
+ }
+ case kpidCTime:
+ {
+ FILETIME ft;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft))
+ prop = ft;
+ break;
+ }
+ case kpidATime:
+ {
+ FILETIME ft;
+ if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft))
+ prop = ft;
+ break;
+ }
+ case kpidMTime:
+ {
+ FILETIME utc;
+ if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc))
+ {
+ UInt32 unixTime;
+ if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime))
+ NTime::UnixTimeToFileTime(unixTime, utc);
+ else
+ {
+ FILETIME localFileTime;
+ if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
+ !LocalFileTimeToFileTime(&localFileTime, &utc))
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ }
+ }
+ prop = utc;
+ break;
+ }
+ case kpidAttrib: prop = item.GetWinAttributes(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break;
+ case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break;
+ case kpidMethod:
+ {
+ UInt16 methodId = item.CompressionMethod;
+ AString method;
+ if (item.IsEncrypted())
+ {
+ if (methodId == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ method = kAESMethod;
+ CWzAesExtraField aesField;
+ if (item.CentralExtra.GetWzAesField(aesField))
+ {
+ method += '-';
+ char s[32];
+ ConvertUInt64ToString((aesField.Strength + 1) * 64 , s);
+ method += s;
+ method += ' ';
+ methodId = aesField.Method;
+ }
+ }
+ else
+ {
+ if (item.IsStrongEncrypted())
+ {
+ CStrongCryptoField f;
+ bool finded = false;
+ if (item.CentralExtra.GetStrongCryptoField(f))
+ {
+ for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++)
+ {
+ const CStrongCryptoPair &pair = g_StrongCryptoPairs[i];
+ if (f.AlgId == pair.Id)
+ {
+ method += pair.Name;
+ finded = true;
+ break;
+ }
+ }
+ }
+ if (!finded)
+ method += kStrongCryptoMethod;
+ }
+ else
+ method += kZipCryptoMethod;
+ method += ' ';
+ }
+ }
+ if (methodId < sizeof(kMethods) / sizeof(kMethods[0]))
+ method += kMethods[methodId];
+ else switch (methodId)
+ {
+ case NFileHeader::NCompressionMethod::kLZMA:
+ method += kLZMAMethod;
+ if (item.IsLzmaEOS())
+ method += ":EOS";
+ break;
+ case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break;
+ case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break;
+ case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break;
+ case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break;
+ default:
+ {
+ char s[32];
+ ConvertUInt64ToString(methodId, s);
+ method += s;
+ }
+ }
+ prop = method;
+ break;
+ }
+ case kpidHostOS:
+ prop = (item.MadeByVersion.HostOS < sizeof(kHostOS) / sizeof(kHostOS[0])) ?
+ (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS;
+ break;
+ case kpidUnpackVer:
+ prop = (UInt32)item.ExtractVersion.Version;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+public:
+ STDMETHOD(SetTotal)(UInt64 numFiles);
+ STDMETHOD(SetCompleted)(UInt64 numFiles);
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
+};
+
+STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetTotal(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles)
+{
+ if (_callback)
+ return _callback->SetCompleted(&numFiles, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(m_Archive.Open(inStream, maxCheckStartPosition));
+ CProgressImp progressImp(callback);
+ return m_Archive.ReadHeaders(m_Items, &progressImp);
+ }
+ catch(const CInArchiveException &) { Close(); return S_FALSE; }
+ catch(...) { Close(); throw; }
+ COM_TRY_END
+}
+
+STDMETHODIMP CHandler::Close()
+{
+ m_Items.Clear();
+ m_Archive.Close();
+ return S_OK;
+}
+
+//////////////////////////////////////
+// CHandler::DecompressItems
+
+class CLzmaDecoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ NCompress::NLzma::CDecoder *DecoderSpec;
+ CMyComPtr<ICompressCoder> Decoder;
+public:
+ CLzmaDecoder();
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ MY_UNKNOWN_IMP
+};
+
+CLzmaDecoder::CLzmaDecoder()
+{
+ DecoderSpec = new NCompress::NLzma::CDecoder;
+ Decoder = DecoderSpec;
+}
+
+HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ Byte buf[9];
+ RINOK(ReadStream_FALSE(inStream, buf, 9));
+ if (buf[2] != 5 || buf[3] != 0)
+ return E_NOTIMPL;
+ RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5));
+ return Decoder->Code(inStream, outStream, NULL, outSize, progress);
+}
+
+struct CMethodItem
+{
+ UInt16 ZipMethod;
+ CMyComPtr<ICompressCoder> Coder;
+};
+
+class CZipDecoder
+{
+ NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec;
+ NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec;
+ NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec;
+
+ CMyComPtr<ICompressFilter> _zipCryptoDecoder;
+ CMyComPtr<ICompressFilter> _pkAesDecoder;
+ CMyComPtr<ICompressFilter> _wzAesDecoder;
+
+ CFilterCoder *filterStreamSpec;
+ CMyComPtr<ISequentialInStream> filterStream;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ CObjectVector<CMethodItem> methodItems;
+
+public:
+ CZipDecoder():
+ _zipCryptoDecoderSpec(0),
+ _pkAesDecoderSpec(0),
+ _wzAesDecoderSpec(0),
+ filterStreamSpec(0) {}
+
+ HRESULT Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CInArchive &archive, const CItemEx &item,
+ ISequentialOutStream *realOutStream,
+ IArchiveExtractCallback *extractCallback,
+ ICompressProgressInfo *compressProgress,
+ UInt32 numThreads, Int32 &res);
+};
+
+HRESULT CZipDecoder::Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CInArchive &archive, const CItemEx &item,
+ ISequentialOutStream *realOutStream,
+ IArchiveExtractCallback *extractCallback,
+ ICompressProgressInfo *compressProgress,
+ UInt32 numThreads, Int32 &res)
+{
+ res = NExtract::NOperationResult::kDataError;
+ CInStreamReleaser inStreamReleaser;
+
+ bool needCRC = true;
+ bool wzAesMode = false;
+ bool pkAesMode = false;
+ UInt16 methodId = item.CompressionMethod;
+ if (item.IsEncrypted())
+ {
+ if (item.IsStrongEncrypted())
+ {
+ CStrongCryptoField f;
+ if (item.CentralExtra.GetStrongCryptoField(f))
+ {
+ pkAesMode = true;
+ }
+ if (!pkAesMode)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ }
+ if (methodId == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ CWzAesExtraField aesField;
+ if (item.CentralExtra.GetWzAesField(aesField))
+ {
+ wzAesMode = true;
+ needCRC = aesField.NeedCrc();
+ }
+ }
+ }
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init(needCRC);
+
+ UInt64 authenticationPos;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ {
+ UInt64 packSize = item.PackSize;
+ if (wzAesMode)
+ {
+ if (packSize < NCrypto::NWzAes::kMacSize)
+ return S_OK;
+ packSize -= NCrypto::NWzAes::kMacSize;
+ }
+ UInt64 dataPos = item.GetDataPosition();
+ inStream.Attach(archive.CreateLimitedStream(dataPos, packSize));
+ authenticationPos = dataPos + packSize;
+ }
+
+ CMyComPtr<ICompressFilter> cryptoFilter;
+ if (item.IsEncrypted())
+ {
+ if (wzAesMode)
+ {
+ CWzAesExtraField aesField;
+ if (!item.CentralExtra.GetWzAesField(aesField))
+ return S_OK;
+ methodId = aesField.Method;
+ if (!_wzAesDecoder)
+ {
+ _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder;
+ _wzAesDecoder = _wzAesDecoderSpec;
+ }
+ cryptoFilter = _wzAesDecoder;
+ Byte properties = aesField.Strength;
+ RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1));
+ }
+ else if (pkAesMode)
+ {
+ if (!_pkAesDecoder)
+ {
+ _pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder;
+ _pkAesDecoder = _pkAesDecoderSpec;
+ }
+ cryptoFilter = _pkAesDecoder;
+ }
+ else
+ {
+ if (!_zipCryptoDecoder)
+ {
+ _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder;
+ _zipCryptoDecoder = _zipCryptoDecoderSpec;
+ }
+ cryptoFilter = _zipCryptoDecoder;
+ }
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
+
+ if (!getTextPassword)
+ extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password));
+ AString charPassword;
+ if (wzAesMode || pkAesMode)
+ {
+ charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
+ /*
+ for (int i = 0;; i++)
+ {
+ wchar_t c = password[i];
+ if (c == 0)
+ break;
+ if (c >= 0x80)
+ {
+ res = NExtract::NOperationResult::kDataError;
+ return S_OK;
+ }
+ charPassword += (char)c;
+ }
+ */
+ }
+ else
+ {
+ // we use OEM. WinZip/Windows probably use ANSI for some files
+ charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
+ }
+ HRESULT result = cryptoSetPassword->CryptoSetPassword(
+ (const Byte *)(const char *)charPassword, charPassword.Length());
+ if (result != S_OK)
+ return S_OK;
+ }
+ else
+ {
+ RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
+ }
+ }
+
+ int m;
+ for (m = 0; m < methodItems.Size(); m++)
+ if (methodItems[m].ZipMethod == methodId)
+ break;
+
+ if (m == methodItems.Size())
+ {
+ CMethodItem mi;
+ mi.ZipMethod = methodId;
+ if (methodId == NFileHeader::NCompressionMethod::kStored)
+ mi.Coder = new NCompress::CCopyCoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kShrunk)
+ mi.Coder = new NCompress::NShrink::CDecoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kImploded)
+ mi.Coder = new NCompress::NImplode::NDecoder::CCoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kLZMA)
+ mi.Coder = new CLzmaDecoder;
+ else if (methodId == NFileHeader::NCompressionMethod::kPPMd)
+ mi.Coder = new NCompress::NPpmdZip::CDecoder(true);
+ else
+ {
+ CMethodId szMethodID;
+ if (methodId == NFileHeader::NCompressionMethod::kBZip2)
+ szMethodID = kMethodId_BZip2;
+ else
+ {
+ if (methodId > 0xFF)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ szMethodID = kMethodId_ZipBase + (Byte)methodId;
+ }
+
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false));
+
+ if (mi.Coder == 0)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+ }
+ m = methodItems.Add(mi);
+ }
+ ICompressCoder *coder = methodItems[m].Coder;
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ Byte properties = (Byte)item.Flags;
+ RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1));
+ }
+ }
+
+ #ifndef _7ZIP_ST
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(numThreads));
+ }
+ }
+ #endif
+
+ {
+ HRESULT result = S_OK;
+ CMyComPtr<ISequentialInStream> inStreamNew;
+ if (item.IsEncrypted())
+ {
+ if (!filterStream)
+ {
+ filterStreamSpec = new CFilterCoder;
+ filterStream = filterStreamSpec;
+ }
+ filterStreamSpec->Filter = cryptoFilter;
+ if (wzAesMode)
+ {
+ result = _wzAesDecoderSpec->ReadHeader(inStream);
+ }
+ else if (pkAesMode)
+ {
+ result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize);
+ if (result == S_OK)
+ {
+ bool passwOK;
+ result = _pkAesDecoderSpec->CheckPassword(passwOK);
+ if (result == S_OK && !passwOK)
+ result = S_FALSE;
+ }
+ }
+ else
+ {
+ result = _zipCryptoDecoderSpec->ReadHeader(inStream);
+ }
+
+ if (result == S_OK)
+ {
+ RINOK(filterStreamSpec->SetInStream(inStream));
+ inStreamReleaser.FilterCoder = filterStreamSpec;
+ inStreamNew = filterStream;
+ if (wzAesMode)
+ {
+ if (!_wzAesDecoderSpec->CheckPasswordVerifyCode())
+ result = S_FALSE;
+ }
+ }
+ }
+ else
+ inStreamNew = inStream;
+ if (result == S_OK)
+ result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress);
+ if (result == S_FALSE)
+ return S_OK;
+ if (result == E_NOTIMPL)
+ {
+ res = NExtract::NOperationResult::kUnSupportedMethod;
+ return S_OK;
+ }
+
+ RINOK(result);
+ }
+ bool crcOK = true;
+ bool authOk = true;
+ if (needCRC)
+ crcOK = (outStreamSpec->GetCRC() == item.FileCRC);
+ if (wzAesMode)
+ {
+ inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize));
+ if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
+ authOk = false;
+ }
+
+ res = ((crcOK && authOk) ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kCRCError);
+ return S_OK;
+}
+
+
+STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback)
+{
+ COM_TRY_BEGIN
+ CZipDecoder myDecoder;
+ UInt64 totalUnPacked = 0, totalPacked = 0;
+ bool allFilesMode = (numItems == (UInt32)-1);
+ if (allFilesMode)
+ numItems = m_Items.Size();
+ if(numItems == 0)
+ return S_OK;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItemEx &item = m_Items[allFilesMode ? i : indices[i]];
+ totalUnPacked += item.UnPackSize;
+ totalPacked += item.PackSize;
+ }
+ RINOK(extractCallback->SetTotal(totalUnPacked));
+
+ UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
+ UInt64 currentItemUnPacked, currentItemPacked;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
+ currentTotalPacked += currentItemPacked)
+ {
+ currentItemUnPacked = 0;
+ currentItemPacked = 0;
+
+ lps->InSize = currentTotalPacked;
+ lps->OutSize = currentTotalUnPacked;
+ RINOK(lps->SetCur());
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ Int32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
+
+ CItemEx item = m_Items[index];
+ if (!item.FromLocal)
+ {
+ HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item);
+ if (res == S_FALSE)
+ {
+ if (item.IsDir() || realOutStream || testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
+ }
+ continue;
+ }
+ RINOK(res);
+ }
+
+ if (item.IsDir() || item.IgnoreItem())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode));
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
+ }
+ continue;
+ }
+
+ currentItemUnPacked = item.UnPackSize;
+ currentItemPacked = item.PackSize;
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode));
+
+ Int32 res;
+ RINOK(myDecoder.Decode(
+ EXTERNAL_CODECS_VARS
+ m_Archive, item, realOutStream, extractCallback,
+ progress, _numThreads, res));
+ realOutStream.Release();
+
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.h
new file mode 100644
index 000000000..fdb60aafe
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandler.h
@@ -0,0 +1,101 @@
+// Zip/Handler.h
+
+#ifndef __ZIP_HANDLER_H
+#define __ZIP_HANDLER_H
+
+#include "Common/DynamicBuffer.h"
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "ZipIn.h"
+#include "ZipCompressionMode.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/System.h"
+#endif
+
+namespace NArchive {
+namespace NZip {
+
+class CHandler:
+ public IInArchive,
+ public IOutArchive,
+ public ISetProperties,
+ PUBLIC_ISetCompressCodecsInfo
+ public CMyUnknownImp
+{
+public:
+ MY_QUERYINTERFACE_BEGIN2(IInArchive)
+ MY_QUERYINTERFACE_ENTRY(IOutArchive)
+ MY_QUERYINTERFACE_ENTRY(ISetProperties)
+ QUERY_ENTRY_ISetCompressCodecsInfo
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ INTERFACE_IInArchive(;)
+ INTERFACE_IOutArchive(;)
+
+ STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
+
+ DECL_ISetCompressCodecsInfo
+
+ CHandler();
+private:
+ CObjectVector<CItemEx> m_Items;
+ CInArchive m_Archive;
+
+ int m_Level;
+ int m_MainMethod;
+ UInt32 m_DicSize;
+ UInt32 m_Algo;
+ UInt32 m_NumPasses;
+ UInt32 m_NumFastBytes;
+ UInt32 m_NumMatchFinderCycles;
+ UInt32 m_MemSize;
+ UInt32 m_Order;
+
+ bool m_NumMatchFinderCyclesDefined;
+
+ bool m_ForceAesMode;
+ bool m_IsAesMode;
+ Byte m_AesKeyMode;
+
+ bool m_WriteNtfsTimeExtra;
+ bool m_ForceLocal;
+ bool m_ForceUtf8;
+
+ #ifndef _7ZIP_ST
+ UInt32 _numThreads;
+ #endif
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ void InitMethodProperties()
+ {
+ m_Level = -1;
+ m_MainMethod = -1;
+ m_Algo =
+ m_DicSize =
+ m_NumPasses =
+ m_NumFastBytes =
+ m_Order =
+ m_MemSize =
+ m_NumMatchFinderCycles = 0xFFFFFFFF;
+ m_NumMatchFinderCyclesDefined = false;
+ m_ForceAesMode = false;
+ m_IsAesMode = false;
+ m_AesKeyMode = 3; // aes-256
+ m_WriteNtfsTimeExtra = true;
+ m_ForceLocal = false;
+ m_ForceUtf8 = false;
+ #ifndef _7ZIP_ST
+ _numThreads = NWindows::NSystem::GetNumberOfProcessors();;
+ #endif
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
new file mode 100644
index 000000000..a5e0f59d7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
@@ -0,0 +1,531 @@
+// ZipHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Time.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/OutBuffer.h"
+
+#include "../../Crypto/WzAes.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/ParseProperties.h"
+
+#include "ZipHandler.h"
+#include "ZipUpdate.h"
+
+using namespace NWindows;
+using namespace NCOM;
+using namespace NTime;
+
+namespace NArchive {
+namespace NZip {
+
+static const UInt32 kLzAlgoX1 = 0;
+static const UInt32 kLzAlgoX5 = 1;
+
+static const UInt32 kDeflateNumPassesX1 = 1;
+static const UInt32 kDeflateNumPassesX7 = 3;
+static const UInt32 kDeflateNumPassesX9 = 10;
+
+static const UInt32 kDeflateNumFastBytesX1 = 32;
+static const UInt32 kDeflateNumFastBytesX7 = 64;
+static const UInt32 kDeflateNumFastBytesX9 = 128;
+
+static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
+static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
+
+static const UInt32 kLzmaNumFastBytesX1 = 32;
+static const UInt32 kLzmaNumFastBytesX7 = 64;
+
+static const UInt32 kLzmaDicSizeX1 = 1 << 16;
+static const UInt32 kLzmaDicSizeX3 = 1 << 20;
+static const UInt32 kLzmaDicSizeX5 = 1 << 24;
+static const UInt32 kLzmaDicSizeX7 = 1 << 25;
+static const UInt32 kLzmaDicSizeX9 = 1 << 26;
+
+static const UInt32 kBZip2NumPassesX1 = 1;
+static const UInt32 kBZip2NumPassesX7 = 2;
+static const UInt32 kBZip2NumPassesX9 = 7;
+
+static const UInt32 kBZip2DicSizeX1 = 100000;
+static const UInt32 kBZip2DicSizeX3 = 500000;
+static const UInt32 kBZip2DicSizeX5 = 900000;
+
+STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
+{
+ *timeType = NFileTimeType::kDOS;
+ return S_OK;
+}
+
+static bool IsAsciiString(const UString &s)
+{
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ if (c < 0x20 || c > 0x7F)
+ return false;
+ }
+ return true;
+}
+
+#define COM_TRY_BEGIN2 try {
+#define COM_TRY_END2 } \
+catch(const CSystemException &e) { return e.ErrorCode; } \
+catch(...) { return E_OUTOFMEMORY; }
+
+static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &filetime)
+{
+ filetime.dwHighDateTime = filetime.dwLowDateTime = 0;
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ filetime = prop.filetime;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback)
+{
+ COM_TRY_BEGIN2
+ CObjectVector<CUpdateItem> updateItems;
+ bool thereAreAesUpdates = false;
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData;
+ Int32 newProperties;
+ UInt32 indexInArchive;
+ if (!callback)
+ return E_FAIL;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProperties, &indexInArchive));
+ ui.NewProperties = IntToBool(newProperties);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArchive = indexInArchive;
+ ui.IndexInClient = i;
+ bool existInArchive = (indexInArchive != (UInt32)-1);
+ if (existInArchive && newData)
+ if (m_Items[indexInArchive].IsAesEncrypted())
+ thereAreAesUpdates = true;
+
+ if (IntToBool(newProperties))
+ {
+ UString name;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidAttrib, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.Attributes = 0;
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Attributes = prop.ulVal;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop));
+ if (prop.vt == VT_EMPTY)
+ name.Empty();
+ else if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ else
+ name = prop.bstrVal;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop));
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ {
+ CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidTimeType, &prop));
+ if (prop.vt == VT_UI4)
+ ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows);
+ else
+ ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra;
+ }
+ RINOK(GetTime(callback, i, kpidMTime, ui.NtfsMTime));
+ RINOK(GetTime(callback, i, kpidATime, ui.NtfsATime));
+ RINOK(GetTime(callback, i, kpidCTime, ui.NtfsCTime));
+
+ {
+ FILETIME localFileTime = { 0, 0 };
+ if (ui.NtfsMTime.dwHighDateTime != 0 ||
+ ui.NtfsMTime.dwLowDateTime != 0)
+ if (!FileTimeToLocalFileTime(&ui.NtfsMTime, &localFileTime))
+ return E_INVALIDARG;
+ FileTimeToDosTime(localFileTime, ui.Time);
+ }
+
+ name = NItemName::MakeLegalName(name);
+ bool needSlash = ui.IsDir;
+ const wchar_t kSlash = L'/';
+ if (!name.IsEmpty())
+ {
+ if (name[name.Length() - 1] == kSlash)
+ {
+ if (!ui.IsDir)
+ return E_INVALIDARG;
+ needSlash = false;
+ }
+ }
+ if (needSlash)
+ name += kSlash;
+
+ bool tryUtf8 = true;
+ if (m_ForceLocal || !m_ForceUtf8)
+ {
+ bool defaultCharWasUsed;
+ ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP, '_', defaultCharWasUsed);
+ tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed ||
+ MultiByteToUnicodeString(ui.Name, CP_OEMCP) != name));
+ }
+
+ if (tryUtf8)
+ {
+ int i;
+ for (i = 0; i < name.Length() && (unsigned)name[i] < 0x80; i++);
+ ui.IsUtf8 = (i != name.Length());
+ if (!ConvertUnicodeToUTF8(name, ui.Name))
+ return E_INVALIDARG;
+ }
+
+ if (ui.Name.Length() >= (1 << 16))
+ return E_INVALIDARG;
+
+ ui.IndexInClient = i;
+ /*
+ if (existInArchive)
+ {
+ const CItemEx &itemInfo = m_Items[indexInArchive];
+ // ui.Commented = itemInfo.IsCommented();
+ ui.Commented = false;
+ if (ui.Commented)
+ {
+ ui.CommentRange.Position = itemInfo.GetCommentPosition();
+ ui.CommentRange.Size = itemInfo.CommentSize;
+ }
+ }
+ else
+ ui.Commented = false;
+ */
+ }
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ ui.Size = size;
+ }
+ updateItems.Add(ui);
+ }
+
+ CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
+ {
+ CMyComPtr<IArchiveUpdateCallback> udateCallBack2(callback);
+ udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
+ }
+ CCompressionMethodMode options;
+
+ if (getTextPassword)
+ {
+ CMyComBSTR password;
+ Int32 passwordIsDefined;
+ RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password));
+ options.PasswordIsDefined = IntToBool(passwordIsDefined);
+ if (options.PasswordIsDefined)
+ {
+ options.IsAesMode = (m_ForceAesMode ? m_IsAesMode : thereAreAesUpdates);
+ options.AesKeyMode = m_AesKeyMode;
+
+ if (!IsAsciiString((const wchar_t *)password))
+ return E_INVALIDARG;
+ if (options.IsAesMode)
+ {
+ if (options.Password.Length() > NCrypto::NWzAes::kPasswordSizeMax)
+ return E_INVALIDARG;
+ }
+ options.Password = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
+ }
+ }
+ else
+ options.PasswordIsDefined = false;
+
+ int level = m_Level;
+ if (level < 0)
+ level = 5;
+
+ Byte mainMethod;
+ if (m_MainMethod < 0)
+ mainMethod = (Byte)(((level == 0) ?
+ NFileHeader::NCompressionMethod::kStored :
+ NFileHeader::NCompressionMethod::kDeflated));
+ else
+ mainMethod = (Byte)m_MainMethod;
+ options.MethodSequence.Add(mainMethod);
+ if (mainMethod != NFileHeader::NCompressionMethod::kStored)
+ options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStored);
+ bool isDeflate = (mainMethod == NFileHeader::NCompressionMethod::kDeflated) ||
+ (mainMethod == NFileHeader::NCompressionMethod::kDeflated64);
+ bool isLZMA = (mainMethod == NFileHeader::NCompressionMethod::kLZMA);
+ bool isLz = (isLZMA || isDeflate);
+ options.NumPasses = m_NumPasses;
+ options.DicSize = m_DicSize;
+ options.NumFastBytes = m_NumFastBytes;
+ options.NumMatchFinderCycles = m_NumMatchFinderCycles;
+ options.NumMatchFinderCyclesDefined = m_NumMatchFinderCyclesDefined;
+ options.Algo = m_Algo;
+ options.MemSize = m_MemSize;
+ options.Order = m_Order;
+ #ifndef _7ZIP_ST
+ options.NumThreads = _numThreads;
+ #endif
+ if (isLz)
+ {
+ if (isDeflate)
+ {
+ if (options.NumPasses == 0xFFFFFFFF)
+ options.NumPasses = (level >= 9 ? kDeflateNumPassesX9 :
+ (level >= 7 ? kDeflateNumPassesX7 :
+ kDeflateNumPassesX1));
+ if (options.NumFastBytes == 0xFFFFFFFF)
+ options.NumFastBytes = (level >= 9 ? kDeflateNumFastBytesX9 :
+ (level >= 7 ? kDeflateNumFastBytesX7 :
+ kDeflateNumFastBytesX1));
+ }
+ else if (isLZMA)
+ {
+ if (options.DicSize == 0xFFFFFFFF)
+ options.DicSize =
+ (level >= 9 ? kLzmaDicSizeX9 :
+ (level >= 7 ? kLzmaDicSizeX7 :
+ (level >= 5 ? kLzmaDicSizeX5 :
+ (level >= 3 ? kLzmaDicSizeX3 :
+ kLzmaDicSizeX1))));
+
+ if (options.NumFastBytes == 0xFFFFFFFF)
+ options.NumFastBytes = (level >= 7 ? kLzmaNumFastBytesX7 :
+ kLzmaNumFastBytesX1);
+
+ options.MatchFinder =
+ (level >= 5 ? kLzmaMatchFinderX5 :
+ kLzmaMatchFinderX1);
+ }
+
+ if (options.Algo == 0xFFFFFFFF)
+ options.Algo = (level >= 5 ? kLzAlgoX5 :
+ kLzAlgoX1);
+ }
+ if (mainMethod == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ if (options.NumPasses == 0xFFFFFFFF)
+ options.NumPasses = (level >= 9 ? kBZip2NumPassesX9 :
+ (level >= 7 ? kBZip2NumPassesX7 :
+ kBZip2NumPassesX1));
+ if (options.DicSize == 0xFFFFFFFF)
+ options.DicSize = (level >= 5 ? kBZip2DicSizeX5 :
+ (level >= 3 ? kBZip2DicSizeX3 :
+ kBZip2DicSizeX1));
+ }
+ if (mainMethod == NFileHeader::NCompressionMethod::kPPMd)
+ {
+ int level2 = level;
+ if (level2 < 1) level2 = 1;
+ if (level2 > 9) level2 = 9;
+
+ if (options.MemSize == 0xFFFFFFFF)
+ options.MemSize = (1 << (19 + (level2 > 8 ? 8 : level2)));
+
+ if (options.Order == 0xFFFFFFFF)
+ options.Order = 3 + level2;
+
+ if (options.Algo == 0xFFFFFFFF)
+ options.Algo = (level2 >= 7 ? 1 : 0);
+ }
+
+ return Update(
+ EXTERNAL_CODECS_VARS
+ m_Items, updateItems, outStream,
+ m_Archive.IsOpen() ? &m_Archive : NULL, &options, callback);
+ COM_TRY_END2
+}
+
+STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
+{
+ #ifndef _7ZIP_ST
+ const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
+ _numThreads = numProcessors;
+ #endif
+ InitMethodProperties();
+ for (int i = 0; i < numProperties; i++)
+ {
+ UString name = UString(names[i]);
+ name.MakeUpper();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &prop = values[i];
+
+ if (name[0] == L'X')
+ {
+ UInt32 level = 9;
+ RINOK(ParsePropValue(name.Mid(1), prop, level));
+ m_Level = level;
+ continue;
+ }
+ else if (name == L"M")
+ {
+ if (prop.vt == VT_BSTR)
+ {
+ UString m = prop.bstrVal;
+ m.MakeUpper();
+ if (m == L"COPY") m_MainMethod = NFileHeader::NCompressionMethod::kStored;
+ else if (m == L"DEFLATE") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated;
+ else if (m == L"DEFLATE64") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated64;
+ else if (m == L"BZIP2") m_MainMethod = NFileHeader::NCompressionMethod::kBZip2;
+ else if (m == L"LZMA") m_MainMethod = NFileHeader::NCompressionMethod::kLZMA;
+ else if (m == L"PPMD") m_MainMethod = NFileHeader::NCompressionMethod::kPPMd;
+ else return E_INVALIDARG;
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ switch(prop.ulVal)
+ {
+ case NFileHeader::NCompressionMethod::kStored:
+ case NFileHeader::NCompressionMethod::kDeflated:
+ case NFileHeader::NCompressionMethod::kDeflated64:
+ case NFileHeader::NCompressionMethod::kBZip2:
+ case NFileHeader::NCompressionMethod::kLZMA:
+ m_MainMethod = (Byte)prop.ulVal;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else if (name.Left(2) == L"EM")
+ {
+ if (prop.vt == VT_BSTR)
+ {
+ UString valueString = prop.bstrVal;
+ valueString.MakeUpper();
+ if (valueString.Left(3) == L"AES")
+ {
+ valueString = valueString.Mid(3);
+ if (valueString == L"128")
+ m_AesKeyMode = 1;
+ else if (valueString == L"192")
+ m_AesKeyMode = 2;
+ else if (valueString == L"256" || valueString.IsEmpty())
+ m_AesKeyMode = 3;
+ else
+ return E_INVALIDARG;
+ m_IsAesMode = true;
+ m_ForceAesMode = true;
+ }
+ else if (valueString == L"ZIPCRYPTO")
+ {
+ m_IsAesMode = false;
+ m_ForceAesMode = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else if (name[0] == L'D')
+ {
+ UInt32 dicSize = kBZip2DicSizeX5;
+ RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
+ m_DicSize = dicSize;
+ }
+ else if (name.Left(3) == L"MEM")
+ {
+ UInt32 memSize = 1 << 24;
+ RINOK(ParsePropDictionaryValue(name.Mid(3), prop, memSize));
+ m_MemSize = memSize;
+ }
+ else if (name[0] == L'O')
+ {
+ UInt32 order = 8;
+ RINOK(ParsePropValue(name.Mid(1), prop, order));
+ m_Order = order;
+ }
+ else if (name.Left(4) == L"PASS")
+ {
+ UInt32 num = kDeflateNumPassesX9;
+ RINOK(ParsePropValue(name.Mid(4), prop, num));
+ m_NumPasses = num;
+ }
+ else if (name.Left(2) == L"FB")
+ {
+ UInt32 num = kDeflateNumFastBytesX9;
+ RINOK(ParsePropValue(name.Mid(2), prop, num));
+ m_NumFastBytes = num;
+ }
+ else if (name.Left(2) == L"MC")
+ {
+ UInt32 num = 0xFFFFFFFF;
+ RINOK(ParsePropValue(name.Mid(2), prop, num));
+ m_NumMatchFinderCycles = num;
+ m_NumMatchFinderCyclesDefined = true;
+ }
+ else if (name.Left(2) == L"MT")
+ {
+ #ifndef _7ZIP_ST
+ RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
+ #endif
+ }
+ else if (name.Left(1) == L"A")
+ {
+ UInt32 num = kLzAlgoX5;
+ RINOK(ParsePropValue(name.Mid(1), prop, num));
+ m_Algo = num;
+ }
+ else if (name.CompareNoCase(L"TC") == 0)
+ {
+ RINOK(SetBoolProperty(m_WriteNtfsTimeExtra, prop));
+ }
+ else if (name.CompareNoCase(L"CL") == 0)
+ {
+ RINOK(SetBoolProperty(m_ForceLocal, prop));
+ if (m_ForceLocal)
+ m_ForceUtf8 = false;
+ }
+ else if (name.CompareNoCase(L"CU") == 0)
+ {
+ RINOK(SetBoolProperty(m_ForceUtf8, prop));
+ if (m_ForceUtf8)
+ m_ForceLocal = false;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.cpp
new file mode 100644
index 000000000..582187b51
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.cpp
@@ -0,0 +1,36 @@
+// Archive/Zip/Header.h
+
+#include "StdAfx.h"
+
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+namespace NSignature
+{
+ UInt32 kLocalFileHeader = 0x04034B50 + 1;
+ UInt32 kDataDescriptor = 0x08074B50 + 1;
+ UInt32 kCentralFileHeader = 0x02014B50 + 1;
+ UInt32 kEndOfCentralDir = 0x06054B50 + 1;
+ UInt32 kZip64EndOfCentralDir = 0x06064B50 + 1;
+ UInt32 kZip64EndOfCentralDirLocator = 0x07064B50 + 1;
+
+ class CMarkersInitializer
+ {
+ public:
+ CMarkersInitializer()
+ {
+ kLocalFileHeader--;
+ kDataDescriptor--;
+ kCentralFileHeader--;
+ kEndOfCentralDir--;
+ kZip64EndOfCentralDir--;
+ kZip64EndOfCentralDirLocator--;
+ }
+ };
+ static CMarkersInitializer g_MarkerInitializer;
+}
+
+}}
+
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.h
new file mode 100644
index 000000000..ce8c1e4f7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -0,0 +1,284 @@
+// Archive/Zip/Header.h
+
+#ifndef __ARCHIVE_ZIP_HEADER_H
+#define __ARCHIVE_ZIP_HEADER_H
+
+#include "Common/Types.h"
+
+namespace NArchive {
+namespace NZip {
+
+namespace NSignature
+{
+ extern UInt32 kLocalFileHeader;
+ extern UInt32 kDataDescriptor;
+ extern UInt32 kCentralFileHeader;
+ extern UInt32 kEndOfCentralDir;
+ extern UInt32 kZip64EndOfCentralDir;
+ extern UInt32 kZip64EndOfCentralDirLocator;
+
+ static const UInt32 kMarkerSize = 4;
+}
+
+const UInt32 kEcdSize = 22;
+const UInt32 kZip64EcdSize = 44;
+const UInt32 kZip64EcdLocatorSize = 20;
+/*
+struct CEndOfCentralDirectoryRecord
+{
+ UInt16 ThisDiskNumber;
+ UInt16 StartCentralDirectoryDiskNumber;
+ UInt16 NumEntriesInCentaralDirectoryOnThisDisk;
+ UInt16 NumEntriesInCentaralDirectory;
+ UInt32 CentralDirectorySize;
+ UInt32 CentralDirectoryStartOffset;
+ UInt16 CommentSize;
+};
+
+struct CEndOfCentralDirectoryRecordFull
+{
+ UInt32 Signature;
+ CEndOfCentralDirectoryRecord Header;
+};
+*/
+
+namespace NFileHeader
+{
+ /*
+ struct CVersion
+ {
+ Byte Version;
+ Byte HostOS;
+ };
+ */
+
+ namespace NCompressionMethod
+ {
+ enum EType
+ {
+ kStored = 0,
+ kShrunk = 1,
+ kReduced1 = 2,
+ kReduced2 = 3,
+ kReduced3 = 4,
+ kReduced4 = 5,
+ kImploded = 6,
+ kReservedTokenizing = 7, // reserved for tokenizing
+ kDeflated = 8,
+ kDeflated64 = 9,
+ kPKImploding = 10,
+
+ kBZip2 = 12,
+ kLZMA = 14,
+ kTerse = 18,
+ kLz77 = 19,
+ kJpeg = 0x60,
+ kWavPack = 0x61,
+ kPPMd = 0x62,
+ kWzAES = 0x63
+ };
+ const int kNumCompressionMethods = 11;
+ const Byte kMadeByProgramVersion = 63;
+
+ const Byte kExtractVersion_Default = 10;
+ const Byte kExtractVersion_Dir = 20;
+ const Byte kExtractVersion_ZipCrypto = 20;
+ const Byte kExtractVersion_Deflate = 20;
+ const Byte kExtractVersion_Deflate64 = 21;
+ const Byte kExtractVersion_Zip64 = 45;
+ const Byte kExtractVersion_BZip2 = 46;
+ const Byte kExtractVersion_Aes = 51;
+ const Byte kExtractVersion_LZMA = 63;
+ const Byte kExtractVersion_PPMd = 63;
+
+ // const Byte kSupportedVersion = 20;
+ }
+
+ namespace NExtraID
+ {
+ enum
+ {
+ kZip64 = 0x01,
+ kNTFS = 0x0A,
+ kStrongEncrypt = 0x17,
+ kUnixTime = 0x5455,
+ kWzAES = 0x9901
+ };
+ }
+
+ namespace NNtfsExtra
+ {
+ const UInt16 kTagTime = 1;
+ enum
+ {
+ kMTime = 0,
+ kATime,
+ kCTime
+ };
+ }
+
+ namespace NUnixTime
+ {
+ enum
+ {
+ kMTime = 0,
+ kATime,
+ kCTime
+ };
+ }
+
+ const UInt32 kLocalBlockSize = 26;
+ /*
+ struct CLocalBlock
+ {
+ CVersion ExtractVersion;
+
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ UInt16 NameSize;
+ UInt16 ExtraSize;
+ };
+ */
+
+ const UInt32 kDataDescriptorSize = 16;
+ // const UInt32 kDataDescriptor64Size = 16 + 8;
+ /*
+ struct CDataDescriptor
+ {
+ UInt32 Signature;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ };
+
+ struct CLocalBlockFull
+ {
+ UInt32 Signature;
+ CLocalBlock Header;
+ };
+ */
+
+ const UInt32 kCentralBlockSize = 42;
+ /*
+ struct CBlock
+ {
+ CVersion MadeByVersion;
+ CVersion ExtractVersion;
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ UInt16 NameSize;
+ UInt16 ExtraSize;
+ UInt16 CommentSize;
+ UInt16 DiskNumberStart;
+ UInt16 InternalAttributes;
+ UInt32 ExternalAttributes;
+ UInt32 LocalHeaderOffset;
+ };
+
+ struct CBlockFull
+ {
+ UInt32 Signature;
+ CBlock Header;
+ };
+ */
+
+ namespace NFlags
+ {
+ const int kEncrypted = 1 << 0;
+ const int kLzmaEOS = 1 << 1;
+ const int kDescriptorUsedMask = 1 << 3;
+ const int kStrongEncrypted = 1 << 6;
+ const int kUtf8 = 1 << 11;
+
+ const int kImplodeDictionarySizeMask = 1 << 1;
+ const int kImplodeLiteralsOnMask = 1 << 2;
+
+ const int kDeflateTypeBitStart = 1;
+ const int kNumDeflateTypeBits = 2;
+ const int kNumDeflateTypes = (1 << kNumDeflateTypeBits);
+ const int kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1;
+ }
+
+ namespace NHostOS
+ {
+ enum EEnum
+ {
+ kFAT = 0,
+ kAMIGA = 1,
+ kVMS = 2, // VAX/VMS
+ kUnix = 3,
+ kVM_CMS = 4,
+ kAtari = 5, // what if it's a minix filesystem? [cjh]
+ kHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
+ kMac = 7,
+ kZ_System = 8,
+ kCPM = 9,
+ kTOPS20 = 10, // pkzip 2.50 NTFS
+ kNTFS = 11, // filesystem used by Windows NT
+ kQDOS = 12, // SMS/QDOS
+ kAcorn = 13, // Archimedes Acorn RISC OS
+ kVFAT = 14, // filesystem used by Windows 95, NT
+ kMVS = 15,
+ kBeOS = 16, // hybrid POSIX/database filesystem
+ kTandem = 17,
+ kOS400 = 18,
+ kOSX = 19
+ };
+ }
+ namespace NUnixAttribute
+ {
+ const UInt32 kIFMT = 0170000; /* Unix file type mask */
+
+ const UInt32 kIFDIR = 0040000; /* Unix directory */
+ const UInt32 kIFREG = 0100000; /* Unix regular file */
+ const UInt32 kIFSOCK = 0140000; /* Unix socket (BSD, not SysV or Amiga) */
+ const UInt32 kIFLNK = 0120000; /* Unix symbolic link (not SysV, Amiga) */
+ const UInt32 kIFBLK = 0060000; /* Unix block special (not Amiga) */
+ const UInt32 kIFCHR = 0020000; /* Unix character special (not Amiga) */
+ const UInt32 kIFIFO = 0010000; /* Unix fifo (BCC, not MSC or Amiga) */
+
+ const UInt32 kISUID = 04000; /* Unix set user id on execution */
+ const UInt32 kISGID = 02000; /* Unix set group id on execution */
+ const UInt32 kISVTX = 01000; /* Unix directory permissions control */
+ const UInt32 kENFMT = kISGID; /* Unix record locking enforcement flag */
+ const UInt32 kIRWXU = 00700; /* Unix read, write, execute: owner */
+ const UInt32 kIRUSR = 00400; /* Unix read permission: owner */
+ const UInt32 kIWUSR = 00200; /* Unix write permission: owner */
+ const UInt32 kIXUSR = 00100; /* Unix execute permission: owner */
+ const UInt32 kIRWXG = 00070; /* Unix read, write, execute: group */
+ const UInt32 kIRGRP = 00040; /* Unix read permission: group */
+ const UInt32 kIWGRP = 00020; /* Unix write permission: group */
+ const UInt32 kIXGRP = 00010; /* Unix execute permission: group */
+ const UInt32 kIRWXO = 00007; /* Unix read, write, execute: other */
+ const UInt32 kIROTH = 00004; /* Unix read permission: other */
+ const UInt32 kIWOTH = 00002; /* Unix write permission: other */
+ const UInt32 kIXOTH = 00001; /* Unix execute permission: other */
+ }
+
+ namespace NAmigaAttribute
+ {
+ const UInt32 kIFMT = 06000; /* Amiga file type mask */
+ const UInt32 kIFDIR = 04000; /* Amiga directory */
+ const UInt32 kIFREG = 02000; /* Amiga regular file */
+ const UInt32 kIHIDDEN = 00200; /* to be supported in AmigaDOS 3.x */
+ const UInt32 kISCRIPT = 00100; /* executable script (text command file) */
+ const UInt32 kIPURE = 00040; /* allow loading into resident memory */
+ const UInt32 kIARCHIVE = 00020; /* not modified since bit was last set */
+ const UInt32 kIREAD = 00010; /* can be opened for reading */
+ const UInt32 kIWRITE = 00004; /* can be opened for writing */
+ const UInt32 kIEXECUTE = 00002; /* executable image, a loadable runfile */
+ const UInt32 kIDELETE = 00001; /* can be deleted */
+ }
+}
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.cpp
new file mode 100644
index 000000000..b36b61be7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -0,0 +1,893 @@
+// Archive/ZipIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "Common/DynamicBuffer.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "ZipIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NZip {
+
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ _inBufMode = false;
+ Close();
+ RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition));
+ m_Position = m_StreamStartPosition;
+ RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit));
+ RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL));
+ m_Stream = stream;
+ return S_OK;
+}
+
+void CInArchive::Close()
+{
+ _inBuffer.ReleaseStream();
+ m_Stream.Release();
+}
+
+HRESULT CInArchive::Seek(UInt64 offset)
+{
+ return m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+}
+
+//////////////////////////////////////
+// Markers
+
+static inline bool TestMarkerCandidate(const Byte *p, UInt32 &value)
+{
+ value = Get32(p);
+ return
+ (value == NSignature::kLocalFileHeader) ||
+ (value == NSignature::kEndOfCentralDir);
+}
+
+static const UInt32 kNumMarkerAddtionalBytes = 2;
+static inline bool TestMarkerCandidate2(const Byte *p, UInt32 &value)
+{
+ value = Get32(p);
+ if (value == NSignature::kEndOfCentralDir)
+ return (Get16(p + 4) == 0);
+ return (value == NSignature::kLocalFileHeader && p[4] < 128);
+}
+
+HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ ArcInfo.Clear();
+ m_Position = m_StreamStartPosition;
+
+ Byte marker[NSignature::kMarkerSize];
+ RINOK(ReadStream_FALSE(stream, marker, NSignature::kMarkerSize));
+ m_Position += NSignature::kMarkerSize;
+ if (TestMarkerCandidate(marker, m_Signature))
+ return S_OK;
+
+ CByteDynamicBuffer dynamicBuffer;
+ const UInt32 kSearchMarkerBufferSize = 0x10000;
+ dynamicBuffer.EnsureCapacity(kSearchMarkerBufferSize);
+ Byte *buffer = dynamicBuffer;
+ UInt32 numBytesPrev = NSignature::kMarkerSize - 1;
+ memcpy(buffer, marker + 1, numBytesPrev);
+ UInt64 curTestPos = m_StreamStartPosition + 1;
+ for (;;)
+ {
+ if (searchHeaderSizeLimit != NULL)
+ if (curTestPos - m_StreamStartPosition > *searchHeaderSizeLimit)
+ break;
+ size_t numReadBytes = kSearchMarkerBufferSize - numBytesPrev;
+ RINOK(ReadStream(stream, buffer + numBytesPrev, &numReadBytes));
+ m_Position += numReadBytes;
+ UInt32 numBytesInBuffer = numBytesPrev + (UInt32)numReadBytes;
+ const UInt32 kMarker2Size = NSignature::kMarkerSize + kNumMarkerAddtionalBytes;
+ if (numBytesInBuffer < kMarker2Size)
+ break;
+ UInt32 numTests = numBytesInBuffer - kMarker2Size + 1;
+ for (UInt32 pos = 0; pos < numTests; pos++)
+ {
+ if (buffer[pos] != 0x50)
+ continue;
+ if (TestMarkerCandidate2(buffer + pos, m_Signature))
+ {
+ curTestPos += pos;
+ ArcInfo.StartPosition = curTestPos;
+ m_Position = curTestPos + NSignature::kMarkerSize;
+ return S_OK;
+ }
+ }
+ curTestPos += numTests;
+ numBytesPrev = numBytesInBuffer - numTests;
+ memmove(buffer, buffer + numTests, numBytesPrev);
+ }
+ return S_FALSE;
+}
+
+HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t realProcessedSize = size;
+ HRESULT result = S_OK;
+ if (_inBufMode)
+ {
+ try { realProcessedSize = _inBuffer.ReadBytes((Byte *)data, size); }
+ catch (const CInBufferException &e) { return e.ErrorCode; }
+ }
+ else
+ result = ReadStream(m_Stream, data, &realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize = (UInt32)realProcessedSize;
+ m_Position += realProcessedSize;
+ return result;
+}
+
+void CInArchive::Skip(UInt64 num)
+{
+ for (UInt64 i = 0; i < num; i++)
+ ReadByte();
+}
+
+void CInArchive::IncreaseRealPosition(UInt64 addValue)
+{
+ if (m_Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position) != S_OK)
+ throw CInArchiveException(CInArchiveException::kSeekStreamError);
+}
+
+bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
+{
+ UInt32 realProcessedSize;
+ if (ReadBytes(data, size, &realProcessedSize) != S_OK)
+ throw CInArchiveException(CInArchiveException::kReadStreamError);
+ return (realProcessedSize == size);
+}
+
+void CInArchive::SafeReadBytes(void *data, UInt32 size)
+{
+ if (!ReadBytesAndTestSize(data, size))
+ throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
+}
+
+void CInArchive::ReadBuffer(CByteBuffer &buffer, UInt32 size)
+{
+ buffer.SetCapacity(size);
+ if (size > 0)
+ SafeReadBytes(buffer, size);
+}
+
+Byte CInArchive::ReadByte()
+{
+ Byte b;
+ SafeReadBytes(&b, 1);
+ return b;
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ Byte buf[2];
+ SafeReadBytes(buf, 2);
+ return Get16(buf);
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ Byte buf[4];
+ SafeReadBytes(buf, 4);
+ return Get32(buf);
+}
+
+UInt64 CInArchive::ReadUInt64()
+{
+ Byte buf[8];
+ SafeReadBytes(buf, 8);
+ return Get64(buf);
+}
+
+bool CInArchive::ReadUInt32(UInt32 &value)
+{
+ Byte buf[4];
+ if (!ReadBytesAndTestSize(buf, 4))
+ return false;
+ value = Get32(buf);
+ return true;
+}
+
+void CInArchive::ReadFileName(UInt32 nameSize, AString &dest)
+{
+ if (nameSize == 0)
+ dest.Empty();
+ char *p = dest.GetBuffer((int)nameSize);
+ SafeReadBytes(p, nameSize);
+ p[nameSize] = 0;
+ dest.ReleaseBuffer();
+}
+
+void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
+ UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber)
+{
+ extraBlock.Clear();
+ UInt32 remain = extraSize;
+ while(remain >= 4)
+ {
+ CExtraSubBlock subBlock;
+ subBlock.ID = ReadUInt16();
+ UInt32 dataSize = ReadUInt16();
+ remain -= 4;
+ if (dataSize > remain) // it's bug
+ dataSize = remain;
+ if (subBlock.ID == NFileHeader::NExtraID::kZip64)
+ {
+ if (unpackSize == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ unpackSize = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (packSize == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ packSize = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (localHeaderOffset == 0xFFFFFFFF)
+ {
+ if (dataSize < 8)
+ break;
+ localHeaderOffset = ReadUInt64();
+ remain -= 8;
+ dataSize -= 8;
+ }
+ if (diskStartNumber == 0xFFFF)
+ {
+ if (dataSize < 4)
+ break;
+ diskStartNumber = ReadUInt32();
+ remain -= 4;
+ dataSize -= 4;
+ }
+ for (UInt32 i = 0; i < dataSize; i++)
+ ReadByte();
+ }
+ else
+ {
+ ReadBuffer(subBlock.Data, dataSize);
+ extraBlock.SubBlocks.Add(subBlock);
+ }
+ remain -= dataSize;
+ }
+ Skip(remain);
+}
+
+HRESULT CInArchive::ReadLocalItem(CItemEx &item)
+{
+ const int kBufSize = 26;
+ Byte p[kBufSize];
+ SafeReadBytes(p, kBufSize);
+
+ item.ExtractVersion.Version = p[0];
+ item.ExtractVersion.HostOS = p[1];
+ item.Flags = Get16(p + 2);
+ item.CompressionMethod = Get16(p + 4);
+ item.Time = Get32(p + 6);
+ item.FileCRC = Get32(p + 10);
+ item.PackSize = Get32(p + 14);
+ item.UnPackSize = Get32(p + 18);
+ UInt32 fileNameSize = Get16(p + 22);
+ item.LocalExtraSize = Get16(p + 24);
+ ReadFileName(fileNameSize, item.Name);
+ item.FileHeaderWithNameSize = 4 + NFileHeader::kLocalBlockSize + fileNameSize;
+ if (item.LocalExtraSize > 0)
+ {
+ UInt64 localHeaderOffset = 0;
+ UInt32 diskStartNumber = 0;
+ ReadExtra(item.LocalExtraSize, item.LocalExtra, item.UnPackSize, item.PackSize,
+ localHeaderOffset, diskStartNumber);
+ }
+ /*
+ if (item.IsDir())
+ item.UnPackSize = 0; // check It
+ */
+ return S_OK;
+}
+
+static bool FlagsAreSame(CItem &i1, CItem &i2)
+{
+ if (i1.CompressionMethod != i2.CompressionMethod)
+ return false;
+ // i1.Time
+
+ if (i1.Flags == i2.Flags)
+ return true;
+ UInt32 mask = 0xFFFF;
+ switch(i1.CompressionMethod)
+ {
+ case NFileHeader::NCompressionMethod::kDeflated:
+ mask = 0x7FF9;
+ break;
+ default:
+ if (i1.CompressionMethod <= NFileHeader::NCompressionMethod::kImploded)
+ mask = 0x7FFF;
+ }
+ return ((i1.Flags & mask) == (i2.Flags & mask));
+}
+
+HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item)
+{
+ if (item.FromLocal)
+ return S_OK;
+ try
+ {
+ RINOK(Seek(ArcInfo.Base + item.LocalHeaderPosition));
+ CItemEx localItem;
+ if (ReadUInt32() != NSignature::kLocalFileHeader)
+ return S_FALSE;
+ RINOK(ReadLocalItem(localItem));
+ if (!FlagsAreSame(item, localItem))
+ return S_FALSE;
+
+ if ((!localItem.HasDescriptor() &&
+ (
+ item.FileCRC != localItem.FileCRC ||
+ item.PackSize != localItem.PackSize ||
+ item.UnPackSize != localItem.UnPackSize
+ )
+ ) ||
+ item.Name.Length() != localItem.Name.Length()
+ )
+ return S_FALSE;
+ item.FileHeaderWithNameSize = localItem.FileHeaderWithNameSize;
+ item.LocalExtraSize = localItem.LocalExtraSize;
+ item.LocalExtra = localItem.LocalExtra;
+ item.FromLocal = true;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item)
+{
+ if (item.HasDescriptor())
+ {
+ const int kBufferSize = (1 << 12);
+ Byte buffer[kBufferSize];
+
+ UInt32 numBytesInBuffer = 0;
+ UInt32 packedSize = 0;
+
+ bool descriptorWasFound = false;
+ for (;;)
+ {
+ UInt32 processedSize;
+ RINOK(ReadBytes(buffer + numBytesInBuffer, kBufferSize - numBytesInBuffer, &processedSize));
+ numBytesInBuffer += processedSize;
+ if (numBytesInBuffer < NFileHeader::kDataDescriptorSize)
+ return S_FALSE;
+ UInt32 i;
+ for (i = 0; i <= numBytesInBuffer - NFileHeader::kDataDescriptorSize; i++)
+ {
+ // descriptorSignature field is Info-ZIP's extension
+ // to Zip specification.
+ UInt32 descriptorSignature = Get32(buffer + i);
+
+ // !!!! It must be fixed for Zip64 archives
+ UInt32 descriptorPackSize = Get32(buffer + i + 8);
+ if (descriptorSignature== NSignature::kDataDescriptor && descriptorPackSize == packedSize + i)
+ {
+ descriptorWasFound = true;
+ item.FileCRC = Get32(buffer + i + 4);
+ item.PackSize = descriptorPackSize;
+ item.UnPackSize = Get32(buffer + i + 12);
+ IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - NFileHeader::kDataDescriptorSize))));
+ break;
+ }
+ }
+ if (descriptorWasFound)
+ break;
+ packedSize += i;
+ int j;
+ for (j = 0; i < numBytesInBuffer; i++, j++)
+ buffer[j] = buffer[i];
+ numBytesInBuffer = j;
+ }
+ }
+ else
+ IncreaseRealPosition(item.PackSize);
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item)
+{
+ if (item.FromLocal)
+ return S_OK;
+ try
+ {
+ RINOK(ReadLocalItemAfterCdItem(item));
+ if (item.HasDescriptor())
+ {
+ RINOK(Seek(ArcInfo.Base + item.GetDataPosition() + item.PackSize));
+ if (ReadUInt32() != NSignature::kDataDescriptor)
+ return S_FALSE;
+ UInt32 crc = ReadUInt32();
+ UInt64 packSize, unpackSize;
+
+ /*
+ if (IsZip64)
+ {
+ packSize = ReadUInt64();
+ unpackSize = ReadUInt64();
+ }
+ else
+ */
+ {
+ packSize = ReadUInt32();
+ unpackSize = ReadUInt32();
+ }
+
+ if (crc != item.FileCRC || item.PackSize != packSize || item.UnPackSize != unpackSize)
+ return S_FALSE;
+ }
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadCdItem(CItemEx &item)
+{
+ item.FromCentral = true;
+ const int kBufSize = 42;
+ Byte p[kBufSize];
+ SafeReadBytes(p, kBufSize);
+ item.MadeByVersion.Version = p[0];
+ item.MadeByVersion.HostOS = p[1];
+ item.ExtractVersion.Version = p[2];
+ item.ExtractVersion.HostOS = p[3];
+ item.Flags = Get16(p + 4);
+ item.CompressionMethod = Get16(p + 6);
+ item.Time = Get32(p + 8);
+ item.FileCRC = Get32(p + 12);
+ item.PackSize = Get32(p + 16);
+ item.UnPackSize = Get32(p + 20);
+ UInt16 headerNameSize = Get16(p + 24);
+ UInt16 headerExtraSize = Get16(p + 26);
+ UInt16 headerCommentSize = Get16(p + 28);
+ UInt32 headerDiskNumberStart = Get16(p + 30);
+ item.InternalAttributes = Get16(p + 32);
+ item.ExternalAttributes = Get32(p + 34);
+ item.LocalHeaderPosition = Get32(p + 38);
+ ReadFileName(headerNameSize, item.Name);
+
+ if (headerExtraSize > 0)
+ {
+ ReadExtra(headerExtraSize, item.CentralExtra, item.UnPackSize, item.PackSize,
+ item.LocalHeaderPosition, headerDiskNumberStart);
+ }
+
+ if (headerDiskNumberStart != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+
+ // May be these strings must be deleted
+ /*
+ if (item.IsDir())
+ item.UnPackSize = 0;
+ */
+
+ ReadBuffer(item.Comment, headerCommentSize);
+ return S_OK;
+}
+
+HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
+{
+ RINOK(Seek(offset));
+ const UInt32 kEcd64Size = 56;
+ Byte buf[kEcd64Size];
+ if (!ReadBytesAndTestSize(buf, kEcd64Size))
+ return S_FALSE;
+ if (Get32(buf) != NSignature::kZip64EndOfCentralDir)
+ return S_FALSE;
+ // cdInfo.NumEntries = Get64(buf + 24);
+ cdInfo.Size = Get64(buf + 40);
+ cdInfo.Offset = Get64(buf + 48);
+ return S_OK;
+}
+
+HRESULT CInArchive::FindCd(CCdInfo &cdInfo)
+{
+ UInt64 endPosition;
+ RINOK(m_Stream->Seek(0, STREAM_SEEK_END, &endPosition));
+ const UInt32 kBufSizeMax = (1 << 16) + kEcdSize + kZip64EcdLocatorSize;
+ CByteBuffer byteBuffer;
+ byteBuffer.SetCapacity(kBufSizeMax);
+ Byte *buf = byteBuffer;
+ UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeMax;
+ if (bufSize < kEcdSize)
+ return S_FALSE;
+ UInt64 startPosition = endPosition - bufSize;
+ RINOK(m_Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != startPosition)
+ return S_FALSE;
+ if (!ReadBytesAndTestSize(buf, bufSize))
+ return S_FALSE;
+ for (int i = (int)(bufSize - kEcdSize); i >= 0; i--)
+ {
+ if (Get32(buf + i) == NSignature::kEndOfCentralDir)
+ {
+ if (i >= kZip64EcdLocatorSize)
+ {
+ const Byte *locator = buf + i - kZip64EcdLocatorSize;
+ if (Get32(locator) == NSignature::kZip64EndOfCentralDirLocator)
+ {
+ UInt64 ecd64Offset = Get64(locator + 8);
+ if (TryEcd64(ecd64Offset, cdInfo) == S_OK)
+ return S_OK;
+ if (TryEcd64(ArcInfo.StartPosition + ecd64Offset, cdInfo) == S_OK)
+ {
+ ArcInfo.Base = ArcInfo.StartPosition;
+ return S_OK;
+ }
+ }
+ }
+ if (Get32(buf + i + 4) == 0)
+ {
+ // cdInfo.NumEntries = GetUInt16(buf + i + 10);
+ cdInfo.Size = Get32(buf + i + 12);
+ cdInfo.Offset = Get32(buf + i + 16);
+ UInt64 curPos = endPosition - bufSize + i;
+ UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
+ if (curPos != cdEnd)
+ {
+ /*
+ if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
+ {
+ // here we support some rare ZIP files with Central directory at the start
+ ArcInfo.Base = 0;
+ }
+ else
+ */
+ ArcInfo.Base = curPos - cdEnd;
+ }
+ return S_OK;
+ }
+ }
+ }
+ return S_FALSE;
+}
+
+HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress)
+{
+ items.Clear();
+ RINOK(m_Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != cdOffset)
+ return S_FALSE;
+
+ if (!_inBuffer.Create(1 << 15))
+ return E_OUTOFMEMORY;
+ _inBuffer.SetStream(m_Stream);
+ _inBuffer.Init();
+ _inBufMode = true;
+
+ while(m_Position - cdOffset < cdSize)
+ {
+ if (ReadUInt32() != NSignature::kCentralFileHeader)
+ return S_FALSE;
+ CItemEx cdItem;
+ RINOK(ReadCdItem(cdItem));
+ items.Add(cdItem);
+ if (progress && items.Size() % 1000 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ }
+ return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress)
+{
+ ArcInfo.Base = 0;
+ CCdInfo cdInfo;
+ RINOK(FindCd(cdInfo));
+ HRESULT res = S_FALSE;
+ cdSize = cdInfo.Size;
+ cdOffset = cdInfo.Offset;
+ res = TryReadCd(items, ArcInfo.Base + cdOffset, cdSize, progress);
+ if (res == S_FALSE && ArcInfo.Base == 0)
+ {
+ res = TryReadCd(items, cdInfo.Offset + ArcInfo.StartPosition, cdSize, progress);
+ if (res == S_OK)
+ ArcInfo.Base = ArcInfo.StartPosition;
+ }
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ return res;
+}
+
+HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems)
+{
+ items.Clear();
+ numCdItems = 0;
+ while (m_Signature == NSignature::kLocalFileHeader)
+ {
+ // FSeek points to next byte after signature
+ // NFileHeader::CLocalBlock localHeader;
+ CItemEx item;
+ item.LocalHeaderPosition = m_Position - m_StreamStartPosition - 4; // points to signature;
+ RINOK(ReadLocalItem(item));
+ item.FromLocal = true;
+ ReadLocalItemDescriptor(item);
+ items.Add(item);
+ if (progress && items.Size() % 100 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ if (!ReadUInt32(m_Signature))
+ break;
+ }
+ cdOffset = m_Position - 4;
+ int i;
+ for (i = 0; i < items.Size(); i++, numCdItems++)
+ {
+ if (progress && i % 1000 == 0)
+ RINOK(progress->SetCompleted(items.Size()));
+ if (m_Signature == NSignature::kEndOfCentralDir)
+ break;
+
+ if (m_Signature != NSignature::kCentralFileHeader)
+ return S_FALSE;
+
+ CItemEx cdItem;
+ RINOK(ReadCdItem(cdItem));
+
+ if (i == 0)
+ {
+ int j;
+ for (j = 0; j < items.Size(); j++)
+ {
+ CItemEx &item = items[j];
+ if (item.Name == cdItem.Name)
+ {
+ ArcInfo.Base = item.LocalHeaderPosition - cdItem.LocalHeaderPosition;
+ break;
+ }
+ }
+ if (j == items.Size())
+ return S_FALSE;
+ }
+
+ int index;
+ int left = 0, right = items.Size();
+ for (;;)
+ {
+ if (left >= right)
+ return S_FALSE;
+ index = (left + right) / 2;
+ UInt64 position = items[index].LocalHeaderPosition - ArcInfo.Base;
+ if (cdItem.LocalHeaderPosition == position)
+ break;
+ if (cdItem.LocalHeaderPosition < position)
+ right = index;
+ else
+ left = index + 1;
+ }
+ CItemEx &item = items[index];
+ // item.LocalHeaderPosition = cdItem.LocalHeaderPosition;
+ item.MadeByVersion = cdItem.MadeByVersion;
+ item.CentralExtra = cdItem.CentralExtra;
+
+ if (
+ // item.ExtractVersion != cdItem.ExtractVersion ||
+ !FlagsAreSame(item, cdItem) ||
+ item.FileCRC != cdItem.FileCRC)
+ return S_FALSE;
+
+ if (item.Name.Length() != cdItem.Name.Length() ||
+ item.PackSize != cdItem.PackSize ||
+ item.UnPackSize != cdItem.UnPackSize
+ )
+ return S_FALSE;
+ item.Name = cdItem.Name;
+ item.InternalAttributes = cdItem.InternalAttributes;
+ item.ExternalAttributes = cdItem.ExternalAttributes;
+ item.Comment = cdItem.Comment;
+ item.FromCentral = cdItem.FromCentral;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ }
+ for (i = 0; i < items.Size(); i++)
+ items[i].LocalHeaderPosition -= ArcInfo.Base;
+ return S_OK;
+}
+
+struct CEcd
+{
+ UInt16 thisDiskNumber;
+ UInt16 startCDDiskNumber;
+ UInt16 numEntriesInCDOnThisDisk;
+ UInt16 numEntriesInCD;
+ UInt32 cdSize;
+ UInt32 cdStartOffset;
+ UInt16 commentSize;
+ void Parse(const Byte *p);
+};
+
+void CEcd::Parse(const Byte *p)
+{
+ thisDiskNumber = Get16(p);
+ startCDDiskNumber = Get16(p + 2);
+ numEntriesInCDOnThisDisk = Get16(p + 4);
+ numEntriesInCD = Get16(p + 6);
+ cdSize = Get32(p + 8);
+ cdStartOffset = Get32(p + 12);
+ commentSize = Get16(p + 16);
+}
+
+struct CEcd64
+{
+ UInt16 versionMade;
+ UInt16 versionNeedExtract;
+ UInt32 thisDiskNumber;
+ UInt32 startCDDiskNumber;
+ UInt64 numEntriesInCDOnThisDisk;
+ UInt64 numEntriesInCD;
+ UInt64 cdSize;
+ UInt64 cdStartOffset;
+ void Parse(const Byte *p);
+ CEcd64() { memset(this, 0, sizeof(*this)); }
+};
+
+void CEcd64::Parse(const Byte *p)
+{
+ versionMade = Get16(p);
+ versionNeedExtract = Get16(p + 2);
+ thisDiskNumber = Get32(p + 4);
+ startCDDiskNumber = Get32(p + 8);
+ numEntriesInCDOnThisDisk = Get64(p + 12);
+ numEntriesInCD = Get64(p + 20);
+ cdSize = Get64(p + 28);
+ cdStartOffset = Get64(p + 36);
+}
+
+#define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd. n;
+#define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd. n;
+
+HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress)
+{
+ // m_Signature must be kLocalFileHeaderSignature or
+ // kEndOfCentralDirSignature
+ // m_Position points to next byte after signature
+
+ IsZip64 = false;
+ items.Clear();
+
+ UInt64 cdSize, cdStartOffset;
+ HRESULT res;
+ try
+ {
+ res = ReadCd(items, cdStartOffset, cdSize, progress);
+ }
+ catch(CInArchiveException &)
+ {
+ res = S_FALSE;
+ }
+ if (res != S_FALSE && res != S_OK)
+ return res;
+
+ /*
+ if (res != S_OK)
+ return res;
+ res = S_FALSE;
+ */
+
+ int numCdItems = items.Size();
+ if (res == S_FALSE)
+ {
+ _inBufMode = false;
+ ArcInfo.Base = 0;
+ RINOK(m_Stream->Seek(ArcInfo.StartPosition, STREAM_SEEK_SET, &m_Position));
+ if (m_Position != ArcInfo.StartPosition)
+ return S_FALSE;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ RINOK(ReadLocalsAndCd(items, progress, cdStartOffset, numCdItems));
+ cdSize = (m_Position - 4) - cdStartOffset;
+ cdStartOffset -= ArcInfo.Base;
+ }
+
+ CEcd64 ecd64;
+ bool isZip64 = false;
+ UInt64 zip64EcdStartOffset = m_Position - 4 - ArcInfo.Base;
+ if (m_Signature == NSignature::kZip64EndOfCentralDir)
+ {
+ IsZip64 = isZip64 = true;
+ UInt64 recordSize = ReadUInt64();
+
+ const int kBufSize = kZip64EcdSize;
+ Byte buf[kBufSize];
+ SafeReadBytes(buf, kBufSize);
+ ecd64.Parse(buf);
+
+ Skip(recordSize - kZip64EcdSize);
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+ if (ecd64.numEntriesInCDOnThisDisk != numCdItems ||
+ ecd64.numEntriesInCD != numCdItems ||
+ ecd64.cdSize != cdSize ||
+ (ecd64.cdStartOffset != cdStartOffset &&
+ (!items.IsEmpty())))
+ return S_FALSE;
+ }
+ if (m_Signature == NSignature::kZip64EndOfCentralDirLocator)
+ {
+ /* UInt32 startEndCDDiskNumber = */ ReadUInt32();
+ UInt64 endCDStartOffset = ReadUInt64();
+ /* UInt32 numberOfDisks = */ ReadUInt32();
+ if (zip64EcdStartOffset != endCDStartOffset)
+ return S_FALSE;
+ if (!ReadUInt32(m_Signature))
+ return S_FALSE;
+ }
+ if (m_Signature != NSignature::kEndOfCentralDir)
+ return S_FALSE;
+
+ const int kBufSize = kEcdSize - 4;
+ Byte buf[kBufSize];
+ SafeReadBytes(buf, kBufSize);
+ CEcd ecd;
+ ecd.Parse(buf);
+
+ COPY_ECD_ITEM_16(thisDiskNumber);
+ COPY_ECD_ITEM_16(startCDDiskNumber);
+ COPY_ECD_ITEM_16(numEntriesInCDOnThisDisk);
+ COPY_ECD_ITEM_16(numEntriesInCD);
+ COPY_ECD_ITEM_32(cdSize);
+ COPY_ECD_ITEM_32(cdStartOffset);
+
+ ReadBuffer(ArcInfo.Comment, ecd.commentSize);
+
+ if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0)
+ throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported);
+ if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)numCdItems) ||
+ (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) ||
+ (UInt32)ecd64.cdSize != (UInt32)cdSize ||
+ ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdStartOffset &&
+ (!items.IsEmpty())))
+ return S_FALSE;
+
+ _inBufMode = false;
+ _inBuffer.Free();
+ IsOkHeaders = (numCdItems == items.Size());
+ ArcInfo.FinishPosition = m_Position;
+ return S_OK;
+}
+
+ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
+{
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> stream(streamSpec);
+ SeekInArchive(ArcInfo.Base + position);
+ streamSpec->SetStream(m_Stream);
+ streamSpec->Init(size);
+ return stream.Detach();
+}
+
+IInStream* CInArchive::CreateStream()
+{
+ CMyComPtr<IInStream> stream = m_Stream;
+ return stream.Detach();
+}
+
+bool CInArchive::SeekInArchive(UInt64 position)
+{
+ UInt64 newPosition;
+ if (m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition) != S_OK)
+ return false;
+ return (newPosition == position);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.h
new file mode 100644
index 000000000..0565339a0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipIn.h
@@ -0,0 +1,125 @@
+// Archive/ZipIn.h
+
+#ifndef __ZIP_IN_H
+#define __ZIP_IN_H
+
+#include "Common/MyCom.h"
+
+#include "../../IStream.h"
+
+#include "../../Common/InBuffer.h"
+
+#include "ZipHeader.h"
+#include "ZipItemEx.h"
+
+namespace NArchive {
+namespace NZip {
+
+class CInArchiveException
+{
+public:
+ enum ECauseType
+ {
+ kUnexpectedEndOfArchive = 0,
+ kArchiceHeaderCRCError,
+ kFileHeaderCRCError,
+ kIncorrectArchive,
+ kDataDescroptorsAreNotSupported,
+ kMultiVolumeArchiveAreNotSupported,
+ kReadStreamError,
+ kSeekStreamError
+ }
+ Cause;
+ CInArchiveException(ECauseType cause): Cause(cause) {}
+};
+
+class CInArchiveInfo
+{
+public:
+ UInt64 Base;
+ UInt64 StartPosition;
+ UInt64 FinishPosition;
+ CByteBuffer Comment;
+
+ CInArchiveInfo(): Base(0), StartPosition(0) {}
+ UInt64 GetPhySize() const { return FinishPosition - StartPosition; }
+ void Clear()
+ {
+ Base = 0;
+ StartPosition = 0;
+ Comment.SetCapacity(0);
+ }
+};
+
+class CProgressVirt
+{
+public:
+ STDMETHOD(SetTotal)(UInt64 numFiles) PURE;
+ STDMETHOD(SetCompleted)(UInt64 numFiles) PURE;
+};
+
+struct CCdInfo
+{
+ // UInt64 NumEntries;
+ UInt64 Size;
+ UInt64 Offset;
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+ UInt32 m_Signature;
+ UInt64 m_StreamStartPosition;
+ UInt64 m_Position;
+
+ bool _inBufMode;
+ CInBuffer _inBuffer;
+
+ HRESULT Seek(UInt64 offset);
+
+ HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+ void ReadFileName(UInt32 nameSize, AString &dest);
+
+ HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize);
+ bool ReadBytesAndTestSize(void *data, UInt32 size);
+ void SafeReadBytes(void *data, UInt32 size);
+ void ReadBuffer(CByteBuffer &buffer, UInt32 size);
+ Byte ReadByte();
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ bool ReadUInt32(UInt32 &signature);
+
+ void Skip(UInt64 num);
+ void IncreaseRealPosition(UInt64 addValue);
+
+ void ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock,
+ UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber);
+ HRESULT ReadLocalItem(CItemEx &item);
+ HRESULT ReadLocalItemDescriptor(CItemEx &item);
+ HRESULT ReadCdItem(CItemEx &item);
+ HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo);
+ HRESULT FindCd(CCdInfo &cdInfo);
+ HRESULT TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress);
+ HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress);
+ HRESULT ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems);
+public:
+ CInArchiveInfo ArcInfo;
+ bool IsZip64;
+ bool IsOkHeaders;
+
+ HRESULT ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress);
+ HRESULT ReadLocalItemAfterCdItem(CItemEx &item);
+ HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item);
+ HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+ void Close();
+ bool SeekInArchive(UInt64 position);
+ ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size);
+ IInStream* CreateStream();
+
+ bool IsOpen() const { return m_Stream != NULL; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.cpp
new file mode 100644
index 000000000..139b01291
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -0,0 +1,172 @@
+// Archive/ZipItem.cpp
+
+#include "StdAfx.h"
+
+#include "ZipHeader.h"
+#include "ZipItem.h"
+#include "../Common/ItemNameUtils.h"
+#include "../../../../C/CpuArch.h"
+
+namespace NArchive {
+namespace NZip {
+
+bool operator==(const CVersion &v1, const CVersion &v2)
+{
+ return (v1.Version == v2.Version) && (v1.HostOS == v2.HostOS);
+}
+
+bool operator!=(const CVersion &v1, const CVersion &v2)
+{
+ return !(v1 == v2);
+}
+
+bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const
+{
+ ft.dwHighDateTime = ft.dwLowDateTime = 0;
+ UInt32 size = (UInt32)Data.GetCapacity();
+ if (ID != NFileHeader::NExtraID::kNTFS || size < 32)
+ return false;
+ const Byte *p = (const Byte *)Data;
+ p += 4; // for reserved
+ size -= 4;
+ while (size > 4)
+ {
+ UInt16 tag = GetUi16(p);
+ UInt32 attrSize = GetUi16(p + 2);
+ p += 4;
+ size -= 4;
+ if (attrSize > size)
+ attrSize = size;
+
+ if (tag == NFileHeader::NNtfsExtra::kTagTime && attrSize >= 24)
+ {
+ p += 8 * index;
+ ft.dwLowDateTime = GetUi32(p);
+ ft.dwHighDateTime = GetUi32(p + 4);
+ return true;
+ }
+ p += attrSize;
+ size -= attrSize;
+ }
+ return false;
+}
+
+bool CExtraSubBlock::ExtractUnixTime(int index, UInt32 &res) const
+{
+ res = 0;
+ UInt32 size = (UInt32)Data.GetCapacity();
+ if (ID != NFileHeader::NExtraID::kUnixTime || size < 5)
+ return false;
+ const Byte *p = (const Byte *)Data;
+ Byte flags = *p++;
+ size--;
+ for (int i = 0; i < 3; i++)
+ if ((flags & (1 << i)) != 0)
+ {
+ if (size < 4)
+ return false;
+ if (index == i)
+ {
+ res = GetUi32(p);
+ return true;
+ }
+ p += 4;
+ size -= 4;
+ }
+ return false;
+}
+
+bool CLocalItem::IsDir() const
+{
+ return NItemName::HasTailSlash(Name, GetCodePage());
+}
+
+bool CItem::IsDir() const
+{
+ if (NItemName::HasTailSlash(Name, GetCodePage()))
+ return true;
+ if (!FromCentral)
+ return false;
+ WORD highAttributes = WORD((ExternalAttributes >> 16 ) & 0xFFFF);
+ switch(MadeByVersion.HostOS)
+ {
+ case NFileHeader::NHostOS::kAMIGA:
+ switch (highAttributes & NFileHeader::NAmigaAttribute::kIFMT)
+ {
+ case NFileHeader::NAmigaAttribute::kIFDIR: return true;
+ case NFileHeader::NAmigaAttribute::kIFREG: return false;
+ default: return false; // change it throw kUnknownAttributes;
+ }
+ case NFileHeader::NHostOS::kFAT:
+ case NFileHeader::NHostOS::kNTFS:
+ case NFileHeader::NHostOS::kHPFS:
+ case NFileHeader::NHostOS::kVFAT:
+ return ((ExternalAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ case NFileHeader::NHostOS::kAtari:
+ case NFileHeader::NHostOS::kMac:
+ case NFileHeader::NHostOS::kVMS:
+ case NFileHeader::NHostOS::kVM_CMS:
+ case NFileHeader::NHostOS::kAcorn:
+ case NFileHeader::NHostOS::kMVS:
+ return false; // change it throw kUnknownAttributes;
+ default:
+ /*
+ switch (highAttributes & NFileHeader::NUnixAttribute::kIFMT)
+ {
+ case NFileHeader::NUnixAttribute::kIFDIR:
+ return true;
+ default:
+ return false;
+ }
+ */
+ return false;
+ }
+}
+
+UInt32 CLocalItem::GetWinAttributes() const
+{
+ DWORD winAttributes = 0;
+ if (IsDir())
+ winAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAttributes;
+}
+
+UInt32 CItem::GetWinAttributes() const
+{
+ DWORD winAttributes = 0;
+ switch(MadeByVersion.HostOS)
+ {
+ case NFileHeader::NHostOS::kFAT:
+ case NFileHeader::NHostOS::kNTFS:
+ if (FromCentral)
+ winAttributes = ExternalAttributes;
+ break;
+ default:
+ winAttributes = 0; // must be converted from unix value;
+ }
+ if (IsDir()) // test it;
+ winAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAttributes;
+}
+
+void CLocalItem::SetFlagBits(int startBitNumber, int numBits, int value)
+{
+ UInt16 mask = (UInt16)(((1 << numBits) - 1) << startBitNumber);
+ Flags &= ~mask;
+ Flags |= value << startBitNumber;
+}
+
+void CLocalItem::SetBitMask(int bitMask, bool enable)
+{
+ if(enable)
+ Flags |= bitMask;
+ else
+ Flags &= ~bitMask;
+}
+
+void CLocalItem::SetEncrypted(bool encrypted)
+ { SetBitMask(NFileHeader::NFlags::kEncrypted, encrypted); }
+void CLocalItem::SetUtf8(bool isUtf8)
+ { SetBitMask(NFileHeader::NFlags::kUtf8, isUtf8); }
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.h
new file mode 100644
index 000000000..31f2de732
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItem.h
@@ -0,0 +1,281 @@
+// Archive/ZipItem.h
+
+#ifndef __ARCHIVE_ZIP_ITEM_H
+#define __ARCHIVE_ZIP_ITEM_H
+
+#include "Common/Types.h"
+#include "Common/MyString.h"
+#include "Common/Buffer.h"
+#include "Common/UTFConvert.h"
+#include "Common/StringConvert.h"
+
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CVersion
+{
+ Byte Version;
+ Byte HostOS;
+};
+
+bool operator==(const CVersion &v1, const CVersion &v2);
+bool operator!=(const CVersion &v1, const CVersion &v2);
+
+struct CExtraSubBlock
+{
+ UInt16 ID;
+ CByteBuffer Data;
+ bool ExtractNtfsTime(int index, FILETIME &ft) const;
+ bool ExtractUnixTime(int index, UInt32 &res) const;
+};
+
+struct CWzAesExtraField
+{
+ UInt16 VendorVersion; // 0x0001 - AE-1, 0x0002 - AE-2,
+ // UInt16 VendorId; // "AE"
+ Byte Strength; // 1 - 128-bit , 2 - 192-bit , 3 - 256-bit
+ UInt16 Method;
+
+ CWzAesExtraField(): VendorVersion(2), Strength(3), Method(0) {}
+
+ bool NeedCrc() const { return (VendorVersion == 1); }
+
+ bool ParseFromSubBlock(const CExtraSubBlock &sb)
+ {
+ if (sb.ID != NFileHeader::NExtraID::kWzAES)
+ return false;
+ if (sb.Data.GetCapacity() < 7)
+ return false;
+ const Byte *p = (const Byte *)sb.Data;
+ VendorVersion = (((UInt16)p[1]) << 8) | p[0];
+ if (p[2] != 'A' || p[3] != 'E')
+ return false;
+ Strength = p[4];
+ Method = (((UInt16)p[6]) << 16) | p[5];
+ return true;
+ }
+ void SetSubBlock(CExtraSubBlock &sb) const
+ {
+ sb.Data.SetCapacity(7);
+ sb.ID = NFileHeader::NExtraID::kWzAES;
+ Byte *p = (Byte *)sb.Data;
+ p[0] = (Byte)VendorVersion;
+ p[1] = (Byte)(VendorVersion >> 8);
+ p[2] = 'A';
+ p[3] = 'E';
+ p[4] = Strength;
+ p[5] = (Byte)Method;
+ p[6] = (Byte)(Method >> 8);
+ }
+};
+
+namespace NStrongCryptoFlags
+{
+ const UInt16 kDES = 0x6601;
+ const UInt16 kRC2old = 0x6602;
+ const UInt16 k3DES168 = 0x6603;
+ const UInt16 k3DES112 = 0x6609;
+ const UInt16 kAES128 = 0x660E;
+ const UInt16 kAES192 = 0x660F;
+ const UInt16 kAES256 = 0x6610;
+ const UInt16 kRC2 = 0x6702;
+ const UInt16 kBlowfish = 0x6720;
+ const UInt16 kTwofish = 0x6721;
+ const UInt16 kRC4 = 0x6801;
+}
+
+struct CStrongCryptoField
+{
+ UInt16 Format;
+ UInt16 AlgId;
+ UInt16 BitLen;
+ UInt16 Flags;
+
+ bool ParseFromSubBlock(const CExtraSubBlock &sb)
+ {
+ if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt)
+ return false;
+ const Byte *p = (const Byte *)sb.Data;
+ if (sb.Data.GetCapacity() < 8)
+ return false;
+ Format = (((UInt16)p[1]) << 8) | p[0];
+ AlgId = (((UInt16)p[3]) << 8) | p[2];
+ BitLen = (((UInt16)p[5]) << 8) | p[4];
+ Flags = (((UInt16)p[7]) << 8) | p[6];
+ return (Format == 2);
+ }
+};
+
+struct CExtraBlock
+{
+ CObjectVector<CExtraSubBlock> SubBlocks;
+ void Clear() { SubBlocks.Clear(); }
+ size_t GetSize() const
+ {
+ size_t res = 0;
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ res += SubBlocks[i].Data.GetCapacity() + 2 + 2;
+ return res;
+ }
+ bool GetWzAesField(CWzAesExtraField &aesField) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ if (aesField.ParseFromSubBlock(SubBlocks[i]))
+ return true;
+ return false;
+ }
+
+ bool GetStrongCryptoField(CStrongCryptoField &f) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ if (f.ParseFromSubBlock(SubBlocks[i]))
+ return true;
+ return false;
+ }
+
+ bool HasWzAesField() const
+ {
+ CWzAesExtraField aesField;
+ return GetWzAesField(aesField);
+ }
+
+ bool GetNtfsTime(int index, FILETIME &ft) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kNTFS)
+ return sb.ExtractNtfsTime(index, ft);
+ }
+ return false;
+ }
+
+ bool GetUnixTime(int index, UInt32 &res) const
+ {
+ for (int i = 0; i < SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kUnixTime)
+ return sb.ExtractUnixTime(index, res);
+ }
+ return false;
+ }
+
+ /*
+ bool HasStrongCryptoField() const
+ {
+ CStrongCryptoField f;
+ return GetStrongCryptoField(f);
+ }
+ */
+
+ void RemoveUnknownSubBlocks()
+ {
+ for (int i = SubBlocks.Size() - 1; i >= 0; i--)
+ if (SubBlocks[i].ID != NFileHeader::NExtraID::kWzAES)
+ SubBlocks.Delete(i);
+ }
+};
+
+
+class CLocalItem
+{
+public:
+ CVersion ExtractVersion;
+ UInt16 Flags;
+ UInt16 CompressionMethod;
+ UInt32 Time;
+ UInt32 FileCRC;
+ UInt64 PackSize;
+ UInt64 UnPackSize;
+
+ AString Name;
+
+ CExtraBlock LocalExtra;
+
+ bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; }
+
+ bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; }
+ bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; };
+ bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || CompressionMethod == NFileHeader::NCompressionMethod::kWzAES); };
+
+ bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; }
+
+ bool IsDir() const;
+ bool IgnoreItem() const { return false; }
+ UInt32 GetWinAttributes() const;
+
+ bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; }
+
+ UString GetUnicodeString(const AString &s) const
+ {
+ UString res;
+ if (IsUtf8())
+ if (!ConvertUTF8ToUnicode(s, res))
+ res.Empty();
+ if (res.IsEmpty())
+ res = MultiByteToUnicodeString(s, GetCodePage());
+ return res;
+ }
+
+private:
+ void SetFlagBits(int startBitNumber, int numBits, int value);
+ void SetBitMask(int bitMask, bool enable);
+public:
+ void ClearFlags() { Flags = 0; }
+ void SetEncrypted(bool encrypted);
+ void SetUtf8(bool isUtf8);
+
+ WORD GetCodePage() const { return CP_OEMCP; }
+};
+
+class CItem: public CLocalItem
+{
+public:
+ CVersion MadeByVersion;
+ UInt16 InternalAttributes;
+ UInt32 ExternalAttributes;
+
+ UInt64 LocalHeaderPosition;
+
+ FILETIME NtfsMTime;
+ FILETIME NtfsATime;
+ FILETIME NtfsCTime;
+
+ CExtraBlock CentralExtra;
+ CByteBuffer Comment;
+
+ bool FromLocal;
+ bool FromCentral;
+ bool NtfsTimeIsDefined;
+
+ bool IsDir() const;
+ UInt32 GetWinAttributes() const;
+
+ bool IsThereCrc() const
+ {
+ if (CompressionMethod == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ CWzAesExtraField aesField;
+ if (CentralExtra.GetWzAesField(aesField))
+ return aesField.NeedCrc();
+ }
+ return (FileCRC != 0 || !IsDir());
+ }
+
+ WORD GetCodePage() const
+ {
+ return (WORD)((MadeByVersion.HostOS == NFileHeader::NHostOS::kFAT
+ || MadeByVersion.HostOS == NFileHeader::NHostOS::kNTFS
+ ) ? CP_OEMCP : CP_ACP);
+ }
+ CItem() : FromLocal(false), FromCentral(false), NtfsTimeIsDefined(false) {}
+};
+
+}}
+
+#endif
+
+
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItemEx.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItemEx.h
new file mode 100644
index 000000000..ab62cdbb4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipItemEx.h
@@ -0,0 +1,34 @@
+// Archive/ZipItemEx.h
+
+#ifndef __ARCHIVE_ZIP_ITEMEX_H
+#define __ARCHIVE_ZIP_ITEMEX_H
+
+#include "ZipHeader.h"
+#include "ZipItem.h"
+
+namespace NArchive {
+namespace NZip {
+
+class CItemEx: public CItem
+{
+public:
+ UInt32 FileHeaderWithNameSize;
+ UInt16 LocalExtraSize;
+
+ UInt64 GetLocalFullSize() const
+ { return FileHeaderWithNameSize + LocalExtraSize + PackSize +
+ (HasDescriptor() ? NFileHeader::kDataDescriptorSize : 0); };
+ /*
+ UInt64 GetLocalFullSize(bool isZip64) const
+ { return FileHeaderWithNameSize + LocalExtraSize + PackSize +
+ (HasDescriptor() ? (isZip64 ? NFileHeader::kDataDescriptor64Size : NFileHeader::kDataDescriptorSize) : 0); };
+ */
+ UInt64 GetLocalExtraPosition() const
+ { return LocalHeaderPosition + FileHeaderWithNameSize; };
+ UInt64 GetDataPosition() const
+ { return GetLocalExtraPosition() + LocalExtraSize; };
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.cpp
new file mode 100644
index 000000000..aa82143e3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -0,0 +1,289 @@
+// ZipOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/OffsetStream.h"
+
+#include "ZipOut.h"
+
+namespace NArchive {
+namespace NZip {
+
+void COutArchive::Create(IOutStream *outStream)
+{
+ if (!m_OutBuffer.Create(1 << 16))
+ throw CSystemException(E_OUTOFMEMORY);
+ m_Stream = outStream;
+ m_OutBuffer.SetStream(outStream);
+ m_OutBuffer.Init();
+ m_BasePosition = 0;
+}
+
+void COutArchive::MoveBasePosition(UInt64 distanceToMove)
+{
+ m_BasePosition += distanceToMove; // test overflow
+}
+
+void COutArchive::PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption)
+{
+ m_IsZip64 = isZip64;
+ m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0;
+ if (aesEncryption)
+ m_ExtraSize += 4 + 7;
+ m_LocalFileHeaderSize = 4 + NFileHeader::kLocalBlockSize + fileNameLength + m_ExtraSize;
+}
+
+void COutArchive::PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption)
+{
+ // We test it to 0xF8000000 to support case when compressed size
+ // can be larger than uncompressed size.
+ PrepareWriteCompressedDataZip64(fileNameLength, unPackSize >= 0xF8000000, aesEncryption);
+}
+
+void COutArchive::PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
+{
+ bool isUnPack64 = unPackSize >= 0xFFFFFFFF;
+ bool isPack64 = packSize >= 0xFFFFFFFF;
+ bool isZip64 = isPack64 || isUnPack64;
+ PrepareWriteCompressedDataZip64(fileNameLength, isZip64, aesEncryption);
+}
+
+void COutArchive::WriteBytes(const void *buffer, UInt32 size)
+{
+ m_OutBuffer.WriteBytes(buffer, size);
+ m_BasePosition += size;
+}
+
+void COutArchive::WriteByte(Byte b)
+{
+ WriteBytes(&b, 1);
+}
+
+void COutArchive::WriteUInt16(UInt16 value)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteUInt32(UInt32 value)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteUInt64(UInt64 value)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+void COutArchive::WriteExtra(const CExtraBlock &extra)
+{
+ if (extra.SubBlocks.Size() != 0)
+ {
+ for (int i = 0; i < extra.SubBlocks.Size(); i++)
+ {
+ const CExtraSubBlock &subBlock = extra.SubBlocks[i];
+ WriteUInt16(subBlock.ID);
+ WriteUInt16((UInt16)subBlock.Data.GetCapacity());
+ WriteBytes(subBlock.Data, (UInt32)subBlock.Data.GetCapacity());
+ }
+ }
+}
+
+void COutArchive::SeekTo(UInt64 offset)
+{
+ HRESULT res = m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+ if (res != S_OK)
+ throw CSystemException(res);
+}
+
+void COutArchive::WriteLocalHeader(const CLocalItem &item)
+{
+ SeekTo(m_BasePosition);
+
+ bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+
+ WriteUInt32(NSignature::kLocalFileHeader);
+ {
+ Byte ver = item.ExtractVersion.Version;
+ if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
+ ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
+ WriteByte(ver);
+ }
+ WriteByte(item.ExtractVersion.HostOS);
+ WriteUInt16(item.Flags);
+ WriteUInt16(item.CompressionMethod);
+ WriteUInt32(item.Time);
+ WriteUInt32(item.FileCRC);
+ WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
+ WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
+ WriteUInt16((UInt16)item.Name.Length());
+ {
+ UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 16): 0) + item.LocalExtra.GetSize());
+ if (localExtraSize > m_ExtraSize)
+ throw CSystemException(E_FAIL);
+ }
+ WriteUInt16((UInt16)m_ExtraSize); // test it;
+ WriteBytes((const char *)item.Name, item.Name.Length());
+
+ UInt32 extraPos = 0;
+ if (isZip64)
+ {
+ extraPos += 4 + 16;
+ WriteUInt16(NFileHeader::NExtraID::kZip64);
+ WriteUInt16(16);
+ WriteUInt64(item.UnPackSize);
+ WriteUInt64(item.PackSize);
+ }
+
+ WriteExtra(item.LocalExtra);
+ extraPos += (UInt32)item.LocalExtra.GetSize();
+ for (; extraPos < m_ExtraSize; extraPos++)
+ WriteByte(0);
+
+ m_OutBuffer.FlushWithCheck();
+ MoveBasePosition(item.PackSize);
+ SeekTo(m_BasePosition);
+}
+
+void COutArchive::WriteCentralHeader(const CItem &item)
+{
+ bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
+ bool isPack64 = item.PackSize >= 0xFFFFFFFF;
+ bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
+ bool isZip64 = isPack64 || isUnPack64 || isPosition64;
+
+ WriteUInt32(NSignature::kCentralFileHeader);
+ WriteByte(item.MadeByVersion.Version);
+ WriteByte(item.MadeByVersion.HostOS);
+ {
+ Byte ver = item.ExtractVersion.Version;
+ if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
+ ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
+ WriteByte(ver);
+ }
+ WriteByte(item.ExtractVersion.HostOS);
+ WriteUInt16(item.Flags);
+ WriteUInt16(item.CompressionMethod);
+ WriteUInt32(item.Time);
+ WriteUInt32(item.FileCRC);
+ WriteUInt32(isPack64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
+ WriteUInt32(isUnPack64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
+ WriteUInt16((UInt16)item.Name.Length());
+ UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
+ const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8);
+ UInt16 centralExtraSize = (UInt16)(isZip64 ? (4 + zip64ExtraSize) : 0) + (item.NtfsTimeIsDefined ? (4 + kNtfsExtraSize) : 0);
+ centralExtraSize = (UInt16)(centralExtraSize + item.CentralExtra.GetSize());
+ WriteUInt16(centralExtraSize); // test it;
+ WriteUInt16((UInt16)item.Comment.GetCapacity());
+ WriteUInt16(0); // DiskNumberStart;
+ WriteUInt16(item.InternalAttributes);
+ WriteUInt32(item.ExternalAttributes);
+ WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
+ WriteBytes((const char *)item.Name, item.Name.Length());
+ if (isZip64)
+ {
+ WriteUInt16(NFileHeader::NExtraID::kZip64);
+ WriteUInt16(zip64ExtraSize);
+ if(isUnPack64)
+ WriteUInt64(item.UnPackSize);
+ if(isPack64)
+ WriteUInt64(item.PackSize);
+ if(isPosition64)
+ WriteUInt64(item.LocalHeaderPosition);
+ }
+ if (item.NtfsTimeIsDefined)
+ {
+ WriteUInt16(NFileHeader::NExtraID::kNTFS);
+ WriteUInt16(kNtfsExtraSize);
+ WriteUInt32(0); // reserved
+ WriteUInt16(NFileHeader::NNtfsExtra::kTagTime);
+ WriteUInt16(8 * 3);
+ WriteUInt32(item.NtfsMTime.dwLowDateTime);
+ WriteUInt32(item.NtfsMTime.dwHighDateTime);
+ WriteUInt32(item.NtfsATime.dwLowDateTime);
+ WriteUInt32(item.NtfsATime.dwHighDateTime);
+ WriteUInt32(item.NtfsCTime.dwLowDateTime);
+ WriteUInt32(item.NtfsCTime.dwHighDateTime);
+ }
+ WriteExtra(item.CentralExtra);
+ if (item.Comment.GetCapacity() > 0)
+ WriteBytes(item.Comment, (UInt32)item.Comment.GetCapacity());
+}
+
+void COutArchive::WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment)
+{
+ SeekTo(m_BasePosition);
+
+ UInt64 cdOffset = GetCurrentPosition();
+ for(int i = 0; i < items.Size(); i++)
+ WriteCentralHeader(items[i]);
+ UInt64 cd64EndOffset = GetCurrentPosition();
+ UInt64 cdSize = cd64EndOffset - cdOffset;
+ bool cdOffset64 = cdOffset >= 0xFFFFFFFF;
+ bool cdSize64 = cdSize >= 0xFFFFFFFF;
+ bool items64 = items.Size() >= 0xFFFF;
+ bool isZip64 = (cdOffset64 || cdSize64 || items64);
+
+ if (isZip64)
+ {
+ WriteUInt32(NSignature::kZip64EndOfCentralDir);
+ WriteUInt64(kZip64EcdSize); // ThisDiskNumber = 0;
+ WriteUInt16(45); // version
+ WriteUInt16(45); // version
+ WriteUInt32(0); // ThisDiskNumber = 0;
+ WriteUInt32(0); // StartCentralDirectoryDiskNumber;;
+ WriteUInt64((UInt64)items.Size());
+ WriteUInt64((UInt64)items.Size());
+ WriteUInt64((UInt64)cdSize);
+ WriteUInt64((UInt64)cdOffset);
+
+ WriteUInt32(NSignature::kZip64EndOfCentralDirLocator);
+ WriteUInt32(0); // number of the disk with the start of the zip64 end of central directory
+ WriteUInt64(cd64EndOffset);
+ WriteUInt32(1); // total number of disks
+ }
+ WriteUInt32(NSignature::kEndOfCentralDir);
+ WriteUInt16(0); // ThisDiskNumber = 0;
+ WriteUInt16(0); // StartCentralDirectoryDiskNumber;
+ WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
+ WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
+ WriteUInt32(cdSize64 ? 0xFFFFFFFF: (UInt32)cdSize);
+ WriteUInt32(cdOffset64 ? 0xFFFFFFFF: (UInt32)cdOffset);
+ UInt32 commentSize = (UInt32)(comment ? comment->GetCapacity() : 0);
+ WriteUInt16((UInt16)commentSize);
+ if (commentSize > 0)
+ WriteBytes((const Byte *)*comment, commentSize);
+ m_OutBuffer.FlushWithCheck();
+}
+
+void COutArchive::CreateStreamForCompressing(IOutStream **outStream)
+{
+ COffsetOutStream *streamSpec = new COffsetOutStream;
+ CMyComPtr<IOutStream> tempStream(streamSpec);
+ streamSpec->Init(m_Stream, m_BasePosition + m_LocalFileHeaderSize);
+ *outStream = tempStream.Detach();
+}
+
+void COutArchive::SeekToPackedDataPosition()
+{
+ SeekTo(m_BasePosition + m_LocalFileHeaderSize);
+}
+
+void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream)
+{
+ CMyComPtr<ISequentialOutStream> tempStream(m_Stream);
+ *outStream = tempStream.Detach();
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.h
new file mode 100644
index 000000000..2f6349e5c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipOut.h
@@ -0,0 +1,56 @@
+// ZipOut.h
+
+#ifndef __ZIP_OUT_H
+#define __ZIP_OUT_H
+
+#include "Common/MyCom.h"
+
+#include "../../IStream.h"
+#include "../../Common/OutBuffer.h"
+
+#include "ZipItem.h"
+
+namespace NArchive {
+namespace NZip {
+
+// can throw CSystemException and COutBufferException
+
+class COutArchive
+{
+ CMyComPtr<IOutStream> m_Stream;
+ COutBuffer m_OutBuffer;
+
+ UInt64 m_BasePosition;
+ UInt32 m_LocalFileHeaderSize;
+ UInt32 m_ExtraSize;
+ bool m_IsZip64;
+
+ void WriteBytes(const void *buffer, UInt32 size);
+ void WriteByte(Byte b);
+ void WriteUInt16(UInt16 value);
+ void WriteUInt32(UInt32 value);
+ void WriteUInt64(UInt64 value);
+
+ void WriteExtraHeader(const CItem &item);
+ void WriteCentralHeader(const CItem &item);
+ void WriteExtra(const CExtraBlock &extra);
+ void SeekTo(UInt64 offset);
+public:
+ void Create(IOutStream *outStream);
+ void MoveBasePosition(UInt64 distanceToMove);
+ UInt64 GetCurrentPosition() const { return m_BasePosition; };
+ void PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption);
+ void PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption);
+ void PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption);
+ void WriteLocalHeader(const CLocalItem &item);
+
+ void WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment);
+
+ void CreateStreamForCompressing(IOutStream **outStream);
+ void CreateStreamForCopying(ISequentialOutStream **outStream);
+ void SeekToPackedDataPosition();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipRegister.cpp
new file mode 100644
index 000000000..3e7aade85
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipRegister.cpp
@@ -0,0 +1,18 @@
+// ZipRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "ZipHandler.h"
+static IInArchive *CreateArc() { return new NArchive::NZip::CHandler; }
+#ifndef EXTRACT_ONLY
+static IOutArchive *CreateArcOut() { return new NArchive::NZip::CHandler; }
+#else
+#define CreateArcOut 0
+#endif
+
+static CArcInfo g_ArcInfo =
+ { L"zip", L"zip jar xpi odt ods docx xlsx", 0, 1, { 0x50, 0x4B, 0x03, 0x04 }, 4, false, CreateArc, CreateArcOut };
+
+REGISTER_ARC(Zip)
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.cpp
new file mode 100644
index 000000000..d4fdee3d7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -0,0 +1,1068 @@
+// ZipUpdate.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+
+#include "Common/AutoPtr.h"
+#include "Common/Defs.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Defs.h"
+#include "Windows/Thread.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/OutMemStream.h"
+#include "../../Common/ProgressUtils.h"
+#ifndef _7ZIP_ST
+#include "../../Common/ProgressMt.h"
+#endif
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "ZipAddCommon.h"
+#include "ZipOut.h"
+#include "ZipUpdate.h"
+
+using namespace NWindows;
+using namespace NSynchronization;
+
+namespace NArchive {
+namespace NZip {
+
+static const Byte kHostOS =
+ #ifdef _WIN32
+ NFileHeader::NHostOS::kFAT;
+ #else
+ NFileHeader::NHostOS::kUnix;
+ #endif
+
+static const Byte kMadeByHostOS = kHostOS;
+static const Byte kExtractHostOS = kHostOS;
+
+static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored;
+
+static HRESULT CopyBlockToArchive(ISequentialInStream *inStream,
+ COutArchive &outArchive, ICompressProgressInfo *progress)
+{
+ CMyComPtr<ISequentialOutStream> outStream;
+ outArchive.CreateStreamForCopying(&outStream);
+ return NCompress::CopyStream(inStream, outStream, progress);
+}
+
+static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive,
+ const CUpdateRange &range, ICompressProgressInfo *progress)
+{
+ UInt64 position;
+ RINOK(inStream->Seek(range.Position, STREAM_SEEK_SET, &position));
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec);
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(range.Size);
+
+ RINOK(CopyBlockToArchive(inStreamLimited, outArchive, progress));
+ return progress->SetRatioInfo(&range.Size, &range.Size);
+}
+
+static void SetFileHeader(
+ COutArchive &archive,
+ const CCompressionMethodMode &options,
+ const CUpdateItem &ui,
+ CItem &item)
+{
+ item.UnPackSize = ui.Size;
+ bool isDir;
+
+ item.ClearFlags();
+
+ if (ui.NewProperties)
+ {
+ isDir = ui.IsDir;
+ item.Name = ui.Name;
+ item.SetUtf8(ui.IsUtf8);
+ item.ExternalAttributes = ui.Attributes;
+ item.Time = ui.Time;
+ item.NtfsMTime = ui.NtfsMTime;
+ item.NtfsATime = ui.NtfsATime;
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+ }
+ else
+ isDir = item.IsDir();
+
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ item.MadeByVersion.HostOS = kMadeByHostOS;
+ item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
+
+ item.ExtractVersion.HostOS = kExtractHostOS;
+
+ item.InternalAttributes = 0; // test it
+ item.SetEncrypted(!isDir && options.PasswordIsDefined);
+ if (isDir)
+ {
+ item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
+ item.CompressionMethod = kMethodForDirectory;
+ item.PackSize = 0;
+ item.FileCRC = 0; // test it
+ }
+}
+
+static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
+ bool isAesMode, Byte aesKeyMode, CItem &item)
+{
+ item.ExtractVersion.Version = compressingResult.ExtractVersion;
+ item.CompressionMethod = compressingResult.Method;
+ item.FileCRC = compressingResult.CRC;
+ item.UnPackSize = compressingResult.UnpackSize;
+ item.PackSize = compressingResult.PackSize;
+
+ item.LocalExtra.Clear();
+ item.CentralExtra.Clear();
+
+ if (isAesMode)
+ {
+ CWzAesExtraField wzAesField;
+ wzAesField.Strength = aesKeyMode;
+ wzAesField.Method = compressingResult.Method;
+ item.CompressionMethod = NFileHeader::NCompressionMethod::kWzAES;
+ item.FileCRC = 0;
+ CExtraSubBlock sb;
+ wzAesField.SetSubBlock(sb);
+ item.LocalExtra.SubBlocks.Add(sb);
+ item.CentralExtra.SubBlocks.Add(sb);
+ }
+}
+
+#ifndef _7ZIP_ST
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
+
+struct CThreadInfo
+{
+ #ifdef EXTERNAL_CODECS
+ CMyComPtr<ICompressCodecsInfo> _codecsInfo;
+ const CObjectVector<CCodecInfoEx> *_externalCodecs;
+ #endif
+
+ NWindows::CThread Thread;
+ NWindows::NSynchronization::CAutoResetEvent CompressEvent;
+ NWindows::NSynchronization::CAutoResetEvent CompressionCompletedEvent;
+ bool ExitThread;
+
+ CMtCompressProgress *ProgressSpec;
+ CMyComPtr<ICompressProgressInfo> Progress;
+
+ COutMemStream *OutStreamSpec;
+ CMyComPtr<IOutStream> OutStream;
+ CMyComPtr<ISequentialInStream> InStream;
+
+ CAddCommon Coder;
+ HRESULT Result;
+ CCompressingResult CompressingResult;
+
+ bool IsFree;
+ UInt32 UpdateIndex;
+
+ CThreadInfo(const CCompressionMethodMode &options):
+ ExitThread(false),
+ ProgressSpec(0),
+ OutStreamSpec(0),
+ Coder(options)
+ {}
+
+ HRESULT CreateEvents()
+ {
+ RINOK(CompressEvent.CreateIfNotCreated());
+ return CompressionCompletedEvent.CreateIfNotCreated();
+ }
+ HRes CreateThread() { return Thread.Create(CoderThread, this); }
+
+ void WaitAndCode();
+ void StopWaitClose()
+ {
+ ExitThread = true;
+ if (OutStreamSpec != 0)
+ OutStreamSpec->StopWriting(E_ABORT);
+ if (CompressEvent.IsCreated())
+ CompressEvent.Set();
+ Thread.Wait();
+ Thread.Close();
+ }
+
+};
+
+void CThreadInfo::WaitAndCode()
+{
+ for (;;)
+ {
+ CompressEvent.Lock();
+ if (ExitThread)
+ return;
+ Result = Coder.Compress(
+ #ifdef EXTERNAL_CODECS
+ _codecsInfo, _externalCodecs,
+ #endif
+ InStream, OutStream, Progress, CompressingResult);
+ if (Result == S_OK && Progress)
+ Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
+ CompressionCompletedEvent.Set();
+ }
+}
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo)
+{
+ ((CThreadInfo *)threadCoderInfo)->WaitAndCode();
+ return 0;
+}
+
+class CThreads
+{
+public:
+ CObjectVector<CThreadInfo> Threads;
+ ~CThreads()
+ {
+ for (int i = 0; i < Threads.Size(); i++)
+ Threads[i].StopWaitClose();
+ }
+};
+
+struct CMemBlocks2: public CMemLockBlocks
+{
+ CCompressingResult CompressingResult;
+ bool Defined;
+ bool Skip;
+ CMemBlocks2(): Defined(false), Skip(false) {}
+};
+
+class CMemRefs
+{
+public:
+ CMemBlockManagerMt *Manager;
+ CObjectVector<CMemBlocks2> Refs;
+ CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ;
+ ~CMemRefs()
+ {
+ for (int i = 0; i < Refs.Size(); i++)
+ Refs[i].FreeOpt(Manager);
+ }
+};
+
+class CMtProgressMixer2:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ UInt64 ProgressOffset;
+ UInt64 InSizes[2];
+ UInt64 OutSizes[2];
+ CMyComPtr<IProgress> Progress;
+ CMyComPtr<ICompressProgressInfo> RatioProgress;
+ bool _inSizeIsMain;
+public:
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ MY_UNKNOWN_IMP
+ void Create(IProgress *progress, bool inSizeIsMain);
+ void SetProgressOffset(UInt64 progressOffset);
+ HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize);
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain)
+{
+ Progress = progress;
+ Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress);
+ _inSizeIsMain = inSizeIsMain;
+ ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0;
+}
+
+void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset)
+{
+ CriticalSection.Enter();
+ InSizes[1] = OutSizes[1] = 0;
+ ProgressOffset = progressOffset;
+ CriticalSection.Leave();
+}
+
+HRESULT CMtProgressMixer2::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ if (index == 0 && RatioProgress)
+ {
+ RINOK(RatioProgress->SetRatioInfo(inSize, outSize));
+ }
+ if (inSize != 0)
+ InSizes[index] = *inSize;
+ if (outSize != 0)
+ OutSizes[index] = *outSize;
+ UInt64 v = ProgressOffset + (_inSizeIsMain ?
+ (InSizes[0] + InSizes[1]) :
+ (OutSizes[0] + OutSizes[1]));
+ return Progress->SetCompleted(&v);
+}
+
+STDMETHODIMP CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ return SetRatioInfo(0, inSize, outSize);
+}
+
+class CMtProgressMixer:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ CMtProgressMixer2 *Mixer2;
+ CMyComPtr<ICompressProgressInfo> RatioProgress;
+ void Create(IProgress *progress, bool inSizeIsMain);
+ MY_UNKNOWN_IMP
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain)
+{
+ Mixer2 = new CMtProgressMixer2;
+ RatioProgress = Mixer2;
+ Mixer2->Create(progress, inSizeIsMain);
+}
+
+STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ return Mixer2->SetRatioInfo(1, inSize, outSize);
+}
+
+
+#endif
+
+
+static HRESULT UpdateItemOldData(COutArchive &archive,
+ IInStream *inStream,
+ const CUpdateItem &ui, CItemEx &item,
+ /* bool izZip64, */
+ ICompressProgressInfo *progress,
+ UInt64 &complexity)
+{
+ if (ui.NewProperties)
+ {
+ if (item.HasDescriptor())
+ return E_NOTIMPL;
+
+ // use old name size.
+ // CUpdateRange range(item.GetLocalExtraPosition(), item.LocalExtraSize + item.PackSize);
+ CUpdateRange range(item.GetDataPosition(), item.PackSize);
+
+ // item.ExternalAttributes = ui.Attributes;
+ // Test it
+ item.Name = ui.Name;
+ item.SetUtf8(ui.IsUtf8);
+ item.Time = ui.Time;
+ item.NtfsMTime = ui.NtfsMTime;
+ item.NtfsATime = ui.NtfsATime;
+ item.NtfsCTime = ui.NtfsCTime;
+ item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined;
+
+ item.CentralExtra.RemoveUnknownSubBlocks();
+ item.LocalExtra.RemoveUnknownSubBlocks();
+
+ archive.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField());
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+ archive.SeekToPackedDataPosition();
+ RINOK(WriteRange(inStream, archive, range, progress));
+ complexity += range.Size;
+ archive.WriteLocalHeader(item);
+ }
+ else
+ {
+ CUpdateRange range(item.LocalHeaderPosition, item.GetLocalFullSize());
+
+ // set new header position
+ item.LocalHeaderPosition = archive.GetCurrentPosition();
+
+ RINOK(WriteRange(inStream, archive, range, progress));
+ complexity += range.Size;
+ archive.MoveBasePosition(range.Size);
+ }
+ return S_OK;
+}
+
+static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
+ const CUpdateItem &ui, CItemEx &item)
+{
+ SetFileHeader(archive, *options, ui, item);
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ archive.WriteLocalHeader(item);
+}
+
+static HRESULT Update2St(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ COutArchive &archive,
+ CInArchive *inArchive,
+ IInStream *inStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ const CCompressionMethodMode *options,
+ const CByteBuffer *comment,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CAddCommon compressor(*options);
+
+ CObjectVector<CItem> items;
+ UInt64 unpackSizeTotal = 0, packSizeTotal = 0;
+
+ for (int itemIndex = 0; itemIndex < updateItems.Size(); itemIndex++)
+ {
+ lps->InSize = unpackSizeTotal;
+ lps->OutSize = packSizeTotal;
+ RINOK(lps->SetCur());
+ const CUpdateItem &ui = updateItems[itemIndex];
+ CItemEx item;
+ if (!ui.NewProperties || !ui.NewData)
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ }
+
+ if (ui.NewData)
+ {
+ bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir());
+ if (isDir)
+ {
+ WriteDirHeader(archive, options, ui, item);
+ }
+ else
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ lps->ProgressOffset += ui.Size;
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ continue;
+ }
+ RINOK(res);
+
+ // file Size can be 64-bit !!!
+ SetFileHeader(archive, *options, ui, item);
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ CCompressingResult compressingResult;
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ RINOK(compressor.Compress(
+ EXTERNAL_CODECS_LOC_VARS
+ fileInStream, outStream, progress, compressingResult));
+ SetItemInfoFromCompressingResult(compressingResult, options->IsAesMode, options->AesKeyMode, item);
+ archive.WriteLocalHeader(item);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ unpackSizeTotal += item.UnPackSize;
+ packSizeTotal += item.PackSize;
+ }
+ }
+ else
+ {
+ UInt64 complexity = 0;
+ lps->SendRatio = false;
+ RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity));
+ lps->SendRatio = true;
+ lps->ProgressOffset += complexity;
+ }
+ items.Add(item);
+ lps->ProgressOffset += NFileHeader::kLocalBlockSize;
+ }
+ archive.WriteCentralDir(items, comment);
+ return S_OK;
+}
+
+static HRESULT Update2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ COutArchive &archive,
+ CInArchive *inArchive,
+ IInStream *inStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ const CCompressionMethodMode *options,
+ const CByteBuffer *comment,
+ IArchiveUpdateCallback *updateCallback)
+{
+ UInt64 complexity = 0;
+ UInt64 numFilesToCompress = 0;
+ UInt64 numBytesToCompress = 0;
+
+ int i;
+ for(i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ complexity += ui.Size;
+ numBytesToCompress += ui.Size;
+ numFilesToCompress++;
+ /*
+ if (ui.Commented)
+ complexity += ui.CommentRange.Size;
+ */
+ }
+ else
+ {
+ CItemEx inputItem = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(inputItem) != S_OK)
+ return E_NOTIMPL;
+ complexity += inputItem.GetLocalFullSize();
+ // complexity += inputItem.GetCentralExtraPlusCommentSize();
+ }
+ complexity += NFileHeader::kLocalBlockSize;
+ complexity += NFileHeader::kCentralBlockSize;
+ }
+
+ if (comment)
+ complexity += comment->GetCapacity();
+ complexity++; // end of central
+ updateCallback->SetTotal(complexity);
+
+ CAddCommon compressor(*options);
+
+ complexity = 0;
+
+ #ifndef _7ZIP_ST
+
+ const size_t kNumMaxThreads = (1 << 10);
+ UInt32 numThreads = options->NumThreads;
+ if (numThreads > kNumMaxThreads)
+ numThreads = kNumMaxThreads;
+
+ const size_t kMemPerThread = (1 << 25);
+ const size_t kBlockSize = 1 << 16;
+
+ CCompressionMethodMode options2;
+ if (options != 0)
+ options2 = *options;
+
+ bool mtMode = ((options != 0) && (numThreads > 1));
+
+ if (numFilesToCompress <= 1)
+ mtMode = false;
+
+ if (mtMode)
+ {
+ Byte method = options->MethodSequence.Front();
+ if (method == NFileHeader::NCompressionMethod::kStored && !options->PasswordIsDefined)
+ mtMode = false;
+ if (method == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ UInt64 averageSize = numBytesToCompress / numFilesToCompress;
+ UInt32 blockSize = options->DicSize;
+ if (blockSize == 0)
+ blockSize = 1;
+ UInt64 averageNumberOfBlocks = averageSize / blockSize;
+ UInt32 numBZip2Threads = 32;
+ if (averageNumberOfBlocks < numBZip2Threads)
+ numBZip2Threads = (UInt32)averageNumberOfBlocks;
+ if (numBZip2Threads < 1)
+ numBZip2Threads = 1;
+ numThreads = numThreads / numBZip2Threads;
+ options2.NumThreads = numBZip2Threads;
+ if (numThreads <= 1)
+ mtMode = false;
+ }
+ if (method == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ UInt32 numLZMAThreads = (options->Algo > 0 ? 2 : 1);
+ numThreads /= numLZMAThreads;
+ options2.NumThreads = numLZMAThreads;
+ if (numThreads <= 1)
+ mtMode = false;
+ }
+ }
+
+ if (!mtMode)
+ #endif
+ return Update2St(
+ EXTERNAL_CODECS_LOC_VARS
+ archive, inArchive,inStream,
+ inputItems, updateItems, options, comment, updateCallback);
+
+
+ #ifndef _7ZIP_ST
+
+ CObjectVector<CItem> items;
+
+ CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
+ CMyComPtr<ICompressProgressInfo> progress = mtProgressMixerSpec;
+ mtProgressMixerSpec->Create(updateCallback, true);
+
+ CMtCompressProgressMixer mtCompressProgressMixer;
+ mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress);
+
+ CMemBlockManagerMt memManager(kBlockSize);
+ CMemRefs refs(&memManager);
+
+ CThreads threads;
+ CRecordVector<HANDLE> compressingCompletedEvents;
+ CRecordVector<int> threadIndices; // list threads in order of updateItems
+
+ {
+ RINOK(memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize)));
+ for(i = 0; i < updateItems.Size(); i++)
+ refs.Refs.Add(CMemBlocks2());
+
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ threads.Threads.Add(CThreadInfo(options2));
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ #ifdef EXTERNAL_CODECS
+ threadInfo._codecsInfo = codecsInfo;
+ threadInfo._externalCodecs = externalCodecs;
+ #endif
+ RINOK(threadInfo.CreateEvents());
+ threadInfo.OutStreamSpec = new COutMemStream(&memManager);
+ RINOK(threadInfo.OutStreamSpec->CreateEvents());
+ threadInfo.OutStream = threadInfo.OutStreamSpec;
+ threadInfo.IsFree = true;
+ threadInfo.ProgressSpec = new CMtCompressProgress();
+ threadInfo.Progress = threadInfo.ProgressSpec;
+ threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i);
+ RINOK(threadInfo.CreateThread());
+ }
+ }
+ int mtItemIndex = 0;
+
+ int itemIndex = 0;
+ int lastRealStreamItemIndex = -1;
+
+ while (itemIndex < updateItems.Size())
+ {
+ if ((UInt32)threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
+ {
+ const CUpdateItem &ui = updateItems[mtItemIndex++];
+ if (!ui.NewData)
+ continue;
+ CItemEx item;
+ if (ui.NewProperties)
+ {
+ if (ui.IsDir)
+ continue;
+ }
+ else
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ if (item.IsDir())
+ continue;
+ }
+ CMyComPtr<ISequentialInStream> fileInStream;
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ complexity += ui.Size;
+ complexity += NFileHeader::kLocalBlockSize;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ refs.Refs[mtItemIndex - 1].Skip = true;
+ continue;
+ }
+ RINOK(res);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ }
+
+ for (UInt32 i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ if (threadInfo.IsFree)
+ {
+ threadInfo.IsFree = false;
+ threadInfo.InStream = fileInStream;
+
+ // !!!!! we must release ref before sending event
+ // BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time
+ fileInStream.Release();
+
+ threadInfo.OutStreamSpec->Init();
+ threadInfo.ProgressSpec->Reinit();
+ threadInfo.CompressEvent.Set();
+ threadInfo.UpdateIndex = mtItemIndex - 1;
+
+ compressingCompletedEvents.Add(threadInfo.CompressionCompletedEvent);
+ threadIndices.Add(i);
+ break;
+ }
+ }
+ continue;
+ }
+
+ if (refs.Refs[itemIndex].Skip)
+ {
+ itemIndex++;
+ continue;
+ }
+
+ const CUpdateItem &ui = updateItems[itemIndex];
+
+ CItemEx item;
+ if (!ui.NewProperties || !ui.NewData)
+ {
+ item = inputItems[ui.IndexInArchive];
+ if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK)
+ return E_NOTIMPL;
+ }
+
+ if (ui.NewData)
+ {
+ bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir());
+ if (isDir)
+ {
+ WriteDirHeader(archive, options, ui, item);
+ }
+ else
+ {
+ if (lastRealStreamItemIndex < itemIndex)
+ {
+ lastRealStreamItemIndex = itemIndex;
+ SetFileHeader(archive, *options, ui, item);
+ // file Size can be 64-bit !!!
+ archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsAesMode);
+ }
+
+ CMemBlocks2 &memRef = refs.Refs[itemIndex];
+ if (memRef.Defined)
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ memRef.WriteToStream(memManager.GetBlockSize(), outStream);
+ SetItemInfoFromCompressingResult(memRef.CompressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ SetFileHeader(archive, *options, ui, item);
+ archive.WriteLocalHeader(item);
+ // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ memRef.FreeOpt(&memManager);
+ }
+ else
+ {
+ {
+ CThreadInfo &thread = threads.Threads[threadIndices.Front()];
+ if (!thread.OutStreamSpec->WasUnlockEventSent())
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(&outStream);
+ thread.OutStreamSpec->SetOutStream(outStream);
+ thread.OutStreamSpec->SetRealStreamMode();
+ }
+ }
+
+ DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(),
+ &compressingCompletedEvents.Front(), FALSE, INFINITE);
+ int t = (int)(result - WAIT_OBJECT_0);
+ CThreadInfo &threadInfo = threads.Threads[threadIndices[t]];
+ threadInfo.InStream.Release();
+ threadInfo.IsFree = true;
+ RINOK(threadInfo.Result);
+ threadIndices.Delete(t);
+ compressingCompletedEvents.Delete(t);
+ if (t == 0)
+ {
+ RINOK(threadInfo.OutStreamSpec->WriteToRealStream());
+ threadInfo.OutStreamSpec->ReleaseOutStream();
+ SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
+ options->IsAesMode, options->AesKeyMode, item);
+ SetFileHeader(archive, *options, ui, item);
+ archive.WriteLocalHeader(item);
+ }
+ else
+ {
+ CMemBlocks2 &memRef = refs.Refs[threadInfo.UpdateIndex];
+ threadInfo.OutStreamSpec->DetachData(memRef);
+ memRef.CompressingResult = threadInfo.CompressingResult;
+ memRef.Defined = true;
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity));
+ }
+ items.Add(item);
+ complexity += NFileHeader::kLocalBlockSize;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
+ itemIndex++;
+ }
+ archive.WriteCentralDir(items, comment);
+ return S_OK;
+ #endif
+}
+
+static const size_t kCacheBlockSize = (1 << 20);
+static const size_t kCacheSize = (kCacheBlockSize << 2);
+static const size_t kCacheMask = (kCacheSize - 1);
+
+class CCacheOutStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IOutStream> _stream;
+ Byte *_cache;
+ UInt64 _virtPos;
+ UInt64 _virtSize;
+ UInt64 _phyPos;
+ UInt64 _phySize; // <= _virtSize
+ UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize
+ size_t _cachedSize;
+
+ HRESULT MyWrite(size_t size);
+ HRESULT MyWriteBlock()
+ {
+ return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)));
+ }
+ HRESULT FlushCache();
+public:
+ CCacheOutStream(): _cache(0) {}
+ ~CCacheOutStream();
+ bool Allocate();
+ HRESULT Init(IOutStream *stream);
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+bool CCacheOutStream::Allocate()
+{
+ if (!_cache)
+ _cache = (Byte *)::MidAlloc(kCacheSize);
+ return (_cache != NULL);
+}
+
+HRESULT CCacheOutStream::Init(IOutStream *stream)
+{
+ _virtPos = _phyPos = 0;
+ _stream = stream;
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos));
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize));
+ RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos));
+ _phyPos = _virtPos;
+ _phySize = _virtSize;
+ _cachedPos = 0;
+ _cachedSize = 0;
+ return S_OK;
+}
+
+HRESULT CCacheOutStream::MyWrite(size_t size)
+{
+ while (size != 0 && _cachedSize != 0)
+ {
+ if (_phyPos != _cachedPos)
+ {
+ RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos));
+ }
+ size_t pos = (size_t)_cachedPos & kCacheMask;
+ size_t curSize = MyMin(kCacheSize - pos, _cachedSize);
+ curSize = MyMin(curSize, size);
+ RINOK(WriteStream(_stream, _cache + pos, curSize));
+ _phyPos += curSize;
+ if (_phySize < _phyPos)
+ _phySize = _phyPos;
+ _cachedPos += curSize;
+ _cachedSize -= curSize;
+ size -= curSize;
+ }
+ return S_OK;
+}
+
+HRESULT CCacheOutStream::FlushCache()
+{
+ return MyWrite(_cachedSize);
+}
+
+CCacheOutStream::~CCacheOutStream()
+{
+ FlushCache();
+ if (_virtSize != _phySize)
+ _stream->SetSize(_virtSize);
+ if (_virtPos != _phyPos)
+ _stream->Seek(_virtPos, STREAM_SEEK_SET, NULL);
+ ::MidFree(_cache);
+}
+
+STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+
+ UInt64 zerosStart = _virtPos;
+ if (_cachedSize != 0)
+ {
+ if (_virtPos < _cachedPos)
+ {
+ RINOK(FlushCache());
+ }
+ else
+ {
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ if (cachedEnd < _virtPos)
+ {
+ if (cachedEnd < _phySize)
+ {
+ RINOK(FlushCache());
+ }
+ else
+ zerosStart = cachedEnd;
+ }
+ }
+ }
+
+ if (_cachedSize == 0 && _phySize < _virtPos)
+ _cachedPos = zerosStart = _phySize;
+
+ if (zerosStart != _virtPos)
+ {
+ // write zeros to [cachedEnd ... _virtPos)
+
+ for (;;)
+ {
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ size_t endPos = (size_t)cachedEnd & kCacheMask;
+ size_t curSize = kCacheSize - endPos;
+ if (curSize > _virtPos - cachedEnd)
+ curSize = (size_t)(_virtPos - cachedEnd);
+ if (curSize == 0)
+ break;
+ while (curSize > (kCacheSize - _cachedSize))
+ {
+ RINOK(MyWriteBlock());
+ }
+ memset(_cache + endPos, 0, curSize);
+ _cachedSize += curSize;
+ }
+ }
+
+ if (_cachedSize == 0)
+ _cachedPos = _virtPos;
+
+ size_t pos = (size_t)_virtPos & kCacheMask;
+ size = (UInt32)MyMin((size_t)size, kCacheSize - pos);
+ UInt64 cachedEnd = _cachedPos + _cachedSize;
+ if (_virtPos != cachedEnd) // _virtPos < cachedEnd
+ size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos));
+ else
+ {
+ // _virtPos == cachedEnd
+ if (_cachedSize == kCacheSize)
+ {
+ RINOK(MyWriteBlock());
+ }
+ size_t startPos = (size_t)_cachedPos & kCacheMask;
+ if (startPos > pos)
+ size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos));
+ _cachedSize += size;
+ }
+ memcpy(_cache + pos, data, size);
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ if (_virtSize < _virtPos)
+ _virtSize = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = _virtSize + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize)
+{
+ _virtSize = newSize;
+ if (newSize < _phySize)
+ {
+ RINOK(_stream->SetSize(newSize));
+ _phySize = newSize;
+ }
+ if (newSize <= _cachedPos)
+ {
+ _cachedSize = 0;
+ _cachedPos = newSize;
+ }
+ if (newSize < _cachedPos + _cachedSize)
+ _cachedSize = (size_t)(newSize - _cachedPos);
+ return S_OK;
+}
+
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ ISequentialOutStream *seqOutStream,
+ CInArchive *inArchive,
+ CCompressionMethodMode *compressionMethodMode,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CMyComPtr<IOutStream> outStream;
+ {
+ CMyComPtr<IOutStream> outStreamReal;
+ seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
+ if (!outStreamReal)
+ return E_NOTIMPL;
+ CCacheOutStream *cacheStream = new CCacheOutStream();
+ outStream = cacheStream;
+ if (!cacheStream->Allocate())
+ return E_OUTOFMEMORY;
+ RINOK(cacheStream->Init(outStreamReal));
+ }
+
+ if (inArchive)
+ {
+ if (inArchive->ArcInfo.Base != 0 ||
+ inArchive->ArcInfo.StartPosition != 0 ||
+ !inArchive->IsOkHeaders)
+ return E_NOTIMPL;
+ }
+
+ COutArchive outArchive;
+ outArchive.Create(outStream);
+ /*
+ if (inArchive && inArchive->ArcInfo.StartPosition > 0)
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+ inStream.Attach(inArchive->CreateLimitedStream(0, inArchive->ArcInfo.StartPosition));
+ RINOK(CopyBlockToArchive(inStream, outArchive, NULL));
+ outArchive.MoveBasePosition(inArchive->ArcInfo.StartPosition);
+ }
+ */
+ CMyComPtr<IInStream> inStream;
+ if (inArchive)
+ inStream.Attach(inArchive->CreateStream());
+
+ return Update2(
+ EXTERNAL_CODECS_LOC_VARS
+ outArchive, inArchive, inStream,
+ inputItems, updateItems,
+ compressionMethodMode,
+ inArchive ? &inArchive->ArcInfo.Comment : NULL,
+ updateCallback);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.h b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.h
new file mode 100644
index 000000000..eee16738c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Archive/Zip/ZipUpdate.h
@@ -0,0 +1,58 @@
+// Zip/Update.h
+
+#ifndef __ZIP_UPDATE_H
+#define __ZIP_UPDATE_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "ZipCompressionMode.h"
+#include "ZipIn.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CUpdateRange
+{
+ UInt64 Position;
+ UInt64 Size;
+ CUpdateRange() {};
+ CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {};
+};
+
+struct CUpdateItem
+{
+ bool NewData;
+ bool NewProperties;
+ bool IsDir;
+ bool NtfsTimeIsDefined;
+ bool IsUtf8;
+ int IndexInArchive;
+ int IndexInClient;
+ UInt32 Attributes;
+ UInt32 Time;
+ UInt64 Size;
+ AString Name;
+ // bool Commented;
+ // CUpdateRange CommentRange;
+ FILETIME NtfsMTime;
+ FILETIME NtfsATime;
+ FILETIME NtfsCTime;
+
+ CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {}
+};
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ ISequentialOutStream *seqOutStream,
+ CInArchive *inArchive,
+ CCompressionMethodMode *compressionMethodMode,
+ IArchiveUpdateCallback *updateCallback);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/CWrappers.cpp b/src/libs/7zip/win/CPP/7zip/Common/CWrappers.cpp
new file mode 100644
index 000000000..358f0b503
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/CWrappers.cpp
@@ -0,0 +1,226 @@
+// CWrappers.h
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "CWrappers.h"
+
+#include "StreamUtils.h"
+
+#define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1)
+
+#define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x)
+
+static SRes CompressProgress(void *pp, UInt64 inSize, UInt64 outSize)
+{
+ CCompressProgressWrap *p = (CCompressProgressWrap *)pp;
+ p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize));
+ return (SRes)p->Res;
+}
+
+CCompressProgressWrap::CCompressProgressWrap(ICompressProgressInfo *progress)
+{
+ p.Progress = CompressProgress;
+ Progress = progress;
+ Res = SZ_OK;
+}
+
+static const UInt32 kStreamStepSize = (UInt32)1 << 31;
+
+SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes)
+{
+ switch(res)
+ {
+ case S_OK: return SZ_OK;
+ case E_OUTOFMEMORY: return SZ_ERROR_MEM;
+ case E_INVALIDARG: return SZ_ERROR_PARAM;
+ case E_ABORT: return SZ_ERROR_PROGRESS;
+ case S_FALSE: return SZ_ERROR_DATA;
+ }
+ return defaultRes;
+}
+
+static SRes MyRead(void *object, void *data, size_t *size)
+{
+ CSeqInStreamWrap *p = (CSeqInStreamWrap *)object;
+ UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
+ p->Res = (p->Stream->Read(data, curSize, &curSize));
+ *size = curSize;
+ if (p->Res == S_OK)
+ return SZ_OK;
+ return HRESULT_To_SRes(p->Res, SZ_ERROR_READ);
+}
+
+static size_t MyWrite(void *object, const void *data, size_t size)
+{
+ CSeqOutStreamWrap *p = (CSeqOutStreamWrap *)object;
+ if (p->Stream)
+ {
+ p->Res = WriteStream(p->Stream, data, size);
+ if (p->Res != 0)
+ return 0;
+ }
+ else
+ p->Res = S_OK;
+ p->Processed += size;
+ return size;
+}
+
+CSeqInStreamWrap::CSeqInStreamWrap(ISequentialInStream *stream)
+{
+ p.Read = MyRead;
+ Stream = stream;
+}
+
+CSeqOutStreamWrap::CSeqOutStreamWrap(ISequentialOutStream *stream)
+{
+ p.Write = MyWrite;
+ Stream = stream;
+ Res = SZ_OK;
+ Processed = 0;
+}
+
+HRESULT SResToHRESULT(SRes res)
+{
+ switch(res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PARAM: return E_INVALIDARG;
+ case SZ_ERROR_PROGRESS: return E_ABORT;
+ case SZ_ERROR_DATA: return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+static SRes InStreamWrap_Read(void *pp, void *data, size_t *size)
+{
+ CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp;
+ UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
+ p->Res = p->Stream->Read(data, curSize, &curSize);
+ *size = curSize;
+ return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes InStreamWrap_Seek(void *pp, Int64 *offset, ESzSeek origin)
+{
+ CSeekInStreamWrap *p = (CSeekInStreamWrap *)pp;
+ UInt32 moveMethod;
+ switch(origin)
+ {
+ case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break;
+ case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break;
+ case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break;
+ default: return SZ_ERROR_PARAM;
+ }
+ UInt64 newPosition;
+ p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition);
+ *offset = (Int64)newPosition;
+ return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
+}
+
+CSeekInStreamWrap::CSeekInStreamWrap(IInStream *stream)
+{
+ Stream = stream;
+ p.Read = InStreamWrap_Read;
+ p.Seek = InStreamWrap_Seek;
+ Res = S_OK;
+}
+
+
+/* ---------- CByteInBufWrap ---------- */
+
+void CByteInBufWrap::Free()
+{
+ ::MidFree(Buf);
+ Buf = 0;
+}
+
+bool CByteInBufWrap::Alloc(UInt32 size)
+{
+ if (Buf == 0 || size != Size)
+ {
+ Free();
+ Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size);
+ Size = size;
+ }
+ return (Buf != 0);
+}
+
+Byte CByteInBufWrap::ReadByteFromNewBlock()
+{
+ if (Res == S_OK)
+ {
+ UInt32 avail;
+ Processed += (Cur - Buf);
+ Res = Stream->Read(Buf, Size, &avail);
+ Cur = Buf;
+ Lim = Buf + avail;
+ if (avail != 0)
+ return *Cur++;
+ }
+ Extra = true;
+ return 0;
+}
+
+static Byte Wrap_ReadByte(void *pp)
+{
+ CByteInBufWrap *p = (CByteInBufWrap *)pp;
+ if (p->Cur != p->Lim)
+ return *p->Cur++;
+ return p->ReadByteFromNewBlock();
+}
+
+CByteInBufWrap::CByteInBufWrap(): Buf(0)
+{
+ p.Read = Wrap_ReadByte;
+}
+
+
+/* ---------- CByteOutBufWrap ---------- */
+
+void CByteOutBufWrap::Free()
+{
+ ::MidFree(Buf);
+ Buf = 0;
+}
+
+bool CByteOutBufWrap::Alloc(size_t size)
+{
+ if (Buf == 0 || size != Size)
+ {
+ Free();
+ Buf = (Byte *)::MidAlloc(size);
+ Size = size;
+ }
+ return (Buf != 0);
+}
+
+HRESULT CByteOutBufWrap::Flush()
+{
+ if (Res == S_OK)
+ {
+ size_t size = (Cur - Buf);
+ Res = WriteStream(Stream, Buf, size);
+ if (Res == S_OK)
+ Processed += size;
+ Cur = Buf;
+ }
+ return Res;
+}
+
+static void Wrap_WriteByte(void *pp, Byte b)
+{
+ CByteOutBufWrap *p = (CByteOutBufWrap *)pp;
+ Byte *dest = p->Cur;
+ *dest = b;
+ p->Cur = ++dest;
+ if (dest == p->Lim)
+ p->Flush();
+}
+
+CByteOutBufWrap::CByteOutBufWrap(): Buf(0)
+{
+ p.Write = Wrap_WriteByte;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/CWrappers.h b/src/libs/7zip/win/CPP/7zip/Common/CWrappers.h
new file mode 100644
index 000000000..80a8a1b61
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/CWrappers.h
@@ -0,0 +1,109 @@
+// CWrappers.h
+
+#ifndef __C_WRAPPERS_H
+#define __C_WRAPPERS_H
+
+#include "../ICoder.h"
+#include "../../Common/MyCom.h"
+
+struct CCompressProgressWrap
+{
+ ICompressProgress p;
+ ICompressProgressInfo *Progress;
+ HRESULT Res;
+ CCompressProgressWrap(ICompressProgressInfo *progress);
+};
+
+struct CSeqInStreamWrap
+{
+ ISeqInStream p;
+ ISequentialInStream *Stream;
+ HRESULT Res;
+ CSeqInStreamWrap(ISequentialInStream *stream);
+};
+
+struct CSeekInStreamWrap
+{
+ ISeekInStream p;
+ IInStream *Stream;
+ HRESULT Res;
+ CSeekInStreamWrap(IInStream *stream);
+};
+
+struct CSeqOutStreamWrap
+{
+ ISeqOutStream p;
+ ISequentialOutStream *Stream;
+ HRESULT Res;
+ UInt64 Processed;
+ CSeqOutStreamWrap(ISequentialOutStream *stream);
+};
+
+HRESULT SResToHRESULT(SRes res);
+
+struct CByteInBufWrap
+{
+ IByteIn p;
+ const Byte *Cur;
+ const Byte *Lim;
+ Byte *Buf;
+ UInt32 Size;
+ ISequentialInStream *Stream;
+ UInt64 Processed;
+ bool Extra;
+ HRESULT Res;
+
+ CByteInBufWrap();
+ ~CByteInBufWrap() { Free(); }
+ void Free();
+ bool Alloc(UInt32 size);
+ void Init()
+ {
+ Lim = Cur = Buf;
+ Processed = 0;
+ Extra = false;
+ Res = S_OK;
+ }
+ UInt64 GetProcessed() const { return Processed + (Cur - Buf); }
+ Byte ReadByteFromNewBlock();
+ Byte ReadByte()
+ {
+ if (Cur != Lim)
+ return *Cur++;
+ return ReadByteFromNewBlock();
+ }
+};
+
+struct CByteOutBufWrap
+{
+ IByteOut p;
+ Byte *Cur;
+ const Byte *Lim;
+ Byte *Buf;
+ size_t Size;
+ ISequentialOutStream *Stream;
+ UInt64 Processed;
+ HRESULT Res;
+
+ CByteOutBufWrap();
+ ~CByteOutBufWrap() { Free(); }
+ void Free();
+ bool Alloc(size_t size);
+ void Init()
+ {
+ Cur = Buf;
+ Lim = Buf + Size;
+ Processed = 0;
+ Res = S_OK;
+ }
+ UInt64 GetProcessed() const { return Processed + (Cur - Buf); }
+ HRESULT Flush();
+ void WriteByte(Byte b)
+ {
+ *Cur++ = b;
+ if (Cur == Lim)
+ Flush();
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/CreateCoder.cpp b/src/libs/7zip/win/CPP/7zip/Common/CreateCoder.cpp
new file mode 100644
index 000000000..cc82a0db5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/CreateCoder.cpp
@@ -0,0 +1,293 @@
+// CreateCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Windows/Defs.h"
+#include "../../Windows/PropVariant.h"
+
+#include "CreateCoder.h"
+
+#include "FilterCoder.h"
+#include "RegisterCodec.h"
+
+static const unsigned int kNumCodecsMax = 64;
+unsigned int g_NumCodecs = 0;
+const CCodecInfo *g_Codecs[kNumCodecsMax];
+void RegisterCodec(const CCodecInfo *codecInfo)
+{
+ if (g_NumCodecs < kNumCodecsMax)
+ g_Codecs[g_NumCodecs++] = codecInfo;
+}
+
+#ifdef EXTERNAL_CODECS
+static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(codecsInfo->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_EMPTY)
+ res = 1;
+ else if (prop.vt == VT_UI4)
+ res = prop.ulVal;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(codecsInfo->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_EMPTY)
+ res = true;
+ else if (prop.vt == VT_BOOL)
+ res = VARIANT_BOOLToBool(prop.boolVal);
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+HRESULT LoadExternalCodecs(ICompressCodecsInfo *codecsInfo, CObjectVector<CCodecInfoEx> &externalCodecs)
+{
+ UInt32 num;
+ RINOK(codecsInfo->GetNumberOfMethods(&num));
+ for (UInt32 i = 0; i < num; i++)
+ {
+ CCodecInfoEx info;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(codecsInfo->GetProperty(i, NMethodPropID::kID, &prop));
+ // if (prop.vt != VT_BSTR)
+ // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal);
+ // memmove(info.Id.ID, prop.bstrVal, info.Id.IDSize);
+ if (prop.vt != VT_UI8)
+ {
+ continue; // old Interface
+ // return E_INVALIDARG;
+ }
+ info.Id = prop.uhVal.QuadPart;
+ prop.Clear();
+
+ RINOK(codecsInfo->GetProperty(i, NMethodPropID::kName, &prop));
+ if (prop.vt == VT_BSTR)
+ info.Name = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;;
+
+ RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kInStreams, info.NumInStreams));
+ RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kOutStreams, info.NumOutStreams));
+ RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned));
+ RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned));
+
+ externalCodecs.Add(info);
+ }
+ return S_OK;
+}
+
+#endif
+
+bool FindMethod(
+ #ifdef EXTERNAL_CODECS
+ ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
+ #endif
+ const UString &name,
+ CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams)
+{
+ UInt32 i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (name.CompareNoCase(codec.Name) == 0)
+ {
+ methodId = codec.Id;
+ numInStreams = codec.NumInStreams;
+ numOutStreams = 1;
+ return true;
+ }
+ }
+ #ifdef EXTERNAL_CODECS
+ if (externalCodecs)
+ for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+ {
+ const CCodecInfoEx &codec = (*externalCodecs)[i];
+ if (codec.Name.CompareNoCase(name) == 0)
+ {
+ methodId = codec.Id;
+ numInStreams = codec.NumInStreams;
+ numOutStreams = codec.NumOutStreams;
+ return true;
+ }
+ }
+ #endif
+ return false;
+}
+
+bool FindMethod(
+ #ifdef EXTERNAL_CODECS
+ ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
+ #endif
+ CMethodId methodId, UString &name)
+{
+ UInt32 i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (methodId == codec.Id)
+ {
+ name = codec.Name;
+ return true;
+ }
+ }
+ #ifdef EXTERNAL_CODECS
+ if (externalCodecs)
+ for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+ {
+ const CCodecInfoEx &codec = (*externalCodecs)[i];
+ if (methodId == codec.Id)
+ {
+ name = codec.Name;
+ return true;
+ }
+ }
+ #endif
+ return false;
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode, bool onlyCoder)
+{
+ bool created = false;
+ UInt32 i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (codec.Id == methodId)
+ {
+ if (encode)
+ {
+ if (codec.CreateEncoder)
+ {
+ void *p = codec.CreateEncoder();
+ if (codec.IsFilter) filter = (ICompressFilter *)p;
+ else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
+ else coder2 = (ICompressCoder2 *)p;
+ created = (p != 0);
+ break;
+ }
+ }
+ else
+ if (codec.CreateDecoder)
+ {
+ void *p = codec.CreateDecoder();
+ if (codec.IsFilter) filter = (ICompressFilter *)p;
+ else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
+ else coder2 = (ICompressCoder2 *)p;
+ created = (p != 0);
+ break;
+ }
+ }
+ }
+
+ #ifdef EXTERNAL_CODECS
+ if (!created && externalCodecs)
+ for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
+ {
+ const CCodecInfoEx &codec = (*externalCodecs)[i];
+ if (codec.Id == methodId)
+ {
+ if (encode)
+ {
+ if (codec.EncoderIsAssigned)
+ {
+ if (codec.IsSimpleCodec())
+ {
+ HRESULT result = codecsInfo->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder);
+ if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
+ return result;
+ if (!coder)
+ {
+ RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter));
+ }
+ }
+ else
+ {
+ RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2));
+ }
+ break;
+ }
+ }
+ else
+ if (codec.DecoderIsAssigned)
+ {
+ if (codec.IsSimpleCodec())
+ {
+ HRESULT result = codecsInfo->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder);
+ if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
+ return result;
+ if (!coder)
+ {
+ RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter));
+ }
+ }
+ else
+ {
+ RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2));
+ }
+ break;
+ }
+ }
+ }
+ #endif
+
+ if (onlyCoder && filter)
+ {
+ CFilterCoder *coderSpec = new CFilterCoder;
+ coder = coderSpec;
+ coderSpec->Filter = filter;
+ }
+ return S_OK;
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode)
+{
+ CMyComPtr<ICompressFilter> filter;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ filter, coder, coder2, encode, true);
+}
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder, bool encode)
+{
+ CMyComPtr<ICompressFilter> filter;
+ CMyComPtr<ICompressCoder2> coder2;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ coder, coder2, encode);
+}
+
+HRESULT CreateFilter(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ bool encode)
+{
+ CMyComPtr<ICompressCoder> coder;
+ CMyComPtr<ICompressCoder2> coder2;
+ return CreateCoder(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId,
+ filter, coder, coder2, encode, false);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/CreateCoder.h b/src/libs/7zip/win/CPP/7zip/Common/CreateCoder.h
new file mode 100644
index 000000000..bf0e96a38
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/CreateCoder.h
@@ -0,0 +1,98 @@
+// CreateCoder.h
+
+#ifndef __CREATE_CODER_H
+#define __CREATE_CODER_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyString.h"
+#include "../ICoder.h"
+
+#include "MethodId.h"
+
+#ifdef EXTERNAL_CODECS
+
+struct CCodecInfoEx
+{
+ UString Name;
+ CMethodId Id;
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+ bool IsSimpleCodec() const { return NumOutStreams == 1 && NumInStreams == 1; }
+ CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {}
+};
+
+HRESULT LoadExternalCodecs(ICompressCodecsInfo *codecsInfo, CObjectVector<CCodecInfoEx> &externalCodecs);
+
+#define PUBLIC_ISetCompressCodecsInfo public ISetCompressCodecsInfo,
+#define QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_ENTRY(ISetCompressCodecsInfo)
+#define DECL_ISetCompressCodecsInfo STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo);
+#define IMPL_ISetCompressCodecsInfo2(x) \
+STDMETHODIMP x::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo) { \
+ COM_TRY_BEGIN _codecsInfo = compressCodecsInfo; return LoadExternalCodecs(_codecsInfo, _externalCodecs); COM_TRY_END }
+#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler)
+
+#define EXTERNAL_CODECS_VARS2 _codecsInfo, &_externalCodecs
+
+#define DECL_EXTERNAL_CODECS_VARS CMyComPtr<ICompressCodecsInfo> _codecsInfo; CObjectVector<CCodecInfoEx> _externalCodecs;
+#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2,
+
+#define DECL_EXTERNAL_CODECS_LOC_VARS2 ICompressCodecsInfo *codecsInfo, const CObjectVector<CCodecInfoEx> *externalCodecs
+#define EXTERNAL_CODECS_LOC_VARS2 codecsInfo, externalCodecs
+
+#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2,
+#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2,
+
+#else
+
+#define PUBLIC_ISetCompressCodecsInfo
+#define QUERY_ENTRY_ISetCompressCodecsInfo
+#define DECL_ISetCompressCodecsInfo
+#define IMPL_ISetCompressCodecsInfo
+#define EXTERNAL_CODECS_VARS2
+#define DECL_EXTERNAL_CODECS_VARS
+#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS2
+#define EXTERNAL_CODECS_LOC_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS
+#define EXTERNAL_CODECS_LOC_VARS
+
+#endif
+
+bool FindMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams);
+
+bool FindMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, UString &name);
+
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode, bool onlyCoder);
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder,
+ CMyComPtr<ICompressCoder2> &coder2,
+ bool encode);
+
+HRESULT CreateCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressCoder> &coder, bool encode);
+
+HRESULT CreateFilter(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ CMyComPtr<ICompressFilter> &filter,
+ bool encode);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.cpp b/src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.cpp
new file mode 100644
index 000000000..7d6e36f14
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.cpp
@@ -0,0 +1,55 @@
+// FilePathAutoRename.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Defs.h"
+#include "Common/IntToString.h"
+
+#include "Windows/FileFind.h"
+
+#include "FilePathAutoRename.h"
+
+using namespace NWindows;
+
+static bool MakeAutoName(const UString &name,
+ const UString &extension, unsigned value, UString &path)
+{
+ wchar_t number[16];
+ ConvertUInt32ToString(value, number);
+ path = name;
+ path += number;
+ path += extension;
+ return NFile::NFind::DoesFileOrDirExist(path);
+}
+
+bool AutoRenamePath(UString &fullProcessedPath)
+{
+ UString path;
+ int dotPos = fullProcessedPath.ReverseFind(L'.');
+
+ int slashPos = fullProcessedPath.ReverseFind(L'/');
+ #ifdef _WIN32
+ int slash1Pos = fullProcessedPath.ReverseFind(L'\\');
+ slashPos = MyMax(slashPos, slash1Pos);
+ #endif
+
+ UString name, extension;
+ if (dotPos > slashPos && dotPos > 0)
+ {
+ name = fullProcessedPath.Left(dotPos);
+ extension = fullProcessedPath.Mid(dotPos);
+ }
+ else
+ name = fullProcessedPath;
+ name += L'_';
+ unsigned left = 1, right = (1 << 30);
+ while (left != right)
+ {
+ unsigned mid = (left + right) / 2;
+ if (MakeAutoName(name, extension, mid, path))
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ return !MakeAutoName(name, extension, right, fullProcessedPath);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.h b/src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.h
new file mode 100644
index 000000000..3ef87f482
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/FilePathAutoRename.h
@@ -0,0 +1,10 @@
+// Util/FilePathAutoRename.h
+
+#ifndef __FILEPATHAUTORENAME_H
+#define __FILEPATHAUTORENAME_H
+
+#include "Common/MyString.h"
+
+bool AutoRenamePath(UString &fullProcessedPath);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/FileStreams.cpp b/src/libs/7zip/win/CPP/7zip/Common/FileStreams.cpp
new file mode 100644
index 000000000..426a0d3d6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/FileStreams.cpp
@@ -0,0 +1,422 @@
+// FileStreams.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#ifdef SUPPORT_DEVICE_FILE
+#include "../../../C/Alloc.h"
+#include "../../Common/Defs.h"
+#endif
+
+#include "FileStreams.h"
+
+static inline HRESULT ConvertBoolToHRESULT(bool result)
+{
+ #ifdef _WIN32
+ if (result)
+ return S_OK;
+ DWORD lastError = ::GetLastError();
+ if (lastError == 0)
+ return E_FAIL;
+ return HRESULT_FROM_WIN32(lastError);
+ #else
+ return result ? S_OK: E_FAIL;
+ #endif
+}
+
+bool CInFileStream::Open(LPCTSTR fileName)
+{
+ return File.Open(fileName);
+}
+
+#ifdef USE_WIN_FILE
+#ifndef _UNICODE
+bool CInFileStream::Open(LPCWSTR fileName)
+{
+ return File.Open(fileName);
+}
+#endif
+#endif
+
+bool CInFileStream::OpenShared(LPCTSTR fileName, bool shareForWrite)
+{
+ return File.OpenShared(fileName, shareForWrite);
+}
+
+#ifdef USE_WIN_FILE
+#ifndef _UNICODE
+bool CInFileStream::OpenShared(LPCWSTR fileName, bool shareForWrite)
+{
+ return File.OpenShared(fileName, shareForWrite);
+}
+#endif
+#endif
+
+#ifdef SUPPORT_DEVICE_FILE
+
+static const UInt32 kClusterSize = 1 << 18;
+CInFileStream::CInFileStream():
+ VirtPos(0),
+ PhyPos(0),
+ Buffer(0),
+ BufferSize(0)
+{
+}
+
+#endif
+
+CInFileStream::~CInFileStream()
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ MidFree(Buffer);
+ #endif
+}
+
+STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef USE_WIN_FILE
+
+ #ifdef SUPPORT_DEVICE_FILE
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (File.IsDeviceFile)
+ {
+ if (File.LengthDefined)
+ {
+ if (VirtPos >= File.Length)
+ return VirtPos == File.Length ? S_OK : E_FAIL;
+ UInt64 rem = File.Length - VirtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ for (;;)
+ {
+ const UInt32 mask = kClusterSize - 1;
+ UInt64 mask2 = ~(UInt64)mask;
+ UInt64 alignedPos = VirtPos & mask2;
+ if (BufferSize > 0 && BufferStartPos == alignedPos)
+ {
+ UInt32 pos = (UInt32)VirtPos & mask;
+ if (pos >= BufferSize)
+ return S_OK;
+ UInt32 rem = MyMin(BufferSize - pos, size);
+ memcpy(data, Buffer + pos, rem);
+ VirtPos += rem;
+ if (processedSize != NULL)
+ *processedSize += rem;
+ return S_OK;
+ }
+
+ bool useBuffer = false;
+ if ((VirtPos & mask) != 0 || ((ptrdiff_t)data & mask) != 0 )
+ useBuffer = true;
+ else
+ {
+ UInt64 end = VirtPos + size;
+ if ((end & mask) != 0)
+ {
+ end &= mask2;
+ if (end <= VirtPos)
+ useBuffer = true;
+ else
+ size = (UInt32)(end - VirtPos);
+ }
+ }
+ if (!useBuffer)
+ break;
+ if (alignedPos != PhyPos)
+ {
+ UInt64 realNewPosition;
+ bool result = File.Seek(alignedPos, FILE_BEGIN, realNewPosition);
+ if (!result)
+ return ConvertBoolToHRESULT(result);
+ PhyPos = realNewPosition;
+ }
+
+ BufferStartPos = alignedPos;
+ UInt32 readSize = kClusterSize;
+ if (File.LengthDefined)
+ readSize = (UInt32)MyMin(File.Length - PhyPos, (UInt64)kClusterSize);
+
+ if (Buffer == 0)
+ {
+ Buffer = (Byte *)MidAlloc(kClusterSize);
+ if (Buffer == 0)
+ return E_OUTOFMEMORY;
+ }
+ bool result = File.Read1(Buffer, readSize, BufferSize);
+ if (!result)
+ return ConvertBoolToHRESULT(result);
+
+ if (BufferSize == 0)
+ return S_OK;
+ PhyPos += BufferSize;
+ }
+
+ if (VirtPos != PhyPos)
+ {
+ UInt64 realNewPosition;
+ bool result = File.Seek(VirtPos, FILE_BEGIN, realNewPosition);
+ if (!result)
+ return ConvertBoolToHRESULT(result);
+ PhyPos = VirtPos = realNewPosition;
+ }
+ }
+ #endif
+
+ UInt32 realProcessedSize;
+ bool result = File.ReadPart(data, size, realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ #ifdef SUPPORT_DEVICE_FILE
+ VirtPos += realProcessedSize;
+ PhyPos += realProcessedSize;
+ #endif
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ if (processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res = File.Read(data, (size_t)size);
+ if (res == -1)
+ return E_FAIL;
+ if (processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+#ifdef UNDER_CE
+STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t s2 = fread(data, 1, size, stdout);
+ if (processedSize != 0)
+ *processedSize = s2;
+ return (s2 = size) ? S_OK : E_FAIL;
+}
+#else
+STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef _WIN32
+
+ DWORD realProcessedSize;
+ UInt32 sizeTemp = (1 << 20);
+ if (sizeTemp > size)
+ sizeTemp = size;
+ BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
+ return S_OK;
+ return ConvertBoolToHRESULT(res != FALSE);
+
+ #else
+
+ if (processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res;
+ do
+ {
+ res = read(0, data, (size_t)size);
+ }
+ while (res < 0 && (errno == EINTR));
+ if (res == -1)
+ return E_FAIL;
+ if (processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+#endif
+
+STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin,
+ UInt64 *newPosition)
+{
+ if (seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+
+ #ifdef USE_WIN_FILE
+
+ #ifdef SUPPORT_DEVICE_FILE
+ if (File.IsDeviceFile)
+ {
+ UInt64 newVirtPos = offset;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: newVirtPos += VirtPos; break;
+ case STREAM_SEEK_END: newVirtPos += File.Length; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ VirtPos = newVirtPos;
+ if (newPosition)
+ *newPosition = newVirtPos;
+ return S_OK;
+ }
+ #endif
+
+ UInt64 realNewPosition;
+ bool result = File.Seek(offset, seekOrigin, realNewPosition);
+
+ #ifdef SUPPORT_DEVICE_FILE
+ PhyPos = VirtPos = realNewPosition;
+ #endif
+
+ if (newPosition != NULL)
+ *newPosition = realNewPosition;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ off_t res = File.Seek(offset, seekOrigin);
+ if (res == -1)
+ return E_FAIL;
+ if (newPosition != NULL)
+ *newPosition = (UInt64)res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
+{
+ return ConvertBoolToHRESULT(File.GetLength(*size));
+}
+
+
+//////////////////////////
+// COutFileStream
+
+HRESULT COutFileStream::Close()
+{
+ return ConvertBoolToHRESULT(File.Close());
+}
+
+STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef USE_WIN_FILE
+
+ UInt32 realProcessedSize;
+ bool result = File.WritePart(data, size, realProcessedSize);
+ ProcessedSize += realProcessedSize;
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ if (processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res = File.Write(data, (size_t)size);
+ if (res == -1)
+ return E_FAIL;
+ if (processedSize != NULL)
+ *processedSize = (UInt32)res;
+ ProcessedSize += res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if (seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+ #ifdef USE_WIN_FILE
+
+ UInt64 realNewPosition;
+ bool result = File.Seek(offset, seekOrigin, realNewPosition);
+ if (newPosition != NULL)
+ *newPosition = realNewPosition;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ off_t res = File.Seek(offset, seekOrigin);
+ if (res == -1)
+ return E_FAIL;
+ if (newPosition != NULL)
+ *newPosition = (UInt64)res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP COutFileStream::SetSize(UInt64 newSize)
+{
+ #ifdef USE_WIN_FILE
+ UInt64 currentPos;
+ if (!File.Seek(0, FILE_CURRENT, currentPos))
+ return E_FAIL;
+ bool result = File.SetLength(newSize);
+ UInt64 currentPos2;
+ result = result && File.Seek(currentPos, currentPos2);
+ return result ? S_OK : E_FAIL;
+ #else
+ return E_FAIL;
+ #endif
+}
+
+#ifdef UNDER_CE
+STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t s2 = fwrite(data, 1, size, stdout);
+ if (processedSize != 0)
+ *processedSize = s2;
+ return (s2 = size) ? S_OK : E_FAIL;
+}
+#else
+STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+
+ #ifdef _WIN32
+ UInt32 realProcessedSize;
+ BOOL res = TRUE;
+ if (size > 0)
+ {
+ // Seems that Windows doesn't like big amounts writing to stdout.
+ // So we limit portions by 32KB.
+ UInt32 sizeTemp = (1 << 15);
+ if (sizeTemp > size)
+ sizeTemp = size;
+ res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
+ data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
+ size -= realProcessedSize;
+ data = (const void *)((const Byte *)data + realProcessedSize);
+ if (processedSize != NULL)
+ *processedSize += realProcessedSize;
+ }
+ return ConvertBoolToHRESULT(res != FALSE);
+
+ #else
+
+ ssize_t res;
+ do
+ {
+ res = write(1, data, (size_t)size);
+ }
+ while (res < 0 && (errno == EINTR));
+ if (res == -1)
+ return E_FAIL;
+ if (processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ return S_OK;
+ #endif
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/FileStreams.h b/src/libs/7zip/win/CPP/7zip/Common/FileStreams.h
new file mode 100644
index 000000000..895745d36
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/FileStreams.h
@@ -0,0 +1,144 @@
+// FileStreams.h
+
+#ifndef __FILESTREAMS_H
+#define __FILESTREAMS_H
+
+#ifdef _WIN32
+#define USE_WIN_FILE
+#endif
+
+#ifdef USE_WIN_FILE
+#include "../../Windows/FileIO.h"
+#else
+#include "../../Common/C_FileIO.h"
+#endif
+
+#include "../../Common/MyCom.h"
+
+#include "../IStream.h"
+
+class CInFileStream:
+ public IInStream,
+ public IStreamGetSize,
+ public CMyUnknownImp
+{
+public:
+ #ifdef USE_WIN_FILE
+ NWindows::NFile::NIO::CInFile File;
+ #ifdef SUPPORT_DEVICE_FILE
+ UInt64 VirtPos;
+ UInt64 PhyPos;
+ UInt64 BufferStartPos;
+ Byte *Buffer;
+ UInt32 BufferSize;
+ #endif
+ #else
+ NC::NFile::NIO::CInFile File;
+ #endif
+ virtual ~CInFileStream();
+
+ #ifdef SUPPORT_DEVICE_FILE
+ CInFileStream();
+ #endif
+
+ bool Open(LPCTSTR fileName);
+ #ifdef USE_WIN_FILE
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName);
+ #endif
+ #endif
+
+ bool OpenShared(LPCTSTR fileName, bool shareForWrite);
+ #ifdef USE_WIN_FILE
+ #ifndef _UNICODE
+ bool OpenShared(LPCWSTR fileName, bool shareForWrite);
+ #endif
+ #endif
+
+ MY_UNKNOWN_IMP2(IInStream, IStreamGetSize)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+
+ STDMETHOD(GetSize)(UInt64 *size);
+};
+
+class CStdInFileStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ virtual ~CStdInFileStream() {}
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class COutFileStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ #ifdef USE_WIN_FILE
+ NWindows::NFile::NIO::COutFile File;
+ #else
+ NC::NFile::NIO::COutFile File;
+ #endif
+public:
+ virtual ~COutFileStream() {}
+ bool Create(LPCTSTR fileName, bool createAlways)
+ {
+ ProcessedSize = 0;
+ return File.Create(fileName, createAlways);
+ }
+ bool Open(LPCTSTR fileName, DWORD creationDisposition)
+ {
+ ProcessedSize = 0;
+ return File.Open(fileName, creationDisposition);
+ }
+ #ifdef USE_WIN_FILE
+ #ifndef _UNICODE
+ bool Create(LPCWSTR fileName, bool createAlways)
+ {
+ ProcessedSize = 0;
+ return File.Create(fileName, createAlways);
+ }
+ bool Open(LPCWSTR fileName, DWORD creationDisposition)
+ {
+ ProcessedSize = 0;
+ return File.Open(fileName, creationDisposition);
+ }
+ #endif
+ #endif
+
+ HRESULT Close();
+
+ UInt64 ProcessedSize;
+
+ #ifdef USE_WIN_FILE
+ bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
+ {
+ return File.SetTime(cTime, aTime, mTime);
+ }
+ bool SetMTime(const FILETIME *mTime) { return File.SetMTime(mTime); }
+ #endif
+
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+class CStdOutFileStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ virtual ~CStdOutFileStream() {}
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/FilterCoder.cpp b/src/libs/7zip/win/CPP/7zip/Common/FilterCoder.cpp
new file mode 100644
index 000000000..696735278
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/FilterCoder.cpp
@@ -0,0 +1,247 @@
+// FilterCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../../Common/Defs.h"
+
+#include "FilterCoder.h"
+#include "StreamUtils.h"
+
+static const UInt32 kBufferSize = 1 << 17;
+
+CFilterCoder::CFilterCoder()
+{
+ _buffer = (Byte *)::MidAlloc(kBufferSize);
+ if (_buffer == 0)
+ throw 1;
+}
+
+CFilterCoder::~CFilterCoder()
+{
+ ::MidFree(_buffer);
+}
+
+HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size)
+{
+ if (_outSizeIsDefined)
+ {
+ UInt64 remSize = _outSize - _nowPos64;
+ if (size > remSize)
+ size = (UInt32)remSize;
+ }
+ RINOK(WriteStream(outStream, _buffer, size));
+ _nowPos64 += size;
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ RINOK(Init());
+ UInt32 bufferPos = 0;
+ _outSizeIsDefined = (outSize != 0);
+ if (_outSizeIsDefined)
+ _outSize = *outSize;
+
+ while (!_outSizeIsDefined || _nowPos64 < _outSize)
+ {
+ size_t processedSize = kBufferSize - bufferPos;
+
+ // Change it: It can be optimized using ReadPart
+ RINOK(ReadStream(inStream, _buffer + bufferPos, &processedSize));
+
+ UInt32 endPos = bufferPos + (UInt32)processedSize;
+
+ bufferPos = Filter->Filter(_buffer, endPos);
+ if (bufferPos > endPos)
+ {
+ for (; endPos < bufferPos; endPos++)
+ _buffer[endPos] = 0;
+ bufferPos = Filter->Filter(_buffer, endPos);
+ }
+
+ if (bufferPos == 0)
+ {
+ if (endPos == 0)
+ return S_OK;
+ return WriteWithLimit(outStream, endPos);
+ }
+ RINOK(WriteWithLimit(outStream, bufferPos));
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64));
+ }
+ UInt32 i = 0;
+ while (bufferPos < endPos)
+ _buffer[i++] = _buffer[bufferPos++];
+ bufferPos = i;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
+{
+ _bufferPos = 0;
+ _outStream = outStream;
+ return Init();
+}
+
+STDMETHODIMP CFilterCoder::ReleaseOutStream()
+{
+ _outStream.Release();
+ return S_OK;
+}
+
+
+STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ UInt32 sizeTemp = MyMin(size, kBufferSize - _bufferPos);
+ memcpy(_buffer + _bufferPos, data, sizeTemp);
+ size -= sizeTemp;
+ if (processedSize != NULL)
+ *processedSize += sizeTemp;
+ data = (const Byte *)data + sizeTemp;
+ UInt32 endPos = _bufferPos + sizeTemp;
+ _bufferPos = Filter->Filter(_buffer, endPos);
+ if (_bufferPos == 0)
+ {
+ _bufferPos = endPos;
+ break;
+ }
+ if (_bufferPos > endPos)
+ {
+ if (size != 0)
+ return E_FAIL;
+ break;
+ }
+ RINOK(WriteWithLimit(_outStream, _bufferPos));
+ UInt32 i = 0;
+ while (_bufferPos < endPos)
+ _buffer[i++] = _buffer[_bufferPos++];
+ _bufferPos = i;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Flush()
+{
+ if (_bufferPos != 0)
+ {
+ // _buffer contains only data refused by previous Filter->Filter call.
+ UInt32 endPos = Filter->Filter(_buffer, _bufferPos);
+ if (endPos > _bufferPos)
+ {
+ for (; _bufferPos < endPos; _bufferPos++)
+ _buffer[_bufferPos] = 0;
+ if (Filter->Filter(_buffer, endPos) != endPos)
+ return E_FAIL;
+ }
+ RINOK(WriteWithLimit(_outStream, _bufferPos));
+ _bufferPos = 0;
+ }
+ CMyComPtr<IOutStreamFlush> flush;
+ _outStream.QueryInterface(IID_IOutStreamFlush, &flush);
+ if (flush)
+ return flush->Flush();
+ return S_OK;
+}
+
+
+STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
+{
+ _convertedPosBegin = _convertedPosEnd = _bufferPos = 0;
+ _inStream = inStream;
+ return Init();
+}
+
+STDMETHODIMP CFilterCoder::ReleaseInStream()
+{
+ _inStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_convertedPosBegin != _convertedPosEnd)
+ {
+ UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin);
+ memcpy(data, _buffer + _convertedPosBegin, sizeTemp);
+ _convertedPosBegin += sizeTemp;
+ data = (void *)((Byte *)data + sizeTemp);
+ size -= sizeTemp;
+ if (processedSize != NULL)
+ *processedSize += sizeTemp;
+ break;
+ }
+ UInt32 i;
+ for (i = 0; _convertedPosEnd + i < _bufferPos; i++)
+ _buffer[i] = _buffer[_convertedPosEnd + i];
+ _bufferPos = i;
+ _convertedPosBegin = _convertedPosEnd = 0;
+ size_t processedSizeTemp = kBufferSize - _bufferPos;
+ RINOK(ReadStream(_inStream, _buffer + _bufferPos, &processedSizeTemp));
+ _bufferPos += (UInt32)processedSizeTemp;
+ _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
+ if (_convertedPosEnd == 0)
+ {
+ if (_bufferPos == 0)
+ break;
+ _convertedPosEnd = _bufferPos; // check it
+ continue;
+ }
+ if (_convertedPosEnd > _bufferPos)
+ {
+ for (; _bufferPos < _convertedPosEnd; _bufferPos++)
+ _buffer[_bufferPos] = 0;
+ _convertedPosEnd = Filter->Filter(_buffer, _bufferPos);
+ }
+ }
+ return S_OK;
+}
+
+#ifndef _NO_CRYPTO
+STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ return _setPassword->CryptoSetPassword(data, size);
+}
+#endif
+
+#ifndef EXTRACT_ONLY
+STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties)
+{
+ return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties);
+}
+
+STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ return _writeCoderProperties->WriteCoderProperties(outStream);
+}
+
+/*
+STDMETHODIMP CFilterCoder::ResetSalt()
+{
+ return _CryptoResetSalt->ResetSalt();
+}
+*/
+
+STDMETHODIMP CFilterCoder::ResetInitVector()
+{
+ return _CryptoResetInitVector->ResetInitVector();
+}
+#endif
+
+STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ return _setDecoderProperties->SetDecoderProperties2(data, size);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/FilterCoder.h b/src/libs/7zip/win/CPP/7zip/Common/FilterCoder.h
new file mode 100644
index 000000000..8132a6dd7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/FilterCoder.h
@@ -0,0 +1,128 @@
+// FilterCoder.h
+
+#ifndef __FILTER_CODER_H
+#define __FILTER_CODER_H
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#define MY_QUERYINTERFACE_ENTRY_AG(i, sub0, sub) if (iid == IID_ ## i) \
+{ if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \
+*outObject = (void *)(i *)this; AddRef(); return S_OK; }
+
+class CFilterCoder:
+ public ICompressCoder,
+ public ICompressSetInStream,
+ public ISequentialInStream,
+ public ICompressSetOutStream,
+ public ISequentialOutStream,
+ public IOutStreamFlush,
+
+ #ifndef _NO_CRYPTO
+ public ICryptoSetPassword,
+ #endif
+ #ifndef EXTRACT_ONLY
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector,
+ #endif
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+protected:
+ Byte *_buffer;
+ CMyComPtr<ISequentialInStream> _inStream;
+ CMyComPtr<ISequentialOutStream> _outStream;
+ UInt32 _bufferPos;
+ UInt32 _convertedPosBegin;
+ UInt32 _convertedPosEnd;
+ bool _outSizeIsDefined;
+ UInt64 _outSize;
+ UInt64 _nowPos64;
+
+ HRESULT Init()
+ {
+ _nowPos64 = 0;
+ _outSizeIsDefined = false;
+ return Filter->Init();
+ }
+
+ CMyComPtr<ICryptoSetPassword> _setPassword;
+ #ifndef EXTRACT_ONLY
+ CMyComPtr<ICompressSetCoderProperties> _SetCoderProperties;
+ CMyComPtr<ICompressWriteCoderProperties> _writeCoderProperties;
+ // CMyComPtr<ICryptoResetSalt> _CryptoResetSalt;
+ CMyComPtr<ICryptoResetInitVector> _CryptoResetInitVector;
+ #endif
+ CMyComPtr<ICompressSetDecoderProperties2> _setDecoderProperties;
+public:
+ CMyComPtr<ICompressFilter> Filter;
+
+ CFilterCoder();
+ ~CFilterCoder();
+ HRESULT WriteWithLimit(ISequentialOutStream *outStream, UInt32 size);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
+ MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream)
+ MY_QUERYINTERFACE_ENTRY(ISequentialOutStream)
+ MY_QUERYINTERFACE_ENTRY(IOutStreamFlush)
+
+ #ifndef _NO_CRYPTO
+ MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword)
+ #endif
+
+ #ifndef EXTRACT_ONLY
+ MY_QUERYINTERFACE_ENTRY_AG(ICompressSetCoderProperties, Filter, _SetCoderProperties)
+ MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties)
+ // MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetSalt, Filter, _CryptoResetSalt)
+ MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetInitVector, Filter, _CryptoResetInitVector)
+ #endif
+
+ MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties)
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); \
+ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
+ STDMETHOD(ReleaseOutStream)();
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Flush)();
+
+ #ifndef _NO_CRYPTO
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+ #endif
+ #ifndef EXTRACT_ONLY
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+ // STDMETHOD(ResetSalt)();
+ STDMETHOD(ResetInitVector)();
+ #endif
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+class CInStreamReleaser
+{
+public:
+ CFilterCoder *FilterCoder;
+ CInStreamReleaser(): FilterCoder(0) {}
+ ~CInStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }
+};
+
+class COutStreamReleaser
+{
+public:
+ CFilterCoder *FilterCoder;
+ COutStreamReleaser(): FilterCoder(0) {}
+ ~COutStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/InBuffer.cpp b/src/libs/7zip/win/CPP/7zip/Common/InBuffer.cpp
new file mode 100644
index 000000000..ad4f8825e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/InBuffer.cpp
@@ -0,0 +1,83 @@
+// InBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "InBuffer.h"
+
+CInBuffer::CInBuffer():
+ _buffer(0),
+ _bufferLimit(0),
+ _bufferBase(0),
+ _stream(0),
+ _bufferSize(0)
+{}
+
+bool CInBuffer::Create(UInt32 bufferSize)
+{
+ const UInt32 kMinBlockSize = 1;
+ if (bufferSize < kMinBlockSize)
+ bufferSize = kMinBlockSize;
+ if (_bufferBase != 0 && _bufferSize == bufferSize)
+ return true;
+ Free();
+ _bufferSize = bufferSize;
+ _bufferBase = (Byte *)::MidAlloc(bufferSize);
+ return (_bufferBase != 0);
+}
+
+void CInBuffer::Free()
+{
+ ::MidFree(_bufferBase);
+ _bufferBase = 0;
+}
+
+void CInBuffer::SetStream(ISequentialInStream *stream)
+{
+ _stream = stream;
+}
+
+void CInBuffer::Init()
+{
+ _processedSize = 0;
+ _buffer = _bufferBase;
+ _bufferLimit = _buffer;
+ _wasFinished = false;
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
+
+bool CInBuffer::ReadBlock()
+{
+ #ifdef _NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ return false;
+ #endif
+ if (_wasFinished)
+ return false;
+ _processedSize += (_buffer - _bufferBase);
+ UInt32 numProcessedBytes;
+ HRESULT result = _stream->Read(_bufferBase, _bufferSize, &numProcessedBytes);
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = result;
+ #else
+ if (result != S_OK)
+ throw CInBufferException(result);
+ #endif
+ _buffer = _bufferBase;
+ _bufferLimit = _buffer + numProcessedBytes;
+ _wasFinished = (numProcessedBytes == 0);
+ return (!_wasFinished);
+}
+
+Byte CInBuffer::ReadBlock2()
+{
+ if (!ReadBlock())
+ {
+ _processedSize++;
+ return 0xFF;
+ }
+ return *_buffer++;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/InBuffer.h b/src/libs/7zip/win/CPP/7zip/Common/InBuffer.h
new file mode 100644
index 000000000..75625bfd9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/InBuffer.h
@@ -0,0 +1,81 @@
+// InBuffer.h
+
+#ifndef __INBUFFER_H
+#define __INBUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+
+#ifndef _NO_EXCEPTIONS
+struct CInBufferException: public CSystemException
+{
+ CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+#endif
+
+class CInBuffer
+{
+ Byte *_buffer;
+ Byte *_bufferLimit;
+ Byte *_bufferBase;
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _processedSize;
+ UInt32 _bufferSize;
+ bool _wasFinished;
+
+ bool ReadBlock();
+ Byte ReadBlock2();
+
+public:
+ #ifdef _NO_EXCEPTIONS
+ HRESULT ErrorCode;
+ #endif
+
+ CInBuffer();
+ ~CInBuffer() { Free(); }
+
+ bool Create(UInt32 bufferSize);
+ void Free();
+
+ void SetStream(ISequentialInStream *stream);
+ void Init();
+ void ReleaseStream() { _stream.Release(); }
+
+ bool ReadByte(Byte &b)
+ {
+ if (_buffer >= _bufferLimit)
+ if (!ReadBlock())
+ return false;
+ b = *_buffer++;
+ return true;
+ }
+ Byte ReadByte()
+ {
+ if (_buffer >= _bufferLimit)
+ return ReadBlock2();
+ return *_buffer++;
+ }
+ UInt32 ReadBytes(Byte *buf, UInt32 size)
+ {
+ if ((UInt32)(_bufferLimit - _buffer) >= size)
+ {
+ for (UInt32 i = 0; i < size; i++)
+ buf[i] = _buffer[i];
+ _buffer += size;
+ return size;
+ }
+ for (UInt32 i = 0; i < size; i++)
+ {
+ if (_buffer >= _bufferLimit)
+ if (!ReadBlock())
+ return i;
+ buf[i] = *_buffer++;
+ }
+ return size;
+ }
+ UInt64 GetProcessedSize() const { return _processedSize + (_buffer - _bufferBase); }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/InMemStream.cpp b/src/libs/7zip/win/CPP/7zip/Common/InMemStream.cpp
new file mode 100644
index 000000000..38c5c92c3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/InMemStream.cpp
@@ -0,0 +1,222 @@
+// InMemStream.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "Windows/Thread.h"
+
+#include "InMemStream.h"
+#include "../../Common/Defs.h"
+
+void CStreamInfo::Free(IInMemStreamMtCallback *callback)
+{
+ for (int i = 0; i < Blocks.Size(); i++)
+ {
+ callback->FreeBlock(Blocks[i]);
+ Blocks[i] = 0;
+ }
+}
+
+bool CInMemStreamMt::Create(int numSubStreams, UInt64 subStreamSize)
+{
+ Free();
+ _subStreamSize = subStreamSize;
+ size_t blockSize = Callback->GetBlockSize();
+ for (int i = 0; i < numSubStreams; i++)
+ {
+ _streams.Add(CStreamInfo());
+ CStreamInfo &blocks = _streams.Back();
+ blocks.Create();
+ for (UInt64 j = 0; (UInt64)j * blockSize < _subStreamSize; j++)
+ blocks.Blocks.Add(0);
+ }
+ if (!_streamIndexAllocator.AllocateList(numSubStreams))
+ return false;
+ return true;
+}
+
+void CInMemStreamMt::Free()
+{
+ while(_streams.Size() > 0)
+ {
+ _streams.Back().Free(Callback);
+ _streams.DeleteBack();
+ }
+}
+
+HRESULT CInMemStreamMt::Read()
+{
+ for (;;)
+ {
+ // printf("\n_streamIndexAllocator.AllocateItem\n");
+ int index = _streamIndexAllocator.AllocateItem();
+ /*
+ if (_stopReading)
+ return E_ABORT;
+ */
+ // printf("\nread Index = %d\n", index);
+ CStreamInfo &blocks = _streams[index];
+ blocks.Init();
+ Callback->AddStreamIndexToQueue(index);
+
+ for (;;)
+ {
+ const Byte *p = (const Byte *)blocks.Blocks[blocks.LastBlockIndex];
+ if (p == 0)
+ {
+ void **pp = &blocks.Blocks[blocks.LastBlockIndex];
+ HRESULT res = Callback->AllocateBlock(pp);
+ p = (const Byte *)*pp;
+ RINOK(res);
+ if (p == 0)
+ return E_FAIL;
+ }
+ size_t blockSize = Callback->GetBlockSize();
+ UInt32 curSize = (UInt32)(blockSize - blocks.LastBlockPos);
+ UInt32 realProcessedSize;
+ UInt64 pos64 = (UInt64)blocks.LastBlockIndex * blockSize + blocks.LastBlockPos;
+ if (curSize > _subStreamSize - pos64)
+ curSize = (UInt32)(_subStreamSize - pos64);
+ RINOK(_stream->Read((void *)(p + blocks.LastBlockPos), curSize, &realProcessedSize));
+
+ blocks.Cs->Enter();
+ if (realProcessedSize == 0)
+ {
+ blocks.StreamWasFinished = true;
+ blocks.CanReadEvent->Set();
+ blocks.Cs->Leave();
+
+ Callback->AddStreamIndexToQueue(-1);
+ return S_OK;
+ }
+
+ blocks.LastBlockPos += realProcessedSize;
+ if (blocks.LastBlockPos == blockSize)
+ {
+ blocks.LastBlockPos = 0;
+ blocks.LastBlockIndex++;
+ }
+ pos64 += realProcessedSize;
+ if (pos64 >= _subStreamSize)
+ blocks.StreamWasFinished = true;
+ blocks.CanReadEvent->Set();
+ blocks.Cs->Leave();
+ if (pos64 >= _subStreamSize)
+ break;
+ }
+ }
+}
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo)
+{
+ ((CInMemStreamMt *)threadCoderInfo)->ReadResult = ((CInMemStreamMt *)threadCoderInfo)->Read();
+ return 0;
+}
+
+HRes CInMemStreamMt::StartReadThread()
+{
+ // _stopReading = false;
+ NWindows::CThread Thread;
+ return Thread.Create(CoderThread, this);
+}
+
+void CInMemStreamMt::FreeSubStream(int subStreamIndex)
+{
+ // printf("\nFreeSubStream\n");
+ _streams[subStreamIndex].Free(Callback);
+ _streamIndexAllocator.FreeItem(subStreamIndex);
+ // printf("\nFreeSubStream end\n");
+}
+
+HRESULT CInMemStreamMt::ReadSubStream(int subStreamIndex, void *data, UInt32 size, UInt32 *processedSize, bool keepData)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ CStreamInfo &blocks = _streams[subStreamIndex];
+ while (size > 0)
+ {
+ if (blocks.CurBlockPos == Callback->GetBlockSize())
+ {
+ blocks.CurBlockPos = 0;
+ blocks.CurBlockIndex++;
+ }
+ UInt32 curSize;
+ UInt32 curPos = blocks.CurBlockPos;
+
+ blocks.Cs->Enter();
+ if (blocks.CurBlockIndex == blocks.LastBlockIndex)
+ {
+ curSize = blocks.LastBlockPos - curPos;
+ if (curSize == 0)
+ {
+ if (blocks.StreamWasFinished)
+ {
+ blocks.Cs->Leave();
+ void *p = blocks.Blocks[blocks.CurBlockIndex];
+ if (p != 0 && !keepData)
+ {
+ Callback->FreeBlock(p);
+ blocks.Blocks[blocks.CurBlockIndex] = 0;
+ }
+ return S_OK;
+ }
+ blocks.CanReadEvent->Reset();
+ blocks.Cs->Leave();
+ // printf("\nBlock Lock\n");
+ blocks.CanReadEvent->Lock();
+ // printf("\nAfter Lock\n");
+ if (blocks.ExitResult != S_OK)
+ return blocks.ExitResult;
+ continue;
+ }
+ }
+ else
+ curSize = Callback->GetBlockSize() - curPos;
+ blocks.Cs->Leave();
+
+ if (curSize > size)
+ curSize = size;
+ void *p = blocks.Blocks[blocks.CurBlockIndex];
+ memmove(data, (const Byte *)p + curPos, curSize);
+ data = (void *)((Byte *)data + curSize);
+ size -= curSize;
+ if (processedSize != NULL)
+ *processedSize += curSize;
+ curPos += curSize;
+
+ bool needFree = false;
+ blocks.CurBlockPos = curPos;
+
+ if (curPos == Callback->GetBlockSize())
+ needFree = true;
+ blocks.Cs->Enter();
+ if (blocks.CurBlockIndex == blocks.LastBlockIndex &&
+ blocks.CurBlockPos == blocks.LastBlockPos &&
+ blocks.StreamWasFinished)
+ needFree = true;
+ blocks.Cs->Leave();
+
+ if (needFree && !keepData)
+ {
+ Callback->FreeBlock(p);
+ blocks.Blocks[blocks.CurBlockIndex] = 0;
+ }
+ return S_OK;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CInMemStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = mtStream->ReadSubStream(Index, data, size, &realProcessedSize, _keepData);
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ if (realProcessedSize != 0)
+ {
+ // printf("\ns = %d\n", Index);
+ }
+ _size += realProcessedSize;
+ return result;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/InMemStream.h b/src/libs/7zip/win/CPP/7zip/Common/InMemStream.h
new file mode 100644
index 000000000..ec493977c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/InMemStream.h
@@ -0,0 +1,284 @@
+// InMemStream.h
+
+#ifndef __IN_MEM_STREAM_H
+#define __IN_MEM_STREAM_H
+
+#include <stdio.h>
+
+#include "../../../C/Alloc.h"
+
+#include "../../Common/MyCom.h"
+
+#include "MemBlocks.h"
+
+class CIntListCheck
+{
+protected:
+ int *_data;
+public:
+ CIntListCheck(): _data(0) {}
+ ~CIntListCheck() { FreeList(); }
+
+ bool AllocateList(int numItems)
+ {
+ FreeList();
+ if (numItems == 0)
+ return true;
+ _data = (int *)::MyAlloc(numItems * sizeof(int));
+ return (_data != 0);
+ }
+
+ void FreeList()
+ {
+ ::MyFree(_data);
+ _data = 0;
+ }
+};
+
+
+class CResourceList : public CIntListCheck
+{
+ int _headFree;
+public:
+ CResourceList(): _headFree(-1) {}
+
+ bool AllocateList(int numItems)
+ {
+ FreeList();
+ if (numItems == 0)
+ return true;
+ if (!CIntListCheck::AllocateList(numItems))
+ return false;
+ for (int i = 0; i < numItems; i++)
+ _data[i] = i + 1;
+ _data[numItems - 1] = -1;
+ _headFree = 0;
+ return true;
+ }
+
+ void FreeList()
+ {
+ CIntListCheck::FreeList();
+ _headFree = -1;
+ }
+
+ int AllocateItem()
+ {
+ int res = _headFree;
+ if (res >= 0)
+ _headFree = _data[res];
+ return res;
+ }
+
+ void FreeItem(int index)
+ {
+ if (index < 0)
+ return;
+ _data[index] = _headFree;
+ _headFree = index;
+ }
+};
+
+class CResourceListMt: public CResourceList
+{
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ NWindows::NSynchronization::CSemaphore Semaphore;
+
+ HRes AllocateList(int numItems)
+ {
+ if (!CResourceList::AllocateList(numItems))
+ return E_OUTOFMEMORY;
+ Semaphore.Close();
+ return Semaphore.Create(numItems, numItems);
+ }
+
+ int AllocateItem()
+ {
+ Semaphore.Lock();
+ _criticalSection.Enter();
+ int res = CResourceList::AllocateItem();
+ _criticalSection.Leave();
+ return res;
+ }
+
+ void FreeItem(int index)
+ {
+ if (index < 0)
+ return;
+ _criticalSection.Enter();
+ CResourceList::FreeItem(index);
+ _criticalSection.Leave();
+ Semaphore.Release();
+ }
+};
+
+class CIntQueueMt: public CIntListCheck
+{
+ int _numItems;
+ int _head;
+ int _cur;
+public:
+ CIntQueueMt(): _numItems(0), _head(0), _cur(0) {}
+ NWindows::NSynchronization::CSemaphore Semaphore;
+
+ HRes AllocateList(int numItems)
+ {
+ FreeList();
+ if (numItems == 0)
+ return S_OK;
+ if (!CIntListCheck::AllocateList(numItems))
+ return E_OUTOFMEMORY;
+ _numItems = numItems;
+ return Semaphore.Create(0, numItems);
+ }
+
+ void FreeList()
+ {
+ CIntListCheck::FreeList();
+ _numItems = 0;
+ _head = 0;
+ _cur = 0;
+ }
+
+ void AddItem(int value)
+ {
+ _data[_head++] = value;
+ if (_head == _numItems)
+ _head = 0;
+ Semaphore.Release();
+ // printf("\nRelease prev = %d\n", previousCount);
+ }
+
+ int GetItem()
+ {
+ // Semaphore.Lock();
+ int res = _data[_cur++];
+ if (_cur == _numItems)
+ _cur = 0;
+ return res;
+ }
+};
+
+struct IInMemStreamMtCallback
+{
+ // must be same for all calls
+ virtual size_t GetBlockSize() = 0;
+
+ // Out:
+ // result != S_OK stops Reading
+ // if *p = 0, result must be != S_OK;
+ // Locking is allowed
+ virtual HRESULT AllocateBlock(void **p) = 0;
+
+ virtual void FreeBlock(void *p) = 0;
+
+ // It must allow to add at least numSubStreams + 1 ,
+ // where numSubStreams is value from CInMemStreamMt::Create
+ // value -1 means End of stream
+ // Locking is not allowed
+ virtual void AddStreamIndexToQueue(int index) = 0;
+};
+
+struct CStreamInfo
+{
+ CRecordVector<void *> Blocks;
+
+ int LastBlockIndex;
+ size_t LastBlockPos;
+ bool StreamWasFinished;
+
+ int CurBlockIndex;
+ size_t CurBlockPos;
+
+ NWindows::NSynchronization::CCriticalSection *Cs;
+ NWindows::NSynchronization::CManualResetEvent *CanReadEvent;
+
+ HRESULT ExitResult;
+
+ CStreamInfo(): Cs(0), CanReadEvent(0), StreamWasFinished(false) { }
+ ~CStreamInfo()
+ {
+ delete Cs;
+ delete CanReadEvent;
+ // Free();
+ }
+ void Create()
+ {
+ Cs = new NWindows::NSynchronization::CCriticalSection;
+ CanReadEvent = new NWindows::NSynchronization::CManualResetEvent;
+ }
+
+ void Free(IInMemStreamMtCallback *callback);
+ void Init()
+ {
+ LastBlockIndex = CurBlockIndex = 0;
+ CurBlockPos = LastBlockPos = 0;
+ StreamWasFinished = false;
+ ExitResult = S_OK;
+ }
+
+ // res must be != S_OK
+ void Exit(HRESULT res)
+ {
+ ExitResult = res;
+ CanReadEvent->Set();
+ }
+};
+
+
+class CInMemStreamMt
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ NWindows::NSynchronization::CCriticalSection CS;
+ CObjectVector<CStreamInfo> _streams;
+ int _nextFreeStreamIndex;
+ int _currentStreamIndex;
+ UInt64 _subStreamSize;
+
+ CResourceListMt _streamIndexAllocator;
+
+ // bool _stopReading;
+
+public:
+ HRESULT Read();
+ HRESULT ReadResult;
+ IInMemStreamMtCallback *Callback;
+ void FreeSubStream(int subStreamIndex);
+ HRESULT ReadSubStream(int subStreamIndex, void *data, UInt32 size, UInt32 *processedSize, bool keepData);
+
+ // numSubStreams: min = 1, good min = numThreads
+ bool Create(int numSubStreams, UInt64 subStreamSize);
+ ~CInMemStreamMt() { Free(); }
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+
+ // to stop reading you must implement
+ // returning Error in IInMemStreamMtCallback::AllocateBlock
+ // and then you must free at least one substream
+ HRes StartReadThread();
+
+ void Free();
+
+ // you must free at least one substream after that function to unlock waiting.
+ // void StopReading() { _stopReading = true; }
+};
+
+class CInMemStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ UInt64 _size;
+ bool _keepData;
+public:
+ int Index;
+ CInMemStreamMt *mtStream;
+ void Init(bool keepData = false)
+ {
+ _size = 0; _keepData = keepData ;
+ }
+ MY_UNKNOWN_IMP
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ UInt64 GetSize() const { return _size; }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.cpp b/src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.cpp
new file mode 100644
index 000000000..dfe8b3d32
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.cpp
@@ -0,0 +1,122 @@
+// InOutTempBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+
+#include "InOutTempBuffer.h"
+#include "StreamUtils.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDirectory;
+
+static const UInt32 kTempBufSize = (1 << 20);
+
+static LPCTSTR kTempFilePrefixString = TEXT("7zt");
+
+CInOutTempBuffer::CInOutTempBuffer(): _buf(NULL) { }
+
+void CInOutTempBuffer::Create()
+{
+ if (!_buf)
+ _buf = new Byte[kTempBufSize];
+}
+
+CInOutTempBuffer::~CInOutTempBuffer()
+{
+ delete []_buf;
+}
+
+void CInOutTempBuffer::InitWriting()
+{
+ _bufPos = 0;
+ _tempFileCreated = false;
+ _size = 0;
+ _crc = CRC_INIT_VAL;
+}
+
+bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size)
+{
+ if (size == 0)
+ return true;
+ if (!_tempFileCreated)
+ {
+ CSysString tempDirPath;
+ if (!MyGetTempPath(tempDirPath))
+ return false;
+ if (_tempFile.Create(tempDirPath, kTempFilePrefixString, _tempFileName) == 0)
+ return false;
+ if (!_outFile.Create(_tempFileName, true))
+ return false;
+ _tempFileCreated = true;
+ }
+ UInt32 processed;
+ if (!_outFile.Write(data, size, processed))
+ return false;
+ _crc = CrcUpdate(_crc, data, processed);
+ _size += processed;
+ return (processed == size);
+}
+
+bool CInOutTempBuffer::Write(const void *data, UInt32 size)
+{
+ if (_bufPos < kTempBufSize)
+ {
+ UInt32 cur = MyMin(kTempBufSize - _bufPos, size);
+ memcpy(_buf + _bufPos, data, cur);
+ _crc = CrcUpdate(_crc, data, cur);
+ _bufPos += cur;
+ size -= cur;
+ data = ((const Byte *)data) + cur;
+ _size += cur;
+ }
+ return WriteToFile(data, size);
+}
+
+HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
+{
+ if (!_outFile.Close())
+ return E_FAIL;
+
+ UInt64 size = 0;
+ UInt32 crc = CRC_INIT_VAL;
+
+ if (_bufPos > 0)
+ {
+ RINOK(WriteStream(stream, _buf, _bufPos));
+ crc = CrcUpdate(crc, _buf, _bufPos);
+ size += _bufPos;
+ }
+ if (_tempFileCreated)
+ {
+ NIO::CInFile inFile;
+ if (!inFile.Open(_tempFileName))
+ return E_FAIL;
+ while (size < _size)
+ {
+ UInt32 processed;
+ if (!inFile.ReadPart(_buf, kTempBufSize, processed))
+ return E_FAIL;
+ if (processed == 0)
+ break;
+ RINOK(WriteStream(stream, _buf, processed));
+ crc = CrcUpdate(crc, _buf, processed);
+ size += processed;
+ }
+ }
+ return (_crc == crc && size == _size) ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processed)
+{
+ if (!_buf->Write(data, size))
+ {
+ if (processed != NULL)
+ *processed = 0;
+ return E_FAIL;
+ }
+ if (processed != NULL)
+ *processed = size;
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.h b/src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.h
new file mode 100644
index 000000000..073f95acf
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/InOutTempBuffer.h
@@ -0,0 +1,48 @@
+// InOutTempBuffer.h
+
+#ifndef __IN_OUT_TEMP_BUFFER_H
+#define __IN_OUT_TEMP_BUFFER_H
+
+#include "../../Common/MyCom.h"
+#include "../../Windows/FileDir.h"
+#include "../../Windows/FileIO.h"
+
+#include "../IStream.h"
+
+class CInOutTempBuffer
+{
+ NWindows::NFile::NDirectory::CTempFile _tempFile;
+ NWindows::NFile::NIO::COutFile _outFile;
+ Byte *_buf;
+ UInt32 _bufPos;
+ CSysString _tempFileName;
+ bool _tempFileCreated;
+ UInt64 _size;
+ UInt32 _crc;
+
+ bool WriteToFile(const void *data, UInt32 size);
+public:
+ CInOutTempBuffer();
+ ~CInOutTempBuffer();
+ void Create();
+
+ void InitWriting();
+ bool Write(const void *data, UInt32 size);
+
+ HRESULT WriteToStream(ISequentialOutStream *stream);
+ UInt64 GetDataSize() const { return _size; }
+};
+
+class CSequentialOutTempBufferImp:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CInOutTempBuffer *_buf;
+public:
+ void Init(CInOutTempBuffer *buffer) { _buf = buffer; }
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.cpp b/src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.cpp
new file mode 100644
index 000000000..1837e3201
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.cpp
@@ -0,0 +1,154 @@
+// LimitedStreams.cpp
+
+#include "StdAfx.h"
+
+#include "LimitedStreams.h"
+#include "../../Common/Defs.h"
+
+STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ UInt32 sizeToRead = (UInt32)MyMin((_size - _pos), (UInt64)size);
+ HRESULT result = S_OK;
+ if (sizeToRead > 0)
+ {
+ result = _stream->Read(data, sizeToRead, &realProcessedSize);
+ _pos += realProcessedSize;
+ if (realProcessedSize == 0)
+ _wasFinished = true;
+ }
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= _size)
+ return (_virtPos == _size) ? S_OK: E_FAIL;
+ UInt64 rem = _size - _virtPos;
+ if (rem < size)
+ size = (UInt32)rem;
+ UInt64 newPos = _startOffset + _virtPos;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+ HRESULT res = _stream->Read(data, size, &size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ _physPos += size;
+ _virtPos += size;
+ return res;
+}
+
+STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _virtPos = offset; break;
+ case STREAM_SEEK_CUR: _virtPos += offset; break;
+ case STREAM_SEEK_END: _virtPos = _size + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return (_virtPos == Size) ? S_OK: E_FAIL;
+
+ if (_curRem == 0)
+ {
+ UInt32 blockSize = (UInt32)1 << BlockSizeLog;
+ UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
+ UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ UInt32 phyBlock = Vector[virtBlock];
+ UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+ _curRem = blockSize - offsetInBlock;
+ for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
+ _curRem += (UInt32)1 << BlockSizeLog;
+ UInt64 rem = Size - _virtPos;
+ if (_curRem > rem)
+ _curRem = (UInt32)rem;
+ }
+ if (size > _curRem)
+ size = _curRem;
+ HRESULT res = Stream->Read(data, size, &size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ _physPos += size;
+ _virtPos += size;
+ _curRem -= size;
+ return res;
+}
+
+STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ UInt64 newVirtPos = offset;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: newVirtPos += _virtPos; break;
+ case STREAM_SEEK_END: newVirtPos += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (_virtPos != newVirtPos)
+ _curRem = 0;
+ _virtPos = newVirtPos;
+ if (newPosition)
+ *newPosition = newVirtPos;
+ return S_OK;
+}
+
+
+HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
+{
+ *resStream = 0;
+ CLimitedInStream *streamSpec = new CLimitedInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->SetStream(inStream);
+ RINOK(streamSpec->InitAndSeek(pos, size));
+ streamSpec->SeekToStart();
+ *resStream = streamTemp.Detach();
+ return S_OK;
+}
+
+STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = S_OK;
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (size > _size)
+ {
+ if (_size == 0)
+ {
+ _overflow = true;
+ if (!_overflowIsAllowed)
+ return E_FAIL;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+ }
+ size = (UInt32)_size;
+ }
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ _size -= size;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.h b/src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.h
new file mode 100644
index 000000000..2cbe18e48
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/LimitedStreams.h
@@ -0,0 +1,125 @@
+// LimitedStreams.h
+
+#ifndef __LIMITED_STREAMS_H
+#define __LIMITED_STREAMS_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyVector.h"
+#include "../IStream.h"
+
+class CLimitedSequentialInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ UInt64 _pos;
+ bool _wasFinished;
+public:
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(UInt64 streamSize)
+ {
+ _size = streamSize;
+ _pos = 0;
+ _wasFinished = false;
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ UInt64 GetSize() const { return _pos; }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+class CLimitedInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<IInStream> _stream;
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt64 _size;
+ UInt64 _startOffset;
+
+ HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
+public:
+ void SetStream(IInStream *stream) { _stream = stream; }
+ HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)
+ {
+ _startOffset = startOffset;
+ _physPos = startOffset;
+ _virtPos = 0;
+ _size = size;
+ return SeekToPhys();
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+
+ HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }
+};
+
+class CClusterInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt32 _curRem;
+public:
+ CMyComPtr<IInStream> Stream;
+ UInt64 StartOffset;
+ UInt64 Size;
+ int BlockSizeLog;
+ CRecordVector<UInt32> Vector;
+
+ HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
+
+ HRESULT InitAndSeek()
+ {
+ _curRem = 0;
+ _virtPos = 0;
+ _physPos = StartOffset;
+ if (Vector.Size() > 0)
+ {
+ _physPos = StartOffset + (Vector[0] << BlockSizeLog);
+ return SeekToPhys();
+ }
+ return S_OK;
+ }
+
+ MY_UNKNOWN_IMP1(IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream);
+
+class CLimitedSequentialOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ bool _overflow;
+ bool _overflowIsAllowed;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(UInt64 size, bool overflowIsAllowed = false)
+ {
+ _size = size;
+ _overflow = false;
+ _overflowIsAllowed = overflowIsAllowed;
+ }
+ bool IsFinishedOK() const { return (_size == 0 && !_overflow); }
+ UInt64 GetRem() const { return _size; }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/LockedStream.cpp b/src/libs/7zip/win/CPP/7zip/Common/LockedStream.cpp
new file mode 100644
index 000000000..f05601cb6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/LockedStream.cpp
@@ -0,0 +1,23 @@
+// LockedStream.cpp
+
+#include "StdAfx.h"
+
+#include "LockedStream.h"
+
+HRESULT CLockedInStream::Read(UInt64 startPos, void *data, UInt32 size,
+ UInt32 *processedSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ RINOK(_stream->Seek(startPos, STREAM_SEEK_SET, NULL));
+ return _stream->Read(data, size, processedSize);
+}
+
+STDMETHODIMP CLockedSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize = 0;
+ HRESULT result = _lockedInStream->Read(_pos, data, size, &realProcessedSize);
+ _pos += realProcessedSize;
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return result;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/LockedStream.h b/src/libs/7zip/win/CPP/7zip/Common/LockedStream.h
new file mode 100644
index 000000000..486e4220b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/LockedStream.h
@@ -0,0 +1,38 @@
+// LockedStream.h
+
+#ifndef __LOCKEDSTREAM_H
+#define __LOCKEDSTREAM_H
+
+#include "../../Windows/Synchronization.h"
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+class CLockedInStream
+{
+ CMyComPtr<IInStream> _stream;
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ void Init(IInStream *stream)
+ { _stream = stream; }
+ HRESULT Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CLockedSequentialInStreamImp:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CLockedInStream *_lockedInStream;
+ UInt64 _pos;
+public:
+ void Init(CLockedInStream *lockedInStream, UInt64 startPos)
+ {
+ _lockedInStream = lockedInStream;
+ _pos = startPos;
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/MemBlocks.cpp b/src/libs/7zip/win/CPP/7zip/Common/MemBlocks.cpp
new file mode 100644
index 000000000..a5b93b5e7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/MemBlocks.cpp
@@ -0,0 +1,183 @@
+// MemBlocks.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "MemBlocks.h"
+#include "StreamUtils.h"
+
+bool CMemBlockManager::AllocateSpace(size_t numBlocks)
+{
+ FreeSpace();
+ if (_blockSize < sizeof(void *) || numBlocks < 1)
+ return false;
+ size_t totalSize = numBlocks * _blockSize;
+ if (totalSize / _blockSize != numBlocks)
+ return false;
+ _data = ::MidAlloc(totalSize);
+ if (_data == 0)
+ return false;
+ Byte *p = (Byte *)_data;
+ for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize)
+ *(Byte **)p = (p + _blockSize);
+ *(Byte **)p = 0;
+ _headFree = _data;
+ return true;
+}
+
+void CMemBlockManager::FreeSpace()
+{
+ ::MidFree(_data);
+ _data = 0;
+ _headFree= 0;
+}
+
+void *CMemBlockManager::AllocateBlock()
+{
+ if (_headFree == 0)
+ return 0;
+ void *p = _headFree;
+ _headFree = *(void **)_headFree;
+ return p;
+}
+
+void CMemBlockManager::FreeBlock(void *p)
+{
+ if (p == 0)
+ return;
+ *(void **)p = _headFree;
+ _headFree = p;
+}
+
+
+HRes CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks)
+{
+ if (numNoLockBlocks > numBlocks)
+ return E_INVALIDARG;
+ if (!CMemBlockManager::AllocateSpace(numBlocks))
+ return E_OUTOFMEMORY;
+ size_t numLockBlocks = numBlocks - numNoLockBlocks;
+ Semaphore.Close();
+ return Semaphore.Create((LONG)numLockBlocks, (LONG)numLockBlocks);
+}
+
+HRes CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks)
+{
+ if (numNoLockBlocks > desiredNumberOfBlocks)
+ return E_INVALIDARG;
+ for (;;)
+ {
+ if (AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks) == 0)
+ return 0;
+ if (desiredNumberOfBlocks == numNoLockBlocks)
+ return E_OUTOFMEMORY;
+ desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1);
+ }
+}
+
+void CMemBlockManagerMt::FreeSpace()
+{
+ Semaphore.Close();
+ CMemBlockManager::FreeSpace();
+}
+
+void *CMemBlockManagerMt::AllocateBlock()
+{
+ // Semaphore.Lock();
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ return CMemBlockManager::AllocateBlock();
+}
+
+void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode)
+{
+ if (p == 0)
+ return;
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ CMemBlockManager::FreeBlock(p);
+ }
+ if (lockMode)
+ Semaphore.Release();
+}
+
+void CMemBlocks::Free(CMemBlockManagerMt *manager)
+{
+ while(Blocks.Size() > 0)
+ {
+ manager->FreeBlock(Blocks.Back());
+ Blocks.DeleteBack();
+ }
+ TotalSize = 0;
+}
+
+void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager)
+{
+ Free(manager);
+ Blocks.ClearAndFree();
+}
+
+HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const
+{
+ UInt64 totalSize = TotalSize;
+ for (int blockIndex = 0; totalSize > 0; blockIndex++)
+ {
+ UInt32 curSize = (UInt32)blockSize;
+ if (totalSize < curSize)
+ curSize = (UInt32)totalSize;
+ if (blockIndex >= Blocks.Size())
+ return E_FAIL;
+ RINOK(WriteStream(outStream, Blocks[blockIndex], curSize));
+ totalSize -= curSize;
+ }
+ return S_OK;
+}
+
+
+void CMemLockBlocks::FreeBlock(int index, CMemBlockManagerMt *memManager)
+{
+ memManager->FreeBlock(Blocks[index], LockMode);
+ Blocks[index] = 0;
+}
+
+void CMemLockBlocks::Free(CMemBlockManagerMt *memManager)
+{
+ while (Blocks.Size() > 0)
+ {
+ FreeBlock(Blocks.Size() - 1, memManager);
+ Blocks.DeleteBack();
+ }
+ TotalSize = 0;
+}
+
+HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager)
+{
+ if (LockMode)
+ {
+ if (Blocks.Size() > 0)
+ {
+ RINOK(memManager->ReleaseLockedBlocks(Blocks.Size()));
+ }
+ LockMode = false;
+ }
+ return 0;
+}
+
+void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager)
+{
+ blocks.Free(memManager);
+ blocks.LockMode = LockMode;
+ UInt64 totalSize = 0;
+ size_t blockSize = memManager->GetBlockSize();
+ for (int i = 0; i < Blocks.Size(); i++)
+ {
+ if (totalSize < TotalSize)
+ blocks.Blocks.Add(Blocks[i]);
+ else
+ FreeBlock(i, memManager);
+ Blocks[i] = 0;
+ totalSize += blockSize;
+ }
+ blocks.TotalSize = TotalSize;
+ Free(memManager);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/MemBlocks.h b/src/libs/7zip/win/CPP/7zip/Common/MemBlocks.h
new file mode 100644
index 000000000..e1058ae38
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/MemBlocks.h
@@ -0,0 +1,71 @@
+// MemBlocks.h
+
+#ifndef __MEM_BLOCKS_H
+#define __MEM_BLOCKS_H
+
+#include "Common/MyVector.h"
+
+#include "Windows/Synchronization.h"
+
+#include "../IStream.h"
+
+class CMemBlockManager
+{
+ void *_data;
+ size_t _blockSize;
+ void *_headFree;
+public:
+ CMemBlockManager(size_t blockSize = (1 << 20)): _data(0), _blockSize(blockSize), _headFree(0) {}
+ ~CMemBlockManager() { FreeSpace(); }
+
+ bool AllocateSpace(size_t numBlocks);
+ void FreeSpace();
+ size_t GetBlockSize() const { return _blockSize; }
+ void *AllocateBlock();
+ void FreeBlock(void *p);
+};
+
+
+class CMemBlockManagerMt: public CMemBlockManager
+{
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ NWindows::NSynchronization::CSemaphore Semaphore;
+
+ CMemBlockManagerMt(size_t blockSize = (1 << 20)): CMemBlockManager(blockSize) {}
+ ~CMemBlockManagerMt() { FreeSpace(); }
+
+ HRes AllocateSpace(size_t numBlocks, size_t numNoLockBlocks = 0);
+ HRes AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks = 0);
+ void FreeSpace();
+ void *AllocateBlock();
+ void FreeBlock(void *p, bool lockMode = true);
+ HRes ReleaseLockedBlocks(int number) { return Semaphore.Release(number); }
+};
+
+
+class CMemBlocks
+{
+ void Free(CMemBlockManagerMt *manager);
+public:
+ CRecordVector<void *> Blocks;
+ UInt64 TotalSize;
+
+ CMemBlocks(): TotalSize(0) {}
+
+ void FreeOpt(CMemBlockManagerMt *manager);
+ HRESULT WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const;
+};
+
+struct CMemLockBlocks: public CMemBlocks
+{
+ bool LockMode;
+
+ CMemLockBlocks(): LockMode(true) {};
+ void Free(CMemBlockManagerMt *memManager);
+ void FreeBlock(int index, CMemBlockManagerMt *memManager);
+ HRes SwitchToNoLockMode(CMemBlockManagerMt *memManager);
+ void Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/MethodId.cpp b/src/libs/7zip/win/CPP/7zip/Common/MethodId.cpp
new file mode 100644
index 000000000..b797b6857
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/MethodId.cpp
@@ -0,0 +1,27 @@
+// MethodId.cpp
+
+#include "StdAfx.h"
+
+#include "MethodId.h"
+#include "../../Common/MyString.h"
+
+static inline wchar_t GetHex(Byte value)
+{
+ return (wchar_t)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+UString ConvertMethodIdToString(UInt64 id)
+{
+ wchar_t s[32];
+ int len = 32;
+ s[--len] = 0;
+ do
+ {
+ s[--len] = GetHex((Byte)id & 0xF);
+ id >>= 4;
+ s[--len] = GetHex((Byte)id & 0xF);
+ id >>= 4;
+ }
+ while (id != 0);
+ return s + len;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/MethodId.h b/src/libs/7zip/win/CPP/7zip/Common/MethodId.h
new file mode 100644
index 000000000..54ebc9f7d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/MethodId.h
@@ -0,0 +1,10 @@
+// MethodId.h
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "../../Common/Types.h"
+
+typedef UInt64 CMethodId;
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/MethodProps.cpp b/src/libs/7zip/win/CPP/7zip/Common/MethodProps.cpp
new file mode 100644
index 000000000..5836d0f84
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/MethodProps.cpp
@@ -0,0 +1,99 @@
+// MethodProps.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "MethodProps.h"
+
+static const UInt64 k_LZMA = 0x030101;
+static const UInt64 k_LZMA2 = 0x21;
+
+HRESULT SetMethodProperties(const CMethod &method, const UInt64 *inSizeForReduce, IUnknown *coder)
+{
+ bool tryReduce = false;
+ UInt32 reducedDictionarySize = 1 << 10;
+ if (inSizeForReduce != 0 && (method.Id == k_LZMA || method.Id == k_LZMA2))
+ {
+ for (;;)
+ {
+ const UInt32 step = (reducedDictionarySize >> 1);
+ if (reducedDictionarySize >= *inSizeForReduce)
+ {
+ tryReduce = true;
+ break;
+ }
+ reducedDictionarySize += step;
+ if (reducedDictionarySize >= *inSizeForReduce)
+ {
+ tryReduce = true;
+ break;
+ }
+ if (reducedDictionarySize >= ((UInt32)3 << 30))
+ break;
+ reducedDictionarySize += step;
+ }
+ }
+
+ {
+ int numProps = method.Props.Size();
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
+ if (setCoderProperties == NULL)
+ {
+ if (numProps != 0)
+ return E_INVALIDARG;
+ }
+ else
+ {
+ CRecordVector<PROPID> propIDs;
+ NWindows::NCOM::CPropVariant *values = new NWindows::NCOM::CPropVariant[numProps];
+ HRESULT res = S_OK;
+ try
+ {
+ for (int i = 0; i < numProps; i++)
+ {
+ const CProp &prop = method.Props[i];
+ propIDs.Add(prop.Id);
+ NWindows::NCOM::CPropVariant &value = values[i];
+ value = prop.Value;
+ // if (tryReduce && prop.Id == NCoderPropID::kDictionarySize && value.vt == VT_UI4 && reducedDictionarySize < value.ulVal)
+ if (tryReduce)
+ if (prop.Id == NCoderPropID::kDictionarySize)
+ if (value.vt == VT_UI4)
+ if (reducedDictionarySize < value.ulVal)
+ value.ulVal = reducedDictionarySize;
+ }
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
+ res = setCoderProperties->SetCoderProperties(&propIDs.Front(), values, numProps);
+ }
+ catch(...)
+ {
+ delete []values;
+ throw;
+ }
+ delete []values;
+ RINOK(res);
+ }
+ }
+
+ /*
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+ coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
+ if (writeCoderProperties != NULL)
+ {
+ CSequentialOutStreamImp *outStreamSpec = new CSequentialOutStreamImp;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init();
+ RINOK(writeCoderProperties->WriteCoderProperties(outStream));
+ size_t size = outStreamSpec->GetSize();
+ filterProps.SetCapacity(size);
+ memmove(filterProps, outStreamSpec->GetBuffer(), size);
+ }
+ */
+ return S_OK;
+}
+
diff --git a/src/libs/7zip/win/CPP/7zip/Common/MethodProps.h b/src/libs/7zip/win/CPP/7zip/Common/MethodProps.h
new file mode 100644
index 000000000..8127e21ee
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/MethodProps.h
@@ -0,0 +1,41 @@
+// MethodProps.h
+
+#ifndef __7Z_METHOD_PROPS_H
+#define __7Z_METHOD_PROPS_H
+
+#include "../../Common/MyVector.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "MethodId.h"
+
+struct CProp
+{
+ PROPID Id;
+ NWindows::NCOM::CPropVariant Value;
+};
+
+struct CMethod
+{
+ CMethodId Id;
+ CObjectVector<CProp> Props;
+};
+
+struct CMethodsMode
+{
+ CObjectVector<CMethod> Methods;
+ #ifndef _7ZIP_ST
+ UInt32 NumThreads;
+ #endif
+
+ CMethodsMode()
+ #ifndef _7ZIP_ST
+ : NumThreads(1)
+ #endif
+ {}
+ bool IsEmpty() const { return Methods.IsEmpty() ; }
+};
+
+HRESULT SetMethodProperties(const CMethod &method, const UInt64 *inSizeForReduce, IUnknown *coder);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/OffsetStream.cpp b/src/libs/7zip/win/CPP/7zip/Common/OffsetStream.cpp
new file mode 100644
index 000000000..c5e4e6da4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/OffsetStream.cpp
@@ -0,0 +1,35 @@
+// OffsetStream.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Defs.h"
+#include "OffsetStream.h"
+
+HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset)
+{
+ _offset = offset;
+ _stream = stream;
+ return _stream->Seek(offset, STREAM_SEEK_SET, NULL);
+}
+
+STDMETHODIMP COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ return _stream->Write(data, size, processedSize);
+}
+
+STDMETHODIMP COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin,
+ UInt64 *newPosition)
+{
+ UInt64 absoluteNewPosition;
+ if (seekOrigin == STREAM_SEEK_SET)
+ offset += _offset;
+ HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition);
+ if (newPosition != NULL)
+ *newPosition = absoluteNewPosition - _offset;
+ return result;
+}
+
+STDMETHODIMP COffsetOutStream::SetSize(UInt64 newSize)
+{
+ return _stream->SetSize(_offset + newSize);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/OffsetStream.h b/src/libs/7zip/win/CPP/7zip/Common/OffsetStream.h
new file mode 100644
index 000000000..de9d06dd0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/OffsetStream.h
@@ -0,0 +1,25 @@
+// OffsetStream.h
+
+#ifndef __OFFSETSTREAM_H
+#define __OFFSETSTREAM_H
+
+#include "Common/MyCom.h"
+#include "../IStream.h"
+
+class COffsetOutStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ UInt64 _offset;
+ CMyComPtr<IOutStream> _stream;
+public:
+ HRESULT Init(IOutStream *stream, UInt64 offset);
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/OutBuffer.cpp b/src/libs/7zip/win/CPP/7zip/Common/OutBuffer.cpp
new file mode 100644
index 000000000..2e5debd83
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/OutBuffer.cpp
@@ -0,0 +1,116 @@
+// OutBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "OutBuffer.h"
+
+bool COutBuffer::Create(UInt32 bufferSize)
+{
+ const UInt32 kMinBlockSize = 1;
+ if (bufferSize < kMinBlockSize)
+ bufferSize = kMinBlockSize;
+ if (_buffer != 0 && _bufferSize == bufferSize)
+ return true;
+ Free();
+ _bufferSize = bufferSize;
+ _buffer = (Byte *)::MidAlloc(bufferSize);
+ return (_buffer != 0);
+}
+
+void COutBuffer::Free()
+{
+ ::MidFree(_buffer);
+ _buffer = 0;
+}
+
+void COutBuffer::SetStream(ISequentialOutStream *stream)
+{
+ _stream = stream;
+}
+
+void COutBuffer::Init()
+{
+ _streamPos = 0;
+ _limitPos = _bufferSize;
+ _pos = 0;
+ _processedSize = 0;
+ _overDict = false;
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
+
+UInt64 COutBuffer::GetProcessedSize() const
+{
+ UInt64 res = _processedSize + _pos - _streamPos;
+ if (_streamPos > _pos)
+ res += _bufferSize;
+ return res;
+}
+
+
+HRESULT COutBuffer::FlushPart()
+{
+ // _streamPos < _bufferSize
+ UInt32 size = (_streamPos >= _pos) ? (_bufferSize - _streamPos) : (_pos - _streamPos);
+ HRESULT result = S_OK;
+ #ifdef _NO_EXCEPTIONS
+ result = ErrorCode;
+ #endif
+ if (_buffer2 != 0)
+ {
+ memmove(_buffer2, _buffer + _streamPos, size);
+ _buffer2 += size;
+ }
+
+ if (_stream != 0
+ #ifdef _NO_EXCEPTIONS
+ && (ErrorCode == S_OK)
+ #endif
+ )
+ {
+ UInt32 processedSize = 0;
+ result = _stream->Write(_buffer + _streamPos, size, &processedSize);
+ size = processedSize;
+ }
+ _streamPos += size;
+ if (_streamPos == _bufferSize)
+ _streamPos = 0;
+ if (_pos == _bufferSize)
+ {
+ _overDict = true;
+ _pos = 0;
+ }
+ _limitPos = (_streamPos > _pos) ? _streamPos : _bufferSize;
+ _processedSize += size;
+ return result;
+}
+
+HRESULT COutBuffer::Flush()
+{
+ #ifdef _NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ return ErrorCode;
+ #endif
+
+ while(_streamPos != _pos)
+ {
+ HRESULT result = FlushPart();
+ if (result != S_OK)
+ return result;
+ }
+ return S_OK;
+}
+
+void COutBuffer::FlushWithCheck()
+{
+ HRESULT result = Flush();
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = result;
+ #else
+ if (result != S_OK)
+ throw COutBufferException(result);
+ #endif
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/OutBuffer.h b/src/libs/7zip/win/CPP/7zip/Common/OutBuffer.h
new file mode 100644
index 000000000..62e77caae
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/OutBuffer.h
@@ -0,0 +1,64 @@
+// OutBuffer.h
+
+#ifndef __OUTBUFFER_H
+#define __OUTBUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+
+#ifndef _NO_EXCEPTIONS
+struct COutBufferException: public CSystemException
+{
+ COutBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+#endif
+
+class COutBuffer
+{
+protected:
+ Byte *_buffer;
+ UInt32 _pos;
+ UInt32 _limitPos;
+ UInt32 _streamPos;
+ UInt32 _bufferSize;
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _processedSize;
+ Byte *_buffer2;
+ bool _overDict;
+
+ HRESULT FlushPart();
+public:
+ #ifdef _NO_EXCEPTIONS
+ HRESULT ErrorCode;
+ #endif
+
+ COutBuffer(): _buffer(0), _pos(0), _stream(0), _buffer2(0) {}
+ ~COutBuffer() { Free(); }
+
+ bool Create(UInt32 bufferSize);
+ void Free();
+
+ void SetMemStream(Byte *buffer) { _buffer2 = buffer; }
+ void SetStream(ISequentialOutStream *stream);
+ void Init();
+ HRESULT Flush();
+ void FlushWithCheck();
+ void ReleaseStream() { _stream.Release(); }
+
+ void WriteByte(Byte b)
+ {
+ _buffer[_pos++] = b;
+ if(_pos == _limitPos)
+ FlushWithCheck();
+ }
+ void WriteBytes(const void *data, size_t size)
+ {
+ for (size_t i = 0; i < size; i++)
+ WriteByte(((const Byte *)data)[i]);
+ }
+
+ UInt64 GetProcessedSize() const;
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/OutMemStream.cpp b/src/libs/7zip/win/CPP/7zip/Common/OutMemStream.cpp
new file mode 100644
index 000000000..2e92886b8
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/OutMemStream.cpp
@@ -0,0 +1,142 @@
+// OutMemStream.cpp
+
+#include "StdAfx.h"
+
+#include "OutMemStream.h"
+
+void COutMemStream::Free()
+{
+ Blocks.Free(_memManager);
+ Blocks.LockMode = true;
+}
+
+void COutMemStream::Init()
+{
+ WriteToRealStreamEvent.Reset();
+ _unlockEventWasSent = false;
+ _realStreamMode = false;
+ Free();
+ _curBlockPos = 0;
+ _curBlockIndex = 0;
+}
+
+void COutMemStream::DetachData(CMemLockBlocks &blocks)
+{
+ Blocks.Detach(blocks, _memManager);
+ Free();
+}
+
+
+HRESULT COutMemStream::WriteToRealStream()
+{
+ RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream));
+ Blocks.Free(_memManager);
+ return S_OK;
+}
+
+STDMETHODIMP COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (_realStreamMode)
+ return OutSeqStream->Write(data, size, processedSize);
+ if (processedSize != 0)
+ *processedSize = 0;
+ while(size != 0)
+ {
+ if ((int)_curBlockIndex < Blocks.Blocks.Size())
+ {
+ Byte *p = (Byte *)Blocks.Blocks[(int)_curBlockIndex] + _curBlockPos;
+ size_t curSize = _memManager->GetBlockSize() - _curBlockPos;
+ if (size < curSize)
+ curSize = size;
+ memmove(p, data, curSize);
+ if (processedSize != 0)
+ *processedSize += (UInt32)curSize;
+ data = (const void *)((const Byte *)data + curSize);
+ size -= (UInt32)curSize;
+ _curBlockPos += curSize;
+
+ UInt64 pos64 = GetPos();
+ if (pos64 > Blocks.TotalSize)
+ Blocks.TotalSize = pos64;
+ if (_curBlockPos == _memManager->GetBlockSize())
+ {
+ _curBlockIndex++;
+ _curBlockPos = 0;
+ }
+ continue;
+ }
+ HANDLE events[3] = { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore };
+ DWORD waitResult = ::WaitForMultipleObjects((Blocks.LockMode ? 3 : 2), events, FALSE, INFINITE);
+ switch (waitResult)
+ {
+ case (WAIT_OBJECT_0 + 0):
+ return StopWriteResult;
+ case (WAIT_OBJECT_0 + 1):
+ {
+ _realStreamMode = true;
+ RINOK(WriteToRealStream());
+ UInt32 processedSize2;
+ HRESULT res = OutSeqStream->Write(data, size, &processedSize2);
+ if (processedSize != 0)
+ *processedSize += processedSize2;
+ return res;
+ }
+ /*
+ case (WAIT_OBJECT_0 + 2):
+ {
+ // it has bug: no write.
+ if (!Blocks.SwitchToNoLockMode(_memManager))
+ return E_FAIL;
+ break;
+ }
+ */
+ case (WAIT_OBJECT_0 + 2):
+ break;
+ default:
+ return E_FAIL;
+ }
+ Blocks.Blocks.Add(_memManager->AllocateBlock());
+ if (Blocks.Blocks.Back() == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if (_realStreamMode)
+ {
+ if (!OutStream)
+ return E_FAIL;
+ return OutStream->Seek(offset, seekOrigin, newPosition);
+ }
+ if (seekOrigin == STREAM_SEEK_CUR)
+ {
+ if (offset != 0)
+ return E_NOTIMPL;
+ }
+ else if (seekOrigin == STREAM_SEEK_SET)
+ {
+ if (offset != 0)
+ return E_NOTIMPL;
+ _curBlockIndex = 0;
+ _curBlockPos = 0;
+ }
+ else
+ return E_NOTIMPL;
+ if (newPosition != 0)
+ *newPosition = GetPos();
+ return S_OK;
+}
+
+STDMETHODIMP COutMemStream::SetSize(UInt64 newSize)
+{
+ if (_realStreamMode)
+ {
+ if (!OutStream)
+ return E_FAIL;
+ return OutStream->SetSize(newSize);
+ }
+ Blocks.TotalSize = newSize;
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/OutMemStream.h b/src/libs/7zip/win/CPP/7zip/Common/OutMemStream.h
new file mode 100644
index 000000000..b47f339e9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/OutMemStream.h
@@ -0,0 +1,96 @@
+// OutMemStream.h
+
+#ifndef __OUTMEMSTREAM_H
+#define __OUTMEMSTREAM_H
+
+#include "Common/MyCom.h"
+#include "MemBlocks.h"
+
+class COutMemStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ CMemBlockManagerMt *_memManager;
+ size_t _curBlockIndex;
+ size_t _curBlockPos;
+ bool _realStreamMode;
+
+ bool _unlockEventWasSent;
+ NWindows::NSynchronization::CAutoResetEvent StopWritingEvent;
+ NWindows::NSynchronization::CAutoResetEvent WriteToRealStreamEvent;
+ // NWindows::NSynchronization::CAutoResetEvent NoLockEvent;
+
+ HRESULT StopWriteResult;
+ CMemLockBlocks Blocks;
+
+ UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; }
+
+ CMyComPtr<ISequentialOutStream> OutSeqStream;
+ CMyComPtr<IOutStream> OutStream;
+
+public:
+
+ HRes CreateEvents()
+ {
+ RINOK(StopWritingEvent.CreateIfNotCreated());
+ return WriteToRealStreamEvent.CreateIfNotCreated();
+ }
+
+ void SetOutStream(IOutStream *outStream)
+ {
+ OutStream = outStream;
+ OutSeqStream = outStream;
+ }
+
+ void SetSeqOutStream(ISequentialOutStream *outStream)
+ {
+ OutStream = NULL;
+ OutSeqStream = outStream;
+ }
+
+ void ReleaseOutStream()
+ {
+ OutStream.Release();
+ OutSeqStream.Release();
+ }
+
+ COutMemStream(CMemBlockManagerMt *memManager): _memManager(memManager) { }
+
+ ~COutMemStream() { Free(); }
+ void Free();
+
+ void Init();
+ HRESULT WriteToRealStream();
+
+ void DetachData(CMemLockBlocks &blocks);
+
+ bool WasUnlockEventSent() const { return _unlockEventWasSent; }
+
+ void SetRealStreamMode()
+ {
+ _unlockEventWasSent = true;
+ WriteToRealStreamEvent.Set();
+ }
+
+ /*
+ void SetNoLockMode()
+ {
+ _unlockEventWasSent = true;
+ NoLockEvent.Set();
+ }
+ */
+
+ void StopWriting(HRESULT res)
+ {
+ StopWriteResult = res;
+ StopWritingEvent.Set();
+ }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/ProgressMt.cpp b/src/libs/7zip/win/CPP/7zip/Common/ProgressMt.cpp
new file mode 100644
index 000000000..319bd241b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/ProgressMt.cpp
@@ -0,0 +1,53 @@
+// ProgressMt.h
+
+#include "StdAfx.h"
+
+#include "ProgressMt.h"
+
+void CMtCompressProgressMixer::Init(int numItems, ICompressProgressInfo *progress)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ InSizes.Clear();
+ OutSizes.Clear();
+ for (int i = 0; i < numItems; i++)
+ {
+ InSizes.Add(0);
+ OutSizes.Add(0);
+ }
+ TotalInSize = 0;
+ TotalOutSize = 0;
+ _progress = progress;
+}
+
+void CMtCompressProgressMixer::Reinit(int index)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ InSizes[index] = 0;
+ OutSizes[index] = 0;
+}
+
+HRESULT CMtCompressProgressMixer::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ if (inSize != 0)
+ {
+ UInt64 diff = *inSize - InSizes[index];
+ InSizes[index] = *inSize;
+ TotalInSize += diff;
+ }
+ if (outSize != 0)
+ {
+ UInt64 diff = *outSize - OutSizes[index];
+ OutSizes[index] = *outSize;
+ TotalOutSize += diff;
+ }
+ if (_progress)
+ return _progress->SetRatioInfo(&TotalInSize, &TotalOutSize);
+ return S_OK;
+}
+
+
+STDMETHODIMP CMtCompressProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ return _progress->SetRatioInfo(_index, inSize, outSize);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/ProgressMt.h b/src/libs/7zip/win/CPP/7zip/Common/ProgressMt.h
new file mode 100644
index 000000000..26079d4e9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/ProgressMt.h
@@ -0,0 +1,46 @@
+// ProgressMt.h
+
+#ifndef __PROGRESSMT_H
+#define __PROGRESSMT_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyVector.h"
+#include "../../Windows/Synchronization.h"
+
+#include "../ICoder.h"
+#include "../IProgress.h"
+
+class CMtCompressProgressMixer
+{
+ CMyComPtr<ICompressProgressInfo> _progress;
+ CRecordVector<UInt64> InSizes;
+ CRecordVector<UInt64> OutSizes;
+ UInt64 TotalInSize;
+ UInt64 TotalOutSize;
+public:
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ void Init(int numItems, ICompressProgressInfo *progress);
+ void Reinit(int index);
+ HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize);
+};
+
+class CMtCompressProgress:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ CMtCompressProgressMixer *_progress;
+ int _index;
+public:
+ void Init(CMtCompressProgressMixer *progress, int index)
+ {
+ _progress = progress;
+ _index = index;
+ }
+ void Reinit() { _progress->Reinit(_index); }
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.cpp b/src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.cpp
new file mode 100644
index 000000000..f24ff6b6f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.cpp
@@ -0,0 +1,42 @@
+// ProgressUtils.h
+
+#include "StdAfx.h"
+
+#include "ProgressUtils.h"
+
+CLocalProgress::CLocalProgress()
+{
+ ProgressOffset = InSize = OutSize = 0;
+ SendRatio = SendProgress = true;
+}
+
+void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain)
+{
+ _ratioProgress.Release();
+ _progress = progress;
+ _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress);
+ _inSizeIsMain = inSizeIsMain;
+}
+
+STDMETHODIMP CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ UInt64 inSizeNew = InSize, outSizeNew = OutSize;
+ if (inSize)
+ inSizeNew += (*inSize);
+ if (outSize)
+ outSizeNew += (*outSize);
+ if (SendRatio && _ratioProgress)
+ {
+ RINOK(_ratioProgress->SetRatioInfo(&inSizeNew, &outSizeNew));
+ }
+ inSizeNew += ProgressOffset;
+ outSizeNew += ProgressOffset;
+ if (SendProgress)
+ return _progress->SetCompleted(_inSizeIsMain ? &inSizeNew : &outSizeNew);
+ return S_OK;
+}
+
+HRESULT CLocalProgress::SetCur()
+{
+ return SetRatioInfo(NULL, NULL);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.h b/src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.h
new file mode 100644
index 000000000..bae5395c1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/ProgressUtils.h
@@ -0,0 +1,34 @@
+// ProgressUtils.h
+
+#ifndef __PROGRESSUTILS_H
+#define __PROGRESSUTILS_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IProgress.h"
+
+class CLocalProgress:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ CMyComPtr<IProgress> _progress;
+ CMyComPtr<ICompressProgressInfo> _ratioProgress;
+ bool _inSizeIsMain;
+public:
+ UInt64 ProgressOffset;
+ UInt64 InSize;
+ UInt64 OutSize;
+ bool SendRatio;
+ bool SendProgress;
+
+ CLocalProgress();
+ void Init(IProgress *progress, bool inSizeIsMain);
+ HRESULT SetCur();
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h b/src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h
new file mode 100644
index 000000000..9b8cbd39d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/RegisterArc.h
@@ -0,0 +1,32 @@
+// RegisterArc.h
+
+#ifndef __REGISTER_ARC_H
+#define __REGISTER_ARC_H
+
+#include "../Archive/IArchive.h"
+
+typedef IInArchive * (*CreateInArchiveP)();
+typedef IOutArchive * (*CreateOutArchiveP)();
+
+struct CArcInfo
+{
+ const wchar_t *Name;
+ const wchar_t *Ext;
+ const wchar_t *AddExt;
+ Byte ClassId;
+ Byte Signature[16];
+ int SignatureSize;
+ bool KeepName;
+ CreateInArchiveP CreateInArchive;
+ CreateOutArchiveP CreateOutArchive;
+};
+
+void RegisterArc(const CArcInfo *arcInfo);
+
+#define REGISTER_ARC_NAME(x) CRegister ## x
+
+#define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \
+ REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \
+ static REGISTER_ARC_NAME(x) g_RegisterArc; \
+ void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; }
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h b/src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h
new file mode 100644
index 000000000..d53c4344a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/RegisterCodec.h
@@ -0,0 +1,34 @@
+// RegisterCodec.h
+
+#ifndef __REGISTERCODEC_H
+#define __REGISTERCODEC_H
+
+#include "../Common/MethodId.h"
+
+typedef void * (*CreateCodecP)();
+struct CCodecInfo
+{
+ CreateCodecP CreateDecoder;
+ CreateCodecP CreateEncoder;
+ CMethodId Id;
+ const wchar_t *Name;
+ UInt32 NumInStreams;
+ bool IsFilter;
+};
+
+void RegisterCodec(const CCodecInfo *codecInfo);
+
+#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x
+
+#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \
+ REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \
+ static REGISTER_CODEC_NAME(x) g_RegisterCodec; \
+ void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; }
+
+#define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x
+#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \
+ REGISTER_CODECS_NAME(x)() { for (int i = 0; i < sizeof(g_CodecsInfo) / sizeof(g_CodecsInfo[0]); i++) \
+ RegisterCodec(&g_CodecsInfo[i]); }}; \
+ static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \
+ void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; }
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Common/StdAfx.h
new file mode 100644
index 000000000..ef555ec12
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/MyWindows.h"
+#include "../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/StreamBinder.cpp b/src/libs/7zip/win/CPP/7zip/Common/StreamBinder.cpp
new file mode 100644
index 000000000..03f886258
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/StreamBinder.cpp
@@ -0,0 +1,150 @@
+// StreamBinder.cpp
+
+#include "StdAfx.h"
+
+#include "StreamBinder.h"
+#include "../../Common/Defs.h"
+#include "../../Common/MyCom.h"
+
+using namespace NWindows;
+using namespace NSynchronization;
+
+class CSequentialInStreamForBinder:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+private:
+ CStreamBinder *m_StreamBinder;
+public:
+ ~CSequentialInStreamForBinder() { m_StreamBinder->CloseRead(); }
+ void SetBinder(CStreamBinder *streamBinder) { m_StreamBinder = streamBinder; }
+};
+
+STDMETHODIMP CSequentialInStreamForBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
+ { return m_StreamBinder->Read(data, size, processedSize); }
+
+class CSequentialOutStreamForBinder:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+
+private:
+ CStreamBinder *m_StreamBinder;
+public:
+ ~CSequentialOutStreamForBinder() { m_StreamBinder->CloseWrite(); }
+ void SetBinder(CStreamBinder *streamBinder) { m_StreamBinder = streamBinder; }
+};
+
+STDMETHODIMP CSequentialOutStreamForBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+ { return m_StreamBinder->Write(data, size, processedSize); }
+
+
+//////////////////////////
+// CStreamBinder
+// (_thereAreBytesToReadEvent && _bufferSize == 0) means that stream is finished.
+
+HRes CStreamBinder::CreateEvents()
+{
+ RINOK(_allBytesAreWritenEvent.Create(true));
+ RINOK(_thereAreBytesToReadEvent.Create());
+ return _readStreamIsClosedEvent.Create();
+}
+
+void CStreamBinder::ReInit()
+{
+ _thereAreBytesToReadEvent.Reset();
+ _readStreamIsClosedEvent.Reset();
+ ProcessedSize = 0;
+}
+
+
+
+void CStreamBinder::CreateStreams(ISequentialInStream **inStream,
+ ISequentialOutStream **outStream)
+{
+ CSequentialInStreamForBinder *inStreamSpec = new
+ CSequentialInStreamForBinder;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ inStreamSpec->SetBinder(this);
+ *inStream = inStreamLoc.Detach();
+
+ CSequentialOutStreamForBinder *outStreamSpec = new
+ CSequentialOutStreamForBinder;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(outStreamSpec);
+ outStreamSpec->SetBinder(this);
+ *outStream = outStreamLoc.Detach();
+
+ _buffer = NULL;
+ _bufferSize= 0;
+ ProcessedSize = 0;
+}
+
+HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 sizeToRead = size;
+ if (size > 0)
+ {
+ RINOK(_thereAreBytesToReadEvent.Lock());
+ sizeToRead = MyMin(_bufferSize, size);
+ if (_bufferSize > 0)
+ {
+ memcpy(data, _buffer, sizeToRead);
+ _buffer = ((const Byte *)_buffer) + sizeToRead;
+ _bufferSize -= sizeToRead;
+ if (_bufferSize == 0)
+ {
+ _thereAreBytesToReadEvent.Reset();
+ _allBytesAreWritenEvent.Set();
+ }
+ }
+ }
+ if (processedSize != NULL)
+ *processedSize = sizeToRead;
+ ProcessedSize += sizeToRead;
+ return S_OK;
+}
+
+void CStreamBinder::CloseRead()
+{
+ _readStreamIsClosedEvent.Set();
+}
+
+HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (size > 0)
+ {
+ _buffer = data;
+ _bufferSize = size;
+ _allBytesAreWritenEvent.Reset();
+ _thereAreBytesToReadEvent.Set();
+
+ HANDLE events[2];
+ events[0] = _allBytesAreWritenEvent;
+ events[1] = _readStreamIsClosedEvent;
+ DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
+ if (waitResult != WAIT_OBJECT_0 + 0)
+ {
+ // ReadingWasClosed = true;
+ return S_FALSE;
+ }
+ // if(!_allBytesAreWritenEvent.Lock())
+ // return E_FAIL;
+ }
+ if (processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+void CStreamBinder::CloseWrite()
+{
+ // _bufferSize must be = 0
+ _thereAreBytesToReadEvent.Set();
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/StreamBinder.h b/src/libs/7zip/win/CPP/7zip/Common/StreamBinder.h
new file mode 100644
index 000000000..48f68e60f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/StreamBinder.h
@@ -0,0 +1,32 @@
+// StreamBinder.h
+
+#ifndef __STREAMBINDER_H
+#define __STREAMBINDER_H
+
+#include "../IStream.h"
+#include "../../Windows/Synchronization.h"
+
+class CStreamBinder
+{
+ NWindows::NSynchronization::CManualResetEvent _allBytesAreWritenEvent;
+ NWindows::NSynchronization::CManualResetEvent _thereAreBytesToReadEvent;
+ NWindows::NSynchronization::CManualResetEvent _readStreamIsClosedEvent;
+ UInt32 _bufferSize;
+ const void *_buffer;
+public:
+ // bool ReadingWasClosed;
+ UInt64 ProcessedSize;
+ CStreamBinder() {}
+ HRes CreateEvents();
+
+ void CreateStreams(ISequentialInStream **inStream,
+ ISequentialOutStream **outStream);
+ HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
+ void CloseRead();
+
+ HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize);
+ void CloseWrite();
+ void ReInit();
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/StreamObjects.cpp b/src/libs/7zip/win/CPP/7zip/Common/StreamObjects.cpp
new file mode 100644
index 000000000..3c86c3aeb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/StreamObjects.cpp
@@ -0,0 +1,221 @@
+// StreamObjects.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "StreamObjects.h"
+
+STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos > _size)
+ return E_FAIL;
+ size_t rem = _size - (size_t)_pos;
+ if (rem > size)
+ rem = (size_t)size;
+ memcpy(data, _data + (size_t)_pos, rem);
+ _pos += rem;
+ if (processedSize)
+ *processedSize = (UInt32)rem;
+ return S_OK;
+}
+
+STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _pos = offset; break;
+ case STREAM_SEEK_CUR: _pos += offset; break;
+ case STREAM_SEEK_END: _pos = _size + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition)
+ *newPosition = _pos;
+ return S_OK;
+}
+
+void CByteDynBuffer::Free()
+{
+ free(_buf);
+ _buf = 0;
+ _capacity = 0;
+}
+
+bool CByteDynBuffer::EnsureCapacity(size_t cap)
+{
+ if (cap <= _capacity)
+ return true;
+ size_t delta;
+ if (_capacity > 64)
+ delta = _capacity / 4;
+ else if (_capacity > 8)
+ delta = 16;
+ else
+ delta = 4;
+ cap = MyMax(_capacity + delta, cap);
+ Byte *buf = (Byte *)realloc(_buf, cap);
+ if (!buf)
+ return false;
+ _buf = buf;
+ _capacity = cap;
+ return true;
+}
+
+Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
+{
+ addSize += _size;
+ if (addSize < _size)
+ return NULL;
+ if (!_buffer.EnsureCapacity(addSize))
+ return NULL;
+ return (Byte *)_buffer + _size;
+}
+
+void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
+{
+ dest.SetCapacity(_size);
+ memcpy(dest, _buffer, _size);
+}
+
+STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ Byte *buf = GetBufPtrForWriting(size);
+ if (!buf)
+ return E_OUTOFMEMORY;
+ memcpy(buf, data, size);
+ UpdateSize(size);
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t rem = _size - _pos;
+ if (rem > size)
+ rem = (size_t)size;
+ memcpy(_buffer + _pos, data, rem);
+ _pos += rem;
+ if (processedSize)
+ *processedSize = (UInt32)rem;
+ return (rem != 0 || size == 0) ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Write(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
+
+void CCachedInStream::Free()
+{
+ MyFree(_tags);
+ _tags = 0;
+ MidFree(_data);
+ _data = 0;
+}
+
+bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog)
+{
+ unsigned sizeLog = blockSizeLog + numBlocksLog;
+ if (sizeLog >= sizeof(size_t) * 8)
+ return false;
+ size_t dataSize = (size_t)1 << sizeLog;
+ if (_data == 0 || dataSize != _dataSize)
+ {
+ MidFree(_data);
+ _data = (Byte *)MidAlloc(dataSize);
+ if (_data == 0)
+ return false;
+ _dataSize = dataSize;
+ }
+ if (_tags == 0 || numBlocksLog != _numBlocksLog)
+ {
+ MyFree(_tags);
+ _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
+ if (_tags == 0)
+ return false;
+ _numBlocksLog = numBlocksLog;
+ }
+ _blockSizeLog = blockSizeLog;
+ return true;
+}
+
+void CCachedInStream::Init(UInt64 size)
+{
+ _size = size;
+ _pos = 0;
+ size_t numBlocks = (size_t)1 << _numBlocksLog;
+ for (size_t i = 0; i < numBlocks; i++)
+ _tags[i] = kEmptyTag;
+}
+
+STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos > _size)
+ return E_FAIL;
+
+ {
+ UInt64 rem = _size - _pos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ while (size != 0)
+ {
+ UInt64 cacheTag = _pos >> _blockSizeLog;
+ size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
+ Byte *p = _data + (cacheIndex << _blockSizeLog);
+ if (_tags[cacheIndex] != cacheTag)
+ {
+ UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
+ size_t blockSize = (size_t)1 << _blockSizeLog;
+ if (blockSize > remInBlock)
+ blockSize = (size_t)remInBlock;
+ RINOK(ReadBlock(cacheTag, p, blockSize));
+ _tags[cacheIndex] = cacheTag;
+ }
+ size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1);
+ UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size);
+ memcpy(data, p + offset, cur);
+ if (processedSize)
+ *processedSize += cur;
+ data = (void *)((const Byte *)data + cur);
+ _pos += cur;
+ size -= cur;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET: _pos = offset; break;
+ case STREAM_SEEK_CUR: _pos = _pos + offset; break;
+ case STREAM_SEEK_END: _pos = _size + offset; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (newPosition != 0)
+ *newPosition = _pos;
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/StreamObjects.h b/src/libs/7zip/win/CPP/7zip/Common/StreamObjects.h
new file mode 100644
index 000000000..8cd95c700
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/StreamObjects.h
@@ -0,0 +1,135 @@
+// StreamObjects.h
+
+#ifndef __STREAM_OBJECTS_H
+#define __STREAM_OBJECTS_H
+
+#include "../../Common/Buffer.h"
+#include "../../Common/MyCom.h"
+#include "../IStream.h"
+
+struct CReferenceBuf:
+ public IUnknown,
+ public CMyUnknownImp
+{
+ CByteBuffer Buf;
+ MY_UNKNOWN_IMP
+};
+
+class CBufInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ const Byte *_data;
+ UInt64 _pos;
+ size_t _size;
+ CMyComPtr<IUnknown> _ref;
+public:
+ void Init(const Byte *data, size_t size, IUnknown *ref = 0)
+ {
+ _data = data;
+ _size = size;
+ _pos = 0;
+ _ref = ref;
+ }
+ void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.GetCapacity(), ref); }
+
+ MY_UNKNOWN_IMP1(IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+class CByteDynBuffer
+{
+ size_t _capacity;
+ Byte *_buf;
+public:
+ CByteDynBuffer(): _capacity(0), _buf(0) {};
+ // there is no copy constructor. So don't copy this object.
+ ~CByteDynBuffer() { Free(); }
+ void Free();
+ size_t GetCapacity() const { return _capacity; }
+ operator Byte*() const { return _buf; };
+ operator const Byte*() const { return _buf; };
+ bool EnsureCapacity(size_t capacity);
+};
+
+class CDynBufSeqOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CByteDynBuffer _buffer;
+ size_t _size;
+public:
+ CDynBufSeqOutStream(): _size(0) {}
+ void Init() { _size = 0; }
+ size_t GetSize() const { return _size; }
+ const Byte *GetBuffer() const { return _buffer; }
+ void CopyToBuffer(CByteBuffer &dest) const;
+ Byte *GetBufPtrForWriting(size_t addSize);
+ void UpdateSize(size_t addSize) { _size += addSize; }
+
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CBufPtrSeqOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ Byte *_buffer;
+ size_t _size;
+ size_t _pos;
+public:
+ void Init(Byte *buffer, size_t size)
+ {
+ _buffer = buffer;
+ _pos = 0;
+ _size = size;
+ }
+ size_t GetPos() const { return _pos; }
+
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CSequentialOutStreamSizeCount:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void Init() { _size = 0; }
+ UInt64 GetSize() const { return _size; }
+
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+class CCachedInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 *_tags;
+ Byte *_data;
+ size_t _dataSize;
+ unsigned _blockSizeLog;
+ unsigned _numBlocksLog;
+ UInt64 _size;
+ UInt64 _pos;
+protected:
+ virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0;
+public:
+ CCachedInStream(): _tags(0), _data(0) {}
+ virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (release calls it) !!!
+ void Free();
+ bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog);
+ void Init(UInt64 size);
+
+ MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/StreamUtils.cpp b/src/libs/7zip/win/CPP/7zip/Common/StreamUtils.cpp
new file mode 100644
index 000000000..049e4aa17
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/StreamUtils.cpp
@@ -0,0 +1,56 @@
+// StreamUtils.cpp
+
+#include "StdAfx.h"
+
+#include "StreamUtils.h"
+
+static const UInt32 kBlockSize = ((UInt32)1 << 31);
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize)
+{
+ size_t size = *processedSize;
+ *processedSize = 0;
+ while (size != 0)
+ {
+ UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
+ UInt32 processedSizeLoc;
+ HRESULT res = stream->Read(data, curSize, &processedSizeLoc);
+ *processedSize += processedSizeLoc;
+ data = (void *)((Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ RINOK(res);
+ if (processedSizeLoc == 0)
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size)
+{
+ size_t processedSize = size;
+ RINOK(ReadStream(stream, data, &processedSize));
+ return (size == processedSize) ? S_OK : S_FALSE;
+}
+
+HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size)
+{
+ size_t processedSize = size;
+ RINOK(ReadStream(stream, data, &processedSize));
+ return (size == processedSize) ? S_OK : E_FAIL;
+}
+
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size)
+{
+ while (size != 0)
+ {
+ UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
+ UInt32 processedSizeLoc;
+ HRESULT res = stream->Write(data, curSize, &processedSizeLoc);
+ data = (const void *)((const Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ RINOK(res);
+ if (processedSizeLoc == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Common/StreamUtils.h b/src/libs/7zip/win/CPP/7zip/Common/StreamUtils.h
new file mode 100644
index 000000000..f1cfd1848
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/StreamUtils.h
@@ -0,0 +1,13 @@
+// StreamUtils.h
+
+#ifndef __STREAMUTILS_H
+#define __STREAMUTILS_H
+
+#include "../IStream.h"
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size);
+HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size);
+HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size);
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Common/VirtThread.cpp b/src/libs/7zip/win/CPP/7zip/Common/VirtThread.cpp
new file mode 100644
index 000000000..cf39bd023
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/VirtThread.cpp
@@ -0,0 +1,46 @@
+// VirtThread.cpp
+
+#include "StdAfx.h"
+
+#include "VirtThread.h"
+
+static THREAD_FUNC_DECL CoderThread(void *p)
+{
+ for (;;)
+ {
+ CVirtThread *t = (CVirtThread *)p;
+ t->StartEvent.Lock();
+ if (t->ExitEvent)
+ return 0;
+ t->Execute();
+ t->FinishedEvent.Set();
+ }
+}
+
+WRes CVirtThread::Create()
+{
+ RINOK(StartEvent.CreateIfNotCreated());
+ RINOK(FinishedEvent.CreateIfNotCreated());
+ StartEvent.Reset();
+ FinishedEvent.Reset();
+ ExitEvent = false;
+ if (Thread.IsCreated())
+ return S_OK;
+ return Thread.Create(CoderThread, this);
+}
+
+void CVirtThread::Start()
+{
+ ExitEvent = false;
+ StartEvent.Set();
+}
+
+CVirtThread::~CVirtThread()
+{
+ ExitEvent = true;
+ if (StartEvent.IsCreated())
+ StartEvent.Set();
+ if (Thread.IsCreated())
+ Thread.Wait();
+}
+
diff --git a/src/libs/7zip/win/CPP/7zip/Common/VirtThread.h b/src/libs/7zip/win/CPP/7zip/Common/VirtThread.h
new file mode 100644
index 000000000..f14a1f223
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Common/VirtThread.h
@@ -0,0 +1,23 @@
+// VirtThread.h
+
+#ifndef __VIRTTHREAD_H
+#define __VIRTTHREAD_H
+
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+
+struct CVirtThread
+{
+ NWindows::NSynchronization::CAutoResetEvent StartEvent;
+ NWindows::NSynchronization::CAutoResetEvent FinishedEvent;
+ NWindows::CThread Thread;
+ bool ExitEvent;
+
+ ~CVirtThread();
+ WRes Create();
+ void Start();
+ void WaitFinish() { FinishedEvent.Lock(); }
+ virtual void Execute() = 0;
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder1.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder1.cpp
new file mode 100644
index 000000000..2c354e1eb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder1.cpp
@@ -0,0 +1,309 @@
+// ArjDecoder1.cpp
+
+#include "StdAfx.h"
+
+#include "ArjDecoder1.h"
+
+namespace NCompress{
+namespace NArj {
+namespace NDecoder1 {
+
+static const UInt32 kHistorySize = 26624;
+static const UInt32 kMatchMinLen = 3;
+static const UInt32 kMatchMaxLen = 256;
+
+// static const UInt32 kNC = 255 + kMatchMaxLen + 2 - kMatchMinLen;
+
+void CCoder::MakeTable(int nchar, Byte *bitlen, int tablebits,
+ UInt32 *table, int tablesize)
+{
+ UInt32 count[17], weight[17], start[18], *p;
+ UInt32 i, k, len, ch, jutbits, avail, nextcode, mask;
+
+ for (i = 1; i <= 16; i++)
+ count[i] = 0;
+ for (i = 0; (int)i < nchar; i++)
+ count[bitlen[i]]++;
+
+ start[1] = 0;
+ for (i = 1; i <= 16; i++)
+ start[i + 1] = start[i] + (count[i] << (16 - i));
+ if (start[17] != (UInt32) (1 << 16))
+ throw "Data error";
+
+ jutbits = 16 - tablebits;
+ for (i = 1; (int)i <= tablebits; i++)
+ {
+ start[i] >>= jutbits;
+ weight[i] = 1 << (tablebits - i);
+ }
+ while (i <= 16)
+ {
+ weight[i] = 1 << (16 - i);
+ i++;
+ }
+
+ i = start[tablebits + 1] >> jutbits;
+ if (i != (UInt32) (1 << 16))
+ {
+ k = 1 << tablebits;
+ while (i != k)
+ table[i++] = 0;
+ }
+
+ avail = nchar;
+ mask = 1 << (15 - tablebits);
+ for (ch = 0; (int)ch < nchar; ch++)
+ {
+ if ((len = bitlen[ch]) == 0)
+ continue;
+ k = start[len];
+ nextcode = k + weight[len];
+ if ((int)len <= tablebits)
+ {
+ if (nextcode > (UInt32)tablesize)
+ throw "Data error";
+ for (i = start[len]; i < nextcode; i++)
+ table[i] = ch;
+ }
+ else
+ {
+ p = &table[k >> jutbits];
+ i = len - tablebits;
+ while (i != 0)
+ {
+ if (*p == 0)
+ {
+ right[avail] = left[avail] = 0;
+ *p = avail++;
+ }
+ if (k & mask)
+ p = &right[*p];
+ else
+ p = &left[*p];
+ k <<= 1;
+ i--;
+ }
+ *p = ch;
+ }
+ start[len] = nextcode;
+ }
+}
+
+void CCoder::read_pt_len(int nn, int nbit, int i_special)
+{
+ UInt32 n = m_InBitStream.ReadBits(nbit);
+ if (n == 0)
+ {
+ UInt32 c = m_InBitStream.ReadBits(nbit);
+ int i;
+ for (i = 0; i < nn; i++)
+ pt_len[i] = 0;
+ for (i = 0; i < 256; i++)
+ pt_table[i] = c;
+ }
+ else
+ {
+ UInt32 i = 0;
+ while (i < n)
+ {
+ UInt32 bitBuf = m_InBitStream.GetValue(16);
+ int c = bitBuf >> 13;
+ if (c == 7)
+ {
+ UInt32 mask = 1 << (12);
+ while (mask & bitBuf)
+ {
+ mask >>= 1;
+ c++;
+ }
+ }
+ m_InBitStream.MovePos((c < 7) ? 3 : (int)(c - 3));
+ pt_len[i++] = (Byte)c;
+ if (i == (UInt32)i_special)
+ {
+ c = m_InBitStream.ReadBits(2);
+ while (--c >= 0)
+ pt_len[i++] = 0;
+ }
+ }
+ while (i < (UInt32)nn)
+ pt_len[i++] = 0;
+ MakeTable(nn, pt_len, 8, pt_table, PTABLESIZE);
+ }
+}
+
+void CCoder::read_c_len()
+{
+ int i, c, n;
+ UInt32 mask;
+
+ n = m_InBitStream.ReadBits(CBIT);
+ if (n == 0)
+ {
+ c = m_InBitStream.ReadBits(CBIT);
+ for (i = 0; i < NC; i++)
+ c_len[i] = 0;
+ for (i = 0; i < CTABLESIZE; i++)
+ c_table[i] = c;
+ }
+ else
+ {
+ i = 0;
+ while (i < n)
+ {
+ UInt32 bitBuf = m_InBitStream.GetValue(16);
+ c = pt_table[bitBuf >> (8)];
+ if (c >= NT)
+ {
+ mask = 1 << (7);
+ do
+ {
+ if (bitBuf & mask)
+ c = right[c];
+ else
+ c = left[c];
+ mask >>= 1;
+ } while (c >= NT);
+ }
+ m_InBitStream.MovePos((int)(pt_len[c]));
+ if (c <= 2)
+ {
+ if (c == 0)
+ c = 1;
+ else if (c == 1)
+ c = m_InBitStream.ReadBits(4) + 3;
+ else
+ c = m_InBitStream.ReadBits(CBIT) + 20;
+ while (--c >= 0)
+ c_len[i++] = 0;
+ }
+ else
+ c_len[i++] = (Byte)(c - 2);
+ }
+ while (i < NC)
+ c_len[i++] = 0;
+ MakeTable(NC, c_len, 12, c_table, CTABLESIZE);
+ }
+}
+
+UInt32 CCoder::decode_c()
+{
+ UInt32 j, mask;
+ UInt32 bitbuf = m_InBitStream.GetValue(16);
+ j = c_table[bitbuf >> 4];
+ if (j >= NC)
+ {
+ mask = 1 << (3);
+ do
+ {
+ if (bitbuf & mask)
+ j = right[j];
+ else
+ j = left[j];
+ mask >>= 1;
+ } while (j >= NC);
+ }
+ m_InBitStream.MovePos((int)(c_len[j]));
+ return j;
+}
+
+UInt32 CCoder::decode_p()
+{
+ UInt32 j, mask;
+ UInt32 bitbuf = m_InBitStream.GetValue(16);
+ j = pt_table[bitbuf >> (8)];
+ if (j >= NP)
+ {
+ mask = 1 << (7);
+ do
+ {
+ if (bitbuf & mask)
+ j = right[j];
+ else
+ j = left[j];
+ mask >>= 1;
+ } while (j >= NP);
+ }
+ m_InBitStream.MovePos((int)(pt_len[j]));
+ if (j != 0)
+ {
+ j--;
+ j = (1 << j) + m_InBitStream.ReadBits((int)j);
+ }
+ return j;
+}
+
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ // check it
+ for (int i = 0; i < CTABLESIZE; i++)
+ c_table[i] = 0;
+
+ UInt64 pos = 0;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ UInt32 blockSize = 0;
+
+ while(pos < *outSize)
+ {
+ if (blockSize == 0)
+ {
+ if (progress != NULL)
+ {
+ UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ }
+ blockSize = m_InBitStream.ReadBits(16);
+ read_pt_len(NT, TBIT, 3);
+ read_c_len();
+ read_pt_len(NP, PBIT, -1);
+ }
+ blockSize--;
+
+ UInt32 number = decode_c();
+ if (number < 256)
+ {
+ m_OutWindowStream.PutByte((Byte)number);
+ pos++;
+ continue;
+ }
+ else
+ {
+ UInt32 len = number - 256 + kMatchMinLen;
+ UInt32 distance = decode_p();
+ if (distance >= pos)
+ return S_FALSE;
+ m_OutWindowStream.CopyBlock(distance, len);
+ pos += len;
+ }
+ }
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder1.h b/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder1.h
new file mode 100644
index 000000000..17939dafb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder1.h
@@ -0,0 +1,98 @@
+// ArjDecoder1.h
+
+#ifndef __COMPRESS_ARJ_DECODER1_H
+#define __COMPRESS_ARJ_DECODER1_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NArj {
+namespace NDecoder1 {
+
+#define CODE_BIT 16
+
+#define THRESHOLD 3
+#define DDICSIZ 26624
+#define MAXDICBIT 16
+#define MATCHBIT 8
+#define MAXMATCH 256
+#define NC (0xFF + MAXMATCH + 2 - THRESHOLD)
+#define NP (MAXDICBIT + 1)
+#define CBIT 9
+#define NT (CODE_BIT + 3)
+#define PBIT 5
+#define TBIT 5
+
+#if NT > NP
+#define NPT NT
+#else
+#define NPT NP
+#endif
+
+#define CTABLESIZE 4096
+#define PTABLESIZE 256
+
+
+class CCoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitm::CDecoder<CInBuffer> m_InBitStream;
+
+ UInt32 left[2 * NC - 1];
+ UInt32 right[2 * NC - 1];
+ Byte c_len[NC];
+ Byte pt_len[NPT];
+
+ UInt32 c_table[CTABLESIZE];
+ UInt32 pt_table[PTABLESIZE];
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CCoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+ void MakeTable(int nchar, Byte *bitlen, int tablebits, UInt32 *table, int tablesize);
+
+ void read_c_len();
+ void read_pt_len(int nn, int nbit, int i_special);
+ UInt32 decode_c();
+ UInt32 decode_p();
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder2.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder2.cpp
new file mode 100644
index 000000000..365993bc5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder2.cpp
@@ -0,0 +1,90 @@
+// ArjDecoder2.cpp
+
+#include "StdAfx.h"
+
+#include "ArjDecoder2.h"
+
+namespace NCompress{
+namespace NArj {
+namespace NDecoder2 {
+
+static const UInt32 kHistorySize = 26624;
+static const UInt32 kMatchMinLen = 3;
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo * /* progress */)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ UInt64 pos = 0;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+ CCoderReleaser coderReleaser(this);
+
+ while(pos < *outSize)
+ {
+ const UInt32 kStartWidth = 0;
+ const UInt32 kStopWidth = 7;
+ UInt32 power = 1 << kStartWidth;
+ UInt32 width;
+ UInt32 len = 0;
+ for (width = kStartWidth; width < kStopWidth; width++)
+ {
+ if (m_InBitStream.ReadBits(1) == 0)
+ break;
+ len += power;
+ power <<= 1;
+ }
+ if (width != 0)
+ len += m_InBitStream.ReadBits(width);
+ if (len == 0)
+ {
+ m_OutWindowStream.PutByte((Byte)m_InBitStream.ReadBits(8));
+ pos++;
+ continue;
+ }
+ else
+ {
+ len = len - 1 + kMatchMinLen;
+ const UInt32 kStartWidth = 9;
+ const UInt32 kStopWidth = 13;
+ UInt32 power = 1 << kStartWidth;
+ UInt32 width;
+ UInt32 distance = 0;
+ for (width = kStartWidth; width < kStopWidth; width++)
+ {
+ if (m_InBitStream.ReadBits(1) == 0)
+ break;
+ distance += power;
+ power <<= 1;
+ }
+ if (width != 0)
+ distance += m_InBitStream.ReadBits(width);
+ if (distance >= pos)
+ return S_FALSE;
+ m_OutWindowStream.CopyBlock(distance, len);
+ pos += len;
+ }
+ }
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder2.h b/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder2.h
new file mode 100644
index 000000000..cf00975da
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ArjDecoder2.h
@@ -0,0 +1,59 @@
+// ArjDecoder2.h
+
+#ifndef __COMPRESS_ARJ_DECODER2_H
+#define __COMPRESS_ARJ_DECODER2_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NArj {
+namespace NDecoder2 {
+
+class CCoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitm::CDecoder<CInBuffer> m_InBitStream;
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CCoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+public:
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BZip2Const.h b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Const.h
new file mode 100644
index 000000000..62427aa68
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Const.h
@@ -0,0 +1,54 @@
+// Compress/BZip2Const.h
+
+#ifndef __COMPRESS_BZIP2_CONST_H
+#define __COMPRESS_BZIP2_CONST_H
+
+namespace NCompress {
+namespace NBZip2 {
+
+const Byte kArSig0 = 'B';
+const Byte kArSig1 = 'Z';
+const Byte kArSig2 = 'h';
+const Byte kArSig3 = '0';
+
+const Byte kFinSig0 = 0x17;
+const Byte kFinSig1 = 0x72;
+const Byte kFinSig2 = 0x45;
+const Byte kFinSig3 = 0x38;
+const Byte kFinSig4 = 0x50;
+const Byte kFinSig5 = 0x90;
+
+const Byte kBlockSig0 = 0x31;
+const Byte kBlockSig1 = 0x41;
+const Byte kBlockSig2 = 0x59;
+const Byte kBlockSig3 = 0x26;
+const Byte kBlockSig4 = 0x53;
+const Byte kBlockSig5 = 0x59;
+
+const int kNumOrigBits = 24;
+
+const int kNumTablesBits = 3;
+const int kNumTablesMin = 2;
+const int kNumTablesMax = 6;
+
+const int kNumLevelsBits = 5;
+
+const int kMaxHuffmanLen = 20; // Check it
+
+const int kMaxAlphaSize = 258;
+
+const int kGroupSize = 50;
+
+const int kBlockSizeMultMin = 1;
+const int kBlockSizeMultMax = 9;
+const UInt32 kBlockSizeStep = 100000;
+const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep;
+
+const int kNumSelectorsBits = 15;
+const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize));
+
+const int kRleModeRepSize = 4;
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BZip2Crc.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Crc.cpp
new file mode 100644
index 000000000..4e4741f40
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Crc.cpp
@@ -0,0 +1,26 @@
+// BZip2Crc.cpp
+
+#include "StdAfx.h"
+
+#include "BZip2Crc.h"
+
+UInt32 CBZip2Crc::Table[256];
+
+static const UInt32 kBZip2CrcPoly = 0x04c11db7; /* AUTODIN II, Ethernet, & FDDI */
+
+void CBZip2Crc::InitTable()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ UInt32 r = (i << 24);
+ for (int j = 8; j > 0; j--)
+ r = (r & 0x80000000) ? ((r << 1) ^ kBZip2CrcPoly) : (r << 1);
+ Table[i] = r;
+ }
+}
+
+class CBZip2CrcTableInit
+{
+public:
+ CBZip2CrcTableInit() { CBZip2Crc::InitTable(); }
+} g_BZip2CrcTableInit;
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BZip2Crc.h b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Crc.h
new file mode 100644
index 000000000..876945b5f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Crc.h
@@ -0,0 +1,31 @@
+// BZip2Crc.h
+
+#ifndef __BZIP2_CRC_H
+#define __BZIP2_CRC_H
+
+#include "Common/Types.h"
+
+class CBZip2Crc
+{
+ UInt32 _value;
+ static UInt32 Table[256];
+public:
+ static void InitTable();
+ CBZip2Crc(): _value(0xFFFFFFFF) {};
+ void Init() { _value = 0xFFFFFFFF; }
+ void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
+ void UpdateByte(unsigned int b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
+ UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; }
+};
+
+class CBZip2CombinedCrc
+{
+ UInt32 _value;
+public:
+ CBZip2CombinedCrc(): _value(0){};
+ void Init() { _value = 0; }
+ void Update(UInt32 v) { _value = ((_value << 1) | (_value >> 31)) ^ v; }
+ UInt32 GetDigest() const { return _value ; }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BZip2Decoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Decoder.cpp
new file mode 100644
index 000000000..cb1f981a7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Decoder.cpp
@@ -0,0 +1,943 @@
+// BZip2Decoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "BZip2Decoder.h"
+#include "Mtf8.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+#undef NO_INLINE
+#define NO_INLINE
+
+static const UInt32 kNumThreadsMax = 4;
+
+static const UInt32 kBufferSize = (1 << 17);
+
+static const UInt16 kRandNums[512] = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+};
+
+bool CState::Alloc()
+{
+ if (!Counters)
+ Counters = (UInt32 *)::BigAlloc((256 + kBlockSizeMax) * sizeof(UInt32));
+ return (Counters != 0);
+}
+
+void CState::Free()
+{
+ ::BigFree(Counters);
+ Counters = 0;
+}
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InStream.ReadBits(numBits); }
+Byte CDecoder::ReadByte() {return (Byte)ReadBits(8); }
+bool CDecoder::ReadBit() { return ReadBits(1) != 0; }
+
+UInt32 CDecoder::ReadCrc()
+{
+ UInt32 crc = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ crc <<= 8;
+ crc |= ReadByte();
+ }
+ return crc;
+}
+
+static UInt32 NO_INLINE ReadBits(NBitm::CDecoder<CInBuffer> *m_InStream, unsigned num)
+{
+ return m_InStream->ReadBits(num);
+}
+
+static UInt32 NO_INLINE ReadBit(NBitm::CDecoder<CInBuffer> *m_InStream)
+{
+ return m_InStream->ReadBits(1);
+}
+
+static HRESULT NO_INLINE ReadBlock(NBitm::CDecoder<CInBuffer> *m_InStream,
+ UInt32 *CharCounters, UInt32 blockSizeMax, Byte *m_Selectors, CHuffmanDecoder *m_HuffmanDecoders,
+ UInt32 *blockSizeRes, UInt32 *origPtrRes, bool *randRes)
+{
+ if (randRes)
+ *randRes = ReadBit(m_InStream) ? true : false;
+ *origPtrRes = ReadBits(m_InStream, kNumOrigBits);
+
+ // in original code it compares OrigPtr to (UInt32)(10 + blockSizeMax)) : why ?
+ if (*origPtrRes >= blockSizeMax)
+ return S_FALSE;
+
+ CMtf8Decoder mtf;
+ mtf.StartInit();
+
+ int numInUse = 0;
+ {
+ Byte inUse16[16];
+ int i;
+ for (i = 0; i < 16; i++)
+ inUse16[i] = (Byte)ReadBit(m_InStream);
+ for (i = 0; i < 256; i++)
+ if (inUse16[i >> 4])
+ {
+ if (ReadBit(m_InStream))
+ mtf.Add(numInUse++, (Byte)i);
+ }
+ if (numInUse == 0)
+ return S_FALSE;
+ // mtf.Init(numInUse);
+ }
+ int alphaSize = numInUse + 2;
+
+ int numTables = ReadBits(m_InStream, kNumTablesBits);
+ if (numTables < kNumTablesMin || numTables > kNumTablesMax)
+ return S_FALSE;
+
+ UInt32 numSelectors = ReadBits(m_InStream, kNumSelectorsBits);
+ if (numSelectors < 1 || numSelectors > kNumSelectorsMax)
+ return S_FALSE;
+
+ {
+ Byte mtfPos[kNumTablesMax];
+ int t = 0;
+ do
+ mtfPos[t] = (Byte)t;
+ while(++t < numTables);
+ UInt32 i = 0;
+ do
+ {
+ int j = 0;
+ while (ReadBit(m_InStream))
+ if (++j >= numTables)
+ return S_FALSE;
+ Byte tmp = mtfPos[j];
+ for (;j > 0; j--)
+ mtfPos[j] = mtfPos[j - 1];
+ m_Selectors[i] = mtfPos[0] = tmp;
+ }
+ while(++i < numSelectors);
+ }
+
+ int t = 0;
+ do
+ {
+ Byte lens[kMaxAlphaSize];
+ int len = (int)ReadBits(m_InStream, kNumLevelsBits);
+ int i;
+ for (i = 0; i < alphaSize; i++)
+ {
+ for (;;)
+ {
+ if (len < 1 || len > kMaxHuffmanLen)
+ return S_FALSE;
+ if (!ReadBit(m_InStream))
+ break;
+ len += 1 - (int)(ReadBit(m_InStream) << 1);
+ }
+ lens[i] = (Byte)len;
+ }
+ for (; i < kMaxAlphaSize; i++)
+ lens[i] = 0;
+ if(!m_HuffmanDecoders[t].SetCodeLengths(lens))
+ return S_FALSE;
+ }
+ while(++t < numTables);
+
+ {
+ for (int i = 0; i < 256; i++)
+ CharCounters[i] = 0;
+ }
+
+ UInt32 blockSize = 0;
+ {
+ UInt32 groupIndex = 0;
+ UInt32 groupSize = 0;
+ CHuffmanDecoder *huffmanDecoder = 0;
+ int runPower = 0;
+ UInt32 runCounter = 0;
+
+ for (;;)
+ {
+ if (groupSize == 0)
+ {
+ if (groupIndex >= numSelectors)
+ return S_FALSE;
+ groupSize = kGroupSize;
+ huffmanDecoder = &m_HuffmanDecoders[m_Selectors[groupIndex++]];
+ }
+ groupSize--;
+
+ UInt32 nextSym = huffmanDecoder->DecodeSymbol(m_InStream);
+
+ if (nextSym < 2)
+ {
+ runCounter += ((UInt32)(nextSym + 1) << runPower++);
+ if (blockSizeMax - blockSize < runCounter)
+ return S_FALSE;
+ continue;
+ }
+ if (runCounter != 0)
+ {
+ UInt32 b = (UInt32)mtf.GetHead();
+ CharCounters[b] += runCounter;
+ do
+ CharCounters[256 + blockSize++] = b;
+ while(--runCounter != 0);
+ runPower = 0;
+ }
+ if (nextSym <= (UInt32)numInUse)
+ {
+ UInt32 b = (UInt32)mtf.GetAndMove((int)nextSym - 1);
+ if (blockSize >= blockSizeMax)
+ return S_FALSE;
+ CharCounters[b]++;
+ CharCounters[256 + blockSize++] = b;
+ }
+ else if (nextSym == (UInt32)numInUse + 1)
+ break;
+ else
+ return S_FALSE;
+ }
+ }
+ *blockSizeRes = blockSize;
+ return (*origPtrRes < blockSize) ? S_OK : S_FALSE;
+}
+
+static void NO_INLINE DecodeBlock1(UInt32 *charCounters, UInt32 blockSize)
+{
+ {
+ UInt32 sum = 0;
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ sum += charCounters[i];
+ charCounters[i] = sum - charCounters[i];
+ }
+ }
+
+ UInt32 *tt = charCounters + 256;
+ // Compute the T^(-1) vector
+ UInt32 i = 0;
+ do
+ tt[charCounters[tt[i] & 0xFF]++] |= (i << 8);
+ while(++i < blockSize);
+}
+
+static UInt32 NO_INLINE DecodeBlock2(const UInt32 *tt, UInt32 blockSize, UInt32 OrigPtr, COutBuffer &m_OutStream)
+{
+ CBZip2Crc crc;
+
+ // it's for speed optimization: prefetch & prevByte_init;
+ UInt32 tPos = tt[tt[OrigPtr] >> 8];
+ unsigned prevByte = (unsigned)(tPos & 0xFF);
+
+ unsigned numReps = 0;
+
+ do
+ {
+ unsigned b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+
+ if (numReps == kRleModeRepSize)
+ {
+ for (; b > 0; b--)
+ {
+ crc.UpdateByte(prevByte);
+ m_OutStream.WriteByte((Byte)prevByte);
+ }
+ numReps = 0;
+ continue;
+ }
+ if (b != prevByte)
+ numReps = 0;
+ numReps++;
+ prevByte = b;
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+
+ /*
+ prevByte = b;
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ for (; --blockSize != 0;)
+ {
+ b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ if (b != prevByte)
+ {
+ prevByte = b;
+ continue;
+ }
+ if (--blockSize == 0)
+ break;
+
+ b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ if (b != prevByte)
+ {
+ prevByte = b;
+ continue;
+ }
+ if (--blockSize == 0)
+ break;
+
+ b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ if (b != prevByte)
+ {
+ prevByte = b;
+ continue;
+ }
+ --blockSize;
+ break;
+ }
+ if (blockSize == 0)
+ break;
+
+ b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+
+ for (; b > 0; b--)
+ {
+ crc.UpdateByte(prevByte);
+ m_OutStream.WriteByte((Byte)prevByte);
+ }
+ */
+ }
+ while(--blockSize != 0);
+ return crc.GetDigest();
+}
+
+static UInt32 NO_INLINE DecodeBlock2Rand(const UInt32 *tt, UInt32 blockSize, UInt32 OrigPtr, COutBuffer &m_OutStream)
+{
+ CBZip2Crc crc;
+
+ UInt32 randIndex = 1;
+ UInt32 randToGo = kRandNums[0] - 2;
+
+ unsigned numReps = 0;
+
+ // it's for speed optimization: prefetch & prevByte_init;
+ UInt32 tPos = tt[tt[OrigPtr] >> 8];
+ unsigned prevByte = (unsigned)(tPos & 0xFF);
+
+ do
+ {
+ unsigned b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+
+ {
+ if (randToGo == 0)
+ {
+ b ^= 1;
+ randToGo = kRandNums[randIndex++];
+ randIndex &= 0x1FF;
+ }
+ randToGo--;
+ }
+
+ if (numReps == kRleModeRepSize)
+ {
+ for (; b > 0; b--)
+ {
+ crc.UpdateByte(prevByte);
+ m_OutStream.WriteByte((Byte)prevByte);
+ }
+ numReps = 0;
+ continue;
+ }
+ if (b != prevByte)
+ numReps = 0;
+ numReps++;
+ prevByte = b;
+ crc.UpdateByte(b);
+ m_OutStream.WriteByte((Byte)b);
+ }
+ while(--blockSize != 0);
+ return crc.GetDigest();
+}
+
+
+CDecoder::CDecoder()
+{
+ #ifndef _7ZIP_ST
+ m_States = 0;
+ m_NumThreadsPrev = 0;
+ NumThreads = 1;
+ #endif
+ _needInStreamInit = true;
+}
+
+#ifndef _7ZIP_ST
+
+CDecoder::~CDecoder()
+{
+ Free();
+}
+
+#define RINOK_THREAD(x) { WRes __result_ = (x); if(__result_ != 0) return __result_; }
+
+HRESULT CDecoder::Create()
+{
+ RINOK_THREAD(CanProcessEvent.CreateIfNotCreated());
+ RINOK_THREAD(CanStartWaitingEvent.CreateIfNotCreated());
+ if (m_States != 0 && m_NumThreadsPrev == NumThreads)
+ return S_OK;
+ Free();
+ MtMode = (NumThreads > 1);
+ m_NumThreadsPrev = NumThreads;
+ try
+ {
+ m_States = new CState[NumThreads];
+ if (!m_States)
+ return E_OUTOFMEMORY;
+ }
+ catch(...) { return E_OUTOFMEMORY; }
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CState &ti = m_States[t];
+ ti.Decoder = this;
+ if (MtMode)
+ {
+ HRESULT res = ti.Create();
+ if (res != S_OK)
+ {
+ NumThreads = t;
+ Free();
+ return res;
+ }
+ }
+ }
+ return S_OK;
+}
+
+void CDecoder::Free()
+{
+ if (!m_States)
+ return;
+ CloseThreads = true;
+ CanProcessEvent.Set();
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CState &s = m_States[t];
+ if (MtMode)
+ s.Thread.Wait();
+ s.Free();
+ }
+ delete []m_States;
+ m_States = 0;
+}
+
+#endif
+
+HRESULT CDecoder::ReadSignatures(bool &wasFinished, UInt32 &crc)
+{
+ wasFinished = false;
+ Byte s[6];
+ for (int i = 0; i < 6; i++)
+ s[i] = ReadByte();
+ crc = ReadCrc();
+ if (s[0] == kFinSig0)
+ {
+ if (s[1] != kFinSig1 ||
+ s[2] != kFinSig2 ||
+ s[3] != kFinSig3 ||
+ s[4] != kFinSig4 ||
+ s[5] != kFinSig5)
+ return S_FALSE;
+
+ wasFinished = true;
+ return (crc == CombinedCrc.GetDigest()) ? S_OK : S_FALSE;
+ }
+ if (s[0] != kBlockSig0 ||
+ s[1] != kBlockSig1 ||
+ s[2] != kBlockSig2 ||
+ s[3] != kBlockSig3 ||
+ s[4] != kBlockSig4 ||
+ s[5] != kBlockSig5)
+ return S_FALSE;
+ CombinedCrc.Update(crc);
+ return S_OK;
+}
+
+HRESULT CDecoder::DecodeFile(bool &isBZ, ICompressProgressInfo *progress)
+{
+ Progress = progress;
+ #ifndef _7ZIP_ST
+ RINOK(Create());
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CState &s = m_States[t];
+ if (!s.Alloc())
+ return E_OUTOFMEMORY;
+ if (MtMode)
+ {
+ RINOK(s.StreamWasFinishedEvent.Reset());
+ RINOK(s.WaitingWasStartedEvent.Reset());
+ RINOK(s.CanWriteEvent.Reset());
+ }
+ }
+ #else
+ if (!m_States[0].Alloc())
+ return E_OUTOFMEMORY;
+ #endif
+
+ isBZ = false;
+ Byte s[6];
+ int i;
+ for (i = 0; i < 4; i++)
+ s[i] = ReadByte();
+ if (s[0] != kArSig0 ||
+ s[1] != kArSig1 ||
+ s[2] != kArSig2 ||
+ s[3] <= kArSig3 ||
+ s[3] > kArSig3 + kBlockSizeMultMax)
+ return S_OK;
+ isBZ = true;
+ UInt32 dicSize = (UInt32)(s[3] - kArSig3) * kBlockSizeStep;
+
+ CombinedCrc.Init();
+ #ifndef _7ZIP_ST
+ if (MtMode)
+ {
+ NextBlockIndex = 0;
+ StreamWasFinished1 = StreamWasFinished2 = false;
+ CloseThreads = false;
+ CanStartWaitingEvent.Reset();
+ m_States[0].CanWriteEvent.Set();
+ BlockSizeMax = dicSize;
+ Result1 = Result2 = S_OK;
+ CanProcessEvent.Set();
+ UInt32 t;
+ for (t = 0; t < NumThreads; t++)
+ m_States[t].StreamWasFinishedEvent.Lock();
+ CanProcessEvent.Reset();
+ CanStartWaitingEvent.Set();
+ for (t = 0; t < NumThreads; t++)
+ m_States[t].WaitingWasStartedEvent.Lock();
+ CanStartWaitingEvent.Reset();
+ RINOK(Result2);
+ RINOK(Result1);
+ }
+ else
+ #endif
+ {
+ CState &state = m_States[0];
+ for (;;)
+ {
+ RINOK(SetRatioProgress(m_InStream.GetProcessedSize()));
+ bool wasFinished;
+ UInt32 crc;
+ RINOK(ReadSignatures(wasFinished, crc));
+ if (wasFinished)
+ return S_OK;
+
+ UInt32 blockSize, origPtr;
+ bool randMode;
+ RINOK(ReadBlock(&m_InStream, state.Counters, dicSize,
+ m_Selectors, m_HuffmanDecoders,
+ &blockSize, &origPtr, &randMode));
+ DecodeBlock1(state.Counters, blockSize);
+ if ((randMode ?
+ DecodeBlock2Rand(state.Counters + 256, blockSize, origPtr, m_OutStream) :
+ DecodeBlock2(state.Counters + 256, blockSize, origPtr, m_OutStream)) != crc)
+ return S_FALSE;
+ }
+ }
+ return SetRatioProgress(m_InStream.GetProcessedSize());
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ bool &isBZ, ICompressProgressInfo *progress)
+{
+ isBZ = false;
+ try
+ {
+
+ if (!m_InStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (!m_OutStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+
+ if (inStream)
+ m_InStream.SetStream(inStream);
+
+ CDecoderFlusher flusher(this, inStream != NULL);
+
+ if (_needInStreamInit)
+ {
+ m_InStream.Init();
+ _needInStreamInit = false;
+ }
+ _inStart = m_InStream.GetProcessedSize();
+
+ m_InStream.AlignToByte();
+
+ m_OutStream.SetStream(outStream);
+ m_OutStream.Init();
+
+ RINOK(DecodeFile(isBZ, progress));
+ flusher.NeedFlush = false;
+ return Flush();
+
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return E_FAIL; }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ _needInStreamInit = true;
+ bool isBZ;
+ RINOK(CodeReal(inStream, outStream, isBZ, progress));
+ return isBZ ? S_OK : S_FALSE;
+}
+
+HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, bool &isBZ, ICompressProgressInfo *progress)
+{
+ return CodeReal(NULL, outStream, isBZ, progress);
+}
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { m_InStream.SetStream(inStream); return S_OK; }
+STDMETHODIMP CDecoder::ReleaseInStream() { m_InStream.ReleaseStream(); return S_OK; }
+
+#ifndef _7ZIP_ST
+
+static THREAD_FUNC_DECL MFThread(void *p) { ((CState *)p)->ThreadFunc(); return 0; }
+
+HRESULT CState::Create()
+{
+ RINOK_THREAD(StreamWasFinishedEvent.CreateIfNotCreated());
+ RINOK_THREAD(WaitingWasStartedEvent.CreateIfNotCreated());
+ RINOK_THREAD(CanWriteEvent.CreateIfNotCreated());
+ RINOK_THREAD(Thread.Create(MFThread, this));
+ return S_OK;
+}
+
+void CState::FinishStream()
+{
+ Decoder->StreamWasFinished1 = true;
+ StreamWasFinishedEvent.Set();
+ Decoder->CS.Leave();
+ Decoder->CanStartWaitingEvent.Lock();
+ WaitingWasStartedEvent.Set();
+}
+
+void CState::ThreadFunc()
+{
+ for (;;)
+ {
+ Decoder->CanProcessEvent.Lock();
+ Decoder->CS.Enter();
+ if (Decoder->CloseThreads)
+ {
+ Decoder->CS.Leave();
+ return;
+ }
+ if (Decoder->StreamWasFinished1)
+ {
+ FinishStream();
+ continue;
+ }
+ HRESULT res = S_OK;
+
+ UInt32 blockIndex = Decoder->NextBlockIndex;
+ UInt32 nextBlockIndex = blockIndex + 1;
+ if (nextBlockIndex == Decoder->NumThreads)
+ nextBlockIndex = 0;
+ Decoder->NextBlockIndex = nextBlockIndex;
+ UInt32 crc;
+ UInt64 packSize = 0;
+ UInt32 blockSize = 0, origPtr = 0;
+ bool randMode = false;
+
+ try
+ {
+ bool wasFinished;
+ res = Decoder->ReadSignatures(wasFinished, crc);
+ if (res != S_OK)
+ {
+ Decoder->Result1 = res;
+ FinishStream();
+ continue;
+ }
+ if (wasFinished)
+ {
+ Decoder->Result1 = res;
+ FinishStream();
+ continue;
+ }
+
+ res = ReadBlock(&Decoder->m_InStream, Counters, Decoder->BlockSizeMax,
+ Decoder->m_Selectors, Decoder->m_HuffmanDecoders,
+ &blockSize, &origPtr, &randMode);
+ if (res != S_OK)
+ {
+ Decoder->Result1 = res;
+ FinishStream();
+ continue;
+ }
+ packSize = Decoder->m_InStream.GetProcessedSize();
+ }
+ catch(const CInBufferException &e) { res = e.ErrorCode; if (res != S_OK) res = E_FAIL; }
+ catch(...) { res = E_FAIL; }
+ if (res != S_OK)
+ {
+ Decoder->Result1 = res;
+ FinishStream();
+ continue;
+ }
+
+ Decoder->CS.Leave();
+
+ DecodeBlock1(Counters, blockSize);
+
+ bool needFinish = true;
+ try
+ {
+ Decoder->m_States[blockIndex].CanWriteEvent.Lock();
+ needFinish = Decoder->StreamWasFinished2;
+ if (!needFinish)
+ {
+ if ((randMode ?
+ DecodeBlock2Rand(Counters + 256, blockSize, origPtr, Decoder->m_OutStream) :
+ DecodeBlock2(Counters + 256, blockSize, origPtr, Decoder->m_OutStream)) == crc)
+ res = Decoder->SetRatioProgress(packSize);
+ else
+ res = S_FALSE;
+ }
+ }
+ catch(const COutBufferException &e) { res = e.ErrorCode; if (res != S_OK) res = E_FAIL; }
+ catch(...) { res = E_FAIL; }
+ if (res != S_OK)
+ {
+ Decoder->Result2 = res;
+ Decoder->StreamWasFinished2 = true;
+ }
+ Decoder->m_States[nextBlockIndex].CanWriteEvent.Set();
+ if (res != S_OK || needFinish)
+ {
+ StreamWasFinishedEvent.Set();
+ Decoder->CanStartWaitingEvent.Lock();
+ WaitingWasStartedEvent.Set();
+ }
+ }
+}
+
+STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)
+{
+ NumThreads = numThreads;
+ if (NumThreads < 1)
+ NumThreads = 1;
+ if (NumThreads > kNumThreadsMax)
+ NumThreads = kNumThreadsMax;
+ return S_OK;
+}
+
+#endif
+
+HRESULT CDecoder::SetRatioProgress(UInt64 packSize)
+{
+ if (!Progress)
+ return S_OK;
+ packSize -= _inStart;
+ UInt64 unpackSize = m_OutStream.GetProcessedSize();
+ return Progress->SetRatioInfo(&packSize, &unpackSize);
+}
+
+
+// ---------- NSIS ----------
+
+enum
+{
+ NSIS_STATE_INIT,
+ NSIS_STATE_NEW_BLOCK,
+ NSIS_STATE_DATA,
+ NSIS_STATE_FINISHED,
+ NSIS_STATE_ERROR
+};
+
+STDMETHODIMP CNsisDecoder::SetInStream(ISequentialInStream *inStream) { m_InStream.SetStream(inStream); return S_OK; }
+STDMETHODIMP CNsisDecoder::ReleaseInStream() { m_InStream.ReleaseStream(); return S_OK; }
+
+STDMETHODIMP CNsisDecoder::SetOutStreamSize(const UInt64 * /* outSize */)
+{
+ _nsisState = NSIS_STATE_INIT;
+ return S_OK;
+}
+
+STDMETHODIMP CNsisDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ try {
+
+ *processedSize = 0;
+ if (_nsisState == NSIS_STATE_FINISHED)
+ return S_OK;
+ if (_nsisState == NSIS_STATE_ERROR)
+ return S_FALSE;
+ if (size == 0)
+ return S_OK;
+
+ CState &state = m_State;
+
+ if (_nsisState == NSIS_STATE_INIT)
+ {
+ if (!m_InStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (!state.Alloc())
+ return E_OUTOFMEMORY;
+ m_InStream.Init();
+ _nsisState = NSIS_STATE_NEW_BLOCK;
+ }
+
+ if (_nsisState == NSIS_STATE_NEW_BLOCK)
+ {
+ Byte b = (Byte)m_InStream.ReadBits(8);
+ if (b == kFinSig0)
+ {
+ _nsisState = NSIS_STATE_FINISHED;
+ return S_OK;
+ }
+ if (b != kBlockSig0)
+ {
+ _nsisState = NSIS_STATE_ERROR;
+ return S_FALSE;
+ }
+ UInt32 origPtr;
+ RINOK(ReadBlock(&m_InStream, state.Counters, 9 * kBlockSizeStep,
+ m_Selectors, m_HuffmanDecoders, &_blockSize, &origPtr, NULL));
+ DecodeBlock1(state.Counters, _blockSize);
+ const UInt32 *tt = state.Counters + 256;
+ _tPos = tt[tt[origPtr] >> 8];
+ _prevByte = (unsigned)(_tPos & 0xFF);
+ _numReps = 0;
+ _repRem = 0;
+ _nsisState = NSIS_STATE_DATA;
+ }
+
+ UInt32 tPos = _tPos;
+ unsigned prevByte = _prevByte;
+ unsigned numReps = _numReps;
+ UInt32 blockSize = _blockSize;
+ const UInt32 *tt = state.Counters + 256;
+
+ while (_repRem)
+ {
+ _repRem--;
+ *(Byte *)data = (Byte)prevByte;
+ data = (Byte *)data + 1;
+ (*processedSize)++;
+ if (--size == 0)
+ return S_OK;
+ }
+
+ if (blockSize == 0)
+ {
+ _nsisState = NSIS_STATE_NEW_BLOCK;
+ return S_OK;
+ }
+
+ do
+ {
+ unsigned b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ blockSize--;
+
+ if (numReps == kRleModeRepSize)
+ {
+ numReps = 0;
+ while (b)
+ {
+ b--;
+ *(Byte *)data = (Byte)prevByte;
+ data = (Byte *)data + 1;
+ (*processedSize)++;
+ if (--size == 0)
+ break;
+ }
+ _repRem = b;
+ continue;
+ }
+ if (b != prevByte)
+ numReps = 0;
+ numReps++;
+ prevByte = b;
+ *(Byte *)data = (Byte)b;
+ data = (Byte *)data + 1;
+ (*processedSize)++;
+ size--;
+ }
+ while (size && blockSize);
+ _tPos = tPos;
+ _prevByte = prevByte;
+ _numReps = numReps;
+ _blockSize = blockSize;
+ return S_OK;
+
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BZip2Decoder.h b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Decoder.h
new file mode 100644
index 000000000..e6dec1eaa
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Decoder.h
@@ -0,0 +1,205 @@
+// Compress/BZip2Decoder.h
+
+#ifndef __COMPRESS_BZIP2_DECODER_H
+#define __COMPRESS_BZIP2_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#ifndef _7ZIP_ST
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+#endif
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "BitmDecoder.h"
+#include "BZip2Const.h"
+#include "BZip2Crc.h"
+#include "HuffmanDecoder.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+typedef NCompress::NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize> CHuffmanDecoder;
+
+class CDecoder;
+
+struct CState
+{
+ UInt32 *Counters;
+
+ #ifndef _7ZIP_ST
+
+ CDecoder *Decoder;
+ NWindows::CThread Thread;
+ bool m_OptimizeNumTables;
+
+ NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
+ NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
+
+ // it's not member of this thread. We just need one event per thread
+ NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
+
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+
+ HRESULT Create();
+ void FinishStream();
+ void ThreadFunc();
+
+ #endif
+
+ CState(): Counters(0) {}
+ ~CState() { Free(); }
+ bool Alloc();
+ void Free();
+};
+
+class CDecoder :
+ public ICompressCoder,
+ #ifndef _7ZIP_ST
+ public ICompressSetCoderMt,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ COutBuffer m_OutStream;
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+ NBitm::CDecoder<CInBuffer> m_InStream;
+ Byte m_Selectors[kNumSelectorsMax];
+ CHuffmanDecoder m_HuffmanDecoders[kNumTablesMax];
+ UInt64 _inStart;
+
+private:
+
+ bool _needInStreamInit;
+
+ UInt32 ReadBits(unsigned numBits);
+ Byte ReadByte();
+ bool ReadBit();
+ UInt32 ReadCrc();
+ HRESULT DecodeFile(bool &isBZ, ICompressProgressInfo *progress);
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ bool &isBZ, ICompressProgressInfo *progress);
+ class CDecoderFlusher
+ {
+ CDecoder *_decoder;
+ public:
+ bool NeedFlush;
+ bool ReleaseInStream;
+ CDecoderFlusher(CDecoder *decoder, bool releaseInStream):
+ _decoder(decoder),
+ ReleaseInStream(releaseInStream),
+ NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ _decoder->Flush();
+ _decoder->ReleaseStreams(ReleaseInStream);
+ }
+ };
+
+public:
+ CBZip2CombinedCrc CombinedCrc;
+ ICompressProgressInfo *Progress;
+
+ #ifndef _7ZIP_ST
+ CState *m_States;
+ UInt32 m_NumThreadsPrev;
+
+ NWindows::NSynchronization::CManualResetEvent CanProcessEvent;
+ NWindows::NSynchronization::CCriticalSection CS;
+ UInt32 NumThreads;
+ bool MtMode;
+ UInt32 NextBlockIndex;
+ bool CloseThreads;
+ bool StreamWasFinished1;
+ bool StreamWasFinished2;
+ NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
+
+ HRESULT Result1;
+ HRESULT Result2;
+
+ UInt32 BlockSizeMax;
+ ~CDecoder();
+ HRESULT Create();
+ void Free();
+
+ #else
+ CState m_States[1];
+ #endif
+
+ CDecoder();
+
+ HRESULT SetRatioProgress(UInt64 packSize);
+ HRESULT ReadSignatures(bool &wasFinished, UInt32 &crc);
+
+ HRESULT Flush() { return m_OutStream.Flush(); }
+ void ReleaseStreams(bool releaseInStream)
+ {
+ if (releaseInStream)
+ m_InStream.ReleaseStream();
+ m_OutStream.ReleaseStream();
+ }
+
+ MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
+ #ifndef _7ZIP_ST
+ MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
+ #endif
+
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+
+ HRESULT CodeResume(ISequentialOutStream *outStream, bool &isBZ, ICompressProgressInfo *progress);
+ UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); }
+
+ #ifndef _7ZIP_ST
+ STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
+ #endif
+};
+
+
+class CNsisDecoder :
+ public ISequentialInStream,
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public CMyUnknownImp
+{
+ NBitm::CDecoder<CInBuffer> m_InStream;
+ Byte m_Selectors[kNumSelectorsMax];
+ CHuffmanDecoder m_HuffmanDecoders[kNumTablesMax];
+ CState m_State;
+
+ int _nsisState;
+ UInt32 _tPos;
+ unsigned _prevByte;
+ unsigned _repRem;
+ unsigned _numReps;
+ UInt32 _blockSize;
+
+public:
+
+ MY_QUERYINTERFACE_BEGIN2(ISequentialInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BZip2Encoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Encoder.cpp
new file mode 100644
index 000000000..eaa108558
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Encoder.cpp
@@ -0,0 +1,895 @@
+// BZip2Encoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/BwtSort.h"
+#include "../../../C/HuffEnc.h"
+
+#include "BZip2Crc.h"
+#include "BZip2Encoder.h"
+#include "Mtf8.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+const int kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20
+
+static const UInt32 kBufferSize = (1 << 17);
+static const int kNumHuffPasses = 4;
+
+bool CThreadInfo::Alloc()
+{
+ if (m_BlockSorterIndex == 0)
+ {
+ m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32));
+ if (m_BlockSorterIndex == 0)
+ return false;
+ }
+
+ if (m_Block == 0)
+ {
+ m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10));
+ if (m_Block == 0)
+ return false;
+ m_MtfArray = m_Block + kBlockSizeMax;
+ m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
+ }
+ return true;
+}
+
+void CThreadInfo::Free()
+{
+ ::BigFree(m_BlockSorterIndex);
+ m_BlockSorterIndex = 0;
+ ::MidFree(m_Block);
+ m_Block = 0;
+}
+
+#ifndef _7ZIP_ST
+
+static THREAD_FUNC_DECL MFThread(void *threadCoderInfo)
+{
+ return ((CThreadInfo *)threadCoderInfo)->ThreadFunc();
+}
+
+#define RINOK_THREAD(x) { WRes __result_ = (x); if(__result_ != 0) return __result_; }
+
+HRESULT CThreadInfo::Create()
+{
+ RINOK_THREAD(StreamWasFinishedEvent.Create());
+ RINOK_THREAD(WaitingWasStartedEvent.Create());
+ RINOK_THREAD(CanWriteEvent.Create());
+ RINOK_THREAD(Thread.Create(MFThread, this));
+ return S_OK;
+}
+
+void CThreadInfo::FinishStream(bool needLeave)
+{
+ Encoder->StreamWasFinished = true;
+ StreamWasFinishedEvent.Set();
+ if (needLeave)
+ Encoder->CS.Leave();
+ Encoder->CanStartWaitingEvent.Lock();
+ WaitingWasStartedEvent.Set();
+}
+
+DWORD CThreadInfo::ThreadFunc()
+{
+ for (;;)
+ {
+ Encoder->CanProcessEvent.Lock();
+ Encoder->CS.Enter();
+ if (Encoder->CloseThreads)
+ {
+ Encoder->CS.Leave();
+ return 0;
+ }
+ if (Encoder->StreamWasFinished)
+ {
+ FinishStream(true);
+ continue;
+ }
+ HRESULT res = S_OK;
+ bool needLeave = true;
+ try
+ {
+ UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
+ m_PackSize = Encoder->m_InStream.GetProcessedSize();
+ m_BlockIndex = Encoder->NextBlockIndex;
+ if (++Encoder->NextBlockIndex == Encoder->NumThreads)
+ Encoder->NextBlockIndex = 0;
+ if (blockSize == 0)
+ {
+ FinishStream(true);
+ continue;
+ }
+ Encoder->CS.Leave();
+ needLeave = false;
+ res = EncodeBlock3(blockSize);
+ }
+ catch(const CInBufferException &e) { res = e.ErrorCode; }
+ catch(const COutBufferException &e) { res = e.ErrorCode; }
+ catch(...) { res = E_FAIL; }
+ if (res != S_OK)
+ {
+ Encoder->Result = res;
+ FinishStream(needLeave);
+ continue;
+ }
+ }
+}
+
+#endif
+
+CEncoder::CEncoder():
+ NumPasses(1),
+ m_OptimizeNumTables(false),
+ m_BlockSizeMult(kBlockSizeMultMax)
+{
+ #ifndef _7ZIP_ST
+ ThreadsInfo = 0;
+ m_NumThreadsPrev = 0;
+ NumThreads = 1;
+ #endif
+}
+
+#ifndef _7ZIP_ST
+CEncoder::~CEncoder()
+{
+ Free();
+}
+
+HRESULT CEncoder::Create()
+{
+ RINOK_THREAD(CanProcessEvent.CreateIfNotCreated());
+ RINOK_THREAD(CanStartWaitingEvent.CreateIfNotCreated());
+ if (ThreadsInfo != 0 && m_NumThreadsPrev == NumThreads)
+ return S_OK;
+ try
+ {
+ Free();
+ MtMode = (NumThreads > 1);
+ m_NumThreadsPrev = NumThreads;
+ ThreadsInfo = new CThreadInfo[NumThreads];
+ if (ThreadsInfo == 0)
+ return E_OUTOFMEMORY;
+ }
+ catch(...) { return E_OUTOFMEMORY; }
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CThreadInfo &ti = ThreadsInfo[t];
+ ti.Encoder = this;
+ if (MtMode)
+ {
+ HRESULT res = ti.Create();
+ if (res != S_OK)
+ {
+ NumThreads = t;
+ Free();
+ return res;
+ }
+ }
+ }
+ return S_OK;
+}
+
+void CEncoder::Free()
+{
+ if (!ThreadsInfo)
+ return;
+ CloseThreads = true;
+ CanProcessEvent.Set();
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CThreadInfo &ti = ThreadsInfo[t];
+ if (MtMode)
+ ti.Thread.Wait();
+ ti.Free();
+ }
+ delete []ThreadsInfo;
+ ThreadsInfo = 0;
+}
+#endif
+
+UInt32 CEncoder::ReadRleBlock(Byte *buffer)
+{
+ UInt32 i = 0;
+ Byte prevByte;
+ if (m_InStream.ReadByte(prevByte))
+ {
+ UInt32 blockSize = m_BlockSizeMult * kBlockSizeStep - 1;
+ int numReps = 1;
+ buffer[i++] = prevByte;
+ while (i < blockSize) // "- 1" to support RLE
+ {
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ break;
+ if (b != prevByte)
+ {
+ if (numReps >= kRleModeRepSize)
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ buffer[i++] = b;
+ numReps = 1;
+ prevByte = b;
+ continue;
+ }
+ numReps++;
+ if (numReps <= kRleModeRepSize)
+ buffer[i++] = b;
+ else if (numReps == kRleModeRepSize + 255)
+ {
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ numReps = 0;
+ }
+ }
+ // it's to support original BZip2 decoder
+ if (numReps >= kRleModeRepSize)
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ }
+ return i;
+}
+
+void CThreadInfo::WriteBits2(UInt32 value, UInt32 numBits)
+ { m_OutStreamCurrent->WriteBits(value, numBits); }
+void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b , 8); }
+void CThreadInfo::WriteBit2(bool v) { WriteBits2((v ? 1 : 0), 1); }
+void CThreadInfo::WriteCrc2(UInt32 v)
+{
+ for (int i = 0; i < 4; i++)
+ WriteByte2(((Byte)(v >> (24 - i * 8))));
+}
+
+void CEncoder::WriteBits(UInt32 value, UInt32 numBits)
+ { m_OutStream.WriteBits(value, numBits); }
+void CEncoder::WriteByte(Byte b) { WriteBits(b , 8); }
+void CEncoder::WriteBit(bool v) { WriteBits((v ? 1 : 0), 1); }
+void CEncoder::WriteCrc(UInt32 v)
+{
+ for (int i = 0; i < 4; i++)
+ WriteByte(((Byte)(v >> (24 - i * 8))));
+}
+
+
+// blockSize > 0
+void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
+{
+ WriteBit2(false); // Randomised = false
+
+ {
+ UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
+ // if (m_BlockSorterIndex[origPtr] != 0) throw 1;
+ m_BlockSorterIndex[origPtr] = blockSize;
+ WriteBits2(origPtr, kNumOrigBits);
+ }
+
+ CMtf8Encoder mtf;
+ int numInUse = 0;
+ {
+ bool inUse[256];
+ bool inUse16[16];
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ inUse[i] = false;
+ for (i = 0; i < 16; i++)
+ inUse16[i] = false;
+ for (i = 0; i < blockSize; i++)
+ inUse[block[i]] = true;
+ for (i = 0; i < 256; i++)
+ if (inUse[i])
+ {
+ inUse16[i >> 4] = true;
+ mtf.Buf[numInUse++] = (Byte)i;
+ }
+ for (i = 0; i < 16; i++)
+ WriteBit2(inUse16[i]);
+ for (i = 0; i < 256; i++)
+ if (inUse16[i >> 4])
+ WriteBit2(inUse[i]);
+ }
+ int alphaSize = numInUse + 2;
+
+ Byte *mtfs = m_MtfArray;
+ UInt32 mtfArraySize = 0;
+ UInt32 symbolCounts[kMaxAlphaSize];
+ {
+ for (int i = 0; i < kMaxAlphaSize; i++)
+ symbolCounts[i] = 0;
+ }
+
+ {
+ UInt32 rleSize = 0;
+ UInt32 i = 0;
+ const UInt32 *bsIndex = m_BlockSorterIndex;
+ block--;
+ do
+ {
+ int pos = mtf.FindAndMove(block[bsIndex[i]]);
+ if (pos == 0)
+ rleSize++;
+ else
+ {
+ while (rleSize != 0)
+ {
+ rleSize--;
+ mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
+ symbolCounts[rleSize & 1]++;
+ rleSize >>= 1;
+ }
+ if (pos >= 0xFE)
+ {
+ mtfs[mtfArraySize++] = 0xFF;
+ mtfs[mtfArraySize++] = (Byte)(pos - 0xFE);
+ }
+ else
+ mtfs[mtfArraySize++] = (Byte)(pos + 1);
+ symbolCounts[pos + 1]++;
+ }
+ }
+ while (++i < blockSize);
+
+ while (rleSize != 0)
+ {
+ rleSize--;
+ mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
+ symbolCounts[rleSize & 1]++;
+ rleSize >>= 1;
+ }
+
+ if (alphaSize < 256)
+ mtfs[mtfArraySize++] = (Byte)(alphaSize - 1);
+ else
+ {
+ mtfs[mtfArraySize++] = 0xFF;
+ mtfs[mtfArraySize++] = (Byte)(alphaSize - 256);
+ }
+ symbolCounts[alphaSize - 1]++;
+ }
+
+ UInt32 numSymbols = 0;
+ {
+ for (int i = 0; i < kMaxAlphaSize; i++)
+ numSymbols += symbolCounts[i];
+ }
+
+ int bestNumTables = kNumTablesMin;
+ UInt32 bestPrice = 0xFFFFFFFF;
+ UInt32 startPos = m_OutStreamCurrent->GetPos();
+ Byte startCurByte = m_OutStreamCurrent->GetCurByte();
+ for (int nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
+ {
+ int numTables;
+
+ if(m_OptimizeNumTables)
+ {
+ m_OutStreamCurrent->SetPos(startPos);
+ m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
+ if (nt <= kNumTablesMax)
+ numTables = nt;
+ else
+ numTables = bestNumTables;
+ }
+ else
+ {
+ if (numSymbols < 200) numTables = 2;
+ else if (numSymbols < 600) numTables = 3;
+ else if (numSymbols < 1200) numTables = 4;
+ else if (numSymbols < 2400) numTables = 5;
+ else numTables = 6;
+ }
+
+ WriteBits2(numTables, kNumTablesBits);
+
+ UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
+ WriteBits2(numSelectors, kNumSelectorsBits);
+
+ {
+ UInt32 remFreq = numSymbols;
+ int gs = 0;
+ int t = numTables;
+ do
+ {
+ UInt32 tFreq = remFreq / t;
+ int ge = gs;
+ UInt32 aFreq = 0;
+ while (aFreq < tFreq) // && ge < alphaSize)
+ aFreq += symbolCounts[ge++];
+
+ if (ge - 1 > gs && t != numTables && t != 1 && (((numTables - t) & 1) == 1))
+ aFreq -= symbolCounts[--ge];
+
+ Byte *lens = Lens[t - 1];
+ int i = 0;
+ do
+ lens[i] = (i >= gs && i < ge) ? 0 : 1;
+ while (++i < alphaSize);
+ gs = ge;
+ remFreq -= aFreq;
+ }
+ while(--t != 0);
+ }
+
+
+ for (int pass = 0; pass < kNumHuffPasses; pass++)
+ {
+ {
+ int t = 0;
+ do
+ memset(Freqs[t], 0, sizeof(Freqs[t]));
+ while(++t < numTables);
+ }
+
+ {
+ UInt32 mtfPos = 0;
+ UInt32 g = 0;
+ do
+ {
+ UInt32 symbols[kGroupSize];
+ int i = 0;
+ do
+ {
+ UInt32 symbol = mtfs[mtfPos++];
+ if (symbol >= 0xFF)
+ symbol += mtfs[mtfPos++];
+ symbols[i] = symbol;
+ }
+ while (++i < kGroupSize && mtfPos < mtfArraySize);
+
+ UInt32 bestPrice = 0xFFFFFFFF;
+ int t = 0;
+ do
+ {
+ const Byte *lens = Lens[t];
+ UInt32 price = 0;
+ int j = 0;
+ do
+ price += lens[symbols[j]];
+ while (++j < i);
+ if (price < bestPrice)
+ {
+ m_Selectors[g] = (Byte)t;
+ bestPrice = price;
+ }
+ }
+ while(++t < numTables);
+ UInt32 *freqs = Freqs[m_Selectors[g++]];
+ int j = 0;
+ do
+ freqs[symbols[j]]++;
+ while (++j < i);
+ }
+ while (mtfPos < mtfArraySize);
+ }
+
+ int t = 0;
+ do
+ {
+ UInt32 *freqs = Freqs[t];
+ int i = 0;
+ do
+ if (freqs[i] == 0)
+ freqs[i] = 1;
+ while(++i < alphaSize);
+ Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding);
+ }
+ while(++t < numTables);
+ }
+
+ {
+ Byte mtfSel[kNumTablesMax];
+ {
+ int t = 0;
+ do
+ mtfSel[t] = (Byte)t;
+ while(++t < numTables);
+ }
+
+ UInt32 i = 0;
+ do
+ {
+ Byte sel = m_Selectors[i];
+ int pos;
+ for (pos = 0; mtfSel[pos] != sel; pos++)
+ WriteBit2(true);
+ WriteBit2(false);
+ for (; pos > 0; pos--)
+ mtfSel[pos] = mtfSel[pos - 1];
+ mtfSel[0] = sel;
+ }
+ while(++i < numSelectors);
+ }
+
+ {
+ int t = 0;
+ do
+ {
+ const Byte *lens = Lens[t];
+ UInt32 len = lens[0];
+ WriteBits2(len, kNumLevelsBits);
+ int i = 0;
+ do
+ {
+ UInt32 level = lens[i];
+ while (len != level)
+ {
+ WriteBit2(true);
+ if (len < level)
+ {
+ WriteBit2(false);
+ len++;
+ }
+ else
+ {
+ WriteBit2(true);
+ len--;
+ }
+ }
+ WriteBit2(false);
+ }
+ while (++i < alphaSize);
+ }
+ while(++t < numTables);
+ }
+
+ {
+ UInt32 groupSize = 0;
+ UInt32 groupIndex = 0;
+ const Byte *lens = 0;
+ const UInt32 *codes = 0;
+ UInt32 mtfPos = 0;
+ do
+ {
+ UInt32 symbol = mtfs[mtfPos++];
+ if (symbol >= 0xFF)
+ symbol += mtfs[mtfPos++];
+ if (groupSize == 0)
+ {
+ groupSize = kGroupSize;
+ int t = m_Selectors[groupIndex++];
+ lens = Lens[t];
+ codes = Codes[t];
+ }
+ groupSize--;
+ m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
+ }
+ while (mtfPos < mtfArraySize);
+ }
+
+ if (!m_OptimizeNumTables)
+ break;
+ UInt32 price = m_OutStreamCurrent->GetPos() - startPos;
+ if (price <= bestPrice)
+ {
+ if (nt == kNumTablesMax)
+ break;
+ bestPrice = price;
+ bestNumTables = nt;
+ }
+ }
+}
+
+// blockSize > 0
+UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
+{
+ WriteByte2(kBlockSig0);
+ WriteByte2(kBlockSig1);
+ WriteByte2(kBlockSig2);
+ WriteByte2(kBlockSig3);
+ WriteByte2(kBlockSig4);
+ WriteByte2(kBlockSig5);
+
+ CBZip2Crc crc;
+ int numReps = 0;
+ Byte prevByte = block[0];
+ UInt32 i = 0;
+ do
+ {
+ Byte b = block[i];
+ if (numReps == kRleModeRepSize)
+ {
+ for (; b > 0; b--)
+ crc.UpdateByte(prevByte);
+ numReps = 0;
+ continue;
+ }
+ if (prevByte == b)
+ numReps++;
+ else
+ {
+ numReps = 1;
+ prevByte = b;
+ }
+ crc.UpdateByte(b);
+ }
+ while (++i < blockSize);
+ UInt32 crcRes = crc.GetDigest();
+ WriteCrc2(crcRes);
+ EncodeBlock(block, blockSize);
+ return crcRes;
+}
+
+void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
+{
+ UInt32 numCrcs = m_NumCrcs;
+ bool needCompare = false;
+
+ UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();
+ UInt32 startPos = m_OutStreamCurrent->GetPos();
+ Byte startCurByte = m_OutStreamCurrent->GetCurByte();
+ Byte endCurByte = 0;
+ UInt32 endPos = 0;
+ if (numPasses > 1 && blockSize >= (1 << 10))
+ {
+ UInt32 blockSize0 = blockSize / 2;
+ for (;(block[blockSize0] == block[blockSize0 - 1] ||
+ block[blockSize0 - 1] == block[blockSize0 - 2]) &&
+ blockSize0 < blockSize; blockSize0++);
+ if (blockSize0 < blockSize)
+ {
+ EncodeBlock2(block, blockSize0, numPasses - 1);
+ EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);
+ endPos = m_OutStreamCurrent->GetPos();
+ endCurByte = m_OutStreamCurrent->GetCurByte();
+ if ((endPos & 7) > 0)
+ WriteBits2(0, 8 - (endPos & 7));
+ m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
+ needCompare = true;
+ }
+ }
+
+ UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos();
+ UInt32 startPos2 = m_OutStreamCurrent->GetPos();
+ UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
+ UInt32 endPos2 = m_OutStreamCurrent->GetPos();
+
+ if (needCompare)
+ {
+ UInt32 size2 = endPos2 - startPos2;
+ if (size2 < endPos - startPos)
+ {
+ UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;
+ Byte *buffer = m_OutStreamCurrent->GetStream();
+ for (UInt32 i = 0; i < numBytes; i++)
+ buffer[startBytePos + i] = buffer[startBytePos2 + i];
+ m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
+ m_NumCrcs = numCrcs;
+ m_CRCs[m_NumCrcs++] = crcVal;
+ }
+ else
+ {
+ m_OutStreamCurrent->SetPos(endPos);
+ m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);
+ }
+ }
+ else
+ {
+ m_NumCrcs = numCrcs;
+ m_CRCs[m_NumCrcs++] = crcVal;
+ }
+}
+
+HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
+{
+ CMsbfEncoderTemp outStreamTemp;
+ outStreamTemp.SetStream(m_TempArray);
+ outStreamTemp.Init();
+ m_OutStreamCurrent = &outStreamTemp;
+
+ m_NumCrcs = 0;
+
+ EncodeBlock2(m_Block, blockSize, Encoder->NumPasses);
+
+ #ifndef _7ZIP_ST
+ if (Encoder->MtMode)
+ Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
+ #endif
+ for (UInt32 i = 0; i < m_NumCrcs; i++)
+ Encoder->CombinedCrc.Update(m_CRCs[i]);
+ Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());
+ HRESULT res = S_OK;
+ #ifndef _7ZIP_ST
+ if (Encoder->MtMode)
+ {
+ UInt32 blockIndex = m_BlockIndex + 1;
+ if (blockIndex == Encoder->NumThreads)
+ blockIndex = 0;
+
+ if (Encoder->Progress)
+ {
+ UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize();
+ res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize);
+ }
+
+ Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
+ }
+ #endif
+ return res;
+}
+
+void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
+{
+ UInt32 bytesSize = (sizeInBits / 8);
+ for (UInt32 i = 0; i < bytesSize; i++)
+ m_OutStream.WriteBits(data[i], 8);
+ WriteBits(lastByte, (sizeInBits & 7));
+}
+
+
+HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ #ifndef _7ZIP_ST
+ Progress = progress;
+ RINOK(Create());
+ for (UInt32 t = 0; t < NumThreads; t++)
+ #endif
+ {
+ #ifndef _7ZIP_ST
+ CThreadInfo &ti = ThreadsInfo[t];
+ if (MtMode)
+ {
+ RINOK(ti.StreamWasFinishedEvent.Reset());
+ RINOK(ti.WaitingWasStartedEvent.Reset());
+ RINOK(ti.CanWriteEvent.Reset());
+ }
+ #else
+ CThreadInfo &ti = ThreadsInfo;
+ ti.Encoder = this;
+ #endif
+
+ ti.m_OptimizeNumTables = m_OptimizeNumTables;
+
+ if (!ti.Alloc())
+ return E_OUTOFMEMORY;
+ }
+
+
+ if (!m_InStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (!m_OutStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+
+
+ m_InStream.SetStream(inStream);
+ m_InStream.Init();
+
+ m_OutStream.SetStream(outStream);
+ m_OutStream.Init();
+
+ CFlusher flusher(this);
+
+ CombinedCrc.Init();
+ #ifndef _7ZIP_ST
+ NextBlockIndex = 0;
+ StreamWasFinished = false;
+ CloseThreads = false;
+ CanStartWaitingEvent.Reset();
+ #endif
+
+ WriteByte(kArSig0);
+ WriteByte(kArSig1);
+ WriteByte(kArSig2);
+ WriteByte((Byte)(kArSig3 + m_BlockSizeMult));
+
+ #ifndef _7ZIP_ST
+
+ if (MtMode)
+ {
+ ThreadsInfo[0].CanWriteEvent.Set();
+ Result = S_OK;
+ CanProcessEvent.Set();
+ UInt32 t;
+ for (t = 0; t < NumThreads; t++)
+ ThreadsInfo[t].StreamWasFinishedEvent.Lock();
+ CanProcessEvent.Reset();
+ CanStartWaitingEvent.Set();
+ for (t = 0; t < NumThreads; t++)
+ ThreadsInfo[t].WaitingWasStartedEvent.Lock();
+ CanStartWaitingEvent.Reset();
+ RINOK(Result);
+ }
+ else
+ #endif
+ {
+ for (;;)
+ {
+ CThreadInfo &ti =
+ #ifndef _7ZIP_ST
+ ThreadsInfo[0];
+ #else
+ ThreadsInfo;
+ #endif
+ UInt32 blockSize = ReadRleBlock(ti.m_Block);
+ if (blockSize == 0)
+ break;
+ RINOK(ti.EncodeBlock3(blockSize));
+ if (progress)
+ {
+ UInt64 packSize = m_InStream.GetProcessedSize();
+ UInt64 unpackSize = m_OutStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
+ }
+ }
+ }
+ WriteByte(kFinSig0);
+ WriteByte(kFinSig1);
+ WriteByte(kFinSig2);
+ WriteByte(kFinSig3);
+ WriteByte(kFinSig4);
+ WriteByte(kFinSig5);
+
+ WriteCrc(CombinedCrc.GetDigest());
+ return Flush();
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ for(UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kNumPasses:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 numPasses = prop.ulVal;
+ if (numPasses == 0)
+ numPasses = 1;
+ if (numPasses > kNumPassesMax)
+ numPasses = kNumPassesMax;
+ NumPasses = numPasses;
+ m_OptimizeNumTables = (NumPasses > 1);
+ break;
+ }
+ case NCoderPropID::kDictionarySize:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 dictionary = prop.ulVal / kBlockSizeStep;
+ if (dictionary < kBlockSizeMultMin)
+ dictionary = kBlockSizeMultMin;
+ else if (dictionary > kBlockSizeMultMax)
+ dictionary = kBlockSizeMultMax;
+ m_BlockSizeMult = dictionary;
+ break;
+ }
+ case NCoderPropID::kNumThreads:
+ {
+ #ifndef _7ZIP_ST
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ NumThreads = prop.ulVal;
+ if (NumThreads < 1)
+ NumThreads = 1;
+ #endif
+ break;
+ }
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+#ifndef _7ZIP_ST
+STDMETHODIMP CEncoder::SetNumberOfThreads(UInt32 numThreads)
+{
+ NumThreads = numThreads;
+ if (NumThreads < 1)
+ NumThreads = 1;
+ return S_OK;
+}
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BZip2Encoder.h b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Encoder.h
new file mode 100644
index 000000000..a863172fe
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Encoder.h
@@ -0,0 +1,245 @@
+// BZip2Encoder.h
+
+#ifndef __COMPRESS_BZIP2_ENCODER_H
+#define __COMPRESS_BZIP2_ENCODER_H
+
+#include "../../Common/Defs.h"
+#include "../../Common/MyCom.h"
+
+#ifndef _7ZIP_ST
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+#endif
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "BitmEncoder.h"
+#include "BZip2Const.h"
+#include "BZip2Crc.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+class CMsbfEncoderTemp
+{
+ UInt32 m_Pos;
+ int m_BitPos;
+ Byte m_CurByte;
+ Byte *Buffer;
+public:
+ void SetStream(Byte *buffer) { Buffer = buffer; }
+ Byte *GetStream() const { return Buffer; }
+
+ void Init()
+ {
+ m_Pos = 0;
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+
+ void Flush()
+ {
+ if (m_BitPos < 8)
+ WriteBits(0, m_BitPos);
+ }
+
+ void WriteBits(UInt32 value, int numBits)
+ {
+ while (numBits > 0)
+ {
+ int numNewBits = MyMin(numBits, m_BitPos);
+ numBits -= numNewBits;
+
+ m_CurByte <<= numNewBits;
+ UInt32 newBits = value >> numBits;
+ m_CurByte |= Byte(newBits);
+ value -= (newBits << numBits);
+
+ m_BitPos -= numNewBits;
+
+ if (m_BitPos == 0)
+ {
+ Buffer[m_Pos++] = m_CurByte;
+ m_BitPos = 8;
+ }
+ }
+ }
+
+ UInt32 GetBytePos() const { return m_Pos ; }
+ UInt32 GetPos() const { return m_Pos * 8 + (8 - m_BitPos); }
+ Byte GetCurByte() const { return m_CurByte; }
+ void SetPos(UInt32 bitPos)
+ {
+ m_Pos = bitPos / 8;
+ m_BitPos = 8 - ((int)bitPos & 7);
+ }
+ void SetCurState(int bitPos, Byte curByte)
+ {
+ m_BitPos = 8 - bitPos;
+ m_CurByte = curByte;
+ }
+};
+
+class CEncoder;
+
+const int kNumPassesMax = 10;
+
+class CThreadInfo
+{
+public:
+ Byte *m_Block;
+private:
+ Byte *m_MtfArray;
+ Byte *m_TempArray;
+ UInt32 *m_BlockSorterIndex;
+
+ CMsbfEncoderTemp *m_OutStreamCurrent;
+
+ Byte Lens[kNumTablesMax][kMaxAlphaSize];
+ UInt32 Freqs[kNumTablesMax][kMaxAlphaSize];
+ UInt32 Codes[kNumTablesMax][kMaxAlphaSize];
+
+ Byte m_Selectors[kNumSelectorsMax];
+
+ UInt32 m_CRCs[1 << kNumPassesMax];
+ UInt32 m_NumCrcs;
+
+ UInt32 m_BlockIndex;
+
+ void WriteBits2(UInt32 value, UInt32 numBits);
+ void WriteByte2(Byte b);
+ void WriteBit2(bool v);
+ void WriteCrc2(UInt32 v);
+
+ void EncodeBlock(const Byte *block, UInt32 blockSize);
+ UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize);
+ void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses);
+public:
+ bool m_OptimizeNumTables;
+ CEncoder *Encoder;
+ #ifndef _7ZIP_ST
+ NWindows::CThread Thread;
+
+ NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
+ NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
+
+ // it's not member of this thread. We just need one event per thread
+ NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
+
+ UInt64 m_PackSize;
+
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+ HRESULT Create();
+ void FinishStream(bool needLeave);
+ DWORD ThreadFunc();
+ #endif
+
+ CThreadInfo(): m_BlockSorterIndex(0), m_Block(0) {}
+ ~CThreadInfo() { Free(); }
+ bool Alloc();
+ void Free();
+
+ HRESULT EncodeBlock3(UInt32 blockSize);
+};
+
+class CEncoder :
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ #ifndef _7ZIP_ST
+ public ICompressSetCoderMt,
+ #endif
+ public CMyUnknownImp
+{
+ UInt32 m_BlockSizeMult;
+ bool m_OptimizeNumTables;
+
+ UInt32 m_NumPassesPrev;
+
+ UInt32 m_NumThreadsPrev;
+public:
+ CInBuffer m_InStream;
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+ CBitmEncoder<COutBuffer> m_OutStream;
+ UInt32 NumPasses;
+ CBZip2CombinedCrc CombinedCrc;
+
+ #ifndef _7ZIP_ST
+ CThreadInfo *ThreadsInfo;
+ NWindows::NSynchronization::CManualResetEvent CanProcessEvent;
+ NWindows::NSynchronization::CCriticalSection CS;
+ UInt32 NumThreads;
+ bool MtMode;
+ UInt32 NextBlockIndex;
+
+ bool CloseThreads;
+ bool StreamWasFinished;
+ NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
+
+ HRESULT Result;
+ ICompressProgressInfo *Progress;
+ #else
+ CThreadInfo ThreadsInfo;
+ #endif
+
+ UInt32 ReadRleBlock(Byte *buffer);
+ void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte);
+
+ void WriteBits(UInt32 value, UInt32 numBits);
+ void WriteByte(Byte b);
+ void WriteBit(bool v);
+ void WriteCrc(UInt32 v);
+
+ #ifndef _7ZIP_ST
+ HRESULT Create();
+ void Free();
+ #endif
+
+public:
+ CEncoder();
+ #ifndef _7ZIP_ST
+ ~CEncoder();
+ #endif
+
+ HRESULT Flush() { return m_OutStream.Flush(); }
+
+ void ReleaseStreams()
+ {
+ m_InStream.ReleaseStream();
+ m_OutStream.ReleaseStream();
+ }
+
+ class CFlusher
+ {
+ CEncoder *_coder;
+ public:
+ CFlusher(CEncoder *coder): _coder(coder) {}
+ ~CFlusher()
+ {
+ _coder->ReleaseStreams();
+ }
+ };
+
+ #ifndef _7ZIP_ST
+ MY_UNKNOWN_IMP2(ICompressSetCoderMt, ICompressSetCoderProperties)
+ #else
+ MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
+ #endif
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+
+ #ifndef _7ZIP_ST
+ STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
+ #endif
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BZip2Register.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Register.cpp
new file mode 100644
index 000000000..ef14204b0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BZip2Register.cpp
@@ -0,0 +1,20 @@
+// BZip2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BZip2Decoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NBZip2::CDecoder); }
+#if !defined(EXTRACT_ONLY) && !defined(BZIP2_EXTRACT_ONLY)
+#include "BZip2Encoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NBZip2::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x040202, L"BZip2", 1, false };
+
+REGISTER_CODEC(BZip2)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.cpp
new file mode 100644
index 000000000..684da5abf
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.cpp
@@ -0,0 +1,386 @@
+// Bcj2Coder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "Bcj2Coder.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); }
+inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); }
+inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); }
+
+#ifndef EXTRACT_ONLY
+
+static const int kBufferSize = 1 << 17;
+
+static bool inline Test86MSByte(Byte b)
+{
+ return (b == 0 || b == 0xFF);
+}
+
+bool CEncoder::Create()
+{
+ if (!_mainStream.Create(1 << 18))
+ return false;
+ if (!_callStream.Create(1 << 18))
+ return false;
+ if (!_jumpStream.Create(1 << 18))
+ return false;
+ if (!_rangeEncoder.Create(1 << 20))
+ return false;
+ if (_buffer == 0)
+ {
+ _buffer = (Byte *)MidAlloc(kBufferSize);
+ if (_buffer == 0)
+ return false;
+ }
+ return true;
+}
+
+CEncoder::~CEncoder()
+{
+ ::MidFree(_buffer);
+}
+
+HRESULT CEncoder::Flush()
+{
+ RINOK(_mainStream.Flush());
+ RINOK(_callStream.Flush());
+ RINOK(_jumpStream.Flush());
+ _rangeEncoder.FlushData();
+ return _rangeEncoder.FlushStream();
+}
+
+const UInt32 kDefaultLimit = (1 << 24);
+
+HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 1 || numOutStreams != 4)
+ return E_INVALIDARG;
+
+ if (!Create())
+ return E_OUTOFMEMORY;
+
+ bool sizeIsDefined = false;
+ UInt64 inSize = 0;
+ if (inSizes != NULL)
+ if (inSizes[0] != NULL)
+ {
+ inSize = *inSizes[0];
+ if (inSize <= kDefaultLimit)
+ sizeIsDefined = true;
+ }
+
+ CCoderReleaser releaser(this);
+
+ ISequentialInStream *inStream = inStreams[0];
+
+ _mainStream.SetStream(outStreams[0]);
+ _mainStream.Init();
+ _callStream.SetStream(outStreams[1]);
+ _callStream.Init();
+ _jumpStream.SetStream(outStreams[2]);
+ _jumpStream.Init();
+ _rangeEncoder.SetStream(outStreams[3]);
+ _rangeEncoder.Init();
+ for (int i = 0; i < 256 + 2; i++)
+ _statusEncoder[i].Init();
+
+ CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
+ {
+ inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
+ }
+
+ UInt32 nowPos = 0;
+ UInt64 nowPos64 = 0;
+ UInt32 bufferPos = 0;
+
+ Byte prevByte = 0;
+
+ UInt64 subStreamIndex = 0;
+ UInt64 subStreamStartPos = 0;
+ UInt64 subStreamEndPos = 0;
+
+ for (;;)
+ {
+ UInt32 processedSize = 0;
+ for (;;)
+ {
+ UInt32 size = kBufferSize - (bufferPos + processedSize);
+ UInt32 processedSizeLoc;
+ if (size == 0)
+ break;
+ RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc));
+ if (processedSizeLoc == 0)
+ break;
+ processedSize += processedSizeLoc;
+ }
+ UInt32 endPos = bufferPos + processedSize;
+
+ if (endPos < 5)
+ {
+ // change it
+ for (bufferPos = 0; bufferPos < endPos; bufferPos++)
+ {
+ Byte b = _buffer[bufferPos];
+ _mainStream.WriteByte(b);
+ UInt32 index;
+ if (b == 0xE8)
+ index = prevByte;
+ else if (b == 0xE9)
+ index = 256;
+ else if (IsJcc(prevByte, b))
+ index = 257;
+ else
+ {
+ prevByte = b;
+ continue;
+ }
+ _statusEncoder[index].Encode(&_rangeEncoder, 0);
+ prevByte = b;
+ }
+ return Flush();
+ }
+
+ bufferPos = 0;
+
+ UInt32 limit = endPos - 5;
+ while(bufferPos <= limit)
+ {
+ Byte b = _buffer[bufferPos];
+ _mainStream.WriteByte(b);
+ if (!IsJ(prevByte, b))
+ {
+ bufferPos++;
+ prevByte = b;
+ continue;
+ }
+ Byte nextByte = _buffer[bufferPos + 4];
+ UInt32 src =
+ (UInt32(nextByte) << 24) |
+ (UInt32(_buffer[bufferPos + 3]) << 16) |
+ (UInt32(_buffer[bufferPos + 2]) << 8) |
+ (_buffer[bufferPos + 1]);
+ UInt32 dest = (nowPos + bufferPos + 5) + src;
+ // if (Test86MSByte(nextByte))
+ bool convert;
+ if (getSubStreamSize != NULL)
+ {
+ UInt64 currentPos = (nowPos64 + bufferPos);
+ while (subStreamEndPos < currentPos)
+ {
+ UInt64 subStreamSize;
+ HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
+ if (result == S_OK)
+ {
+ subStreamStartPos = subStreamEndPos;
+ subStreamEndPos += subStreamSize;
+ subStreamIndex++;
+ }
+ else if (result == S_FALSE || result == E_NOTIMPL)
+ {
+ getSubStreamSize.Release();
+ subStreamStartPos = 0;
+ subStreamEndPos = subStreamStartPos - 1;
+ }
+ else
+ return result;
+ }
+ if (getSubStreamSize == NULL)
+ {
+ if (sizeIsDefined)
+ convert = (dest < inSize);
+ else
+ convert = Test86MSByte(nextByte);
+ }
+ else if (subStreamEndPos - subStreamStartPos > kDefaultLimit)
+ convert = Test86MSByte(nextByte);
+ else
+ {
+ UInt64 dest64 = (currentPos + 5) + Int64(Int32(src));
+ convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos);
+ }
+ }
+ else if (sizeIsDefined)
+ convert = (dest < inSize);
+ else
+ convert = Test86MSByte(nextByte);
+ unsigned index = GetIndex(prevByte, b);
+ if (convert)
+ {
+ _statusEncoder[index].Encode(&_rangeEncoder, 1);
+ bufferPos += 5;
+ COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
+ for (int i = 24; i >= 0; i -= 8)
+ s.WriteByte((Byte)(dest >> i));
+ prevByte = nextByte;
+ }
+ else
+ {
+ _statusEncoder[index].Encode(&_rangeEncoder, 0);
+ bufferPos++;
+ prevByte = b;
+ }
+ }
+ nowPos += bufferPos;
+ nowPos64 += bufferPos;
+
+ if (progress != NULL)
+ {
+ /*
+ const UInt64 compressedSize =
+ _mainStream.GetProcessedSize() +
+ _callStream.GetProcessedSize() +
+ _jumpStream.GetProcessedSize() +
+ _rangeEncoder.GetProcessedSize();
+ */
+ RINOK(progress->SetRatioInfo(&nowPos64, NULL));
+ }
+
+ UInt32 i = 0;
+ while(bufferPos < endPos)
+ _buffer[i++] = _buffer[bufferPos++];
+ bufferPos = i;
+ }
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+#endif
+
+
+STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _inBufSizes[streamIndex] = size; return S_OK; }
+STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
+
+CDecoder::CDecoder():
+ _outBufSize(1 << 16)
+{
+ _inBufSizes[0] = 1 << 20;
+ _inBufSizes[1] = 1 << 20;
+ _inBufSizes[2] = 1 << 20;
+ _inBufSizes[3] = 1 << 20;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 4 || numOutStreams != 1)
+ return E_INVALIDARG;
+
+ if (!_mainInStream.Create(_inBufSizes[0]))
+ return E_OUTOFMEMORY;
+ if (!_callStream.Create(_inBufSizes[1]))
+ return E_OUTOFMEMORY;
+ if (!_jumpStream.Create(_inBufSizes[2]))
+ return E_OUTOFMEMORY;
+ if (!_rangeDecoder.Create(_inBufSizes[3]))
+ return E_OUTOFMEMORY;
+ if (!_outStream.Create(_outBufSize))
+ return E_OUTOFMEMORY;
+
+ CCoderReleaser releaser(this);
+
+ _mainInStream.SetStream(inStreams[0]);
+ _callStream.SetStream(inStreams[1]);
+ _jumpStream.SetStream(inStreams[2]);
+ _rangeDecoder.SetStream(inStreams[3]);
+ _outStream.SetStream(outStreams[0]);
+
+ _mainInStream.Init();
+ _callStream.Init();
+ _jumpStream.Init();
+ _rangeDecoder.Init();
+ _outStream.Init();
+
+ for (int i = 0; i < 256 + 2; i++)
+ _statusDecoder[i].Init();
+
+ Byte prevByte = 0;
+ UInt32 processedBytes = 0;
+ for (;;)
+ {
+ if (processedBytes >= (1 << 20) && progress != NULL)
+ {
+ /*
+ const UInt64 compressedSize =
+ _mainInStream.GetProcessedSize() +
+ _callStream.GetProcessedSize() +
+ _jumpStream.GetProcessedSize() +
+ _rangeDecoder.GetProcessedSize();
+ */
+ const UInt64 nowPos64 = _outStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(NULL, &nowPos64));
+ processedBytes = 0;
+ }
+ UInt32 i;
+ Byte b = 0;
+ const UInt32 kBurstSize = (1 << 18);
+ for (i = 0; i < kBurstSize; i++)
+ {
+ if (!_mainInStream.ReadByte(b))
+ return Flush();
+ _outStream.WriteByte(b);
+ if (IsJ(prevByte, b))
+ break;
+ prevByte = b;
+ }
+ processedBytes += i;
+ if (i == kBurstSize)
+ continue;
+ unsigned index = GetIndex(prevByte, b);
+ if (_statusDecoder[index].Decode(&_rangeDecoder) == 1)
+ {
+ UInt32 src = 0;
+ CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream;
+ for (int i = 0; i < 4; i++)
+ {
+ Byte b0;
+ if(!s.ReadByte(b0))
+ return S_FALSE;
+ src <<= 8;
+ src |= ((UInt32)b0);
+ }
+ UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ;
+ _outStream.WriteByte((Byte)(dest));
+ _outStream.WriteByte((Byte)(dest >> 8));
+ _outStream.WriteByte((Byte)(dest >> 16));
+ _outStream.WriteByte((Byte)(dest >> 24));
+ prevByte = (Byte)(dest >> 24);
+ processedBytes += 4;
+ }
+ else
+ prevByte = b;
+ }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.h b/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.h
new file mode 100644
index 000000000..79a713f17
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Coder.h
@@ -0,0 +1,115 @@
+// Bcj2Coder.h
+
+#ifndef __COMPRESS_BCJ2_CODER_H
+#define __COMPRESS_BCJ2_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "RangeCoderBit.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+const int kNumMoveBits = 5;
+
+#ifndef EXTRACT_ONLY
+
+class CEncoder:
+ public ICompressCoder2,
+ public CMyUnknownImp
+{
+ Byte *_buffer;
+ bool Create();
+
+ COutBuffer _mainStream;
+ COutBuffer _callStream;
+ COutBuffer _jumpStream;
+ NCompress::NRangeCoder::CEncoder _rangeEncoder;
+ NCompress::NRangeCoder::CBitEncoder<kNumMoveBits> _statusEncoder[256 + 2];
+
+ HRESULT Flush();
+public:
+ void ReleaseStreams()
+ {
+ _mainStream.ReleaseStream();
+ _callStream.ReleaseStream();
+ _jumpStream.ReleaseStream();
+ _rangeEncoder.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CEncoder *_coder;
+ public:
+ CCoderReleaser(CEncoder *coder): _coder(coder) {}
+ ~CCoderReleaser() { _coder->ReleaseStreams(); }
+ };
+
+public:
+ MY_UNKNOWN_IMP
+
+ HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ CEncoder(): _buffer(0) {};
+ ~CEncoder();
+};
+
+#endif
+
+class CDecoder:
+ public ICompressCoder2,
+ public ICompressSetBufSize,
+ public CMyUnknownImp
+{
+ CInBuffer _mainInStream;
+ CInBuffer _callStream;
+ CInBuffer _jumpStream;
+ NCompress::NRangeCoder::CDecoder _rangeDecoder;
+ NCompress::NRangeCoder::CBitDecoder<kNumMoveBits> _statusDecoder[256 + 2];
+
+ COutBuffer _outStream;
+ UInt32 _inBufSizes[4];
+ UInt32 _outBufSize;
+
+public:
+ void ReleaseStreams()
+ {
+ _mainInStream.ReleaseStream();
+ _callStream.ReleaseStream();
+ _jumpStream.ReleaseStream();
+ _rangeDecoder.ReleaseStream();
+ _outStream.ReleaseStream();
+ }
+
+ HRESULT Flush() { return _outStream.Flush(); }
+ class CCoderReleaser
+ {
+ CDecoder *_coder;
+ public:
+ CCoderReleaser(CDecoder *coder): _coder(coder) {}
+ ~CCoderReleaser() { _coder->ReleaseStreams(); }
+ };
+
+public:
+ MY_UNKNOWN_IMP1(ICompressSetBufSize);
+ HRESULT CodeReal(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
+ CDecoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Register.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Register.cpp
new file mode 100644
index 000000000..8eb1e7360
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Bcj2Register.cpp
@@ -0,0 +1,19 @@
+// Bcj2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Bcj2Coder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CDecoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressCoder2 *)(new NCompress::NBcj2::CEncoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x0303011B, L"BCJ2", 4, false };
+
+REGISTER_CODEC(BCJ2)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.cpp
new file mode 100644
index 000000000..0e34ef488
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.cpp
@@ -0,0 +1,15 @@
+// BcjCoder.cpp
+
+#include "StdAfx.h"
+
+#include "BcjCoder.h"
+
+UInt32 CBCJ_x86_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 1);
+}
+
+UInt32 CBCJ_x86_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, 0);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.h b/src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.h
new file mode 100644
index 000000000..0754bcd23
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BcjCoder.h
@@ -0,0 +1,19 @@
+// BcjCoder.h
+
+#ifndef __COMPRESS_BCJ_CODER_H
+#define __COMPRESS_BCJ_CODER_H
+
+#include "../../../C/Bra.h"
+
+#include "BranchCoder.h"
+
+struct CBranch86
+{
+ UInt32 _prevMask;
+ void x86Init() { x86_Convert_Init(_prevMask); }
+};
+
+MyClassB(BCJ_x86, 0x01, 3, CBranch86 ,
+ virtual void SubInit() { x86Init(); })
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BcjRegister.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BcjRegister.cpp
new file mode 100644
index 000000000..648ad8e03
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BcjRegister.cpp
@@ -0,0 +1,19 @@
+// BcjRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BcjCoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressFilter *)(new CBCJ_x86_Decoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new CBCJ_x86_Encoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x03030103, L"BCJ", 1, true };
+
+REGISTER_CODEC(BCJ)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BitlDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BitlDecoder.cpp
new file mode 100644
index 000000000..78665be8f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BitlDecoder.cpp
@@ -0,0 +1,24 @@
+// BitlDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "BitlDecoder.h"
+
+namespace NBitl {
+
+Byte kInvertTable[256];
+
+struct CInverterTableInitializer
+{
+ CInverterTableInitializer()
+ {
+ for (int i = 0; i < 256; i++)
+ {
+ int x = ((i & 0x55) << 1) | ((i & 0xAA) >> 1);
+ x = ((x & 0x33) << 2) | ((x & 0xCC) >> 2);
+ kInvertTable[i] = (Byte)(((x & 0x0F) << 4) | ((x & 0xF0) >> 4));
+ }
+ }
+} g_InverterTableInitializer;
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BitlDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/BitlDecoder.h
new file mode 100644
index 000000000..ff373bac6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BitlDecoder.h
@@ -0,0 +1,141 @@
+// BitlDecoder.h -- the Least Significant Bit of byte is First
+
+#ifndef __BITL_DECODER_H
+#define __BITL_DECODER_H
+
+#include "../IStream.h"
+
+namespace NBitl {
+
+const unsigned kNumBigValueBits = 8 * 4;
+const unsigned kNumValueBytes = 3;
+const unsigned kNumValueBits = 8 * kNumValueBytes;
+
+const UInt32 kMask = (1 << kNumValueBits) - 1;
+
+extern Byte kInvertTable[256];
+
+template<class TInByte>
+class CBaseDecoder
+{
+protected:
+ unsigned m_BitPos;
+ UInt32 m_Value;
+ TInByte m_Stream;
+public:
+ UInt32 NumExtraBytes;
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream); }
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = kNumBigValueBits;
+ m_Value = 0;
+ NumExtraBytes = 0;
+ }
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() + NumExtraBytes - (kNumBigValueBits - m_BitPos) / 8; }
+
+ void Normalize()
+ {
+ for (; m_BitPos >= 8; m_BitPos -= 8)
+ {
+ Byte b = 0;
+ if (!m_Stream.ReadByte(b))
+ {
+ b = 0xFF; // check it
+ NumExtraBytes++;
+ }
+ m_Value = (b << (kNumBigValueBits - m_BitPos)) | m_Value;
+ }
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ Normalize();
+ UInt32 res = m_Value & ((1 << numBits) - 1);
+ m_BitPos += numBits;
+ m_Value >>= numBits;
+ return res;
+ }
+
+ bool ExtraBitsWereRead() const
+ {
+ if (NumExtraBytes == 0)
+ return false;
+ return ((UInt32)(kNumBigValueBits - m_BitPos) < (NumExtraBytes << 3));
+ }
+};
+
+template<class TInByte>
+class CDecoder: public CBaseDecoder<TInByte>
+{
+ UInt32 m_NormalValue;
+
+public:
+ void Init()
+ {
+ CBaseDecoder<TInByte>::Init();
+ m_NormalValue = 0;
+ }
+
+ void Normalize()
+ {
+ for (; this->m_BitPos >= 8; this->m_BitPos -= 8)
+ {
+ Byte b = 0;
+ if (!this->m_Stream.ReadByte(b))
+ {
+ b = 0xFF; // check it
+ this->NumExtraBytes++;
+ }
+ m_NormalValue = (b << (kNumBigValueBits - this->m_BitPos)) | m_NormalValue;
+ this->m_Value = (this->m_Value << 8) | kInvertTable[b];
+ }
+ }
+
+ UInt32 GetValue(unsigned numBits)
+ {
+ Normalize();
+ return ((this->m_Value >> (8 - this->m_BitPos)) & kMask) >> (kNumValueBits - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ this->m_BitPos += numBits;
+ m_NormalValue >>= numBits;
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ Normalize();
+ UInt32 res = m_NormalValue & ((1 << numBits) - 1);
+ MovePos(numBits);
+ return res;
+ }
+
+ void AlignToByte() { MovePos((32 - this->m_BitPos) & 7); }
+
+ Byte ReadByte()
+ {
+ if (this->m_BitPos == kNumBigValueBits)
+ {
+ Byte b = 0;
+ if (!this->m_Stream.ReadByte(b))
+ {
+ b = 0xFF;
+ this->NumExtraBytes++;
+ }
+ return b;
+ }
+ {
+ Byte b = (Byte)(m_NormalValue & 0xFF);
+ MovePos(8);
+ return b;
+ }
+ }
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BitlEncoder.h b/src/libs/7zip/win/CPP/7zip/Compress/BitlEncoder.h
new file mode 100644
index 000000000..7de575456
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BitlEncoder.h
@@ -0,0 +1,57 @@
+// BitlEncoder.h -- the Least Significant Bit of byte is First
+
+#ifndef __BITL_ENCODER_H
+#define __BITL_ENCODER_H
+
+#include "../Common/OutBuffer.h"
+
+class CBitlEncoder
+{
+ COutBuffer m_Stream;
+ unsigned m_BitPos;
+ Byte m_CurByte;
+public:
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialOutStream *outStream) { m_Stream.SetStream(outStream); }
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+ UInt32 GetBitPosition() const { return (8 - m_BitPos); }
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() + (8 - m_BitPos + 7) /8; }
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ HRESULT Flush()
+ {
+ FlushByte();
+ return m_Stream.Flush();
+ }
+ void FlushByte()
+ {
+ if (m_BitPos < 8)
+ m_Stream.WriteByte(m_CurByte);
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ void WriteBits(UInt32 value, unsigned numBits)
+ {
+ while (numBits > 0)
+ {
+ if (numBits < m_BitPos)
+ {
+ m_CurByte |= (value & ((1 << numBits) - 1)) << (8 - m_BitPos);
+ m_BitPos -= numBits;
+ return;
+ }
+ numBits -= m_BitPos;
+ m_Stream.WriteByte((Byte)(m_CurByte | (value << (8 - m_BitPos))));
+ value >>= m_BitPos;
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ }
+ void WriteByte(Byte b) { m_Stream.WriteByte(b);}
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BitmDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/BitmDecoder.h
new file mode 100644
index 000000000..4369b4524
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BitmDecoder.h
@@ -0,0 +1,66 @@
+// BitmDecoder.h -- the Most Significant Bit of byte is First
+
+#ifndef __BITM_DECODER_H
+#define __BITM_DECODER_H
+
+#include "../IStream.h"
+
+namespace NBitm {
+
+const unsigned kNumBigValueBits = 8 * 4;
+const unsigned kNumValueBytes = 3;
+const unsigned kNumValueBits = 8 * kNumValueBytes;
+
+const UInt32 kMask = (1 << kNumValueBits) - 1;
+
+template<class TInByte>
+class CDecoder
+{
+ unsigned m_BitPos;
+ UInt32 m_Value;
+public:
+ TInByte m_Stream;
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);}
+ void ReleaseStream() { m_Stream.ReleaseStream();}
+
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = kNumBigValueBits;
+ Normalize();
+ }
+
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - (kNumBigValueBits - m_BitPos) / 8; }
+
+ void Normalize()
+ {
+ for (;m_BitPos >= 8; m_BitPos -= 8)
+ m_Value = (m_Value << 8) | m_Stream.ReadByte();
+ }
+
+ UInt32 GetValue(unsigned numBits) const
+ {
+ // return (m_Value << m_BitPos) >> (kNumBigValueBits - numBits);
+ return ((m_Value >> (8 - m_BitPos)) & kMask) >> (kNumValueBits - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ m_BitPos += numBits;
+ Normalize();
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ MovePos(numBits);
+ return res;
+ }
+
+ void AlignToByte() { MovePos((32 - m_BitPos) & 7); }
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BitmEncoder.h b/src/libs/7zip/win/CPP/7zip/Compress/BitmEncoder.h
new file mode 100644
index 000000000..a85dbff89
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BitmEncoder.h
@@ -0,0 +1,50 @@
+// BitmEncoder.h -- the Most Significant Bit of byte is First
+
+#ifndef __BITM_ENCODER_H
+#define __BITM_ENCODER_H
+
+#include "../IStream.h"
+
+template<class TOutByte>
+class CBitmEncoder
+{
+ TOutByte m_Stream;
+ unsigned m_BitPos;
+ Byte m_CurByte;
+public:
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialOutStream *outStream) { m_Stream.SetStream(outStream);}
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() + (8 - m_BitPos + 7) / 8; }
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ HRESULT Flush()
+ {
+ if (m_BitPos < 8)
+ WriteBits(0, m_BitPos);
+ return m_Stream.Flush();
+ }
+ void WriteBits(UInt32 value, unsigned numBits)
+ {
+ while (numBits > 0)
+ {
+ if (numBits < m_BitPos)
+ {
+ m_CurByte |= ((Byte)value << (m_BitPos -= numBits));
+ return;
+ }
+ numBits -= m_BitPos;
+ UInt32 newBits = (value >> numBits);
+ value -= (newBits << numBits);
+ m_Stream.WriteByte((Byte)(m_CurByte | newBits));
+ m_BitPos = 8;
+ m_CurByte = 0;
+ }
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.cpp
new file mode 100644
index 000000000..431709526
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.cpp
@@ -0,0 +1,19 @@
+// BranchCoder.cpp
+
+#include "StdAfx.h"
+
+#include "BranchCoder.h"
+
+STDMETHODIMP CBranchConverter::Init()
+{
+ _bufferPos = 0;
+ SubInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CBranchConverter::Filter(Byte *data, UInt32 size)
+{
+ UInt32 processedSize = SubFilter(data, size);
+ _bufferPos += processedSize;
+ return processedSize;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.h b/src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.h
new file mode 100644
index 000000000..0e3a5c4e1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BranchCoder.h
@@ -0,0 +1,44 @@
+// BranchCoder.h
+
+#ifndef __COMPRESS_BRANCH_CODER_H
+#define __COMPRESS_BRANCH_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+class CBranchConverter:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+protected:
+ UInt32 _bufferPos;
+ virtual void SubInit() {}
+ virtual UInt32 SubFilter(Byte *data, UInt32 size) = 0;
+public:
+ MY_UNKNOWN_IMP;
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+#define MyClassEncoderA(Name) class C ## Name: public CBranchConverter \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); };
+
+#define MyClassDecoderA(Name) class C ## Name: public CBranchConverter \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); };
+
+#define MyClassEncoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT};
+
+#define MyClassDecoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT};
+
+#define MyClassA(Name, id, subId) \
+MyClassEncoderA(Name ## _Encoder) \
+MyClassDecoderA(Name ## _Decoder)
+
+#define MyClassB(Name, id, subId, ADD_ITEMS, ADD_INIT) \
+MyClassEncoderB(Name ## _Encoder, ADD_ITEMS, ADD_INIT) \
+MyClassDecoderB(Name ## _Decoder, ADD_ITEMS, ADD_INIT)
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.cpp
new file mode 100644
index 000000000..423b723ab
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.cpp
@@ -0,0 +1,37 @@
+// BranchMisc.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Bra.h"
+
+#include "BranchMisc.h"
+
+UInt32 CBC_ARM_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::ARM_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_ARM_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::ARM_Convert(data, size, _bufferPos, 0); }
+
+UInt32 CBC_ARMT_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::ARMT_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_ARMT_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::ARMT_Convert(data, size, _bufferPos, 0); }
+
+UInt32 CBC_PPC_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::PPC_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_PPC_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::PPC_Convert(data, size, _bufferPos, 0); }
+
+UInt32 CBC_SPARC_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::SPARC_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_SPARC_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::SPARC_Convert(data, size, _bufferPos, 0); }
+
+UInt32 CBC_IA64_Encoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::IA64_Convert(data, size, _bufferPos, 1); }
+
+UInt32 CBC_IA64_Decoder::SubFilter(Byte *data, UInt32 size)
+ { return (UInt32)::IA64_Convert(data, size, _bufferPos, 0); }
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.h b/src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.h
new file mode 100644
index 000000000..81198b21c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BranchMisc.h
@@ -0,0 +1,14 @@
+// BranchMisc.h
+
+#ifndef __COMPRESS_BRANCH_MISC_H
+#define __COMPRESS_BRANCH_MISC_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_ARM, 0x05, 1)
+MyClassA(BC_ARMT, 0x07, 1)
+MyClassA(BC_PPC, 0x02, 5)
+MyClassA(BC_SPARC, 0x08, 5)
+MyClassA(BC_IA64, 0x04, 1)
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/BranchRegister.cpp b/src/libs/7zip/win/CPP/7zip/Compress/BranchRegister.cpp
new file mode 100644
index 000000000..380828c6d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/BranchRegister.cpp
@@ -0,0 +1,30 @@
+// BranchRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BranchMisc.h"
+
+#define CREATE_CODEC(x) \
+ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## _Decoder); } \
+ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## _Encoder); }
+
+CREATE_CODEC(BC_PPC)
+CREATE_CODEC(BC_IA64)
+CREATE_CODEC(BC_ARM)
+CREATE_CODEC(BC_ARMT)
+CREATE_CODEC(BC_SPARC)
+
+#define METHOD_ITEM(x, id1, id2, name) { CreateCodec ## x, CreateCodec ## x ## Out, 0x03030000 + (id1 * 256) + id2, name, 1, true }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ METHOD_ITEM(BC_PPC, 0x02, 0x05, L"PPC"),
+ METHOD_ITEM(BC_IA64, 0x04, 1, L"IA64"),
+ METHOD_ITEM(BC_ARM, 0x05, 1, L"ARM"),
+ METHOD_ITEM(BC_ARMT, 0x07, 1, L"ARMT"),
+ METHOD_ITEM(BC_SPARC, 0x08, 0x05, L"SPARC")
+};
+
+REGISTER_CODECS(Branch)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ByteSwap.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ByteSwap.cpp
new file mode 100644
index 000000000..645b6ffcd
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ByteSwap.cpp
@@ -0,0 +1,73 @@
+// ByteSwap.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+class CByteSwap2:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+class CByteSwap4:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+STDMETHODIMP CByteSwap2::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size)
+{
+ const UInt32 kStep = 2;
+ UInt32 i;
+ for (i = 0; i + kStep <= size; i += kStep)
+ {
+ Byte b = data[i];
+ data[i] = data[i + 1];
+ data[i + 1] = b;
+ }
+ return i;
+}
+
+STDMETHODIMP CByteSwap4::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size)
+{
+ const UInt32 kStep = 4;
+ UInt32 i;
+ for (i = 0; i + kStep <= size; i += kStep)
+ {
+ Byte b0 = data[i];
+ Byte b1 = data[i + 1];
+ data[i] = data[i + 3];
+ data[i + 1] = data[i + 2];
+ data[i + 2] = b1;
+ data[i + 3] = b0;
+ }
+ return i;
+}
+
+static void *CreateCodec2() { return (void *)(ICompressFilter *)(new CByteSwap2); }
+static void *CreateCodec4() { return (void *)(ICompressFilter *)(new CByteSwap4); }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ { CreateCodec2, CreateCodec2, 0x020302, L"Swap2", 1, true },
+ { CreateCodec4, CreateCodec4, 0x020304, L"Swap4", 1, true }
+};
+
+REGISTER_CODECS(ByteSwap)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/CodecExports.cpp b/src/libs/7zip/win/CPP/7zip/Compress/CodecExports.cpp
new file mode 100644
index 000000000..4ff1c0fcb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/CodecExports.cpp
@@ -0,0 +1,160 @@
+// CodecExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+extern unsigned int g_NumCodecs;
+extern const CCodecInfo *g_Codecs[];
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value)
+{
+ if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0)
+ value->vt = VT_BSTR;
+ return S_OK;
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
+{
+ return SetPropString((const char *)&guid, sizeof(GUID), value);
+}
+
+static HRESULT SetClassID(CMethodId id, bool encode, PROPVARIANT *value)
+{
+ GUID clsId = CLSID_CCodec;
+ for (int i = 0; i < sizeof(id); i++, id >>= 8)
+ clsId.Data4[i] = (Byte)(id & 0xFF);
+ if (encode)
+ clsId.Data3++;
+ return SetPropGUID(clsId, value);
+}
+
+static HRESULT FindCodecClassId(const GUID *clsID, UInt32 isCoder2, bool isFilter, bool &encode, int &index)
+{
+ index = -1;
+ if (clsID->Data1 != CLSID_CCodec.Data1 ||
+ clsID->Data2 != CLSID_CCodec.Data2 ||
+ (clsID->Data3 & ~1) != kDecodeId)
+ return S_OK;
+ encode = (clsID->Data3 != kDecodeId);
+ UInt64 id = 0;
+ for (int j = 0; j < 8; j++)
+ id |= ((UInt64)clsID->Data4[j]) << (8 * j);
+ for (unsigned i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (id != codec.Id || encode && !codec.CreateEncoder || !encode && !codec.CreateDecoder)
+ continue;
+ if (!isFilter && codec.IsFilter || isFilter && !codec.IsFilter ||
+ codec.NumInStreams != 1 && !isCoder2 || codec.NumInStreams == 1 && isCoder2)
+ return E_NOINTERFACE;
+ index = i;
+ return S_OK;
+ }
+ return S_OK;
+}
+
+STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject)
+{
+ COM_TRY_BEGIN
+ *outObject = 0;
+ bool isCoder = (*iid == IID_ICompressCoder) != 0;
+ bool isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+ bool isFilter = (*iid == IID_ICompressFilter) != 0;
+ const CCodecInfo &codec = *g_Codecs[index];
+ if (!isFilter && codec.IsFilter || isFilter && !codec.IsFilter ||
+ codec.NumInStreams != 1 && !isCoder2 || codec.NumInStreams == 1 && isCoder2)
+ return E_NOINTERFACE;
+ if (encode)
+ {
+ if (!codec.CreateEncoder)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ *outObject = codec.CreateEncoder();
+ }
+ else
+ {
+ if (!codec.CreateDecoder)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ *outObject = codec.CreateDecoder();
+ }
+ if (isCoder)
+ ((ICompressCoder *)*outObject)->AddRef();
+ else if (isCoder2)
+ ((ICompressCoder2 *)*outObject)->AddRef();
+ else
+ ((ICompressFilter *)*outObject)->AddRef();
+ return S_OK;
+ COM_TRY_END
+}
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ *outObject = 0;
+ bool isCoder = (*iid == IID_ICompressCoder) != 0;
+ bool isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+ bool isFilter = (*iid == IID_ICompressFilter) != 0;
+ if (!isCoder && !isCoder2 && !isFilter)
+ return E_NOINTERFACE;
+ bool encode;
+ int codecIndex;
+ HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
+ if (res != S_OK)
+ return res;
+ if (codecIndex < 0)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ return CreateCoder2(encode, codecIndex, iid, outObject);
+}
+
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
+{
+ ::VariantClear((VARIANTARG *)value);
+ const CCodecInfo &codec = *g_Codecs[codecIndex];
+ switch(propID)
+ {
+ case NMethodPropID::kID:
+ {
+ value->uhVal.QuadPart = (UInt64)codec.Id;
+ value->vt = VT_UI8;
+ break;
+ }
+ case NMethodPropID::kName:
+ if ((value->bstrVal = ::SysAllocString(codec.Name)) != 0)
+ value->vt = VT_BSTR;
+ break;
+ case NMethodPropID::kDecoder:
+ if (codec.CreateDecoder)
+ return SetClassID(codec.Id, false, value);
+ break;
+ case NMethodPropID::kEncoder:
+ if (codec.CreateEncoder)
+ return SetClassID(codec.Id, true, value);
+ break;
+ case NMethodPropID::kInStreams:
+ {
+ if (codec.NumInStreams != 1)
+ {
+ value->vt = VT_UI4;
+ value->ulVal = (ULONG)codec.NumInStreams;
+ }
+ break;
+ }
+ }
+ return S_OK;
+}
+
+STDAPI GetNumberOfMethods(UINT32 *numCodecs)
+{
+ *numCodecs = g_NumCodecs;
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.cpp
new file mode 100644
index 000000000..f71692a77
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.cpp
@@ -0,0 +1,67 @@
+// Compress/CopyCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "CopyCoder.h"
+
+namespace NCompress {
+
+static const UInt32 kBufferSize = 1 << 17;
+
+CCopyCoder::~CCopyCoder()
+{
+ ::MidFree(_buffer);
+}
+
+STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ if (_buffer == 0)
+ {
+ _buffer = (Byte *)::MidAlloc(kBufferSize);
+ if (_buffer == 0)
+ return E_OUTOFMEMORY;
+ }
+
+ TotalSize = 0;
+ for (;;)
+ {
+ UInt32 size = kBufferSize;
+ if (outSize != 0)
+ if (size > *outSize - TotalSize)
+ size = (UInt32)(*outSize - TotalSize);
+ RINOK(inStream->Read(_buffer, size, &size));
+ if (size == 0)
+ break;
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, _buffer, size));
+ }
+ TotalSize += size;
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)
+{
+ *value = TotalSize;
+ return S_OK;
+}
+
+HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+ return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.h b/src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.h
new file mode 100644
index 000000000..c5445ccf8
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/CopyCoder.h
@@ -0,0 +1,34 @@
+// Compress/CopyCoder.h
+
+#ifndef __COMPRESS_COPY_CODER_H
+#define __COMPRESS_COPY_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+
+class CCopyCoder:
+ public ICompressCoder,
+ public ICompressGetInStreamProcessedSize,
+ public CMyUnknownImp
+{
+ Byte *_buffer;
+public:
+ UInt64 TotalSize;
+ CCopyCoder(): TotalSize(0), _buffer(0) {};
+ ~CCopyCoder();
+
+ MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+};
+
+HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/CopyRegister.cpp b/src/libs/7zip/win/CPP/7zip/Compress/CopyRegister.cpp
new file mode 100644
index 000000000..efb9b9e95
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/CopyRegister.cpp
@@ -0,0 +1,14 @@
+// CopyRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "CopyCoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::CCopyCoder); }
+
+static CCodecInfo g_CodecInfo =
+{ CreateCodec, CreateCodec, 0x00, L"Copy", 1, false };
+
+REGISTER_CODEC(Copy)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Deflate64Register.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Deflate64Register.cpp
new file mode 100644
index 000000000..509e675a5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Deflate64Register.cpp
@@ -0,0 +1,20 @@
+// Deflate64Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "DeflateDecoder.h"
+
+static void *CreateCodecDeflate64() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NDecoder::CCOMCoder64); }
+#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY)
+#include "DeflateEncoder.h"
+static void *CreateCodecOutDeflate64() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NEncoder::CCOMCoder64); }
+#else
+#define CreateCodecOutDeflate64 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodecDeflate64, CreateCodecOutDeflate64, 0x040109, L"Deflate64", 1, false };
+
+REGISTER_CODEC(Deflate64)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DeflateConst.h b/src/libs/7zip/win/CPP/7zip/Compress/DeflateConst.h
new file mode 100644
index 000000000..00e5ab8bf
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DeflateConst.h
@@ -0,0 +1,134 @@
+// DeflateConst.h
+
+#ifndef __DEFLATE_CONST_H
+#define __DEFLATE_CONST_H
+
+namespace NCompress {
+namespace NDeflate {
+
+const int kNumHuffmanBits = 15;
+
+const UInt32 kHistorySize32 = (1 << 15);
+const UInt32 kHistorySize64 = (1 << 16);
+
+const UInt32 kDistTableSize32 = 30;
+const UInt32 kDistTableSize64 = 32;
+
+const UInt32 kNumLenSymbols32 = 256;
+const UInt32 kNumLenSymbols64 = 255; // don't change it. It must be <= 255.
+const UInt32 kNumLenSymbolsMax = kNumLenSymbols32;
+
+const UInt32 kNumLenSlots = 29;
+
+const UInt32 kFixedDistTableSize = 32;
+const UInt32 kFixedLenTableSize = 31;
+
+const UInt32 kSymbolEndOfBlock = 0x100;
+const UInt32 kSymbolMatch = kSymbolEndOfBlock + 1;
+
+const UInt32 kMainTableSize = kSymbolMatch + kNumLenSlots;
+const UInt32 kFixedMainTableSize = kSymbolMatch + kFixedLenTableSize;
+
+const UInt32 kLevelTableSize = 19;
+
+const UInt32 kTableDirectLevels = 16;
+const UInt32 kTableLevelRepNumber = kTableDirectLevels;
+const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1;
+const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1;
+
+const UInt32 kLevelMask = 0xF;
+
+const Byte kLenStart32[kFixedLenTableSize] =
+ {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, 0, 0};
+const Byte kLenStart64[kFixedLenTableSize] =
+ {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, 0, 0};
+
+const Byte kLenDirectBits32[kFixedLenTableSize] =
+ {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, 0, 0};
+const Byte kLenDirectBits64[kFixedLenTableSize] =
+ {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, 0, 0};
+
+const UInt32 kDistStart[kDistTableSize64] =
+ {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,
+ 1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768,49152};
+const Byte kDistDirectBits[kDistTableSize64] =
+ {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};
+
+const Byte kLevelDirectBits[3] = {2, 3, 7};
+
+const Byte kCodeLengthAlphabetOrder[kLevelTableSize] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+const UInt32 kMatchMinLen = 3;
+const UInt32 kMatchMaxLen32 = kNumLenSymbols32 + kMatchMinLen - 1; //256 + 2
+const UInt32 kMatchMaxLen64 = kNumLenSymbols64 + kMatchMinLen - 1; //255 + 2
+const UInt32 kMatchMaxLen = kMatchMaxLen32;
+
+const int kFinalBlockFieldSize = 1;
+
+namespace NFinalBlockField
+{
+ enum
+ {
+ kNotFinalBlock = 0,
+ kFinalBlock = 1
+ };
+}
+
+const int kBlockTypeFieldSize = 2;
+
+namespace NBlockType
+{
+ enum
+ {
+ kStored = 0,
+ kFixedHuffman = 1,
+ kDynamicHuffman = 2
+ };
+}
+
+const int kNumLenCodesFieldSize = 5;
+const int kNumDistCodesFieldSize = 5;
+const int kNumLevelCodesFieldSize = 4;
+
+const UInt32 kNumLitLenCodesMin = 257;
+const UInt32 kNumDistCodesMin = 1;
+const UInt32 kNumLevelCodesMin = 4;
+
+const int kLevelFieldSize = 3;
+
+const int kStoredBlockLengthFieldSize = 16;
+
+struct CLevels
+{
+ Byte litLenLevels[kFixedMainTableSize];
+ Byte distLevels[kFixedDistTableSize];
+
+ void SubClear()
+ {
+ UInt32 i;
+ for(i = kNumLitLenCodesMin; i < kFixedMainTableSize; i++)
+ litLenLevels[i] = 0;
+ for(i = 0; i < kFixedDistTableSize; i++)
+ distLevels[i] = 0;
+ }
+
+ void SetFixedLevels()
+ {
+ int i;
+
+ for (i = 0; i < 144; i++)
+ litLenLevels[i] = 8;
+ for (; i < 256; i++)
+ litLenLevels[i] = 9;
+ for (; i < 280; i++)
+ litLenLevels[i] = 7;
+ for (; i < 288; i++)
+ litLenLevels[i] = 8;
+ for (i = 0; i < kFixedDistTableSize; i++) // test it: InfoZip only uses kDistTableSize
+ distLevels[i] = 5;
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DeflateDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/DeflateDecoder.cpp
new file mode 100644
index 000000000..2848cd812
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DeflateDecoder.cpp
@@ -0,0 +1,353 @@
+// DeflateDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "DeflateDecoder.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NDecoder {
+
+static const int kLenIdFinished = -1;
+static const int kLenIdNeedInit = -2;
+
+CCoder::CCoder(bool deflate64Mode, bool deflateNSIS):
+ _deflate64Mode(deflate64Mode),
+ _deflateNSIS(deflateNSIS),
+ _keepHistory(false),
+ _needInitInStream(true),
+ ZlibMode(false) {}
+
+UInt32 CCoder::ReadBits(int numBits)
+{
+ return m_InBitStream.ReadBits(numBits);
+}
+
+bool CCoder::DeCodeLevelTable(Byte *values, int numSymbols)
+{
+ int i = 0;
+ do
+ {
+ UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < kTableDirectLevels)
+ values[i++] = (Byte)number;
+ else if (number < kLevelTableSize)
+ {
+ if (number == kTableLevelRepNumber)
+ {
+ if (i == 0)
+ return false;
+ int num = ReadBits(2) + 3;
+ for (; num > 0 && i < numSymbols; num--, i++)
+ values[i] = values[i - 1];
+ }
+ else
+ {
+ int num;
+ if (number == kTableLevel0Number)
+ num = ReadBits(3) + 3;
+ else
+ num = ReadBits(7) + 11;
+ for (;num > 0 && i < numSymbols; num--)
+ values[i++] = 0;
+ }
+ }
+ else
+ return false;
+ }
+ while(i < numSymbols);
+ return true;
+}
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CCoder::ReadTables(void)
+{
+ m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
+ UInt32 blockType = ReadBits(kBlockTypeFieldSize);
+ if (blockType > NBlockType::kDynamicHuffman)
+ return false;
+
+ if (blockType == NBlockType::kStored)
+ {
+ m_StoredMode = true;
+ m_InBitStream.AlignToByte();
+ m_StoredBlockSize = ReadBits(kStoredBlockLengthFieldSize);
+ if (_deflateNSIS)
+ return true;
+ return (m_StoredBlockSize == (UInt16)~ReadBits(kStoredBlockLengthFieldSize));
+ }
+
+ m_StoredMode = false;
+
+ CLevels levels;
+ if (blockType == NBlockType::kFixedHuffman)
+ {
+ levels.SetFixedLevels();
+ _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
+ }
+ else
+ {
+ int numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
+ _numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
+ int numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
+
+ if (!_deflate64Mode)
+ if (_numDistLevels > kDistTableSize32)
+ return false;
+
+ Byte levelLevels[kLevelTableSize];
+ for (int i = 0; i < kLevelTableSize; i++)
+ {
+ int position = kCodeLengthAlphabetOrder[i];
+ if(i < numLevelCodes)
+ levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
+ else
+ levelLevels[position] = 0;
+ }
+
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+
+ Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
+ if (!DeCodeLevelTable(tmpLevels, numLitLenLevels + _numDistLevels))
+ return false;
+
+ levels.SubClear();
+ memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
+ memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
+ }
+ RIF(m_MainDecoder.SetCodeLengths(levels.litLenLevels));
+ return m_DistDecoder.SetCodeLengths(levels.distLevels);
+}
+
+HRESULT CCoder::CodeSpec(UInt32 curSize)
+{
+ if (_remainLen == kLenIdFinished)
+ return S_OK;
+ if (_remainLen == kLenIdNeedInit)
+ {
+ if (!_keepHistory)
+ if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
+ return E_OUTOFMEMORY;
+ RINOK(InitInStream(_needInitInStream));
+ m_OutWindowStream.Init(_keepHistory);
+ m_FinalBlock = false;
+ _remainLen = 0;
+ _needReadTable = true;
+ }
+
+ if (curSize == 0)
+ return S_OK;
+
+ while(_remainLen > 0 && curSize > 0)
+ {
+ _remainLen--;
+ Byte b = m_OutWindowStream.GetByte(_rep0);
+ m_OutWindowStream.PutByte(b);
+ curSize--;
+ }
+
+ while(curSize > 0)
+ {
+ if (_needReadTable)
+ {
+ if (m_FinalBlock)
+ {
+ _remainLen = kLenIdFinished;
+ break;
+ }
+ if (!ReadTables())
+ return S_FALSE;
+ _needReadTable = false;
+ }
+
+ if(m_StoredMode)
+ {
+ for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)
+ m_OutWindowStream.PutByte(m_InBitStream.ReadByte());
+ _needReadTable = (m_StoredBlockSize == 0);
+ continue;
+ }
+ while(curSize > 0)
+ {
+ if (m_InBitStream.NumExtraBytes > 4)
+ return S_FALSE;
+
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < 0x100)
+ {
+ m_OutWindowStream.PutByte((Byte)number);
+ curSize--;
+ continue;
+ }
+ else if (number == kSymbolEndOfBlock)
+ {
+ _needReadTable = true;
+ break;
+ }
+ else if (number < kMainTableSize)
+ {
+ number -= kSymbolMatch;
+ UInt32 len;
+ {
+ int numBits;
+ if (_deflate64Mode)
+ {
+ len = kLenStart64[number];
+ numBits = kLenDirectBits64[number];
+ }
+ else
+ {
+ len = kLenStart32[number];
+ numBits = kLenDirectBits32[number];
+ }
+ len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
+ }
+ UInt32 locLen = len;
+ if (locLen > curSize)
+ locLen = (UInt32)curSize;
+ number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
+ if (number >= _numDistLevels)
+ return S_FALSE;
+ UInt32 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
+ if (!m_OutWindowStream.CopyBlock(distance, locLen))
+ return S_FALSE;
+ curSize -= locLen;
+ len -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (Int32)len;
+ _rep0 = distance;
+ break;
+ }
+ }
+ else
+ return S_FALSE;
+ }
+ }
+ return S_OK;
+}
+
+#ifdef _NO_EXCEPTIONS
+
+#define DEFLATE_TRY_BEGIN
+#define DEFLATE_TRY_END
+
+#else
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } \
+ catch(const CInBufferException &e) { return e.ErrorCode; } \
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; } \
+ catch(...) { return S_FALSE; }
+
+#endif
+
+HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
+ const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ DEFLATE_TRY_BEGIN
+ m_OutWindowStream.SetStream(outStream);
+ CCoderReleaser flusher(this);
+
+ const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
+ const UInt64 start = m_OutWindowStream.GetProcessedSize();
+ for (;;)
+ {
+ UInt32 curSize = 1 << 18;
+ if (outSize != 0)
+ {
+ const UInt64 rem = *outSize - (m_OutWindowStream.GetProcessedSize() - start);
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ }
+ if (curSize == 0)
+ break;
+ RINOK(CodeSpec(curSize));
+ if (_remainLen == kLenIdFinished)
+ break;
+ if (progress != NULL)
+ {
+ const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
+ const UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+ }
+ }
+ if (_remainLen == kLenIdFinished && ZlibMode)
+ {
+ m_InBitStream.AlignToByte();
+ for (int i = 0; i < 4; i++)
+ ZlibFooter[i] = m_InBitStream.ReadByte();
+ }
+ flusher.NeedFlush = false;
+ HRESULT res = Flush();
+ if (res == S_OK && InputEofError())
+ return S_FALSE;
+ return res;
+ DEFLATE_TRY_END
+}
+
+HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ SetInStream(inStream);
+ SetOutStreamSize(outSize);
+ HRESULT res = CodeReal(outStream, outSize, progress);
+ ReleaseInStream();
+ return res;
+}
+
+STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
+{
+ if (value == NULL)
+ return E_INVALIDARG;
+ *value = m_InBitStream.GetProcessedSize();
+ return S_OK;
+}
+
+STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)
+{
+ m_InBitStream.SetStream(inStream);
+ return S_OK;
+}
+
+STDMETHODIMP CCoder::ReleaseInStream()
+{
+ m_InBitStream.ReleaseStream();
+ return S_OK;
+}
+
+STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 * /* outSize */)
+{
+ _remainLen = kLenIdNeedInit;
+ _needInitInStream = true;
+ m_OutWindowStream.Init(_keepHistory);
+ return S_OK;
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ DEFLATE_TRY_BEGIN
+ if (processedSize)
+ *processedSize = 0;
+ const UInt64 startPos = m_OutWindowStream.GetProcessedSize();
+ m_OutWindowStream.SetMemStream((Byte *)data);
+ RINOK(CodeSpec(size));
+ if (processedSize)
+ *processedSize = (UInt32)(m_OutWindowStream.GetProcessedSize() - startPos);
+ return Flush();
+ DEFLATE_TRY_END
+}
+
+#endif
+
+STDMETHODIMP CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ _remainLen = kLenIdNeedInit;
+ m_OutWindowStream.Init(_keepHistory);
+ return CodeReal(outStream, outSize, progress);
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DeflateDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/DeflateDecoder.h
new file mode 100644
index 000000000..56ab2bea2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DeflateDecoder.h
@@ -0,0 +1,157 @@
+// DeflateDecoder.h
+
+#ifndef __DEFLATE_DECODER_H
+#define __DEFLATE_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitlDecoder.h"
+#include "DeflateConst.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NDecoder {
+
+class CCoder:
+ public ICompressCoder,
+ public ICompressGetInStreamProcessedSize,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitl::CDecoder<CInBuffer> m_InBitStream;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedMainTableSize> m_MainDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedDistTableSize> m_DistDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ UInt32 m_StoredBlockSize;
+
+ bool m_FinalBlock;
+ bool m_StoredMode;
+ UInt32 _numDistLevels;
+
+
+ bool _deflateNSIS;
+ bool _deflate64Mode;
+ bool _keepHistory;
+ bool _needInitInStream;
+ Int32 _remainLen;
+ UInt32 _rep0;
+ bool _needReadTable;
+
+ UInt32 ReadBits(int numBits);
+
+ bool DeCodeLevelTable(Byte *values, int numSymbols);
+ bool ReadTables();
+
+ HRESULT Flush() { return m_OutWindowStream.Flush(); }
+ class CCoderReleaser
+ {
+ CCoder *_coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): _coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ _coder->Flush();
+ _coder->ReleaseOutStream();
+ }
+ };
+ friend class CCoderReleaser;
+
+ HRESULT CodeSpec(UInt32 curSize);
+public:
+ bool ZlibMode;
+ Byte ZlibFooter[4];
+
+ CCoder(bool deflate64Mode, bool deflateNSIS = false);
+ virtual ~CCoder() {};
+
+ void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+
+ void ReleaseOutStream()
+ {
+ m_OutWindowStream.ReleaseStream();
+ }
+
+ HRESULT CodeReal(ISequentialOutStream *outStream,
+ const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ #ifndef NO_READ_FROM_CODER
+ MY_UNKNOWN_IMP4(
+ ICompressGetInStreamProcessedSize,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream
+ )
+ #else
+ MY_UNKNOWN_IMP1(
+ ICompressGetInStreamProcessedSize)
+ #endif
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ #ifndef NO_READ_FROM_CODER
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+ STDMETHOD(CodeResume)(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ HRESULT InitInStream(bool needInit)
+ {
+ if (!m_InBitStream.Create(1 << 17))
+ return E_OUTOFMEMORY;
+ if (needInit)
+ {
+ m_InBitStream.Init();
+ _needInitInStream = false;
+ }
+ return S_OK;
+ }
+
+ void AlignToByte() { m_InBitStream.AlignToByte(); }
+ Byte ReadByte() { return (Byte)m_InBitStream.ReadBits(8); }
+ bool InputEofError() const { return m_InBitStream.ExtraBitsWereRead(); }
+ UInt64 GetInputProcessedSize() const { return m_InBitStream.GetProcessedSize(); }
+
+ // IGetInStreamProcessedSize
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+};
+
+class CCOMCoder : public CCoder
+{
+public:
+ CCOMCoder(): CCoder(false) {}
+};
+
+class CNsisCOMCoder : public CCoder
+{
+public:
+ CNsisCOMCoder(): CCoder(false, true) {}
+};
+
+class CCOMCoder64 : public CCoder
+{
+public:
+ CCOMCoder64(): CCoder(true) {}
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DeflateEncoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/DeflateEncoder.cpp
new file mode 100644
index 000000000..35a81cae4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DeflateEncoder.cpp
@@ -0,0 +1,986 @@
+// DeflateEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/HuffEnc.h"
+
+#include "Common/ComTry.h"
+
+#include "DeflateEncoder.h"
+
+#undef NO_INLINE
+
+#ifdef _MSC_VER
+#define NO_INLINE MY_NO_INLINE
+#else
+#define NO_INLINE
+#endif
+
+namespace NCompress {
+namespace NDeflate {
+namespace NEncoder {
+
+const int kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio.
+const UInt32 kNumTables = (1 << kNumDivPassesMax);
+
+static UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio.
+static UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio.
+static UInt32 kDivideBlockSizeMin = (1 << 6); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio.
+
+static const UInt32 kMaxUncompressedBlockSize = ((1 << 16) - 1) * 1; // [1, (1 << 32))
+static const UInt32 kMatchArraySize = kMaxUncompressedBlockSize * 10; // [kMatchMaxLen * 2, (1 << 32))
+static const UInt32 kMatchArrayLimit = kMatchArraySize - kMatchMaxLen * 4 * sizeof(UInt16);
+static const UInt32 kBlockUncompressedSizeThreshold = kMaxUncompressedBlockSize -
+ kMatchMaxLen - kNumOpts;
+
+static const int kMaxCodeBitLength = 11;
+static const int kMaxLevelBitLength = 7;
+
+static Byte kNoLiteralStatPrice = 11;
+static Byte kNoLenStatPrice = 11;
+static Byte kNoPosStatPrice = 6;
+
+static Byte g_LenSlots[kNumLenSymbolsMax];
+static Byte g_FastPos[1 << 9];
+
+class CFastPosInit
+{
+public:
+ CFastPosInit()
+ {
+ int i;
+ for(i = 0; i < kNumLenSlots; i++)
+ {
+ int c = kLenStart32[i];
+ int j = 1 << kLenDirectBits32[i];
+ for(int k = 0; k < j; k++, c++)
+ g_LenSlots[c] = (Byte)i;
+ }
+
+ const int kFastSlots = 18;
+ int c = 0;
+ for (Byte slotFast = 0; slotFast < kFastSlots; slotFast++)
+ {
+ UInt32 k = (1 << kDistDirectBits[slotFast]);
+ for (UInt32 j = 0; j < k; j++, c++)
+ g_FastPos[c] = slotFast;
+ }
+ }
+};
+
+static CFastPosInit g_FastPosInit;
+
+
+inline UInt32 GetPosSlot(UInt32 pos)
+{
+ if (pos < 0x200)
+ return g_FastPos[pos];
+ return g_FastPos[pos >> 8] + 16;
+}
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CCoder::CCoder(bool deflate64Mode):
+ m_Deflate64Mode(deflate64Mode),
+ m_NumPasses(1),
+ m_NumDivPasses(1),
+ m_NumFastBytes(32),
+ _fastMode(false),
+ _btMode(true),
+ m_OnePosMatchesMemory(0),
+ m_DistanceMemory(0),
+ m_Created(false),
+ m_Values(0),
+ m_Tables(0),
+ m_MatchFinderCycles(0)
+ // m_SetMfPasses(0)
+{
+ m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32;
+ m_NumLenCombinations = deflate64Mode ? kNumLenSymbols64 : kNumLenSymbols32;
+ m_LenStart = deflate64Mode ? kLenStart64 : kLenStart32;
+ m_LenDirectBits = deflate64Mode ? kLenDirectBits64 : kLenDirectBits32;
+ MatchFinder_Construct(&_lzInWindow);
+}
+
+HRESULT CCoder::Create()
+{
+ COM_TRY_BEGIN
+ if (m_Values == 0)
+ {
+ m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue));
+ if (m_Values == 0)
+ return E_OUTOFMEMORY;
+ }
+ if (m_Tables == 0)
+ {
+ m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables));
+ if (m_Tables == 0)
+ return E_OUTOFMEMORY;
+ }
+
+ if (m_IsMultiPass)
+ {
+ if (m_OnePosMatchesMemory == 0)
+ {
+ m_OnePosMatchesMemory = (UInt16 *)::MidAlloc(kMatchArraySize * sizeof(UInt16));
+ if (m_OnePosMatchesMemory == 0)
+ return E_OUTOFMEMORY;
+ }
+ }
+ else
+ {
+ if (m_DistanceMemory == 0)
+ {
+ m_DistanceMemory = (UInt16 *)MyAlloc((kMatchMaxLen + 2) * 2 * sizeof(UInt16));
+ if (m_DistanceMemory == 0)
+ return E_OUTOFMEMORY;
+ m_MatchDistances = m_DistanceMemory;
+ }
+ }
+
+ if (!m_Created)
+ {
+ _lzInWindow.btMode = _btMode ? 1 : 0;
+ _lzInWindow.numHashBytes = 3;
+ if (!MatchFinder_Create(&_lzInWindow,
+ m_Deflate64Mode ? kHistorySize64 : kHistorySize32,
+ kNumOpts + kMaxUncompressedBlockSize,
+ m_NumFastBytes, m_MatchMaxLen - m_NumFastBytes, &g_Alloc))
+ return E_OUTOFMEMORY;
+ if (!m_OutStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ }
+ if (m_MatchFinderCycles != 0)
+ _lzInWindow.cutValue = m_MatchFinderCycles;
+ m_Created = true;
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kNumPasses:
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ m_NumDivPasses = prop.ulVal;
+ if (m_NumDivPasses == 0)
+ m_NumDivPasses = 1;
+ if (m_NumDivPasses == 1)
+ m_NumPasses = 1;
+ else if (m_NumDivPasses <= kNumDivPassesMax)
+ m_NumPasses = 2;
+ else
+ {
+ m_NumPasses = 2 + (m_NumDivPasses - kNumDivPassesMax);
+ m_NumDivPasses = kNumDivPassesMax;
+ }
+ break;
+ case NCoderPropID::kNumFastBytes:
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ m_NumFastBytes = prop.ulVal;
+ if(m_NumFastBytes < kMatchMinLen || m_NumFastBytes > m_MatchMaxLen)
+ return E_INVALIDARG;
+ break;
+ case NCoderPropID::kMatchFinderCycles:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ m_MatchFinderCycles = prop.ulVal;
+ break;
+ }
+ case NCoderPropID::kAlgorithm:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 maximize = prop.ulVal;
+ _fastMode = (maximize == 0);
+ _btMode = !_fastMode;
+ break;
+ }
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+void CCoder::Free()
+{
+ ::MidFree(m_OnePosMatchesMemory); m_OnePosMatchesMemory = 0;
+ ::MyFree(m_DistanceMemory); m_DistanceMemory = 0;
+ ::MyFree(m_Values); m_Values = 0;
+ ::MyFree(m_Tables); m_Tables = 0;
+}
+
+CCoder::~CCoder()
+{
+ Free();
+ MatchFinder_Free(&_lzInWindow, &g_Alloc);
+}
+
+NO_INLINE void CCoder::GetMatches()
+{
+ if (m_IsMultiPass)
+ {
+ m_MatchDistances = m_OnePosMatchesMemory + m_Pos;
+ if (m_SecondPass)
+ {
+ m_Pos += *m_MatchDistances + 1;
+ return;
+ }
+ }
+
+ UInt32 distanceTmp[kMatchMaxLen * 2 + 3];
+
+ UInt32 numPairs = (_btMode) ?
+ Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp):
+ Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp);
+
+ *m_MatchDistances = (UInt16)numPairs;
+
+ if (numPairs > 0)
+ {
+ UInt32 i;
+ for(i = 0; i < numPairs; i += 2)
+ {
+ m_MatchDistances[i + 1] = (UInt16)distanceTmp[i];
+ m_MatchDistances[i + 2] = (UInt16)distanceTmp[i + 1];
+ }
+ UInt32 len = distanceTmp[numPairs - 2];
+ if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen)
+ {
+ UInt32 numAvail = Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) + 1;
+ const Byte *pby = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - 1;
+ const Byte *pby2 = pby - (distanceTmp[numPairs - 1] + 1);
+ if (numAvail > m_MatchMaxLen)
+ numAvail = m_MatchMaxLen;
+ for (; len < numAvail && pby[len] == pby2[len]; len++);
+ m_MatchDistances[i - 1] = (UInt16)len;
+ }
+ }
+ if (m_IsMultiPass)
+ m_Pos += numPairs + 1;
+ if (!m_SecondPass)
+ m_AdditionalOffset++;
+}
+
+void CCoder::MovePos(UInt32 num)
+{
+ if (!m_SecondPass && num > 0)
+ {
+ if (_btMode)
+ Bt3Zip_MatchFinder_Skip(&_lzInWindow, num);
+ else
+ Hc3Zip_MatchFinder_Skip(&_lzInWindow, num);
+ m_AdditionalOffset += num;
+ }
+}
+
+static const UInt32 kIfinityPrice = 0xFFFFFFF;
+
+NO_INLINE UInt32 CCoder::Backward(UInt32 &backRes, UInt32 cur)
+{
+ m_OptimumEndIndex = cur;
+ UInt32 posMem = m_Optimum[cur].PosPrev;
+ UInt16 backMem = m_Optimum[cur].BackPrev;
+ do
+ {
+ UInt32 posPrev = posMem;
+ UInt16 backCur = backMem;
+ backMem = m_Optimum[posPrev].BackPrev;
+ posMem = m_Optimum[posPrev].PosPrev;
+ m_Optimum[posPrev].BackPrev = backCur;
+ m_Optimum[posPrev].PosPrev = (UInt16)cur;
+ cur = posPrev;
+ }
+ while(cur > 0);
+ backRes = m_Optimum[0].BackPrev;
+ m_OptimumCurrentIndex = m_Optimum[0].PosPrev;
+ return m_OptimumCurrentIndex;
+}
+
+NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
+{
+ if(m_OptimumEndIndex != m_OptimumCurrentIndex)
+ {
+ UInt32 len = m_Optimum[m_OptimumCurrentIndex].PosPrev - m_OptimumCurrentIndex;
+ backRes = m_Optimum[m_OptimumCurrentIndex].BackPrev;
+ m_OptimumCurrentIndex = m_Optimum[m_OptimumCurrentIndex].PosPrev;
+ return len;
+ }
+ m_OptimumCurrentIndex = m_OptimumEndIndex = 0;
+
+ GetMatches();
+
+ UInt32 numDistancePairs = m_MatchDistances[0];
+ if(numDistancePairs == 0)
+ return 1;
+
+ const UInt16 *matchDistances = m_MatchDistances + 1;
+ UInt32 lenMain = matchDistances[numDistancePairs - 2];
+
+ if(lenMain > m_NumFastBytes)
+ {
+ backRes = matchDistances[numDistancePairs - 1];
+ MovePos(lenMain - 1);
+ return lenMain;
+ }
+ m_Optimum[1].Price = m_LiteralPrices[Inline_MatchFinder_GetIndexByte(&_lzInWindow, 0 - m_AdditionalOffset)];
+ m_Optimum[1].PosPrev = 0;
+
+ m_Optimum[2].Price = kIfinityPrice;
+ m_Optimum[2].PosPrev = 1;
+
+
+ UInt32 offs = 0;
+ for(UInt32 i = kMatchMinLen; i <= lenMain; i++)
+ {
+ UInt32 distance = matchDistances[offs + 1];
+ m_Optimum[i].PosPrev = 0;
+ m_Optimum[i].BackPrev = (UInt16)distance;
+ m_Optimum[i].Price = m_LenPrices[i - kMatchMinLen] + m_PosPrices[GetPosSlot(distance)];
+ if (i == matchDistances[offs])
+ offs += 2;
+ }
+
+ UInt32 cur = 0;
+ UInt32 lenEnd = lenMain;
+ for (;;)
+ {
+ ++cur;
+ if(cur == lenEnd || cur == kNumOptsBase || m_Pos >= kMatchArrayLimit)
+ return Backward(backRes, cur);
+ GetMatches();
+ matchDistances = m_MatchDistances + 1;
+
+ UInt32 numDistancePairs = m_MatchDistances[0];
+ UInt32 newLen = 0;
+ if(numDistancePairs != 0)
+ {
+ newLen = matchDistances[numDistancePairs - 2];
+ if(newLen > m_NumFastBytes)
+ {
+ UInt32 len = Backward(backRes, cur);
+ m_Optimum[cur].BackPrev = matchDistances[numDistancePairs - 1];
+ m_OptimumEndIndex = cur + newLen;
+ m_Optimum[cur].PosPrev = (UInt16)m_OptimumEndIndex;
+ MovePos(newLen - 1);
+ return len;
+ }
+ }
+ UInt32 curPrice = m_Optimum[cur].Price;
+ UInt32 curAnd1Price = curPrice + m_LiteralPrices[Inline_MatchFinder_GetIndexByte(&_lzInWindow, cur - m_AdditionalOffset)];
+ COptimal &optimum = m_Optimum[cur + 1];
+ if (curAnd1Price < optimum.Price)
+ {
+ optimum.Price = curAnd1Price;
+ optimum.PosPrev = (UInt16)cur;
+ }
+ if(numDistancePairs == 0)
+ continue;
+ while(lenEnd < cur + newLen)
+ m_Optimum[++lenEnd].Price = kIfinityPrice;
+ offs = 0;
+ UInt32 distance = matchDistances[offs + 1];
+ curPrice += m_PosPrices[GetPosSlot(distance)];
+ for(UInt32 lenTest = kMatchMinLen; ; lenTest++)
+ {
+ UInt32 curAndLenPrice = curPrice + m_LenPrices[lenTest - kMatchMinLen];
+ COptimal &optimum = m_Optimum[cur + lenTest];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = (UInt16)cur;
+ optimum.BackPrev = (UInt16)distance;
+ }
+ if (lenTest == matchDistances[offs])
+ {
+ offs += 2;
+ if (offs == numDistancePairs)
+ break;
+ curPrice -= m_PosPrices[GetPosSlot(distance)];
+ distance = matchDistances[offs + 1];
+ curPrice += m_PosPrices[GetPosSlot(distance)];
+ }
+ }
+ }
+}
+
+UInt32 CCoder::GetOptimalFast(UInt32 &backRes)
+{
+ GetMatches();
+ UInt32 numDistancePairs = m_MatchDistances[0];
+ if (numDistancePairs == 0)
+ return 1;
+ UInt32 lenMain = m_MatchDistances[numDistancePairs - 1];
+ backRes = m_MatchDistances[numDistancePairs];
+ MovePos(lenMain - 1);
+ return lenMain;
+}
+
+void CTables::InitStructures()
+{
+ UInt32 i;
+ for(i = 0; i < 256; i++)
+ litLenLevels[i] = 8;
+ litLenLevels[i++] = 13;
+ for(;i < kFixedMainTableSize; i++)
+ litLenLevels[i] = 5;
+ for(i = 0; i < kFixedDistTableSize; i++)
+ distLevels[i] = 5;
+}
+
+NO_INLINE void CCoder::LevelTableDummy(const Byte *levels, int numLevels, UInt32 *freqs)
+{
+ int prevLen = 0xFF;
+ int nextLen = levels[0];
+ int count = 0;
+ int maxCount = 7;
+ int minCount = 4;
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ for (int n = 0; n < numLevels; n++)
+ {
+ int curLen = nextLen;
+ nextLen = (n < numLevels - 1) ? levels[n + 1] : 0xFF;
+ count++;
+ if (count < maxCount && curLen == nextLen)
+ continue;
+
+ if (count < minCount)
+ freqs[curLen] += (UInt32)count;
+ else if (curLen != 0)
+ {
+ if (curLen != prevLen)
+ {
+ freqs[curLen]++;
+ count--;
+ }
+ freqs[kTableLevelRepNumber]++;
+ }
+ else if (count <= 10)
+ freqs[kTableLevel0Number]++;
+ else
+ freqs[kTableLevel0Number2]++;
+
+ count = 0;
+ prevLen = curLen;
+
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ else if (curLen == nextLen)
+ {
+ maxCount = 6;
+ minCount = 3;
+ }
+ else
+ {
+ maxCount = 7;
+ minCount = 4;
+ }
+ }
+}
+
+NO_INLINE void CCoder::WriteBits(UInt32 value, int numBits)
+{
+ m_OutStream.WriteBits(value, numBits);
+}
+
+#define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i])
+#define WRITE_HF(i) WriteBits(codes[i], lens[i])
+
+NO_INLINE void CCoder::LevelTableCode(const Byte *levels, int numLevels, const Byte *lens, const UInt32 *codes)
+{
+ int prevLen = 0xFF;
+ int nextLen = levels[0];
+ int count = 0;
+ int maxCount = 7;
+ int minCount = 4;
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ for (int n = 0; n < numLevels; n++)
+ {
+ int curLen = nextLen;
+ nextLen = (n < numLevels - 1) ? levels[n + 1] : 0xFF;
+ count++;
+ if (count < maxCount && curLen == nextLen)
+ continue;
+
+ if (count < minCount)
+ for(int i = 0; i < count; i++)
+ WRITE_HF(curLen);
+ else if (curLen != 0)
+ {
+ if (curLen != prevLen)
+ {
+ WRITE_HF(curLen);
+ count--;
+ }
+ WRITE_HF(kTableLevelRepNumber);
+ WriteBits(count - 3, 2);
+ }
+ else if (count <= 10)
+ {
+ WRITE_HF(kTableLevel0Number);
+ WriteBits(count - 3, 3);
+ }
+ else
+ {
+ WRITE_HF(kTableLevel0Number2);
+ WriteBits(count - 11, 7);
+ }
+
+ count = 0;
+ prevLen = curLen;
+
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ else if (curLen == nextLen)
+ {
+ maxCount = 6;
+ minCount = 3;
+ }
+ else
+ {
+ maxCount = 7;
+ minCount = 4;
+ }
+ }
+}
+
+NO_INLINE void CCoder::MakeTables(unsigned maxHuffLen)
+{
+ Huffman_Generate(mainFreqs, mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize, maxHuffLen);
+ Huffman_Generate(distFreqs, distCodes, m_NewLevels.distLevels, kDistTableSize64, maxHuffLen);
+}
+
+NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens, UInt32 num)
+{
+ UInt32 price = 0;
+ UInt32 i;
+ for (i = 0; i < num; i++)
+ price += lens[i] * freqs[i];
+ return price;
+}
+
+NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase)
+{
+ return Huffman_GetPrice(freqs, lens, num) +
+ Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase);
+}
+
+NO_INLINE UInt32 CCoder::GetLzBlockPrice() const
+{
+ return
+ Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) +
+ Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0);
+}
+
+NO_INLINE void CCoder::TryBlock()
+{
+ memset(mainFreqs, 0, sizeof(mainFreqs));
+ memset(distFreqs, 0, sizeof(distFreqs));
+
+ m_ValueIndex = 0;
+ UInt32 blockSize = BlockSizeRes;
+ BlockSizeRes = 0;
+ for (;;)
+ {
+ if (m_OptimumCurrentIndex == m_OptimumEndIndex)
+ {
+ if (m_Pos >= kMatchArrayLimit || BlockSizeRes >= blockSize || !m_SecondPass &&
+ ((Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0) || m_ValueIndex >= m_ValueBlockSize))
+ break;
+ }
+ UInt32 pos;
+ UInt32 len;
+ if (_fastMode)
+ len = GetOptimalFast(pos);
+ else
+ len = GetOptimal(pos);
+ CCodeValue &codeValue = m_Values[m_ValueIndex++];
+ if (len >= kMatchMinLen)
+ {
+ UInt32 newLen = len - kMatchMinLen;
+ codeValue.Len = (UInt16)newLen;
+ mainFreqs[kSymbolMatch + g_LenSlots[newLen]]++;
+ codeValue.Pos = (UInt16)pos;
+ distFreqs[GetPosSlot(pos)]++;
+ }
+ else
+ {
+ Byte b = Inline_MatchFinder_GetIndexByte(&_lzInWindow, 0 - m_AdditionalOffset);
+ mainFreqs[b]++;
+ codeValue.SetAsLiteral();
+ codeValue.Pos = b;
+ }
+ m_AdditionalOffset -= len;
+ BlockSizeRes += len;
+ }
+ mainFreqs[kSymbolEndOfBlock]++;
+ m_AdditionalOffset += BlockSizeRes;
+ m_SecondPass = true;
+}
+
+NO_INLINE void CCoder::SetPrices(const CLevels &levels)
+{
+ if (_fastMode)
+ return;
+ UInt32 i;
+ for(i = 0; i < 256; i++)
+ {
+ Byte price = levels.litLenLevels[i];
+ m_LiteralPrices[i] = ((price != 0) ? price : kNoLiteralStatPrice);
+ }
+
+ for(i = 0; i < m_NumLenCombinations; i++)
+ {
+ UInt32 slot = g_LenSlots[i];
+ Byte price = levels.litLenLevels[kSymbolMatch + slot];
+ m_LenPrices[i] = (Byte)(((price != 0) ? price : kNoLenStatPrice) + m_LenDirectBits[slot]);
+ }
+
+ for(i = 0; i < kDistTableSize64; i++)
+ {
+ Byte price = levels.distLevels[i];
+ m_PosPrices[i] = (Byte)(((price != 0) ? price: kNoPosStatPrice) + kDistDirectBits[i]);
+ }
+}
+
+NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num)
+{
+ for (UInt32 i = 0; i < num; i++)
+ {
+ UInt32 x = codes[i];
+ x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1);
+ x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2);
+ x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4);
+ codes[i] = (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)) >> (16 - lens[i]);
+ }
+}
+
+NO_INLINE void CCoder::WriteBlock()
+{
+ Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize);
+ Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64);
+
+ for (UInt32 i = 0; i < m_ValueIndex; i++)
+ {
+ const CCodeValue &codeValue = m_Values[i];
+ if (codeValue.IsLiteral())
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, codeValue.Pos);
+ else
+ {
+ UInt32 len = codeValue.Len;
+ UInt32 lenSlot = g_LenSlots[len];
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot);
+ m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]);
+ UInt32 dist = codeValue.Pos;
+ UInt32 posSlot = GetPosSlot(dist);
+ WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot);
+ m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]);
+ }
+ }
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock);
+}
+
+static UInt32 GetStorePrice(UInt32 blockSize, int bitPosition)
+{
+ UInt32 price = 0;
+ do
+ {
+ UInt32 nextBitPosition = (bitPosition + kFinalBlockFieldSize + kBlockTypeFieldSize) & 7;
+ int numBitsForAlign = nextBitPosition > 0 ? (8 - nextBitPosition): 0;
+ UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1;
+ price += kFinalBlockFieldSize + kBlockTypeFieldSize + numBitsForAlign + (2 + 2) * 8 + curBlockSize * 8;
+ bitPosition = 0;
+ blockSize -= curBlockSize;
+ }
+ while(blockSize != 0);
+ return price;
+}
+
+void CCoder::WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock)
+{
+ do
+ {
+ UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1;
+ blockSize -= curBlockSize;
+ WriteBits((finalBlock && (blockSize == 0) ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize);
+ WriteBits(NBlockType::kStored, kBlockTypeFieldSize);
+ m_OutStream.FlushByte();
+ WriteBits((UInt16)curBlockSize, kStoredBlockLengthFieldSize);
+ WriteBits((UInt16)~curBlockSize, kStoredBlockLengthFieldSize);
+ const Byte *data = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow)- additionalOffset;
+ for(UInt32 i = 0; i < curBlockSize; i++)
+ m_OutStream.WriteByte(data[i]);
+ additionalOffset -= curBlockSize;
+ }
+ while(blockSize != 0);
+}
+
+NO_INLINE UInt32 CCoder::TryDynBlock(int tableIndex, UInt32 numPasses)
+{
+ CTables &t = m_Tables[tableIndex];
+ BlockSizeRes = t.BlockSizeRes;
+ UInt32 posTemp = t.m_Pos;
+ SetPrices(t);
+
+ for (UInt32 p = 0; p < numPasses; p++)
+ {
+ m_Pos = posTemp;
+ TryBlock();
+ unsigned numHuffBits =
+ (m_ValueIndex > 18000 ? 12 :
+ (m_ValueIndex > 7000 ? 11 :
+ (m_ValueIndex > 2000 ? 10 : 9)));
+ MakeTables(numHuffBits);
+ SetPrices(m_NewLevels);
+ }
+
+ (CLevels &)t = m_NewLevels;
+
+ m_NumLitLenLevels = kMainTableSize;
+ while(m_NumLitLenLevels > kNumLitLenCodesMin && m_NewLevels.litLenLevels[m_NumLitLenLevels - 1] == 0)
+ m_NumLitLenLevels--;
+
+ m_NumDistLevels = kDistTableSize64;
+ while(m_NumDistLevels > kNumDistCodesMin && m_NewLevels.distLevels[m_NumDistLevels - 1] == 0)
+ m_NumDistLevels--;
+
+ UInt32 levelFreqs[kLevelTableSize];
+ memset(levelFreqs, 0, sizeof(levelFreqs));
+
+ LevelTableDummy(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelFreqs);
+ LevelTableDummy(m_NewLevels.distLevels, m_NumDistLevels, levelFreqs);
+
+ Huffman_Generate(levelFreqs, levelCodes, levelLens, kLevelTableSize, kMaxLevelBitLength);
+
+ m_NumLevelCodes = kNumLevelCodesMin;
+ for (UInt32 i = 0; i < kLevelTableSize; i++)
+ {
+ Byte level = levelLens[kCodeLengthAlphabetOrder[i]];
+ if (level > 0 && i >= m_NumLevelCodes)
+ m_NumLevelCodes = i + 1;
+ m_LevelLevels[i] = level;
+ }
+
+ return GetLzBlockPrice() +
+ Huffman_GetPrice_Spec(levelFreqs, levelLens, kLevelTableSize, kLevelDirectBits, kTableDirectLevels) +
+ kNumLenCodesFieldSize + kNumDistCodesFieldSize + kNumLevelCodesFieldSize +
+ m_NumLevelCodes * kLevelFieldSize + kFinalBlockFieldSize + kBlockTypeFieldSize;
+}
+
+NO_INLINE UInt32 CCoder::TryFixedBlock(int tableIndex)
+{
+ CTables &t = m_Tables[tableIndex];
+ BlockSizeRes = t.BlockSizeRes;
+ m_Pos = t.m_Pos;
+ m_NewLevels.SetFixedLevels();
+ SetPrices(m_NewLevels);
+ TryBlock();
+ return kFinalBlockFieldSize + kBlockTypeFieldSize + GetLzBlockPrice();
+}
+
+NO_INLINE UInt32 CCoder::GetBlockPrice(int tableIndex, int numDivPasses)
+{
+ CTables &t = m_Tables[tableIndex];
+ t.StaticMode = false;
+ UInt32 price = TryDynBlock(tableIndex, m_NumPasses);
+ t.BlockSizeRes = BlockSizeRes;
+ UInt32 numValues = m_ValueIndex;
+ UInt32 posTemp = m_Pos;
+ UInt32 additionalOffsetEnd = m_AdditionalOffset;
+
+ if (m_CheckStatic && m_ValueIndex <= kFixedHuffmanCodeBlockSizeMax)
+ {
+ const UInt32 fixedPrice = TryFixedBlock(tableIndex);
+ t.StaticMode = (fixedPrice < price);
+ if (t.StaticMode)
+ price = fixedPrice;
+ }
+
+ const UInt32 storePrice = GetStorePrice(BlockSizeRes, 0); // bitPosition
+ t.StoreMode = (storePrice <= price);
+ if (t.StoreMode)
+ price = storePrice;
+
+ t.UseSubBlocks = false;
+
+ if (numDivPasses > 1 && numValues >= kDivideCodeBlockSizeMin)
+ {
+ CTables &t0 = m_Tables[(tableIndex << 1)];
+ (CLevels &)t0 = t;
+ t0.BlockSizeRes = t.BlockSizeRes >> 1;
+ t0.m_Pos = t.m_Pos;
+ UInt32 subPrice = GetBlockPrice((tableIndex << 1), numDivPasses - 1);
+
+ UInt32 blockSize2 = t.BlockSizeRes - t0.BlockSizeRes;
+ if (t0.BlockSizeRes >= kDivideBlockSizeMin && blockSize2 >= kDivideBlockSizeMin)
+ {
+ CTables &t1 = m_Tables[(tableIndex << 1) + 1];
+ (CLevels &)t1 = t;
+ t1.BlockSizeRes = blockSize2;
+ t1.m_Pos = m_Pos;
+ m_AdditionalOffset -= t0.BlockSizeRes;
+ subPrice += GetBlockPrice((tableIndex << 1) + 1, numDivPasses - 1);
+ t.UseSubBlocks = (subPrice < price);
+ if (t.UseSubBlocks)
+ price = subPrice;
+ }
+ }
+ m_AdditionalOffset = additionalOffsetEnd;
+ m_Pos = posTemp;
+ return price;
+}
+
+void CCoder::CodeBlock(int tableIndex, bool finalBlock)
+{
+ CTables &t = m_Tables[tableIndex];
+ if (t.UseSubBlocks)
+ {
+ CodeBlock((tableIndex << 1), false);
+ CodeBlock((tableIndex << 1) + 1, finalBlock);
+ }
+ else
+ {
+ if (t.StoreMode)
+ WriteStoreBlock(t.BlockSizeRes, m_AdditionalOffset, finalBlock);
+ else
+ {
+ WriteBits((finalBlock ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize);
+ if (t.StaticMode)
+ {
+ WriteBits(NBlockType::kFixedHuffman, kBlockTypeFieldSize);
+ TryFixedBlock(tableIndex);
+ int i;
+ const int kMaxStaticHuffLen = 9;
+ for (i = 0; i < kFixedMainTableSize; i++)
+ mainFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.litLenLevels[i]);
+ for (i = 0; i < kFixedDistTableSize; i++)
+ distFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.distLevels[i]);
+ MakeTables(kMaxStaticHuffLen);
+ }
+ else
+ {
+ if (m_NumDivPasses > 1 || m_CheckStatic)
+ TryDynBlock(tableIndex, 1);
+ WriteBits(NBlockType::kDynamicHuffman, kBlockTypeFieldSize);
+ WriteBits(m_NumLitLenLevels - kNumLitLenCodesMin, kNumLenCodesFieldSize);
+ WriteBits(m_NumDistLevels - kNumDistCodesMin, kNumDistCodesFieldSize);
+ WriteBits(m_NumLevelCodes - kNumLevelCodesMin, kNumLevelCodesFieldSize);
+
+ for (UInt32 i = 0; i < m_NumLevelCodes; i++)
+ WriteBits(m_LevelLevels[i], kLevelFieldSize);
+
+ Huffman_ReverseBits(levelCodes, levelLens, kLevelTableSize);
+ LevelTableCode(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelLens, levelCodes);
+ LevelTableCode(m_NewLevels.distLevels, m_NumDistLevels, levelLens, levelCodes);
+ }
+ WriteBlock();
+ }
+ m_AdditionalOffset -= t.BlockSizeRes;
+ }
+}
+
+SRes Read(void *object, void *data, size_t *size)
+{
+ const UInt32 kStepSize = (UInt32)1 << 31;
+ UInt32 curSize = ((*size < kStepSize) ? (UInt32)*size : kStepSize);
+ HRESULT res = ((CSeqInStream *)object)->RealStream->Read(data, curSize, &curSize);
+ *size = curSize;
+ return (SRes)res;
+}
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */ , const UInt64 * /* outSize */ , ICompressProgressInfo *progress)
+{
+ m_CheckStatic = (m_NumPasses != 1 || m_NumDivPasses != 1);
+ m_IsMultiPass = (m_CheckStatic || (m_NumPasses != 1 || m_NumDivPasses != 1));
+
+ RINOK(Create());
+
+ m_ValueBlockSize = (7 << 10) + (1 << 12) * m_NumDivPasses;
+
+ UInt64 nowPos = 0;
+
+ _seqInStream.RealStream = inStream;
+ _seqInStream.SeqInStream.Read = Read;
+ _lzInWindow.stream = &_seqInStream.SeqInStream;
+
+ MatchFinder_Init(&_lzInWindow);
+ m_OutStream.SetStream(outStream);
+ m_OutStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ m_OptimumEndIndex = m_OptimumCurrentIndex = 0;
+
+ CTables &t = m_Tables[1];
+ t.m_Pos = 0;
+ t.InitStructures();
+
+ m_AdditionalOffset = 0;
+ do
+ {
+ t.BlockSizeRes = kBlockUncompressedSizeThreshold;
+ m_SecondPass = false;
+ GetBlockPrice(1, m_NumDivPasses);
+ CodeBlock(1, Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0);
+ nowPos += m_Tables[1].BlockSizeRes;
+ if (progress != NULL)
+ {
+ UInt64 packSize = m_OutStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&nowPos, &packSize));
+ }
+ }
+ while (Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) != 0);
+ if (_lzInWindow.result != SZ_OK)
+ return _lzInWindow.result;
+ return m_OutStream.Flush();
+}
+
+HRESULT CCoder::BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return E_FAIL; }
+}
+
+STDMETHODIMP CCOMCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+ { return BaseCode(inStream, outStream, inSize, outSize, progress); }
+
+STDMETHODIMP CCOMCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+ { return BaseSetEncoderProperties2(propIDs, props, numProps); }
+
+STDMETHODIMP CCOMCoder64::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+ { return BaseCode(inStream, outStream, inSize, outSize, progress); }
+
+STDMETHODIMP CCOMCoder64::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+ { return BaseSetEncoderProperties2(propIDs, props, numProps); }
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DeflateEncoder.h b/src/libs/7zip/win/CPP/7zip/Compress/DeflateEncoder.h
new file mode 100644
index 000000000..71c39e4e5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DeflateEncoder.h
@@ -0,0 +1,211 @@
+// DeflateEncoder.h
+
+#ifndef __DEFLATE_ENCODER_H
+#define __DEFLATE_ENCODER_H
+
+#include "../../../C/LzFind.h"
+
+#include "Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "BitlEncoder.h"
+#include "DeflateConst.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NEncoder {
+
+struct CCodeValue
+{
+ UInt16 Len;
+ UInt16 Pos;
+ void SetAsLiteral() { Len = (1 << 15); }
+ bool IsLiteral() const { return (Len >= (1 << 15)); }
+};
+
+struct COptimal
+{
+ UInt32 Price;
+ UInt16 PosPrev;
+ UInt16 BackPrev;
+};
+
+const UInt32 kNumOptsBase = 1 << 12;
+const UInt32 kNumOpts = kNumOptsBase + kMatchMaxLen;
+
+class CCoder;
+
+struct CTables: public CLevels
+{
+ bool UseSubBlocks;
+ bool StoreMode;
+ bool StaticMode;
+ UInt32 BlockSizeRes;
+ UInt32 m_Pos;
+ void InitStructures();
+};
+
+typedef struct _CSeqInStream
+{
+ ISeqInStream SeqInStream;
+ CMyComPtr<ISequentialInStream> RealStream;
+} CSeqInStream;
+
+class CCoder
+{
+ CMatchFinder _lzInWindow;
+ CBitlEncoder m_OutStream;
+
+ CSeqInStream _seqInStream;
+
+public:
+ CCodeValue *m_Values;
+
+ UInt16 *m_MatchDistances;
+ UInt32 m_NumFastBytes;
+ bool _fastMode;
+ bool _btMode;
+
+ UInt16 *m_OnePosMatchesMemory;
+ UInt16 *m_DistanceMemory;
+
+ UInt32 m_Pos;
+
+ int m_NumPasses;
+ int m_NumDivPasses;
+ bool m_CheckStatic;
+ bool m_IsMultiPass;
+ UInt32 m_ValueBlockSize;
+
+ UInt32 m_NumLenCombinations;
+ UInt32 m_MatchMaxLen;
+ const Byte *m_LenStart;
+ const Byte *m_LenDirectBits;
+
+ bool m_Created;
+ bool m_Deflate64Mode;
+
+ Byte m_LevelLevels[kLevelTableSize];
+ int m_NumLitLenLevels;
+ int m_NumDistLevels;
+ UInt32 m_NumLevelCodes;
+ UInt32 m_ValueIndex;
+
+ bool m_SecondPass;
+ UInt32 m_AdditionalOffset;
+
+ UInt32 m_OptimumEndIndex;
+ UInt32 m_OptimumCurrentIndex;
+
+ Byte m_LiteralPrices[256];
+ Byte m_LenPrices[kNumLenSymbolsMax];
+ Byte m_PosPrices[kDistTableSize64];
+
+ CLevels m_NewLevels;
+ UInt32 mainFreqs[kFixedMainTableSize];
+ UInt32 distFreqs[kDistTableSize64];
+ UInt32 mainCodes[kFixedMainTableSize];
+ UInt32 distCodes[kDistTableSize64];
+ UInt32 levelCodes[kLevelTableSize];
+ Byte levelLens[kLevelTableSize];
+
+ UInt32 BlockSizeRes;
+
+ CTables *m_Tables;
+ COptimal m_Optimum[kNumOpts];
+
+ UInt32 m_MatchFinderCycles;
+ // IMatchFinderSetNumPasses *m_SetMfPasses;
+
+ void GetMatches();
+ void MovePos(UInt32 num);
+ UInt32 Backward(UInt32 &backRes, UInt32 cur);
+ UInt32 GetOptimal(UInt32 &backRes);
+ UInt32 GetOptimalFast(UInt32 &backRes);
+
+ void LevelTableDummy(const Byte *levels, int numLevels, UInt32 *freqs);
+
+ void WriteBits(UInt32 value, int numBits);
+ void LevelTableCode(const Byte *levels, int numLevels, const Byte *lens, const UInt32 *codes);
+
+ void MakeTables(unsigned maxHuffLen);
+ UInt32 GetLzBlockPrice() const;
+ void TryBlock();
+ UInt32 TryDynBlock(int tableIndex, UInt32 numPasses);
+
+ UInt32 TryFixedBlock(int tableIndex);
+
+ void SetPrices(const CLevels &levels);
+ void WriteBlock();
+
+ HRESULT Create();
+ void Free();
+
+ void WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock);
+ void WriteTables(bool writeMode, bool finalBlock);
+
+ void WriteBlockData(bool writeMode, bool finalBlock);
+
+ void ReleaseStreams()
+ {
+ _seqInStream.RealStream.Release();
+ m_OutStream.ReleaseStream();
+ }
+ class CCoderReleaser
+ {
+ CCoder *m_Coder;
+ public:
+ CCoderReleaser(CCoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
+ };
+ friend class CCoderReleaser;
+
+ UInt32 GetBlockPrice(int tableIndex, int numDivPasses);
+ void CodeBlock(int tableIndex, bool finalBlock);
+
+public:
+ CCoder(bool deflate64Mode = false);
+ ~CCoder();
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ HRESULT BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ HRESULT BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+};
+
+
+class CCOMCoder :
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public CMyUnknownImp,
+ public CCoder
+{
+public:
+ MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
+ CCOMCoder(): CCoder(false) {};
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+};
+
+class CCOMCoder64 :
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public CMyUnknownImp,
+ public CCoder
+{
+public:
+ MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
+ CCOMCoder64(): CCoder(true) {};
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DeflateRegister.cpp b/src/libs/7zip/win/CPP/7zip/Compress/DeflateRegister.cpp
new file mode 100644
index 000000000..45f55219e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DeflateRegister.cpp
@@ -0,0 +1,21 @@
+// DeflateRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "DeflateDecoder.h"
+
+static void *CreateCodecDeflate() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NDecoder::CCOMCoder); }
+
+#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY)
+#include "DeflateEncoder.h"
+static void *CreateCodecOutDeflate() { return (void *)(ICompressCoder *)(new NCompress::NDeflate::NEncoder::CCOMCoder); }
+#else
+#define CreateCodecOutDeflate 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodecDeflate, CreateCodecOutDeflate, 0x040108, L"Deflate", 1, false };
+
+REGISTER_CODEC(Deflate)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DeltaFilter.cpp b/src/libs/7zip/win/CPP/7zip/Compress/DeltaFilter.cpp
new file mode 100644
index 000000000..2e421acf4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DeltaFilter.cpp
@@ -0,0 +1,112 @@
+// DeltaFilter.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Delta.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BranchCoder.h"
+
+struct CDelta
+{
+ unsigned _delta;
+ Byte _state[DELTA_STATE_SIZE];
+ CDelta(): _delta(1) {}
+ void DeltaInit() { Delta_Init(_state); }
+};
+
+class CDeltaEncoder:
+ public ICompressFilter,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ CDelta,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+};
+
+class CDeltaDecoder:
+ public ICompressFilter,
+ public ICompressSetDecoderProperties2,
+ CDelta,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+STDMETHODIMP CDeltaEncoder::Init()
+{
+ DeltaInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDeltaEncoder::Filter(Byte *data, UInt32 size)
+{
+ Delta_Encode(_state, _delta, data, size);
+ return size;
+}
+
+STDMETHODIMP CDeltaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ UInt32 delta = _delta;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ if (propIDs[i] != NCoderPropID::kDefaultProp || prop.vt != VT_UI4 || prop.ulVal < 1 || prop.ulVal > 256)
+ return E_INVALIDARG;
+ delta = prop.ulVal;
+ }
+ _delta = delta;
+ return S_OK;
+}
+
+STDMETHODIMP CDeltaEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte prop = (Byte)(_delta - 1);
+ return outStream->Write(&prop, 1, NULL);
+}
+
+STDMETHODIMP CDeltaDecoder::Init()
+{
+ DeltaInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDeltaDecoder::Filter(Byte *data, UInt32 size)
+{
+ Delta_Decode(_state, _delta, data, size);
+ return size;
+}
+
+STDMETHODIMP CDeltaDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
+{
+ if (size != 1)
+ return E_INVALIDARG;
+ _delta = (unsigned)props[0] + 1;
+ return S_OK;
+}
+
+#define CREATE_CODEC(x) \
+ static void *CreateCodec ## x() { return (void *)(ICompressFilter *)(new C ## x ## Decoder); } \
+ static void *CreateCodec ## x ## Out() { return (void *)(ICompressFilter *)(new C ## x ## Encoder); }
+
+CREATE_CODEC(Delta)
+
+#define METHOD_ITEM(x, id, name) { CreateCodec ## x, CreateCodec ## x ## Out, id, name, 1, true }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ METHOD_ITEM(Delta, 3, L"Delta")
+};
+
+REGISTER_CODECS(Delta)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DllExports.cpp b/src/libs/7zip/win/CPP/7zip/Compress/DllExports.cpp
new file mode 100644
index 000000000..6af7e5ec5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DllExports.cpp
@@ -0,0 +1,45 @@
+// DllExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+static const unsigned int kNumCodecsMax = 32;
+unsigned int g_NumCodecs = 0;
+const CCodecInfo *g_Codecs[kNumCodecsMax];
+void RegisterCodec(const CCodecInfo *codecInfo)
+{
+ if (g_NumCodecs < kNumCodecsMax)
+ g_Codecs[g_NumCodecs++] = codecInfo;
+}
+
+#ifdef _WIN32
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ , DWORD /* dwReason */, LPVOID /*lpReserved*/)
+{
+ return TRUE;
+}
+#endif
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ return CreateCoder(clsid, iid, outObject);
+}
+
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/DllExports2.cpp b/src/libs/7zip/win/CPP/7zip/Compress/DllExports2.cpp
new file mode 100644
index 000000000..836f3fa42
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/DllExports2.cpp
@@ -0,0 +1,28 @@
+// DllExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+extern "C"
+BOOL WINAPI DllMain(HINSTANCE /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/)
+{
+ return TRUE;
+}
+
+static const UInt16 kDecodeId = 0x2790;
+
+DEFINE_GUID(CLSID_CCodec,
+0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ return CreateCoder(clsid, iid, outObject);
+}
+
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/HuffmanDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/HuffmanDecoder.h
new file mode 100644
index 000000000..82a1e6f2d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/HuffmanDecoder.h
@@ -0,0 +1,89 @@
+// Compress/HuffmanDecoder.h
+
+#ifndef __COMPRESS_HUFFMAN_DECODER_H
+#define __COMPRESS_HUFFMAN_DECODER_H
+
+#include "../../Common/Types.h"
+
+namespace NCompress {
+namespace NHuffman {
+
+const int kNumTableBits = 9;
+
+template <int kNumBitsMax, UInt32 m_NumSymbols>
+class CDecoder
+{
+ UInt32 m_Limits[kNumBitsMax + 1]; // m_Limits[i] = value limit for symbols with length = i
+ UInt32 m_Positions[kNumBitsMax + 1]; // m_Positions[i] = index in m_Symbols[] of first symbol with length = i
+ UInt32 m_Symbols[m_NumSymbols];
+ Byte m_Lengths[1 << kNumTableBits]; // Table oh length for short codes.
+
+public:
+
+ bool SetCodeLengths(const Byte *codeLengths)
+ {
+ int lenCounts[kNumBitsMax + 1];
+ UInt32 tmpPositions[kNumBitsMax + 1];
+ int i;
+ for(i = 1; i <= kNumBitsMax; i++)
+ lenCounts[i] = 0;
+ UInt32 symbol;
+ for (symbol = 0; symbol < m_NumSymbols; symbol++)
+ {
+ int len = codeLengths[symbol];
+ if (len > kNumBitsMax)
+ return false;
+ lenCounts[len]++;
+ m_Symbols[symbol] = 0xFFFFFFFF;
+ }
+ lenCounts[0] = 0;
+ m_Positions[0] = m_Limits[0] = 0;
+ UInt32 startPos = 0;
+ UInt32 index = 0;
+ const UInt32 kMaxValue = (1 << kNumBitsMax);
+ for (i = 1; i <= kNumBitsMax; i++)
+ {
+ startPos += lenCounts[i] << (kNumBitsMax - i);
+ if (startPos > kMaxValue)
+ return false;
+ m_Limits[i] = (i == kNumBitsMax) ? kMaxValue : startPos;
+ m_Positions[i] = m_Positions[i - 1] + lenCounts[i - 1];
+ tmpPositions[i] = m_Positions[i];
+ if(i <= kNumTableBits)
+ {
+ UInt32 limit = (m_Limits[i] >> (kNumBitsMax - kNumTableBits));
+ for (; index < limit; index++)
+ m_Lengths[index] = (Byte)i;
+ }
+ }
+ for (symbol = 0; symbol < m_NumSymbols; symbol++)
+ {
+ int len = codeLengths[symbol];
+ if (len != 0)
+ m_Symbols[tmpPositions[len]++] = symbol;
+ }
+ return true;
+ }
+
+ template <class TBitDecoder>
+ UInt32 DecodeSymbol(TBitDecoder *bitStream)
+ {
+ int numBits;
+ UInt32 value = bitStream->GetValue(kNumBitsMax);
+ if (value < m_Limits[kNumTableBits])
+ numBits = m_Lengths[value >> (kNumBitsMax - kNumTableBits)];
+ else
+ for (numBits = kNumTableBits + 1; value >= m_Limits[numBits]; numBits++);
+ bitStream->MovePos(numBits);
+ UInt32 index = m_Positions[numBits] +
+ ((value - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits));
+ if (index >= m_NumSymbols)
+ // throw CDecoderException(); // test it
+ return 0xFFFFFFFF;
+ return m_Symbols[index];
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ImplodeDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ImplodeDecoder.cpp
new file mode 100644
index 000000000..f84a013c2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ImplodeDecoder.cpp
@@ -0,0 +1,219 @@
+// Implode/Decoder.cpp
+
+#include "StdAfx.h"
+
+#include "ImplodeDecoder.h"
+#include "Common/Defs.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NDecoder {
+
+class CException
+{
+public:
+ enum ECauseType
+ {
+ kData
+ } m_Cause;
+ CException(ECauseType cause): m_Cause(cause) {}
+};
+
+static const int kNumDistanceLowDirectBitsForBigDict = 7;
+static const int kNumDistanceLowDirectBitsForSmallDict = 6;
+
+static const int kNumBitsInByte = 8;
+
+// static const int kLevelStructuresNumberFieldSize = kNumBitsInByte;
+static const int kLevelStructuresNumberAdditionalValue = 1;
+
+static const int kNumLevelStructureLevelBits = 4;
+static const int kLevelStructureLevelAdditionalValue = 1;
+
+static const int kNumLevelStructureRepNumberBits = 4;
+static const int kLevelStructureRepNumberAdditionalValue = 1;
+
+
+static const int kLiteralTableSize = (1 << kNumBitsInByte);
+static const int kDistanceTableSize = 64;
+static const int kLengthTableSize = 64;
+
+static const UInt32 kHistorySize =
+ (1 << MyMax(kNumDistanceLowDirectBitsForBigDict,
+ kNumDistanceLowDirectBitsForSmallDict)) *
+ kDistanceTableSize; // = 8 KB;
+
+static const int kNumAdditionalLengthBits = 8;
+
+static const UInt32 kMatchMinLenWhenLiteralsOn = 3;
+static const UInt32 kMatchMinLenWhenLiteralsOff = 2;
+
+static const UInt32 kMatchMinLenMax = MyMax(kMatchMinLenWhenLiteralsOn,
+ kMatchMinLenWhenLiteralsOff); // 3
+
+// static const UInt32 kMatchMaxLenMax = kMatchMinLenMax + (kLengthTableSize - 1) + (1 << kNumAdditionalLengthBits) - 1; // or 2
+
+enum
+{
+ kMatchId = 0,
+ kLiteralId = 1
+};
+
+
+CCoder::CCoder():
+ m_LiteralDecoder(kLiteralTableSize),
+ m_LengthDecoder(kLengthTableSize),
+ m_DistanceDecoder(kDistanceTableSize)
+{
+}
+
+void CCoder::ReleaseStreams()
+{
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+}
+
+bool CCoder::ReadLevelItems(NImplode::NHuffman::CDecoder &decoder,
+ Byte *levels, int numLevelItems)
+{
+ int numCodedStructures = m_InBitStream.ReadBits(kNumBitsInByte) +
+ kLevelStructuresNumberAdditionalValue;
+ int currentIndex = 0;
+ for(int i = 0; i < numCodedStructures; i++)
+ {
+ int level = m_InBitStream.ReadBits(kNumLevelStructureLevelBits) +
+ kLevelStructureLevelAdditionalValue;
+ int rep = m_InBitStream.ReadBits(kNumLevelStructureRepNumberBits) +
+ kLevelStructureRepNumberAdditionalValue;
+ if (currentIndex + rep > numLevelItems)
+ throw CException(CException::kData);
+ for(int j = 0; j < rep; j++)
+ levels[currentIndex++] = (Byte)level;
+ }
+ if (currentIndex != numLevelItems)
+ return false;
+ return decoder.SetCodeLengths(levels);
+}
+
+
+bool CCoder::ReadTables(void)
+{
+ if (m_LiteralsOn)
+ {
+ Byte literalLevels[kLiteralTableSize];
+ if (!ReadLevelItems(m_LiteralDecoder, literalLevels, kLiteralTableSize))
+ return false;
+ }
+
+ Byte lengthLevels[kLengthTableSize];
+ if (!ReadLevelItems(m_LengthDecoder, lengthLevels, kLengthTableSize))
+ return false;
+
+ Byte distanceLevels[kDistanceTableSize];
+ return ReadLevelItems(m_DistanceDecoder, distanceLevels, kDistanceTableSize);
+}
+
+class CCoderReleaser
+{
+ CCoder *m_Coder;
+public:
+ CCoderReleaser(CCoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
+};
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (outSize == NULL)
+ return E_INVALIDARG;
+ UInt64 pos = 0, unPackSize = *outSize;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+ CCoderReleaser coderReleaser(this);
+
+ if (!ReadTables())
+ return S_FALSE;
+
+ while(pos < unPackSize)
+ {
+ if (progress != NULL && pos % (1 << 16) == 0)
+ {
+ UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ }
+ if(m_InBitStream.ReadBits(1) == kMatchId) // match
+ {
+ UInt32 lowDistBits = m_InBitStream.ReadBits(m_NumDistanceLowDirectBits);
+ UInt32 distance = m_DistanceDecoder.DecodeSymbol(&m_InBitStream);
+ if (distance >= kDistanceTableSize)
+ return S_FALSE;
+ distance = (distance << m_NumDistanceLowDirectBits) + lowDistBits;
+ UInt32 lengthSymbol = m_LengthDecoder.DecodeSymbol(&m_InBitStream);
+ if (lengthSymbol >= kLengthTableSize)
+ return S_FALSE;
+ UInt32 length = lengthSymbol + m_MinMatchLength;
+ if (lengthSymbol == kLengthTableSize - 1) // special symbol = 63
+ length += m_InBitStream.ReadBits(kNumAdditionalLengthBits);
+ while(distance >= pos && length > 0)
+ {
+ m_OutWindowStream.PutByte(0);
+ pos++;
+ length--;
+ }
+ if (length > 0)
+ m_OutWindowStream.CopyBlock(distance, length);
+ pos += length;
+ }
+ else
+ {
+ Byte b;
+ if (m_LiteralsOn)
+ {
+ UInt32 temp = m_LiteralDecoder.DecodeSymbol(&m_InBitStream);
+ if (temp >= kLiteralTableSize)
+ return S_FALSE;
+ b = (Byte)temp;
+ }
+ else
+ b = (Byte)m_InBitStream.ReadBits(kNumBitsInByte);
+ m_OutWindowStream.PutByte(b);
+ pos++;
+ }
+ }
+ if (pos > unPackSize)
+ return S_FALSE;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ Byte flag = data[0];
+ m_BigDictionaryOn = ((flag & 2) != 0);
+ m_NumDistanceLowDirectBits = m_BigDictionaryOn ?
+ kNumDistanceLowDirectBitsForBigDict:
+ kNumDistanceLowDirectBitsForSmallDict;
+ m_LiteralsOn = ((flag & 4) != 0);
+ m_MinMatchLength = m_LiteralsOn ?
+ kMatchMinLenWhenLiteralsOn :
+ kMatchMinLenWhenLiteralsOff;
+ return S_OK;
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ImplodeDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/ImplodeDecoder.h
new file mode 100644
index 000000000..7ea1553ee
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ImplodeDecoder.h
@@ -0,0 +1,57 @@
+// ImplodeDecoder.h
+
+#ifndef __COMPRESS_IMPLODE_DECODER_H
+#define __COMPRESS_IMPLODE_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "ImplodeHuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NDecoder {
+
+class CCoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitl::CDecoder<CInBuffer> m_InBitStream;
+
+ NImplode::NHuffman::CDecoder m_LiteralDecoder;
+ NImplode::NHuffman::CDecoder m_LengthDecoder;
+ NImplode::NHuffman::CDecoder m_DistanceDecoder;
+
+ bool m_BigDictionaryOn;
+ bool m_LiteralsOn;
+
+ int m_NumDistanceLowDirectBits;
+ UInt32 m_MinMatchLength;
+
+ bool ReadLevelItems(NImplode::NHuffman::CDecoder &table, Byte *levels, int numLevelItems);
+ bool ReadTables();
+ void DeCodeLevelTable(Byte *newLevels, int numLevels);
+public:
+ CCoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ void ReleaseStreams();
+ HRESULT Flush() { return m_OutWindowStream.Flush(); }
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp
new file mode 100644
index 000000000..64345e08b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp
@@ -0,0 +1,89 @@
+// ImplodeHuffmanDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "ImplodeHuffmanDecoder.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NHuffman {
+
+CDecoder::CDecoder(UInt32 numSymbols):
+ m_NumSymbols(numSymbols)
+{
+ m_Symbols = new UInt32[m_NumSymbols];
+}
+
+CDecoder::~CDecoder()
+{
+ delete []m_Symbols;
+}
+
+bool CDecoder::SetCodeLengths(const Byte *codeLengths)
+{
+ // int lenCounts[kNumBitsInLongestCode + 1], tmpPositions[kNumBitsInLongestCode + 1];
+ int lenCounts[kNumBitsInLongestCode + 2], tmpPositions[kNumBitsInLongestCode + 1];
+ int i;
+ for(i = 0; i <= kNumBitsInLongestCode; i++)
+ lenCounts[i] = 0;
+ UInt32 symbolIndex;
+ for (symbolIndex = 0; symbolIndex < m_NumSymbols; symbolIndex++)
+ lenCounts[codeLengths[symbolIndex]]++;
+ // lenCounts[0] = 0;
+
+ // tmpPositions[0] = m_Positions[0] = m_Limitits[0] = 0;
+ m_Limitits[kNumBitsInLongestCode + 1] = 0;
+ m_Positions[kNumBitsInLongestCode + 1] = 0;
+ lenCounts[kNumBitsInLongestCode + 1] = 0;
+
+
+ UInt32 startPos = 0;
+ static const UInt32 kMaxValue = (1 << kNumBitsInLongestCode);
+
+ for (i = kNumBitsInLongestCode; i > 0; i--)
+ {
+ startPos += lenCounts[i] << (kNumBitsInLongestCode - i);
+ if (startPos > kMaxValue)
+ return false;
+ m_Limitits[i] = startPos;
+ m_Positions[i] = m_Positions[i + 1] + lenCounts[i + 1];
+ tmpPositions[i] = m_Positions[i] + lenCounts[i];
+
+ }
+
+ // if _ZIP_MODE do not throw exception for trees containing only one node
+ // #ifndef _ZIP_MODE
+ if (startPos != kMaxValue)
+ return false;
+ // #endif
+
+ for (symbolIndex = 0; symbolIndex < m_NumSymbols; symbolIndex++)
+ if (codeLengths[symbolIndex] != 0)
+ m_Symbols[--tmpPositions[codeLengths[symbolIndex]]] = symbolIndex;
+ return true;
+}
+
+UInt32 CDecoder::DecodeSymbol(CInBit *inStream)
+{
+ UInt32 numBits = 0;
+ UInt32 value = inStream->GetValue(kNumBitsInLongestCode);
+ int i;
+ for(i = kNumBitsInLongestCode; i > 0; i--)
+ {
+ if (value < m_Limitits[i])
+ {
+ numBits = i;
+ break;
+ }
+ }
+ if (i == 0)
+ return 0xFFFFFFFF;
+ inStream->MovePos(numBits);
+ UInt32 index = m_Positions[numBits] +
+ ((value - m_Limitits[numBits + 1]) >> (kNumBitsInLongestCode - numBits));
+ if (index >= m_NumSymbols)
+ return 0xFFFFFFFF;
+ return m_Symbols[index];
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ImplodeHuffmanDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/ImplodeHuffmanDecoder.h
new file mode 100644
index 000000000..6120a35ab
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ImplodeHuffmanDecoder.h
@@ -0,0 +1,34 @@
+// ImplodeHuffmanDecoder.h
+
+#ifndef __IMPLODE_HUFFMAN_DECODER_H
+#define __IMPLODE_HUFFMAN_DECODER_H
+
+#include "../Common/InBuffer.h"
+
+#include "BitlDecoder.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NHuffman {
+
+const int kNumBitsInLongestCode = 16;
+
+typedef NBitl::CDecoder<CInBuffer> CInBit;
+
+class CDecoder
+{
+ UInt32 m_Limitits[kNumBitsInLongestCode + 2]; // m_Limitits[i] = value limit for symbols with length = i
+ UInt32 m_Positions[kNumBitsInLongestCode + 2]; // m_Positions[i] = index in m_Symbols[] of first symbol with length = i
+ UInt32 m_NumSymbols; // number of symbols in m_Symbols
+ UInt32 *m_Symbols; // symbols: at first with len=1 then 2, ... 15.
+public:
+ CDecoder(UInt32 numSymbols);
+ ~CDecoder();
+
+ bool SetCodeLengths(const Byte *codeLengths);
+ UInt32 DecodeSymbol(CInBit *inStream);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzOutWindow.cpp b/src/libs/7zip/win/CPP/7zip/Compress/LzOutWindow.cpp
new file mode 100644
index 000000000..df46295bd
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzOutWindow.cpp
@@ -0,0 +1,14 @@
+// LzOutWindow.cpp
+
+#include "StdAfx.h"
+
+#include "LzOutWindow.h"
+
+void CLzOutWindow::Init(bool solid)
+{
+ if (!solid)
+ COutBuffer::Init();
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzOutWindow.h b/src/libs/7zip/win/CPP/7zip/Compress/LzOutWindow.h
new file mode 100644
index 000000000..d8d13c225
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzOutWindow.h
@@ -0,0 +1,66 @@
+// LzOutWindow.h
+
+#ifndef __LZ_OUT_WINDOW_H
+#define __LZ_OUT_WINDOW_H
+
+#include "../IStream.h"
+
+#include "../Common/OutBuffer.h"
+
+#ifndef _NO_EXCEPTIONS
+typedef COutBufferException CLzOutWindowException;
+#endif
+
+class CLzOutWindow: public COutBuffer
+{
+public:
+ void Init(bool solid = false);
+
+ // distance >= 0, len > 0,
+ bool CopyBlock(UInt32 distance, UInt32 len)
+ {
+ UInt32 pos = _pos - distance - 1;
+ if (distance >= _pos)
+ {
+ if (!_overDict || distance >= _bufferSize)
+ return false;
+ pos += _bufferSize;
+ }
+ if (_limitPos - _pos > len && _bufferSize - pos > len)
+ {
+ const Byte *src = _buffer + pos;
+ Byte *dest = _buffer + _pos;
+ _pos += len;
+ do
+ *dest++ = *src++;
+ while(--len != 0);
+ }
+ else do
+ {
+ if (pos == _bufferSize)
+ pos = 0;
+ _buffer[_pos++] = _buffer[pos++];
+ if (_pos == _limitPos)
+ FlushWithCheck();
+ }
+ while(--len != 0);
+ return true;
+ }
+
+ void PutByte(Byte b)
+ {
+ _buffer[_pos++] = b;
+ if (_pos == _limitPos)
+ FlushWithCheck();
+ }
+
+ Byte GetByte(UInt32 distance) const
+ {
+ UInt32 pos = _pos - distance - 1;
+ if (pos >= _bufferSize)
+ pos += _bufferSize;
+ return _buffer[pos];
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzhDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/LzhDecoder.cpp
new file mode 100644
index 000000000..6f9b5065e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzhDecoder.cpp
@@ -0,0 +1,220 @@
+// LzhDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "LzhDecoder.h"
+
+#include "Windows/Defs.h"
+
+namespace NCompress{
+namespace NLzh {
+namespace NDecoder {
+
+static const UInt32 kHistorySize = (1 << 16);
+
+static const int kBlockSizeBits = 16;
+static const int kNumCBits = 9;
+static const int kNumLevelBits = 5; // smallest integer such that (1 << kNumLevelBits) > kNumLevelSymbols/
+
+UInt32 CCoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
+
+HRESULT CCoder::ReadLevelTable()
+{
+ int n = ReadBits(kNumLevelBits);
+ if (n == 0)
+ {
+ m_LevelHuffman.Symbol = ReadBits(kNumLevelBits);
+ if (m_LevelHuffman.Symbol >= kNumLevelSymbols)
+ return S_FALSE;
+ }
+ else
+ {
+ if (n > kNumLevelSymbols)
+ return S_FALSE;
+ m_LevelHuffman.Symbol = -1;
+ Byte lens[kNumLevelSymbols];
+ int i = 0;
+ while (i < n)
+ {
+ int c = m_InBitStream.ReadBits(3);
+ if (c == 7)
+ while (ReadBits(1))
+ if (c++ > kMaxHuffmanLen)
+ return S_FALSE;
+ lens[i++] = (Byte)c;
+ if (i == kNumSpecLevelSymbols)
+ {
+ c = ReadBits(2);
+ while (--c >= 0)
+ lens[i++] = 0;
+ }
+ }
+ while (i < kNumLevelSymbols)
+ lens[i++] = 0;
+ m_LevelHuffman.SetCodeLengths(lens);
+ }
+ return S_OK;
+}
+
+HRESULT CCoder::ReadPTable(int numBits)
+{
+ int n = ReadBits(numBits);
+ if (n == 0)
+ {
+ m_PHuffmanDecoder.Symbol = ReadBits(numBits);
+ if (m_PHuffmanDecoder.Symbol >= kNumDistanceSymbols)
+ return S_FALSE;
+ }
+ else
+ {
+ if (n > kNumDistanceSymbols)
+ return S_FALSE;
+ m_PHuffmanDecoder.Symbol = -1;
+ Byte lens[kNumDistanceSymbols];
+ int i = 0;
+ while (i < n)
+ {
+ int c = m_InBitStream.ReadBits(3);
+ if (c == 7)
+ while (ReadBits(1))
+ {
+ if (c > kMaxHuffmanLen)
+ return S_FALSE;
+ c++;
+ }
+ lens[i++] = (Byte)c;
+ }
+ while (i < kNumDistanceSymbols)
+ lens[i++] = 0;
+ m_PHuffmanDecoder.SetCodeLengths(lens);
+ }
+ return S_OK;
+}
+
+HRESULT CCoder::ReadCTable()
+{
+ int n = ReadBits(kNumCBits);
+ if (n == 0)
+ {
+ m_CHuffmanDecoder.Symbol = ReadBits(kNumCBits);
+ if (m_CHuffmanDecoder.Symbol >= kNumCSymbols)
+ return S_FALSE;
+ }
+ else
+ {
+ if (n > kNumCSymbols)
+ return S_FALSE;
+ m_CHuffmanDecoder.Symbol = -1;
+ Byte lens[kNumCSymbols];
+ int i = 0;
+ while (i < n)
+ {
+ int c = m_LevelHuffman.Decode(&m_InBitStream);
+ if (c < kNumSpecLevelSymbols)
+ {
+ if (c == 0)
+ c = 1;
+ else if (c == 1)
+ c = ReadBits(4) + 3;
+ else
+ c = ReadBits(kNumCBits) + 20;
+ while (--c >= 0)
+ {
+ if (i > kNumCSymbols)
+ return S_FALSE;
+ lens[i++] = 0;
+ }
+ }
+ else
+ lens[i++] = (Byte)(c - 2);
+ }
+ while (i < kNumCSymbols)
+ lens[i++] = 0;
+ m_CHuffmanDecoder.SetCodeLengths(lens);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CCoder::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ UInt64 pos = 0;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ int pbit;
+ if (m_NumDictBits <= 13)
+ pbit = 4;
+ else
+ pbit = 5;
+
+ UInt32 blockSize = 0;
+
+ while(pos < *outSize)
+ {
+ // for (i = 0; i < dictSize; i++) dtext[i] = 0x20;
+
+ if (blockSize == 0)
+ {
+ if (progress != NULL)
+ {
+ UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ }
+ blockSize = ReadBits(kBlockSizeBits);
+ ReadLevelTable();
+ ReadCTable();
+ RINOK(ReadPTable(pbit));
+ }
+ blockSize--;
+ UInt32 c = m_CHuffmanDecoder.Decode(&m_InBitStream);
+ if (c < 256)
+ {
+ m_OutWindowStream.PutByte((Byte)c);
+ pos++;
+ }
+ else if (c >= kNumCSymbols)
+ return S_FALSE;
+ else
+ {
+ // offset = (interface->method == LARC_METHOD_NUM) ? 0x100 - 2 : 0x100 - 3;
+ UInt32 len = c - 256 + kMinMatch;
+ UInt32 distance = m_PHuffmanDecoder.Decode(&m_InBitStream);
+ if (distance != 0)
+ distance = (1 << (distance - 1)) + ReadBits(distance - 1);
+ if (distance >= pos)
+ return S_FALSE;
+ if (pos + len > *outSize)
+ len = (UInt32)(*outSize - pos);
+ pos += len;
+ m_OutWindowStream.CopyBlock(distance, len);
+ }
+ }
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CCoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzhDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/LzhDecoder.h
new file mode 100644
index 000000000..ed631e20d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzhDecoder.h
@@ -0,0 +1,106 @@
+// LzhDecoder.h
+
+#ifndef __COMPRESS_LZH_DECODER_H
+#define __COMPRESS_LZH_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NLzh {
+namespace NDecoder {
+
+const int kMaxHuffmanLen = 16; // Check it
+
+const int kNumSpecLevelSymbols = 3;
+const int kNumLevelSymbols = kNumSpecLevelSymbols + kMaxHuffmanLen;
+
+const int kDictBitsMax = 16;
+const int kNumDistanceSymbols = kDictBitsMax + 1;
+
+const int kMaxMatch = 256;
+const int kMinMatch = 3;
+const int kNumCSymbols = 256 + kMaxMatch + 2 - kMinMatch;
+
+template <UInt32 m_NumSymbols>
+class CHuffmanDecoder:public NCompress::NHuffman::CDecoder<kMaxHuffmanLen, m_NumSymbols>
+{
+public:
+ int Symbol;
+ template <class TBitDecoder>
+ UInt32 Decode(TBitDecoder *bitStream)
+ {
+ if (Symbol >= 0)
+ return (UInt32)Symbol;
+ return DecodeSymbol(bitStream);
+ }
+};
+
+class CCoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ NBitm::CDecoder<CInBuffer> m_InBitStream;
+
+ int m_NumDictBits;
+
+ CHuffmanDecoder<kNumLevelSymbols> m_LevelHuffman;
+ CHuffmanDecoder<kNumDistanceSymbols> m_PHuffmanDecoder;
+ CHuffmanDecoder<kNumCSymbols> m_CHuffmanDecoder;
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CCoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+ void MakeTable(int nchar, Byte *bitlen, int tablebits,
+ UInt32 *table, int tablesize);
+
+ UInt32 ReadBits(int numBits);
+ HRESULT ReadLevelTable();
+ HRESULT ReadPTable(int numBits);
+ HRESULT ReadCTable();
+
+public:
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(CodeReal)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ void SetDictionary(int numDictBits) { m_NumDictBits = numDictBits; }
+ CCoder(): m_NumDictBits(0) {}
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.cpp
new file mode 100644
index 000000000..322015e29
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.cpp
@@ -0,0 +1,189 @@
+// Lzma2Decoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Lzma2Decoder.h"
+
+static HRESULT SResToHRESULT(SRes res)
+{
+ switch(res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PARAM: return E_INVALIDARG;
+ // case SZ_ERROR_PROGRESS: return E_ABORT;
+ case SZ_ERROR_DATA: return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+namespace NCompress {
+namespace NLzma2 {
+
+static const UInt32 kInBufSize = 1 << 20;
+
+CDecoder::CDecoder(): _inBuf(0), _outSizeDefined(false)
+{
+ Lzma2Dec_Construct(&_state);
+}
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CDecoder::~CDecoder()
+{
+ Lzma2Dec_Free(&_state, &g_Alloc);
+ MyFree(_inBuf);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
+{
+ if (size != 1) return SZ_ERROR_UNSUPPORTED;
+ RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc)));
+ if (_inBuf == 0)
+ {
+ _inBuf = (Byte *)MyAlloc(kInBufSize);
+ if (_inBuf == 0)
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; }
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
+STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+
+ Lzma2Dec_Init(&_state);
+
+ _inPos = _inSize = 0;
+ _inSizeProcessed = _outSizeProcessed = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 * /* inSize */,
+ const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0)
+ return S_FALSE;
+ SetOutStreamSize(outSize);
+
+ for (;;)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(inStream->Read(_inBuf, kInBufSize, &_inSize));
+ }
+
+ SizeT dicPos = _state.decoder.dicPos;
+ SizeT curSize = _state.decoder.dicBufSize - dicPos;
+ const UInt32 kStepSize = ((UInt32)1 << 22);
+ if (curSize > kStepSize)
+ curSize = (SizeT)kStepSize;
+
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < curSize)
+ {
+ curSize = (SizeT)rem;
+ /*
+ // finishMode = LZMA_FINISH_END;
+ we can't use LZMA_FINISH_END here to allow partial decoding
+ */
+ }
+ }
+
+ SizeT inSizeProcessed = _inSize - _inPos;
+ ELzmaStatus status;
+ SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
+
+ _inPos += (UInt32)inSizeProcessed;
+ _inSizeProcessed += inSizeProcessed;
+ SizeT outSizeProcessed = _state.decoder.dicPos - dicPos;
+ _outSizeProcessed += outSizeProcessed;
+
+ bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
+ bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
+
+ if (res != 0 || _state.decoder.dicPos == _state.decoder.dicBufSize || finished || stopDecoding)
+ {
+ HRESULT res2 = WriteStream(outStream, _state.decoder.dic, _state.decoder.dicPos);
+ if (res != 0)
+ return S_FALSE;
+ RINOK(res2);
+ if (stopDecoding)
+ return S_OK;
+ if (finished)
+ return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE);
+ }
+ if (_state.decoder.dicPos == _state.decoder.dicBufSize)
+ _state.decoder.dicPos = 0;
+
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed));
+ }
+ }
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ do
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, kInBufSize, &_inSize));
+ }
+ {
+ SizeT inProcessed = _inSize - _inPos;
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < size)
+ size = (UInt32)rem;
+ }
+
+ SizeT outProcessed = size;
+ ELzmaStatus status;
+ SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
+ _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
+ _inPos += (UInt32)inProcessed;
+ _inSizeProcessed += inProcessed;
+ _outSizeProcessed += outProcessed;
+ size -= (UInt32)outProcessed;
+ data = (Byte *)data + outProcessed;
+ if (processedSize)
+ *processedSize += (UInt32)outProcessed;
+ RINOK(SResToHRESULT(res));
+ if (inProcessed == 0 && outProcessed == 0)
+ return S_OK;
+ }
+ }
+ while (size != 0);
+ return S_OK;
+}
+
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.h b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.h
new file mode 100644
index 000000000..fd7ca2f39
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Decoder.h
@@ -0,0 +1,73 @@
+// Lzma2Decoder.h
+
+#ifndef __LZMA2_DECODER_H
+#define __LZMA2_DECODER_H
+
+#include "../../../C/Lzma2Dec.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma2 {
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressGetInStreamProcessedSize,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _inStream;
+ Byte *_inBuf;
+ UInt32 _inPos;
+ UInt32 _inSize;
+ CLzma2Dec _state;
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _inSizeProcessed;
+ UInt64 _outSizeProcessed;
+public:
+
+ #ifndef NO_READ_FROM_CODER
+ MY_UNKNOWN_IMP5(
+ ICompressSetDecoderProperties2,
+ ICompressGetInStreamProcessedSize,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream)
+ #else
+ MY_UNKNOWN_IMP2(
+ ICompressSetDecoderProperties2,
+ ICompressGetInStreamProcessedSize)
+ #endif
+
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *_inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ #ifndef NO_READ_FROM_CODER
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+ CDecoder();
+ virtual ~CDecoder();
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.cpp
new file mode 100644
index 000000000..5e4c71bea
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.cpp
@@ -0,0 +1,94 @@
+// Lzma2Encoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/StreamUtils.h"
+
+#include "Lzma2Encoder.h"
+
+namespace NCompress {
+
+namespace NLzma {
+
+HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep);
+
+}
+
+namespace NLzma2 {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CEncoder::CEncoder()
+{
+ _encoder = 0;
+ _encoder = Lzma2Enc_Create(&g_Alloc, &g_BigAlloc);
+ if (_encoder == 0)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder != 0)
+ Lzma2Enc_Destroy(_encoder);
+}
+
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props)
+{
+ switch (propID)
+ {
+ case NCoderPropID::kBlockSize:
+ if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.blockSize = prop.ulVal; break;
+ case NCoderPropID::kNumThreads:
+ if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.numTotalThreads = (int)(prop.ulVal); break;
+ default:
+ RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps));
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps)
+{
+ CLzma2EncProps lzma2Props;
+ Lzma2EncProps_Init(&lzma2Props);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props));
+ }
+ return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props));
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte prop = Lzma2Enc_WriteProperties(_encoder);
+ return WriteStream(outStream, &prop, 1);
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CSeqInStreamWrap inWrap(inStream);
+ CSeqOutStreamWrap outWrap(outStream);
+ CCompressProgressWrap progressWrap(progress);
+
+ SRes res = Lzma2Enc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL);
+ if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
+ return inWrap.Res;
+ if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
+ return outWrap.Res;
+ if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
+ return progressWrap.Res;
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.h b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.h
new file mode 100644
index 000000000..f0fb74d33
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Encoder.h
@@ -0,0 +1,36 @@
+// Lzma2Encoder.h
+
+#ifndef __LZMA2_ENCODER_H
+#define __LZMA2_ENCODER_H
+
+#include "../../../C/Lzma2Enc.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma2 {
+
+class CEncoder:
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public CMyUnknownImp
+{
+ CLzma2EncHandle _encoder;
+public:
+ MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+
+ CEncoder();
+ virtual ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Register.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Register.cpp
new file mode 100644
index 000000000..cace871ef
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Lzma2Register.cpp
@@ -0,0 +1,20 @@
+// Lzma2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Lzma2Decoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "Lzma2Encoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma2::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x21, L"LZMA2", 1, false };
+
+REGISTER_CODEC(LZMA2)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.cpp
new file mode 100644
index 000000000..b7c260bd9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.cpp
@@ -0,0 +1,252 @@
+// LzmaDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "LzmaDecoder.h"
+
+static HRESULT SResToHRESULT(SRes res)
+{
+ switch(res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PARAM: return E_INVALIDARG;
+ case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
+ case SZ_ERROR_DATA: return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+namespace NCompress {
+namespace NLzma {
+
+CDecoder::CDecoder(): _inBuf(0), _propsWereSet(false), _outSizeDefined(false),
+ _inBufSize(1 << 20),
+ _outBufSize(1 << 22),
+ FinishStream(false)
+{
+ _inSizeProcessed = 0;
+ _inPos = _inSize = 0;
+ LzmaDec_Construct(&_state);
+}
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CDecoder::~CDecoder()
+{
+ LzmaDec_Free(&_state, &g_Alloc);
+ MyFree(_inBuf);
+}
+
+STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
+STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
+
+HRESULT CDecoder::CreateInputBuffer()
+{
+ if (_inBuf == 0 || _inBufSize != _inBufSizeAllocated)
+ {
+ MyFree(_inBuf);
+ _inBuf = (Byte *)MyAlloc(_inBufSize);
+ if (_inBuf == 0)
+ return E_OUTOFMEMORY;
+ _inBufSizeAllocated = _inBufSize;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
+{
+ RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_Alloc)));
+ _propsWereSet = true;
+ return CreateInputBuffer();
+}
+
+void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+ _outSizeProcessed = 0;
+ _wrPos = 0;
+ LzmaDec_Init(&_state);
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ _inSizeProcessed = 0;
+ _inPos = _inSize = 0;
+ SetOutStreamSizeResume(outSize);
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0 || !_propsWereSet)
+ return S_FALSE;
+
+ UInt64 startInProgress = _inSizeProcessed;
+
+ SizeT next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize);
+ for (;;)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ }
+
+ SizeT dicPos = _state.dicPos;
+ SizeT curSize = next - dicPos;
+
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem <= curSize)
+ {
+ curSize = (SizeT)rem;
+ if (FinishStream)
+ finishMode = LZMA_FINISH_END;
+ }
+ }
+
+ SizeT inSizeProcessed = _inSize - _inPos;
+ ELzmaStatus status;
+ SRes res = LzmaDec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
+
+ _inPos += (UInt32)inSizeProcessed;
+ _inSizeProcessed += inSizeProcessed;
+ SizeT outSizeProcessed = _state.dicPos - dicPos;
+ _outSizeProcessed += outSizeProcessed;
+
+ bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
+ bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
+
+ if (res != 0 || _state.dicPos == next || finished || stopDecoding)
+ {
+ HRESULT res2 = WriteStream(outStream, _state.dic + _wrPos, _state.dicPos - _wrPos);
+
+ _wrPos = _state.dicPos;
+ if (_state.dicPos == _state.dicBufSize)
+ {
+ _state.dicPos = 0;
+ _wrPos = 0;
+ }
+ next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize);
+
+ if (res != 0)
+ return S_FALSE;
+ RINOK(res2);
+ if (stopDecoding)
+ return S_OK;
+ if (finished)
+ return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : S_FALSE);
+ }
+ if (progress)
+ {
+ UInt64 inSize = _inSizeProcessed - startInProgress;
+ RINOK(progress->SetRatioInfo(&inSize, &_outSizeProcessed));
+ }
+ }
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (_inBuf == 0)
+ return E_INVALIDARG;
+ SetOutStreamSize(outSize);
+ return CodeSpec(inStream, outStream, progress);
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
+STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ do
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ }
+ {
+ SizeT inProcessed = _inSize - _inPos;
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSizeProcessed;
+ if (rem < size)
+ size = (UInt32)rem;
+ }
+
+ SizeT outProcessed = size;
+ ELzmaStatus status;
+ SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
+ _inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
+ _inPos += (UInt32)inProcessed;
+ _inSizeProcessed += inProcessed;
+ _outSizeProcessed += outProcessed;
+ size -= (UInt32)outProcessed;
+ data = (Byte *)data + outProcessed;
+ if (processedSize)
+ *processedSize += (UInt32)outProcessed;
+ RINOK(SResToHRESULT(res));
+ if (inProcessed == 0 && outProcessed == 0)
+ return S_OK;
+ }
+ }
+ while (size != 0);
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ SetOutStreamSizeResume(outSize);
+ return CodeSpec(_inStream, outStream, progress);
+}
+
+HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)
+{
+ RINOK(CreateInputBuffer());
+ if (processedSize)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_inPos == _inSize)
+ {
+ _inPos = _inSize = 0;
+ RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
+ if (_inSize == 0)
+ break;
+ }
+ {
+ UInt32 curSize = _inSize - _inPos;
+ if (curSize > size)
+ curSize = size;
+ memcpy(data, _inBuf + _inPos, curSize);
+ _inPos += curSize;
+ _inSizeProcessed += curSize;
+ size -= curSize;
+ data = (Byte *)data + curSize;
+ if (processedSize)
+ *processedSize += curSize;
+ }
+ }
+ return S_OK;
+}
+
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.h
new file mode 100644
index 000000000..d28a4634b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzmaDecoder.h
@@ -0,0 +1,84 @@
+// LzmaDecoder.h
+
+#ifndef __LZMA_DECODER_H
+#define __LZMA_DECODER_H
+
+#include "../../../C/LzmaDec.h"
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressSetBufSize,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _inStream;
+ Byte *_inBuf;
+ UInt32 _inPos;
+ UInt32 _inSize;
+ CLzmaDec _state;
+ bool _propsWereSet;
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _inSizeProcessed;
+ UInt64 _outSizeProcessed;
+
+ UInt32 _inBufSizeAllocated;
+ UInt32 _inBufSize;
+ UInt32 _outBufSize;
+ SizeT _wrPos;
+
+ HRESULT CreateInputBuffer();
+ HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+ void SetOutStreamSizeResume(const UInt64 *outSize);
+
+public:
+ MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)
+ #ifndef NO_READ_FROM_CODER
+ MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
+ MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
+ MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
+ #endif
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
+
+ #ifndef NO_READ_FROM_CODER
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+
+ HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize);
+ UInt64 GetInputProcessedSize() const { return _inSizeProcessed; }
+
+ #endif
+
+ bool FinishStream;
+
+ CDecoder();
+ virtual ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.cpp
new file mode 100644
index 000000000..9bdedaeb6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.cpp
@@ -0,0 +1,149 @@
+// LzmaEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/StreamUtils.h"
+
+#include "LzmaEncoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static void *SzAlloc(void *, size_t size) { return MyAlloc(size); }
+static void SzFree(void *, void *address) { MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+CEncoder::CEncoder()
+{
+ _encoder = 0;
+ _encoder = LzmaEnc_Create(&g_Alloc);
+ if (_encoder == 0)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder != 0)
+ LzmaEnc_Destroy(_encoder, &g_Alloc, &g_BigAlloc);
+}
+
+inline wchar_t GetUpperChar(wchar_t c)
+{
+ if (c >= 'a' && c <= 'z')
+ c -= 0x20;
+ return c;
+}
+
+static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
+{
+ wchar_t c = GetUpperChar(*s++);
+ if (c == L'H')
+ {
+ if (GetUpperChar(*s++) != L'C')
+ return 0;
+ int numHashBytesLoc = (int)(*s++ - L'0');
+ if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
+ return 0;
+ if (*s++ != 0)
+ return 0;
+ *btMode = 0;
+ *numHashBytes = numHashBytesLoc;
+ return 1;
+ }
+ if (c != L'B')
+ return 0;
+
+ if (GetUpperChar(*s++) != L'T')
+ return 0;
+ int numHashBytesLoc = (int)(*s++ - L'0');
+ if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
+ return 0;
+ c = GetUpperChar(*s++);
+ if (c != L'\0')
+ return 0;
+ *btMode = 1;
+ *numHashBytes = numHashBytesLoc;
+ return 1;
+}
+
+HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
+{
+ if (propID == NCoderPropID::kMatchFinder)
+ {
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
+ }
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = prop.ulVal;
+ switch (propID)
+ {
+ case NCoderPropID::kNumFastBytes: ep.fb = v; break;
+ case NCoderPropID::kMatchFinderCycles: ep.mc = v; break;
+ case NCoderPropID::kAlgorithm: ep.algo = v; break;
+ case NCoderPropID::kDictionarySize: ep.dictSize = v; break;
+ case NCoderPropID::kPosStateBits: ep.pb = v; break;
+ case NCoderPropID::kLitPosBits: ep.lp = v; break;
+ case NCoderPropID::kLitContextBits: ep.lc = v; break;
+ default: return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps)
+{
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ PROPID propID = propIDs[i];
+ switch (propID)
+ {
+ case NCoderPropID::kEndMarker:
+ if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal == VARIANT_TRUE); break;
+ case NCoderPropID::kNumThreads:
+ if (prop.vt != VT_UI4) return E_INVALIDARG; props.numThreads = prop.ulVal; break;
+ default:
+ RINOK(SetLzmaProp(propID, prop, props));
+ }
+ }
+ return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ size_t size = LZMA_PROPS_SIZE;
+ RINOK(LzmaEnc_WriteProperties(_encoder, props, &size));
+ return WriteStream(outStream, props, size);
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CSeqInStreamWrap inWrap(inStream);
+ CSeqOutStreamWrap outWrap(outStream);
+ CCompressProgressWrap progressWrap(progress);
+
+ SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc);
+ if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
+ return inWrap.Res;
+ if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)
+ return outWrap.Res;
+ if (res == SZ_ERROR_PROGRESS && progressWrap.Res != S_OK)
+ return progressWrap.Res;
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.h b/src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.h
new file mode 100644
index 000000000..904c0002c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzmaEncoder.h
@@ -0,0 +1,36 @@
+// LzmaEncoder.h
+
+#ifndef __LZMA_ENCODER_H
+#define __LZMA_ENCODER_H
+
+#include "../../../C/LzmaEnc.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+class CEncoder:
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public CMyUnknownImp
+{
+ CLzmaEncHandle _encoder;
+public:
+ MY_UNKNOWN_IMP2(ICompressSetCoderProperties, ICompressWriteCoderProperties)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+
+ CEncoder();
+ virtual ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzmaRegister.cpp b/src/libs/7zip/win/CPP/7zip/Compress/LzmaRegister.cpp
new file mode 100644
index 000000000..96ed0baed
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzmaRegister.cpp
@@ -0,0 +1,20 @@
+// LzmaRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "LzmaDecoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "LzmaEncoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NLzma::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x030101, L"LZMA", 1, false };
+
+REGISTER_CODEC(LZMA)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Lzx.h b/src/libs/7zip/win/CPP/7zip/Compress/Lzx.h
new file mode 100644
index 000000000..09ab7f075
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Lzx.h
@@ -0,0 +1,61 @@
+// Lzx.h
+
+#ifndef __COMPRESS_LZX_H
+#define __COMPRESS_LZX_H
+
+namespace NCompress {
+namespace NLzx {
+
+const unsigned kNumHuffmanBits = 16;
+const UInt32 kNumRepDistances = 3;
+
+const UInt32 kNumLenSlots = 8;
+const UInt32 kMatchMinLen = 2;
+const UInt32 kNumLenSymbols = 249;
+const UInt32 kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1;
+
+const unsigned kNumAlignBits = 3;
+const UInt32 kAlignTableSize = 1 << kNumAlignBits;
+
+const UInt32 kNumPosSlots = 50;
+const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
+
+const UInt32 kMainTableSize = 256 + kNumPosLenSlots;
+const UInt32 kLevelTableSize = 20;
+const UInt32 kMaxTableSize = kMainTableSize;
+
+const unsigned kNumBlockTypeBits = 3;
+const unsigned kBlockTypeVerbatim = 1;
+const unsigned kBlockTypeAligned = 2;
+const unsigned kBlockTypeUncompressed = 3;
+
+const unsigned kUncompressedBlockSizeNumBits = 24;
+
+const unsigned kNumBitsForPreTreeLevel = 4;
+
+const unsigned kLevelSymbolZeros = 17;
+const unsigned kLevelSymbolZerosBig = 18;
+const unsigned kLevelSymbolSame = 19;
+
+const unsigned kLevelSymbolZerosStartValue = 4;
+const unsigned kLevelSymbolZerosNumBits = 4;
+
+const unsigned kLevelSymbolZerosBigStartValue = kLevelSymbolZerosStartValue +
+ (1 << kLevelSymbolZerosNumBits);
+const unsigned kLevelSymbolZerosBigNumBits = 5;
+
+const unsigned kLevelSymbolSameNumBits = 1;
+const unsigned kLevelSymbolSameStartValue = 4;
+
+const unsigned kNumBitsForAlignLevel = 3;
+
+const unsigned kNumDictionaryBitsMin = 15;
+const unsigned kNumDictionaryBitsMax = 21;
+const UInt32 kDictionarySizeMax = (1 << kNumDictionaryBitsMax);
+
+const unsigned kNumLinearPosSlotBits = 17;
+const UInt32 kNumPowerPosSlots = 0x26;
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Lzx86Converter.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Lzx86Converter.cpp
new file mode 100644
index 000000000..9e53f18a9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Lzx86Converter.cpp
@@ -0,0 +1,90 @@
+// Lzx86Converter.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+
+#include "Lzx86Converter.h"
+
+namespace NCompress {
+namespace NLzx {
+
+static const int kResidue = 6 + 4;
+
+void Cx86ConvertOutStream::MakeTranslation()
+{
+ if (m_Pos <= kResidue)
+ return;
+ UInt32 numBytes = m_Pos - kResidue;
+ Byte *buffer = m_Buffer;
+ for (UInt32 i = 0; i < numBytes;)
+ {
+ if (buffer[i++] == 0xE8)
+ {
+ Int32 absValue = 0;
+ int j;
+ for(j = 0; j < 4; j++)
+ absValue += (UInt32)buffer[i + j] << (j * 8);
+ Int32 pos = (Int32)(m_ProcessedSize + i - 1);
+ if (absValue >= -pos && absValue < (Int32)m_TranslationSize)
+ {
+ UInt32 offset = (absValue >= 0) ?
+ absValue - pos :
+ absValue + m_TranslationSize;
+ for(j = 0; j < 4; j++)
+ {
+ buffer[i + j] = (Byte)(offset & 0xFF);
+ offset >>= 8;
+ }
+ }
+ i += 4;
+ }
+ }
+}
+
+STDMETHODIMP Cx86ConvertOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ if (!m_TranslationMode)
+ return m_Stream->Write(data, size, processedSize);
+ UInt32 realProcessedSize = 0;
+ while (realProcessedSize < size)
+ {
+ UInt32 writeSize = MyMin(size - realProcessedSize, kUncompressedBlockSize - m_Pos);
+ memmove(m_Buffer + m_Pos, (const Byte *)data + realProcessedSize, writeSize);
+ m_Pos += writeSize;
+ realProcessedSize += writeSize;
+ if (m_Pos == kUncompressedBlockSize)
+ {
+ RINOK(Flush());
+ }
+ }
+ if (processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return S_OK;
+}
+
+HRESULT Cx86ConvertOutStream::Flush()
+{
+ if (m_Pos == 0)
+ return S_OK;
+ if (m_TranslationMode)
+ MakeTranslation();
+ UInt32 pos = 0;
+ do
+ {
+ UInt32 processed;
+ RINOK(m_Stream->Write(m_Buffer + pos, m_Pos - pos, &processed));
+ if (processed == 0)
+ return E_FAIL;
+ pos += processed;
+ }
+ while(pos < m_Pos);
+ m_ProcessedSize += m_Pos;
+ m_Pos = 0;
+ m_TranslationMode = (m_TranslationMode && (m_ProcessedSize < (1 << 30)));
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Lzx86Converter.h b/src/libs/7zip/win/CPP/7zip/Compress/Lzx86Converter.h
new file mode 100644
index 000000000..9f110c29b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Lzx86Converter.h
@@ -0,0 +1,46 @@
+// Lzx86Converter.h
+
+#ifndef __LZX_86_CONVERTER_H
+#define __LZX_86_CONVERTER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../IStream.h"
+
+namespace NCompress {
+namespace NLzx {
+
+const int kUncompressedBlockSize = 1 << 15;
+
+class Cx86ConvertOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> m_Stream;
+ UInt32 m_ProcessedSize;
+ UInt32 m_Pos;
+ UInt32 m_TranslationSize;
+ bool m_TranslationMode;
+ Byte m_Buffer[kUncompressedBlockSize];
+
+ void MakeTranslation();
+public:
+ void SetStream(ISequentialOutStream *outStream) { m_Stream = outStream; }
+ void ReleaseStream() { m_Stream.Release(); }
+ void Init(bool translationMode, UInt32 translationSize)
+ {
+ m_TranslationMode = translationMode;
+ m_TranslationSize = translationSize;
+ m_ProcessedSize = 0;
+ m_Pos = 0;
+ }
+ HRESULT Flush();
+
+ MY_UNKNOWN_IMP
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzxDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/LzxDecoder.cpp
new file mode 100644
index 000000000..d1027f1f3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzxDecoder.cpp
@@ -0,0 +1,387 @@
+// LzxDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+
+#include "LzxDecoder.h"
+
+namespace NCompress {
+namespace NLzx {
+
+const int kLenIdNeedInit = -2;
+
+CDecoder::CDecoder(bool wimMode):
+ _keepHistory(false),
+ _skipByte(false),
+ _wimMode(wimMode)
+{
+ m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;
+ m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;
+}
+
+void CDecoder::ReleaseStreams()
+{
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ m_x86ConvertOutStreamSpec->ReleaseStream();
+}
+
+STDMETHODIMP CDecoder::Flush()
+{
+ RINOK(m_OutWindowStream.Flush());
+ return m_x86ConvertOutStreamSpec->Flush();
+}
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols)
+{
+ Byte levelLevels[kLevelTableSize];
+ UInt32 i;
+ for (i = 0; i < kLevelTableSize; i++)
+ levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+ unsigned num = 0;
+ Byte symbol = 0;
+ for (i = 0; i < numSymbols;)
+ {
+ if (num != 0)
+ {
+ lastLevels[i] = newLevels[i] = symbol;
+ i++;
+ num--;
+ continue;
+ }
+ UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
+ if (number == kLevelSymbolZeros)
+ {
+ num = kLevelSymbolZerosStartValue + (unsigned)ReadBits(kLevelSymbolZerosNumBits);
+ symbol = 0;
+ }
+ else if (number == kLevelSymbolZerosBig)
+ {
+ num = kLevelSymbolZerosBigStartValue + (unsigned)ReadBits(kLevelSymbolZerosBigNumBits);
+ symbol = 0;
+ }
+ else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
+ {
+ if (number <= kNumHuffmanBits)
+ num = 1;
+ else
+ {
+ num = kLevelSymbolSameStartValue + (unsigned)ReadBits(kLevelSymbolSameNumBits);
+ number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
+ if (number > kNumHuffmanBits)
+ return false;
+ }
+ symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
+bool CDecoder::ReadTables(void)
+{
+ Byte newLevels[kMaxTableSize];
+ {
+ if (_skipByte)
+ m_InBitStream.DirectReadByte();
+ m_InBitStream.Normalize();
+
+ unsigned blockType = (unsigned)ReadBits(kNumBlockTypeBits);
+ if (blockType > kBlockTypeUncompressed)
+ return false;
+ if (_wimMode)
+ if (ReadBits(1) == 1)
+ m_UnCompressedBlockSize = (1 << 15);
+ else
+ m_UnCompressedBlockSize = ReadBits(16);
+ else
+ m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);
+
+ m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed);
+
+ _skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0));
+
+ if (m_IsUncompressedBlock)
+ {
+ ReadBits(16 - m_InBitStream.GetBitPosition());
+ if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))
+ return false;
+ m_RepDistances[0]--;
+ for (unsigned i = 1; i < kNumRepDistances; i++)
+ {
+ UInt32 rep = 0;
+ for (unsigned j = 0; j < 4; j++)
+ rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);
+ m_RepDistances[i] = rep - 1;
+ }
+ return true;
+ }
+ m_AlignIsUsed = (blockType == kBlockTypeAligned);
+ if (m_AlignIsUsed)
+ {
+ for (unsigned i = 0; i < kAlignTableSize; i++)
+ newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel);
+ RIF(m_AlignDecoder.SetCodeLengths(newLevels));
+ }
+ }
+
+ RIF(ReadTable(m_LastMainLevels, newLevels, 256));
+ RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));
+ for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)
+ newLevels[i] = 0;
+ RIF(m_MainDecoder.SetCodeLengths(newLevels));
+
+ RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));
+ return m_LenDecoder.SetCodeLengths(newLevels);
+}
+
+class CDecoderFlusher
+{
+ CDecoder *m_Decoder;
+public:
+ bool NeedFlush;
+ CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ m_Decoder->Flush();
+ m_Decoder->ReleaseStreams();
+ }
+};
+
+
+void CDecoder::ClearPrevLevels()
+{
+ unsigned i;
+ for (i = 0; i < kMainTableSize; i++)
+ m_LastMainLevels[i] = 0;
+ for (i = 0; i < kNumLenSymbols; i++)
+ m_LastLenLevels[i] = 0;
+}
+
+
+HRESULT CDecoder::CodeSpec(UInt32 curSize)
+{
+ if (_remainLen == kLenIdNeedInit)
+ {
+ _remainLen = 0;
+ m_InBitStream.Init();
+ if (!_keepHistory || !m_IsUncompressedBlock)
+ m_InBitStream.Normalize();
+ if (!_keepHistory)
+ {
+ _skipByte = false;
+ m_UnCompressedBlockSize = 0;
+ ClearPrevLevels();
+ UInt32 i86TranslationSize = 12000000;
+ bool translationMode = true;
+ if (!_wimMode)
+ {
+ translationMode = (ReadBits(1) != 0);
+ if (translationMode)
+ {
+ i86TranslationSize = ReadBits(16) << 16;
+ i86TranslationSize |= ReadBits(16);
+ }
+ }
+ m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);
+
+ for (unsigned i = 0 ; i < kNumRepDistances; i++)
+ m_RepDistances[i] = 0;
+ }
+ }
+
+ while (_remainLen > 0 && curSize > 0)
+ {
+ m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));
+ _remainLen--;
+ curSize--;
+ }
+
+ while (curSize > 0)
+ {
+ if (m_UnCompressedBlockSize == 0)
+ if (!ReadTables())
+ return S_FALSE;
+ UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);
+ curSize -= next;
+ m_UnCompressedBlockSize -= next;
+ if (m_IsUncompressedBlock)
+ {
+ while (next > 0)
+ {
+ m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());
+ next--;
+ }
+ }
+ else while (next > 0)
+ {
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < 256)
+ {
+ m_OutWindowStream.PutByte((Byte)number);
+ next--;
+ }
+ else
+ {
+ UInt32 posLenSlot = number - 256;
+ if (posLenSlot >= m_NumPosLenSlots)
+ return S_FALSE;
+ UInt32 posSlot = posLenSlot / kNumLenSlots;
+ UInt32 lenSlot = posLenSlot % kNumLenSlots;
+ UInt32 len = kMatchMinLen + lenSlot;
+ if (lenSlot == kNumLenSlots - 1)
+ {
+ UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);
+ if (lenTemp >= kNumLenSymbols)
+ return S_FALSE;
+ len += lenTemp;
+ }
+
+ if (posSlot < kNumRepDistances)
+ {
+ UInt32 distance = m_RepDistances[posSlot];
+ m_RepDistances[posSlot] = m_RepDistances[0];
+ m_RepDistances[0] = distance;
+ }
+ else
+ {
+ UInt32 distance;
+ unsigned numDirectBits;
+ if (posSlot < kNumPowerPosSlots)
+ {
+ numDirectBits = (unsigned)(posSlot >> 1) - 1;
+ distance = ((2 | (posSlot & 1)) << numDirectBits);
+ }
+ else
+ {
+ numDirectBits = kNumLinearPosSlotBits;
+ distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);
+ }
+
+ if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)
+ {
+ distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);
+ UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
+ if (alignTemp >= kAlignTableSize)
+ return S_FALSE;
+ distance += alignTemp;
+ }
+ else
+ distance += m_InBitStream.ReadBits(numDirectBits);
+ m_RepDistances[2] = m_RepDistances[1];
+ m_RepDistances[1] = m_RepDistances[0];
+ m_RepDistances[0] = distance - kNumRepDistances;
+ }
+
+ UInt32 locLen = len;
+ if (locLen > next)
+ locLen = next;
+
+ if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))
+ return S_FALSE;
+
+ len -= locLen;
+ next -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (int)len;
+ return S_OK;
+ }
+ }
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+ UInt64 size = *outSize;
+
+ RINOK(SetInStream(inStream));
+ m_x86ConvertOutStreamSpec->SetStream(outStream);
+ m_OutWindowStream.SetStream(m_x86ConvertOutStream);
+ RINOK(SetOutStreamSize(outSize));
+
+ CDecoderFlusher flusher(this);
+
+ const UInt64 start = m_OutWindowStream.GetProcessedSize();
+ for (;;)
+ {
+ UInt32 curSize = 1 << 18;
+ UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ if (curSize == 0)
+ break;
+ RINOK(CodeSpec(curSize));
+ if (progress != NULL)
+ {
+ UInt64 inSize = m_InBitStream.GetProcessedSize();
+ UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+ }
+ }
+ flusher.NeedFlush = false;
+ return Flush();
+}
+
+HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
+{
+ m_InBitStream.SetStream(inStream);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::ReleaseInStream()
+{
+ m_InBitStream.ReleaseStream();
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ if (outSize == NULL)
+ return E_FAIL;
+ _remainLen = kLenIdNeedInit;
+ m_OutWindowStream.Init(_keepHistory);
+ return S_OK;
+}
+
+HRESULT CDecoder::SetParams(unsigned numDictBits)
+{
+ if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)
+ return E_INVALIDARG;
+ UInt32 numPosSlots;
+ if (numDictBits < 20)
+ numPosSlots = 30 + (numDictBits - 15) * 2;
+ else if (numDictBits == 20)
+ numPosSlots = 42;
+ else
+ numPosSlots = 50;
+ m_NumPosLenSlots = numPosSlots * kNumLenSlots;
+ if (!m_OutWindowStream.Create(kDictionarySizeMax))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 16))
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/LzxDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/LzxDecoder.h
new file mode 100644
index 000000000..73a050619
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/LzxDecoder.h
@@ -0,0 +1,159 @@
+// LzxDecoder.h
+
+#ifndef __LZX_DECODER_H
+#define __LZX_DECODER_H
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+#include "Lzx.h"
+#include "Lzx86Converter.h"
+
+namespace NCompress {
+namespace NLzx {
+
+namespace NBitStream {
+
+const unsigned kNumBigValueBits = 8 * 4;
+const unsigned kNumValueBits = 17;
+const UInt32 kBitDecoderValueMask = (1 << kNumValueBits) - 1;
+
+class CDecoder
+{
+ CInBuffer m_Stream;
+ UInt32 m_Value;
+ unsigned m_BitPos;
+public:
+ CDecoder() {}
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+
+ void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); }
+ void ReleaseStream() { m_Stream.ReleaseStream(); }
+
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = kNumBigValueBits;
+ }
+
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - (kNumBigValueBits - m_BitPos) / 8; }
+
+ unsigned GetBitPosition() const { return m_BitPos & 0xF; }
+
+ void Normalize()
+ {
+ for (; m_BitPos >= 16; m_BitPos -= 16)
+ {
+ Byte b0 = m_Stream.ReadByte();
+ Byte b1 = m_Stream.ReadByte();
+ m_Value = (m_Value << 8) | b1;
+ m_Value = (m_Value << 8) | b0;
+ }
+ }
+
+ UInt32 GetValue(unsigned numBits) const
+ {
+ return ((m_Value >> ((32 - kNumValueBits) - m_BitPos)) & kBitDecoderValueMask) >> (kNumValueBits - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ m_BitPos += numBits;
+ Normalize();
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ MovePos(numBits);
+ return res;
+ }
+
+ UInt32 ReadBitsBig(unsigned numBits)
+ {
+ unsigned numBits0 = numBits / 2;
+ unsigned numBits1 = numBits - numBits0;
+ UInt32 res = ReadBits(numBits0) << numBits1;
+ return res + ReadBits(numBits1);
+ }
+
+ bool ReadUInt32(UInt32 &v)
+ {
+ if (m_BitPos != 0)
+ return false;
+ v = ((m_Value >> 16) & 0xFFFF) | ((m_Value << 16) & 0xFFFF0000);
+ m_BitPos = kNumBigValueBits;
+ return true;
+ }
+
+ Byte DirectReadByte() { return m_Stream.ReadByte(); }
+
+};
+}
+
+class CDecoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ NBitStream::CDecoder m_InBitStream;
+ CLzOutWindow m_OutWindowStream;
+
+ UInt32 m_RepDistances[kNumRepDistances];
+ UInt32 m_NumPosLenSlots;
+
+ bool m_IsUncompressedBlock;
+ bool m_AlignIsUsed;
+
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kNumLenSymbols> m_LenDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ Byte m_LastMainLevels[kMainTableSize];
+ Byte m_LastLenLevels[kNumLenSymbols];
+
+ Cx86ConvertOutStream *m_x86ConvertOutStreamSpec;
+ CMyComPtr<ISequentialOutStream> m_x86ConvertOutStream;
+
+ UInt32 m_UnCompressedBlockSize;
+
+ bool _keepHistory;
+ int _remainLen;
+ bool _skipByte;
+
+ bool _wimMode;
+
+ UInt32 ReadBits(unsigned numBits);
+ bool ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols);
+ bool ReadTables();
+ void ClearPrevLevels();
+
+ HRESULT CodeSpec(UInt32 size);
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+public:
+ CDecoder(bool wimMode = false);
+
+ MY_UNKNOWN_IMP
+
+ void ReleaseStreams();
+ STDMETHOD(Flush)();
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ HRESULT SetParams(unsigned numDictBits);
+ void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Mtf8.h b/src/libs/7zip/win/CPP/7zip/Compress/Mtf8.h
new file mode 100644
index 000000000..d15dd4a56
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Mtf8.h
@@ -0,0 +1,193 @@
+// Mtf8.h
+
+#ifndef __COMPRESS_MTF8_H
+#define __COMPRESS_MTF8_H
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/Types.h"
+
+namespace NCompress {
+
+struct CMtf8Encoder
+{
+ Byte Buf[256];
+
+ int FindAndMove(Byte v)
+ {
+ int pos;
+ for (pos = 0; Buf[pos] != v; pos++);
+ int resPos = pos;
+ for (; pos >= 8; pos -= 8)
+ {
+ Buf[pos] = Buf[pos - 1];
+ Buf[pos - 1] = Buf[pos - 2];
+ Buf[pos - 2] = Buf[pos - 3];
+ Buf[pos - 3] = Buf[pos - 4];
+ Buf[pos - 4] = Buf[pos - 5];
+ Buf[pos - 5] = Buf[pos - 6];
+ Buf[pos - 6] = Buf[pos - 7];
+ Buf[pos - 7] = Buf[pos - 8];
+ }
+ for (; pos > 0; pos--)
+ Buf[pos] = Buf[pos - 1];
+ Buf[0] = v;
+ return resPos;
+ }
+};
+
+/*
+struct CMtf8Decoder
+{
+ Byte Buf[256];
+
+ void Init(int) {};
+ Byte GetHead() const { return Buf[0]; }
+ Byte GetAndMove(int pos)
+ {
+ Byte res = Buf[pos];
+ for (; pos >= 8; pos -= 8)
+ {
+ Buf[pos] = Buf[pos - 1];
+ Buf[pos - 1] = Buf[pos - 2];
+ Buf[pos - 2] = Buf[pos - 3];
+ Buf[pos - 3] = Buf[pos - 4];
+ Buf[pos - 4] = Buf[pos - 5];
+ Buf[pos - 5] = Buf[pos - 6];
+ Buf[pos - 6] = Buf[pos - 7];
+ Buf[pos - 7] = Buf[pos - 8];
+ }
+ for (; pos > 0; pos--)
+ Buf[pos] = Buf[pos - 1];
+ Buf[0] = res;
+ return res;
+ }
+};
+*/
+
+#ifdef MY_CPU_64BIT
+typedef UInt64 CMtfVar;
+#define MTF_MOVS 3
+#else
+typedef UInt32 CMtfVar;
+#define MTF_MOVS 2
+#endif
+
+#define MTF_MASK ((1 << MTF_MOVS) - 1)
+
+
+struct CMtf8Decoder
+{
+ CMtfVar Buf[256 >> MTF_MOVS];
+
+ void StartInit() { memset(Buf, 0, sizeof(Buf)); }
+ void Add(unsigned int pos, Byte val) { Buf[pos >> MTF_MOVS] |= ((CMtfVar)val << ((pos & MTF_MASK) << 3)); }
+ Byte GetHead() const { return (Byte)Buf[0]; }
+ Byte GetAndMove(unsigned int pos)
+ {
+ UInt32 lim = ((UInt32)pos >> MTF_MOVS);
+ pos = (pos & MTF_MASK) << 3;
+ CMtfVar prev = (Buf[lim] >> pos) & 0xFF;
+
+ UInt32 i = 0;
+ if ((lim & 1) != 0)
+ {
+ CMtfVar next = Buf[0];
+ Buf[0] = (next << 8) | prev;
+ prev = (next >> (MTF_MASK << 3));
+ i = 1;
+ lim -= 1;
+ }
+ for (; i < lim; i += 2)
+ {
+ CMtfVar n0 = Buf[i];
+ CMtfVar n1 = Buf[i + 1];
+ Buf[i ] = (n0 << 8) | prev;
+ Buf[i + 1] = (n1 << 8) | (n0 >> (MTF_MASK << 3));
+ prev = (n1 >> (MTF_MASK << 3));
+ }
+ CMtfVar next = Buf[i];
+ CMtfVar mask = (((CMtfVar)0x100 << pos) - 1);
+ Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask);
+ return (Byte)Buf[0];
+ }
+};
+
+/*
+const int kSmallSize = 64;
+class CMtf8Decoder
+{
+ Byte SmallBuffer[kSmallSize];
+ int SmallSize;
+ Byte Counts[16];
+ int Size;
+public:
+ Byte Buf[256];
+
+ Byte GetHead() const
+ {
+ if (SmallSize > 0)
+ return SmallBuffer[kSmallSize - SmallSize];
+ return Buf[0];
+ }
+
+ void Init(int size)
+ {
+ Size = size;
+ SmallSize = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ Counts[i] = ((size >= 16) ? 16 : size);
+ size -= Counts[i];
+ }
+ }
+
+ Byte GetAndMove(int pos)
+ {
+ if (pos < SmallSize)
+ {
+ Byte *p = SmallBuffer + kSmallSize - SmallSize;
+ Byte res = p[pos];
+ for (; pos > 0; pos--)
+ p[pos] = p[pos - 1];
+ SmallBuffer[kSmallSize - SmallSize] = res;
+ return res;
+ }
+ if (SmallSize == kSmallSize)
+ {
+ int i = Size - 1;
+ int g = 16;
+ do
+ {
+ g--;
+ int offset = (g << 4);
+ for (int t = Counts[g] - 1; t >= 0; t--, i--)
+ Buf[i] = Buf[offset + t];
+ }
+ while(g != 0);
+
+ for (i = kSmallSize - 1; i >= 0; i--)
+ Buf[i] = SmallBuffer[i];
+ Init(Size);
+ }
+ pos -= SmallSize;
+ int g;
+ for (g = 0; pos >= Counts[g]; g++)
+ pos -= Counts[g];
+ int offset = (g << 4);
+ Byte res = Buf[offset + pos];
+ for (pos; pos < 16 - 1; pos++)
+ Buf[offset + pos] = Buf[offset + pos + 1];
+
+ SmallSize++;
+ SmallBuffer[kSmallSize - SmallSize] = res;
+
+ Counts[g]--;
+ return res;
+ }
+};
+*/
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/PpmdDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/PpmdDecoder.cpp
new file mode 100644
index 000000000..c02f44f16
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/PpmdDecoder.cpp
@@ -0,0 +1,167 @@
+// PpmdDecoder.cpp
+// 2009-03-11 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "PpmdDecoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+static const UInt32 kBufSize = (1 << 20);
+
+enum
+{
+ kStatus_NeedInit,
+ kStatus_Normal,
+ kStatus_Finished,
+ kStatus_Error
+};
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+CDecoder::~CDecoder()
+{
+ ::MidFree(_outBuf);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
+{
+ if (size < 5)
+ return E_INVALIDARG;
+ _order = props[0];
+ UInt32 memSize = GetUi32(props + 1);
+ if (_order < PPMD7_MIN_ORDER ||
+ _order > PPMD7_MAX_ORDER ||
+ memSize < PPMD7_MIN_MEM_SIZE ||
+ memSize > PPMD7_MAX_MEM_SIZE)
+ return E_NOTIMPL;
+ if (!_inStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
+{
+ switch(_status)
+ {
+ case kStatus_Finished: return S_OK;
+ case kStatus_Error: return S_FALSE;
+ case kStatus_NeedInit:
+ _inStream.Init();
+ if (!Ppmd7z_RangeDec_Init(&_rangeDec))
+ {
+ _status = kStatus_Error;
+ return S_FALSE;
+ }
+ _status = kStatus_Normal;
+ Ppmd7_Init(&_ppmd, _order);
+ break;
+ }
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _processedSize;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ UInt32 i;
+ int sym = 0;
+ for (i = 0; i != size; i++)
+ {
+ sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.p);
+ if (_inStream.Extra || sym < 0)
+ break;
+ memStream[i] = (Byte)sym;
+ }
+
+ _processedSize += i;
+ if (_inStream.Extra)
+ {
+ _status = kStatus_Error;
+ return _inStream.Res;
+ }
+ if (sym < 0)
+ _status = (sym < -1) ? kStatus_Error : kStatus_Finished;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (!_outBuf)
+ {
+ _outBuf = (Byte *)::MidAlloc(kBufSize);
+ if (!_outBuf)
+ return E_OUTOFMEMORY;
+ }
+
+ _inStream.Stream = inStream;
+ SetOutStreamSize(outSize);
+
+ do
+ {
+ const UInt64 startPos = _processedSize;
+ HRESULT res = CodeSpec(_outBuf, kBufSize);
+ size_t processed = (size_t)(_processedSize - startPos);
+ RINOK(WriteStream(outStream, _outBuf, processed));
+ RINOK(res);
+ if (_status == kStatus_Finished)
+ break;
+ if (progress)
+ {
+ UInt64 inSize = _inStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
+ }
+ }
+ while (!_outSizeDefined || _processedSize < _outSize);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+ _processedSize = 0;
+ _status = kStatus_NeedInit;
+ return S_OK;
+}
+
+#ifndef NO_READ_FROM_CODER
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
+{
+ InSeqStream = inStream;
+ _inStream.Stream = inStream;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::ReleaseInStream()
+{
+ InSeqStream.Release();
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ const UInt64 startPos = _processedSize;
+ HRESULT res = CodeSpec((Byte *)data, size);
+ if (processedSize)
+ *processedSize = (UInt32)(_processedSize - startPos);
+ return res;
+}
+
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/PpmdDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/PpmdDecoder.h
new file mode 100644
index 000000000..8ebcd700c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/PpmdDecoder.h
@@ -0,0 +1,78 @@
+// PpmdDecoder.h
+// 2009-03-11 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_PPMD_DECODER_H
+#define __COMPRESS_PPMD_DECODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../Common/CWrappers.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+class CDecoder :
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ #ifndef NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ Byte *_outBuf;
+ CPpmd7z_RangeDec _rangeDec;
+ CByteInBufWrap _inStream;
+ CPpmd7 _ppmd;
+
+ Byte _order;
+ bool _outSizeDefined;
+ int _status;
+ UInt64 _outSize;
+ UInt64 _processedSize;
+
+ HRESULT CodeSpec(Byte *memStream, UInt32 size);
+
+public:
+
+ #ifndef NO_READ_FROM_CODER
+ CMyComPtr<ISequentialInStream> InSeqStream;
+ MY_UNKNOWN_IMP4(
+ ICompressSetDecoderProperties2,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream)
+ #else
+ MY_UNKNOWN_IMP1(
+ ICompressSetDecoderProperties2)
+ #endif
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ #ifndef NO_READ_FROM_CODER
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+ CDecoder(): _outBuf(NULL), _outSizeDefined(false)
+ {
+ Ppmd7z_RangeDec_CreateVTable(&_rangeDec);
+ _rangeDec.Stream = &_inStream.p;
+ Ppmd7_Construct(&_ppmd);
+ }
+
+ ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/PpmdEncoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/PpmdEncoder.cpp
new file mode 100644
index 000000000..d823ffe85
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/PpmdEncoder.cpp
@@ -0,0 +1,119 @@
+// PpmdEncoder.cpp
+// 2009-03-11 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "PpmdEncoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+static const UInt32 kBufSize = (1 << 20);
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+CEncoder::CEncoder():
+ _inBuf(NULL),
+ _usedMemSize(1 << 24),
+ _order(6)
+{
+ _rangeEnc.Stream = &_outStream.p;
+ Ppmd7_Construct(&_ppmd);
+}
+
+CEncoder::~CEncoder()
+{
+ ::MidFree(_inBuf);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = (UInt32)prop.ulVal;
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kUsedMemorySize:
+ if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0)
+ return E_INVALIDARG;
+ _usedMemSize = v;
+ break;
+ case NCoderPropID::kOrder:
+ if (v < 2 || v > 32)
+ return E_INVALIDARG;
+ _order = (Byte)v;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ const UInt32 kPropSize = 5;
+ Byte props[kPropSize];
+ props[0] = _order;
+ SetUi32(props + 1, _usedMemSize);
+ return WriteStream(outStream, props, kPropSize);
+}
+
+HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ if (!_inBuf)
+ {
+ _inBuf = (Byte *)::MidAlloc(kBufSize);
+ if (!_inBuf)
+ return E_OUTOFMEMORY;
+ }
+ if (!_outStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd7_Alloc(&_ppmd, _usedMemSize, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ _outStream.Stream = outStream;
+ _outStream.Init();
+
+ Ppmd7z_RangeEnc_Init(&_rangeEnc);
+ Ppmd7_Init(&_ppmd, _order);
+
+ UInt64 processed = 0;
+ for (;;)
+ {
+ UInt32 size;
+ RINOK(inStream->Read(_inBuf, kBufSize, &size));
+ if (size == 0)
+ {
+ // We don't write EndMark in PPMD-7z.
+ // Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1);
+ Ppmd7z_RangeEnc_FlushData(&_rangeEnc);
+ return _outStream.Flush();
+ }
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]);
+ RINOK(_outStream.Res);
+ }
+ processed += size;
+ if (progress)
+ {
+ UInt64 outSize = _outStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&processed, &outSize));
+ }
+ }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/PpmdEncoder.h b/src/libs/7zip/win/CPP/7zip/Compress/PpmdEncoder.h
new file mode 100644
index 000000000..ed8b37131
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/PpmdEncoder.h
@@ -0,0 +1,48 @@
+// PpmdEncoder.h
+// 2009-03-11 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_PPMD_ENCODER_H
+#define __COMPRESS_PPMD_ENCODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/CWrappers.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+class CEncoder :
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public CMyUnknownImp
+{
+ Byte *_inBuf;
+ CByteOutBufWrap _outStream;
+ CPpmd7z_RangeEnc _rangeEnc;
+ CPpmd7 _ppmd;
+
+ UInt32 _usedMemSize;
+ Byte _order;
+
+public:
+ MY_UNKNOWN_IMP2(
+ ICompressSetCoderProperties,
+ ICompressWriteCoderProperties)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+
+ CEncoder();
+ ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/PpmdRegister.cpp b/src/libs/7zip/win/CPP/7zip/Compress/PpmdRegister.cpp
new file mode 100644
index 000000000..9f59fcdd3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/PpmdRegister.cpp
@@ -0,0 +1,21 @@
+// PpmdRegister.cpp
+// 2009-05-30 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "PpmdDecoder.h"
+
+static void *CreateCodec() { return (void *)(ICompressCoder *)(new NCompress::NPpmd::CDecoder); }
+#ifndef EXTRACT_ONLY
+#include "PpmdEncoder.h"
+static void *CreateCodecOut() { return (void *)(ICompressCoder *)(new NCompress::NPpmd::CEncoder); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x030401, L"PPMD", 1, false };
+
+REGISTER_CODEC(PPMD)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp b/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp
new file mode 100644
index 000000000..e83d979c3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.cpp
@@ -0,0 +1,223 @@
+// PpmdZip.cpp
+// 2010-03-24 : Igor Pavlov : Public domain
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "PpmdZip.h"
+
+namespace NCompress {
+namespace NPpmdZip {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+CDecoder::CDecoder(bool fullFileMode):
+ _fullFileMode(fullFileMode)
+{
+ _ppmd.Stream.In = &_inStream.p;
+ Ppmd8_Construct(&_ppmd);
+}
+
+CDecoder::~CDecoder()
+{
+ Ppmd8_Free(&_ppmd, &g_BigAlloc);
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (!_outStream.Alloc())
+ return E_OUTOFMEMORY;
+ if (!_inStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+
+ _inStream.Stream = inStream;
+ _inStream.Init();
+
+ {
+ Byte buf[2];
+ for (int i = 0; i < 2; i++)
+ buf[i] = _inStream.ReadByte();
+ if (_inStream.Extra)
+ return S_FALSE;
+
+ UInt32 val = GetUi16(buf);
+ UInt32 order = (val & 0xF) + 1;
+ UInt32 mem = ((val >> 4) & 0xFF) + 1;
+ UInt32 restor = (val >> 12);
+ if (order < 2 || restor > 2)
+ return S_FALSE;
+
+ #ifndef PPMD8_FREEZE_SUPPORT
+ if (restor == 2)
+ return E_NOTIMPL;
+ #endif
+
+ if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ if (!Ppmd8_RangeDec_Init(&_ppmd))
+ return S_FALSE;
+ Ppmd8_Init(&_ppmd, order, restor);
+ }
+
+ bool wasFinished = false;
+ UInt64 processedSize = 0;
+ while (!outSize || processedSize < *outSize)
+ {
+ size_t size = kBufSize;
+ if (outSize != NULL)
+ {
+ const UInt64 rem = *outSize - processedSize;
+ if (size > rem)
+ size = (size_t)rem;
+ }
+ Byte *data = _outStream.Buf;
+ size_t i = 0;
+ int sym = 0;
+ do
+ {
+ sym = Ppmd8_DecodeSymbol(&_ppmd);
+ if (_inStream.Extra || sym < 0)
+ break;
+ data[i] = (Byte)sym;
+ }
+ while (++i != size);
+ processedSize += i;
+
+ RINOK(WriteStream(outStream, _outStream.Buf, i));
+
+ RINOK(_inStream.Res);
+ if (_inStream.Extra)
+ return S_FALSE;
+
+ if (sym < 0)
+ {
+ if (sym != -1)
+ return S_FALSE;
+ wasFinished = true;
+ break;
+ }
+ if (progress)
+ {
+ UInt64 inSize = _inStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&inSize, &processedSize));
+ }
+ }
+ RINOK(_inStream.Res);
+ if (_fullFileMode)
+ {
+ if (!wasFinished)
+ {
+ int res = Ppmd8_DecodeSymbol(&_ppmd);
+ RINOK(_inStream.Res);
+ if (_inStream.Extra || res != -1)
+ return S_FALSE;
+ }
+ if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd))
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+
+// ---------- Encoder ----------
+
+CEncoder::~CEncoder()
+{
+ Ppmd8_Free(&_ppmd, &g_BigAlloc);
+}
+
+HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = (UInt32)prop.ulVal;
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kAlgorithm:
+ if (v > 1)
+ return E_INVALIDARG;
+ _restor = v;
+ break;
+ case NCoderPropID::kUsedMemorySize:
+ if (v < (1 << 20) || v > (1 << 28))
+ return E_INVALIDARG;
+ _usedMemInMB = v >> 20;
+ break;
+ case NCoderPropID::kOrder:
+ if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER)
+ return E_INVALIDARG;
+ _order = (Byte)v;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+CEncoder::CEncoder():
+ _usedMemInMB(16),
+ _order(6),
+ _restor(PPMD8_RESTORE_METHOD_RESTART)
+{
+ _ppmd.Stream.Out = &_outStream.p;
+ Ppmd8_Construct(&_ppmd);
+}
+
+HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ if (!_inStream.Alloc())
+ return E_OUTOFMEMORY;
+ if (!_outStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd8_Alloc(&_ppmd, _usedMemInMB << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ _outStream.Stream = outStream;
+ _outStream.Init();
+
+ Ppmd8_RangeEnc_Init(&_ppmd);
+ Ppmd8_Init(&_ppmd, _order, _restor);
+
+ UInt32 val = (UInt32)((_order - 1) + ((_usedMemInMB - 1) << 4) + (_restor << 12));
+ _outStream.WriteByte((Byte)(val & 0xFF));
+ _outStream.WriteByte((Byte)(val >> 8));
+ RINOK(_outStream.Res);
+
+ UInt64 processed = 0;
+ for (;;)
+ {
+ UInt32 size;
+ RINOK(inStream->Read(_inStream.Buf, kBufSize, &size));
+ if (size == 0)
+ {
+ Ppmd8_EncodeSymbol(&_ppmd, -1);
+ Ppmd8_RangeEnc_FlushData(&_ppmd);
+ return _outStream.Flush();
+ }
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Ppmd8_EncodeSymbol(&_ppmd, _inStream.Buf[i]);
+ RINOK(_outStream.Res);
+ }
+ processed += size;
+ if (progress != NULL)
+ {
+ UInt64 outSize = _outStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&processed, &outSize));
+ }
+ }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.h b/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.h
new file mode 100644
index 000000000..c2288b5af
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/PpmdZip.h
@@ -0,0 +1,72 @@
+// PpmdZip.h
+// 2010-03-11 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_PPMD_ZIP_H
+#define __COMPRESS_PPMD_ZIP_H
+
+#include "../../../C/Alloc.h"
+#include "../../../C/Ppmd8.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../Common/CWrappers.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NPpmdZip {
+
+static const UInt32 kBufSize = (1 << 20);
+
+struct CBuf
+{
+ Byte *Buf;
+
+ CBuf(): Buf(0) {}
+ ~CBuf() { ::MidFree(Buf); }
+ bool Alloc()
+ {
+ if (!Buf)
+ Buf = (Byte *)::MidAlloc(kBufSize);
+ return (Buf != 0);
+ }
+};
+
+class CDecoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CByteInBufWrap _inStream;
+ CBuf _outStream;
+ CPpmd8 _ppmd;
+ bool _fullFileMode;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ CDecoder(bool fullFileMode);
+ ~CDecoder();
+};
+
+class CEncoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CByteOutBufWrap _outStream;
+ CBuf _inStream;
+ CPpmd8 _ppmd;
+ UInt32 _usedMemInMB;
+ unsigned _order;
+ unsigned _restor;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+ CEncoder();
+ ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/QuantumDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/QuantumDecoder.cpp
new file mode 100644
index 000000000..501bd0e1f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/QuantumDecoder.cpp
@@ -0,0 +1,175 @@
+// QuantumDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+
+#include "QuantumDecoder.h"
+
+namespace NCompress {
+namespace NQuantum {
+
+static const int kLenIdNeedInit = -2;
+
+static const unsigned kNumLenSymbols = 27;
+static const unsigned kMatchMinLen = 3;
+static const unsigned kNumSimplePosSlots = 4;
+static const unsigned kNumSimpleLenSlots = 6;
+
+void CDecoder::Init()
+{
+ m_Selector.Init(kNumSelectors);
+ unsigned i;
+ for (i = 0; i < kNumLitSelectors; i++)
+ m_Literals[i].Init(kNumLitSymbols);
+ unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1));
+ const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 };
+ for (i = 0; i < kNumMatchSelectors; i++)
+ m_PosSlot[i].Init(MyMin(numItems, kNumPosSymbolsMax[i]));
+ m_LenSlot.Init(kNumLenSymbols);
+}
+
+HRESULT CDecoder::CodeSpec(UInt32 curSize)
+{
+ if (_remainLen == kLenIdNeedInit)
+ {
+ if (!_keepHistory)
+ {
+ if (!_outWindowStream.Create((UInt32)1 << _numDictBits))
+ return E_OUTOFMEMORY;
+ Init();
+ }
+ if (!_rangeDecoder.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ _rangeDecoder.Init();
+ _remainLen = 0;
+ }
+ if (curSize == 0)
+ return S_OK;
+
+ while (_remainLen > 0 && curSize > 0)
+ {
+ _remainLen--;
+ Byte b = _outWindowStream.GetByte(_rep0);
+ _outWindowStream.PutByte(b);
+ curSize--;
+ }
+
+ while (curSize > 0)
+ {
+ if (_rangeDecoder.Stream.WasFinished())
+ return S_FALSE;
+
+ unsigned selector = m_Selector.Decode(&_rangeDecoder);
+ if (selector < kNumLitSelectors)
+ {
+ Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder));
+ _outWindowStream.PutByte(b);
+ curSize--;
+ }
+ else
+ {
+ selector -= kNumLitSelectors;
+ unsigned len = selector + kMatchMinLen;
+ if (selector == 2)
+ {
+ unsigned lenSlot = m_LenSlot.Decode(&_rangeDecoder);
+ if (lenSlot >= kNumSimpleLenSlots)
+ {
+ lenSlot -= 2;
+ int numDirectBits = (int)(lenSlot >> 2);
+ len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
+ if (numDirectBits < 6)
+ len += _rangeDecoder.Stream.ReadBits(numDirectBits);
+ }
+ else
+ len += lenSlot;
+ }
+ UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder);
+ if (rep0 >= kNumSimplePosSlots)
+ {
+ int numDirectBits = (int)((rep0 >> 1) - 1);
+ rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits);
+ }
+ unsigned locLen = len;
+ if (len > curSize)
+ locLen = (unsigned)curSize;
+ if (!_outWindowStream.CopyBlock(rep0, locLen))
+ return S_FALSE;
+ curSize -= locLen;
+ len -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (int)len;
+ _rep0 = rep0;
+ break;
+ }
+ }
+ }
+ return _rangeDecoder.Stream.WasFinished() ? S_FALSE : S_OK;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (outSize == NULL)
+ return E_INVALIDARG;
+ UInt64 size = *outSize;
+
+ SetInStream(inStream);
+ _outWindowStream.SetStream(outStream);
+ SetOutStreamSize(outSize);
+ CDecoderFlusher flusher(this);
+
+ const UInt64 start = _outWindowStream.GetProcessedSize();
+ for (;;)
+ {
+ UInt32 curSize = 1 << 18;
+ UInt64 rem = size - (_outWindowStream.GetProcessedSize() - start);
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ if (curSize == 0)
+ break;
+ RINOK(CodeSpec(curSize));
+ if (progress != NULL)
+ {
+ UInt64 inSize = _rangeDecoder.GetProcessedSize();
+ UInt64 nowPos64 = _outWindowStream.GetProcessedSize() - start;
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+ }
+ }
+ flusher.NeedFlush = false;
+ return Flush();
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
+{
+ _rangeDecoder.SetStream(inStream);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::ReleaseInStream()
+{
+ _rangeDecoder.ReleaseStream();
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ if (outSize == NULL)
+ return E_FAIL;
+ _remainLen = kLenIdNeedInit;
+ _outWindowStream.Init(_keepHistory);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/QuantumDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/QuantumDecoder.h
new file mode 100644
index 000000000..e9ab023ba
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/QuantumDecoder.h
@@ -0,0 +1,264 @@
+// QuantumDecoder.h
+
+#ifndef __COMPRESS_QUANTUM_DECODER_H
+#define __COMPRESS_QUANTUM_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NQuantum {
+
+class CStreamBitDecoder
+{
+ UInt32 Value;
+ CInBuffer Stream;
+public:
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ void Finish() { Value = 0x10000; }
+
+ void Init()
+ {
+ Stream.Init();
+ Value = 0x10000;
+ }
+
+ UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
+ bool WasFinished() const { return Stream.WasFinished(); }
+
+ UInt32 ReadBit()
+ {
+ if (Value >= 0x10000)
+ Value = 0x100 | Stream.ReadByte();
+ UInt32 res = (Value >> 7) & 1;
+ Value <<= 1;
+ return res;
+ }
+
+ UInt32 ReadBits(int numBits) // numBits > 0
+ {
+ UInt32 res = 0;
+ do
+ res = (res << 1) | ReadBit();
+ while (--numBits != 0);
+ return res;
+ }
+};
+
+const unsigned kNumLitSelectorBits = 2;
+const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits);
+const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
+const unsigned kNumMatchSelectors = 3;
+const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
+const unsigned kNumSymbolsMax = kNumLitSymbols; // 64
+
+namespace NRangeCoder {
+
+class CDecoder
+{
+ UInt32 Low;
+ UInt32 Range;
+ UInt32 Code;
+public:
+ CStreamBitDecoder Stream;
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ void Init()
+ {
+ Stream.Init();
+ Low = 0;
+ Range = 0x10000;
+ Code = Stream.ReadBits(16);
+ }
+
+ void Finish()
+ {
+ // we need these extra two Bit_reads
+ Stream.ReadBit();
+ Stream.ReadBit();
+ Stream.Finish();
+ }
+
+ UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
+
+ UInt32 GetThreshold(UInt32 total) const
+ {
+ return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
+ }
+
+ void Decode(UInt32 start, UInt32 end, UInt32 total)
+ {
+ UInt32 high = Low + end * Range / total - 1;
+ UInt32 offset = start * Range / total;
+ Code -= offset;
+ Low += offset;
+ for (;;)
+ {
+ if ((Low & 0x8000) != (high & 0x8000))
+ {
+ if ((Low & 0x4000) == 0 || (high & 0x4000) != 0)
+ break;
+ Low &= 0x3FFF;
+ high |= 0x4000;
+ }
+ Low = (Low << 1) & 0xFFFF;
+ high = ((high << 1) | 1) & 0xFFFF;
+ Code = ((Code << 1) | Stream.ReadBit());
+ }
+ Range = high - Low + 1;
+ }
+};
+
+const UInt16 kUpdateStep = 8;
+const UInt16 kFreqSumMax = 3800;
+const UInt16 kReorderCountStart = 4;
+const UInt16 kReorderCount = 50;
+
+class CModelDecoder
+{
+ unsigned NumItems;
+ unsigned ReorderCount;
+ UInt16 Freqs[kNumSymbolsMax + 1];
+ Byte Values[kNumSymbolsMax];
+public:
+ void Init(unsigned numItems)
+ {
+ NumItems = numItems;
+ ReorderCount = kReorderCountStart;
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ Freqs[i] = (UInt16)(numItems - i);
+ Values[i] = (Byte)i;
+ }
+ Freqs[numItems] = 0;
+ }
+
+ unsigned Decode(CDecoder *rangeDecoder)
+ {
+ UInt32 threshold = rangeDecoder->GetThreshold(Freqs[0]);
+ unsigned i;
+ for (i = 1; Freqs[i] > threshold; i++);
+ rangeDecoder->Decode(Freqs[i], Freqs[i - 1], Freqs[0]);
+ unsigned res = Values[--i];
+ do
+ Freqs[i] += kUpdateStep;
+ while (i-- != 0);
+
+ if (Freqs[0] > kFreqSumMax)
+ {
+ if (--ReorderCount == 0)
+ {
+ ReorderCount = kReorderCount;
+ for (i = 0; i < NumItems; i++)
+ Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1);
+ for (i = 0; i < NumItems - 1; i++)
+ for (unsigned j = i + 1; j < NumItems; j++)
+ if (Freqs[i] < Freqs[j])
+ {
+ UInt16 tmpFreq = Freqs[i];
+ Byte tmpVal = Values[i];
+ Freqs[i] = Freqs[j];
+ Values[i] = Values[j];
+ Freqs[j] = tmpFreq;
+ Values[j] = tmpVal;
+ }
+ do
+ Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]);
+ while (i-- != 0);
+ }
+ else
+ {
+ i = NumItems - 1;
+ do
+ {
+ Freqs[i] >>= 1;
+ if (Freqs[i] <= Freqs[i + 1])
+ Freqs[i] = (UInt16)(Freqs[i + 1] + 1);
+ }
+ while (i-- != 0);
+ }
+ }
+ return res;
+ }
+};
+
+}
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public CMyUnknownImp
+{
+ CLzOutWindow _outWindowStream;
+ NRangeCoder::CDecoder _rangeDecoder;
+
+ UInt64 _outSize;
+ int _remainLen; // -1 means end of stream. // -2 means need Init
+ UInt32 _rep0;
+
+ int _numDictBits;
+ bool _keepHistory;
+
+ NRangeCoder::CModelDecoder m_Selector;
+ NRangeCoder::CModelDecoder m_Literals[kNumLitSelectors];
+ NRangeCoder::CModelDecoder m_PosSlot[kNumMatchSelectors];
+ NRangeCoder::CModelDecoder m_LenSlot;
+ void Init();
+ HRESULT CodeSpec(UInt32 size);
+public:
+ MY_UNKNOWN_IMP2(
+ ICompressSetInStream,
+ ICompressSetOutStreamSize)
+
+ void ReleaseStreams()
+ {
+ _outWindowStream.ReleaseStream();
+ ReleaseInStream();
+ }
+
+ class CDecoderFlusher
+ {
+ CDecoder *_decoder;
+ public:
+ bool NeedFlush;
+ CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ _decoder->Flush();
+ _decoder->ReleaseStreams();
+ }
+ };
+
+ HRESULT Flush() { return _outWindowStream.Flush(); }
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ void SetParams(int numDictBits) { _numDictBits = numDictBits; }
+ void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+ CDecoder(): _keepHistory(false) {}
+ virtual ~CDecoder() {}
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/RangeCoder.h b/src/libs/7zip/win/CPP/7zip/Compress/RangeCoder.h
new file mode 100644
index 000000000..1eb2a6d47
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/RangeCoder.h
@@ -0,0 +1,205 @@
+// Compress/RangeCoder.h
+// 2009-05-30 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_RANGE_CODER_H
+#define __COMPRESS_RANGE_CODER_H
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const int kNumTopBits = 24;
+const UInt32 kTopValue = (1 << kNumTopBits);
+
+class CEncoder
+{
+ UInt32 _cacheSize;
+ Byte _cache;
+public:
+ UInt64 Low;
+ UInt32 Range;
+ COutBuffer Stream;
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+
+ void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); }
+ void Init()
+ {
+ Stream.Init();
+ Low = 0;
+ Range = 0xFFFFFFFF;
+ _cacheSize = 1;
+ _cache = 0;
+ }
+
+ void FlushData()
+ {
+ // Low += 1;
+ for(int i = 0; i < 5; i++)
+ ShiftLow();
+ }
+
+ HRESULT FlushStream() { return Stream.Flush(); }
+
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ void Encode(UInt32 start, UInt32 size, UInt32 total)
+ {
+ Low += start * (Range /= total);
+ Range *= size;
+ while (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+
+ void ShiftLow()
+ {
+ if ((UInt32)Low < (UInt32)0xFF000000 || (int)(Low >> 32) != 0)
+ {
+ Byte temp = _cache;
+ do
+ {
+ Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32)));
+ temp = 0xFF;
+ }
+ while(--_cacheSize != 0);
+ _cache = (Byte)((UInt32)Low >> 24);
+ }
+ _cacheSize++;
+ Low = (UInt32)Low << 8;
+ }
+
+ void EncodeDirectBits(UInt32 value, int numBits)
+ {
+ for (numBits--; numBits >= 0; numBits--)
+ {
+ Range >>= 1;
+ Low += Range & (0 - ((value >> numBits) & 1));
+ if (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+ }
+
+ void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol)
+ {
+ UInt32 newBound = (Range >> numTotalBits) * size0;
+ if (symbol == 0)
+ Range = newBound;
+ else
+ {
+ Low += newBound;
+ Range -= newBound;
+ }
+ while (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+
+ UInt64 GetProcessedSize() { return Stream.GetProcessedSize() + _cacheSize + 4; }
+};
+
+class CDecoder
+{
+public:
+ CInBuffer Stream;
+ UInt32 Range;
+ UInt32 Code;
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+
+ void Normalize()
+ {
+ while (Range < kTopValue)
+ {
+ Code = (Code << 8) | Stream.ReadByte();
+ Range <<= 8;
+ }
+ }
+
+ void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+ void Init()
+ {
+ Stream.Init();
+ Code = 0;
+ Range = 0xFFFFFFFF;
+ for(int i = 0; i < 5; i++)
+ Code = (Code << 8) | Stream.ReadByte();
+ }
+
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ UInt32 GetThreshold(UInt32 total)
+ {
+ return (Code) / ( Range /= total);
+ }
+
+ void Decode(UInt32 start, UInt32 size)
+ {
+ Code -= start * Range;
+ Range *= size;
+ Normalize();
+ }
+
+ UInt32 DecodeDirectBits(int numTotalBits)
+ {
+ UInt32 range = Range;
+ UInt32 code = Code;
+ UInt32 result = 0;
+ for (int i = numTotalBits; i != 0; i--)
+ {
+ range >>= 1;
+ /*
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ */
+ UInt32 t = (code - range) >> 31;
+ code -= range & (t - 1);
+ result = (result << 1) | (1 - t);
+
+ if (range < kTopValue)
+ {
+ code = (code << 8) | Stream.ReadByte();
+ range <<= 8;
+ }
+ }
+ Range = range;
+ Code = code;
+ return result;
+ }
+
+ UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits)
+ {
+ UInt32 newBound = (Range >> numTotalBits) * size0;
+ UInt32 symbol;
+ if (Code < newBound)
+ {
+ symbol = 0;
+ Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ Code -= newBound;
+ Range -= newBound;
+ }
+ Normalize();
+ return symbol;
+ }
+
+ UInt64 GetProcessedSize() {return Stream.GetProcessedSize(); }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/RangeCoderBit.h b/src/libs/7zip/win/CPP/7zip/Compress/RangeCoderBit.h
new file mode 100644
index 000000000..b5a1830d6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/RangeCoderBit.h
@@ -0,0 +1,114 @@
+// Compress/RangeCoderBit.h
+// 2009-05-30 : Igor Pavlov : Public domain
+
+#ifndef __COMPRESS_RANGE_CODER_BIT_H
+#define __COMPRESS_RANGE_CODER_BIT_H
+
+#include "RangeCoder.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const int kNumBitModelTotalBits = 11;
+const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits);
+
+const int kNumMoveReducingBits = 4;
+
+const int kNumBitPriceShiftBits = 4;
+const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits;
+
+extern UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+
+template <int numMoveBits>
+class CBitModel
+{
+public:
+ UInt32 Prob;
+ void UpdateModel(UInt32 symbol)
+ {
+ /*
+ Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits;
+ Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits);
+ */
+ if (symbol == 0)
+ Prob += (kBitModelTotal - Prob) >> numMoveBits;
+ else
+ Prob -= (Prob) >> numMoveBits;
+ }
+public:
+ void Init() { Prob = kBitModelTotal / 2; }
+};
+
+template <int numMoveBits>
+class CBitEncoder: public CBitModel<numMoveBits>
+{
+public:
+ void Encode(CEncoder *encoder, UInt32 symbol)
+ {
+ /*
+ encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol);
+ this->UpdateModel(symbol);
+ */
+ UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob;
+ if (symbol == 0)
+ {
+ encoder->Range = newBound;
+ this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+ }
+ else
+ {
+ encoder->Low += newBound;
+ encoder->Range -= newBound;
+ this->Prob -= (this->Prob) >> numMoveBits;
+ }
+ if (encoder->Range < kTopValue)
+ {
+ encoder->Range <<= 8;
+ encoder->ShiftLow();
+ }
+ }
+ UInt32 GetPrice(UInt32 symbol) const
+ {
+ return ProbPrices[(this->Prob ^ ((-(int)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
+ }
+ UInt32 GetPrice0() const { return ProbPrices[this->Prob >> kNumMoveReducingBits]; }
+ UInt32 GetPrice1() const { return ProbPrices[(this->Prob ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]; }
+};
+
+
+template <int numMoveBits>
+class CBitDecoder: public CBitModel<numMoveBits>
+{
+public:
+ UInt32 Decode(CDecoder *decoder)
+ {
+ UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob;
+ if (decoder->Code < newBound)
+ {
+ decoder->Range = newBound;
+ this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+ if (decoder->Range < kTopValue)
+ {
+ decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+ decoder->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ decoder->Range -= newBound;
+ decoder->Code -= newBound;
+ this->Prob -= (this->Prob) >> numMoveBits;
+ if (decoder->Range < kTopValue)
+ {
+ decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+ decoder->Range <<= 8;
+ }
+ return 1;
+ }
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Rar1Decoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Rar1Decoder.cpp
new file mode 100644
index 000000000..eadca7b3d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Rar1Decoder.cpp
@@ -0,0 +1,480 @@
+// Rar1Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+#include "Rar1Decoder.h"
+
+namespace NCompress {
+namespace NRar1 {
+
+static UInt32 PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32, 256};
+static UInt32 PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36, 256};
+static UInt32 PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33, 257};
+static UInt32 PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127, 257};
+static UInt32 PosHf2[]={0,0,0,0,0,0,2,7,53,117,233, 257,0};
+static UInt32 PosHf3[]={0,0,0,0,0,0,0,2,16,218,251, 257,0};
+static UInt32 PosHf4[]={0,0,0,0,0,0,0,0,0,255, 257,0,0};
+
+static const UInt32 kHistorySize = (1 << 16);
+
+class CCoderReleaser
+{
+ CDecoder *m_Coder;
+public:
+ CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
+};
+
+CDecoder::CDecoder(): m_IsSolid(false) { }
+
+void CDecoder::InitStructures()
+{
+ for(int i = 0; i < kNumRepDists; i++)
+ m_RepDists[i] = 0;
+ m_RepDistPtr = 0;
+ LastLength = 0;
+ LastDist = 0;
+}
+
+UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
+
+HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len)
+{
+ if (len == 0)
+ return S_FALSE;
+ m_UnpackSize -= len;
+ return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE;
+}
+
+
+UInt32 CDecoder::DecodeNum(const UInt32 *posTab)
+{
+ UInt32 startPos = 2;
+ UInt32 num = m_InBitStream.GetValue(12);
+ for (;;)
+ {
+ UInt32 cur = (posTab[startPos + 1] - posTab[startPos]) << (12 - startPos);
+ if (num < cur)
+ break;
+ startPos++;
+ num -= cur;
+ }
+ m_InBitStream.MovePos(startPos);
+ return((num >> (12 - startPos)) + posTab[startPos]);
+}
+
+static Byte kShortLen1[] = {1,3,4,4,5,6,7,8,8,4,4,5,6,6 };
+static Byte kShortLen1a[] = {1,4,4,4,5,6,7,8,8,4,4,5,6,6,4 };
+static Byte kShortLen2[] = {2,3,3,3,4,4,5,6,6,4,4,5,6,6 };
+static Byte kShortLen2a[] = {2,3,3,4,4,4,5,6,6,4,4,5,6,6,4 };
+static UInt32 kShortXor1[] = {0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0};
+static UInt32 kShortXor2[] = {0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0};
+
+HRESULT CDecoder::ShortLZ()
+{
+ UInt32 len, saveLen, dist;
+ int distancePlace;
+ Byte *kShortLen;
+ const UInt32 *kShortXor;
+ NumHuf = 0;
+
+ if (LCount == 2)
+ {
+ if (ReadBits(1))
+ return CopyBlock(LastDist, LastLength);
+ LCount = 0;
+ }
+
+ UInt32 bitField = m_InBitStream.GetValue(8);
+
+ if (AvrLn1 < 37)
+ {
+ kShortLen = Buf60 ? kShortLen1a : kShortLen1;
+ kShortXor = kShortXor1;
+ }
+ else
+ {
+ kShortLen = Buf60 ? kShortLen2a : kShortLen2;
+ kShortXor = kShortXor2;
+ }
+
+ for (len = 0; ((bitField ^ kShortXor[len]) & (~(0xff >> kShortLen[len]))) != 0; len++);
+ m_InBitStream.MovePos(kShortLen[len]);
+
+ if (len >= 9)
+ {
+ if (len == 9)
+ {
+ LCount++;
+ return CopyBlock(LastDist, LastLength);
+ }
+ if (len == 14)
+ {
+ LCount = 0;
+ len = DecodeNum(PosL2) + 5;
+ dist = 0x8000 + ReadBits(15) - 1;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+ }
+
+ LCount = 0;
+ saveLen = len;
+ dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3];
+ len = DecodeNum(PosL1) + 2;
+ if (len == 0x101 && saveLen == 10)
+ {
+ Buf60 ^= 1;
+ return S_OK;
+ }
+ if (dist >= 256)
+ len++;
+ if (dist >= MaxDist3 - 1)
+ len++;
+ }
+ else
+ {
+ LCount = 0;
+ AvrLn1 += len;
+ AvrLn1 -= AvrLn1 >> 4;
+
+ distancePlace = DecodeNum(PosHf2) & 0xff;
+ dist = ChSetA[distancePlace];
+ if (--distancePlace != -1)
+ {
+ PlaceA[dist]--;
+ UInt32 lastDistance = ChSetA[distancePlace];
+ PlaceA[lastDistance]++;
+ ChSetA[distancePlace + 1] = lastDistance;
+ ChSetA[distancePlace] = dist;
+ }
+ len += 2;
+ }
+ m_RepDists[m_RepDistPtr++] = dist;
+ m_RepDistPtr &= 3;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+}
+
+
+HRESULT CDecoder::LongLZ()
+{
+ UInt32 len;
+ UInt32 dist;
+ UInt32 distancePlace, newDistancePlace;
+ UInt32 oldAvr2, oldAvr3;
+
+ NumHuf = 0;
+ Nlzb += 16;
+ if (Nlzb > 0xff)
+ {
+ Nlzb = 0x90;
+ Nhfb >>= 1;
+ }
+ oldAvr2=AvrLn2;
+
+ if (AvrLn2 >= 122)
+ len = DecodeNum(PosL2);
+ else if (AvrLn2 >= 64)
+ len = DecodeNum(PosL1);
+ else
+ {
+ UInt32 bitField = m_InBitStream.GetValue(16);
+ if (bitField < 0x100)
+ {
+ len = bitField;
+ m_InBitStream.MovePos(16);
+ }
+ else
+ {
+ for (len = 0; ((bitField << len) & 0x8000) == 0; len++)
+ ;
+ m_InBitStream.MovePos(len + 1);
+ }
+ }
+
+ AvrLn2 += len;
+ AvrLn2 -= AvrLn2 >> 5;
+
+ if (AvrPlcB > 0x28ff)
+ distancePlace = DecodeNum(PosHf2);
+ else if (AvrPlcB > 0x6ff)
+ distancePlace = DecodeNum(PosHf1);
+ else
+ distancePlace = DecodeNum(PosHf0);
+
+ AvrPlcB += distancePlace;
+ AvrPlcB -= AvrPlcB >> 8;
+ for (;;)
+ {
+ dist = ChSetB[distancePlace & 0xff];
+ newDistancePlace = NToPlB[dist++ & 0xff]++;
+ if (!(dist & 0xff))
+ CorrHuff(ChSetB,NToPlB);
+ else
+ break;
+ }
+
+ ChSetB[distancePlace] = ChSetB[newDistancePlace];
+ ChSetB[newDistancePlace] = dist;
+
+ dist = ((dist & 0xff00) >> 1) | ReadBits(7);
+
+ oldAvr3 = AvrLn3;
+ if (len != 1 && len != 4)
+ if (len == 0 && dist <= MaxDist3)
+ {
+ AvrLn3++;
+ AvrLn3 -= AvrLn3 >> 8;
+ }
+ else
+ if (AvrLn3 > 0)
+ AvrLn3--;
+ len += 3;
+ if (dist >= MaxDist3)
+ len++;
+ if (dist <= 256)
+ len += 8;
+ if (oldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && oldAvr2 < 0x40)
+ MaxDist3 = 0x7f00;
+ else
+ MaxDist3 = 0x2001;
+ m_RepDists[m_RepDistPtr++] = --dist;
+ m_RepDistPtr &= 3;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+}
+
+
+HRESULT CDecoder::HuffDecode()
+{
+ UInt32 curByte, newBytePlace;
+ UInt32 len;
+ UInt32 dist;
+ int bytePlace;
+
+ if (AvrPlc > 0x75ff) bytePlace = DecodeNum(PosHf4);
+ else if (AvrPlc > 0x5dff) bytePlace = DecodeNum(PosHf3);
+ else if (AvrPlc > 0x35ff) bytePlace = DecodeNum(PosHf2);
+ else if (AvrPlc > 0x0dff) bytePlace = DecodeNum(PosHf1);
+ else bytePlace = DecodeNum(PosHf0);
+ if (StMode)
+ {
+ if (--bytePlace == -1)
+ {
+ if (ReadBits(1))
+ {
+ NumHuf = StMode = 0;
+ return S_OK;
+ }
+ else
+ {
+ len = (ReadBits(1)) ? 4 : 3;
+ dist = DecodeNum(PosHf2);
+ dist = (dist << 5) | ReadBits(5);
+ return CopyBlock(dist - 1, len);
+ }
+ }
+ }
+ else if (NumHuf++ >= 16 && FlagsCnt == 0)
+ StMode = 1;
+ bytePlace &= 0xff;
+ AvrPlc += bytePlace;
+ AvrPlc -= AvrPlc >> 8;
+ Nhfb+=16;
+ if (Nhfb > 0xff)
+ {
+ Nhfb=0x90;
+ Nlzb >>= 1;
+ }
+
+ m_UnpackSize --;
+ m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8));
+
+ for (;;)
+ {
+ curByte = ChSet[bytePlace];
+ newBytePlace = NToPl[curByte++ & 0xff]++;
+ if ((curByte & 0xff) > 0xa1)
+ CorrHuff(ChSet, NToPl);
+ else
+ break;
+ }
+
+ ChSet[bytePlace] = ChSet[newBytePlace];
+ ChSet[newBytePlace] = curByte;
+ return S_OK;
+}
+
+
+void CDecoder::GetFlagsBuf()
+{
+ UInt32 flags, newFlagsPlace;
+ UInt32 flagsPlace = DecodeNum(PosHf2);
+
+ for (;;)
+ {
+ flags = ChSetC[flagsPlace];
+ FlagBuf = flags >> 8;
+ newFlagsPlace = NToPlC[flags++ & 0xff]++;
+ if ((flags & 0xff) != 0)
+ break;
+ CorrHuff(ChSetC, NToPlC);
+ }
+
+ ChSetC[flagsPlace] = ChSetC[newFlagsPlace];
+ ChSetC[newFlagsPlace] = flags;
+}
+
+void CDecoder::InitData()
+{
+ if (!m_IsSolid)
+ {
+ AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0;
+ AvrPlc = 0x3500;
+ MaxDist3 = 0x2001;
+ Nhfb = Nlzb = 0x80;
+ }
+ FlagsCnt = 0;
+ FlagBuf = 0;
+ StMode = 0;
+ LCount = 0;
+}
+
+void CDecoder::CorrHuff(UInt32 *CharSet,UInt32 *NumToPlace)
+{
+ int i;
+ for (i = 7; i >= 0; i--)
+ for (int j = 0; j < 32; j++, CharSet++)
+ *CharSet = (*CharSet & ~0xff) | i;
+ memset(NumToPlace, 0, sizeof(NToPl));
+ for (i = 6; i >= 0; i--)
+ NumToPlace[i] = (7 - i) * 32;
+}
+
+void CDecoder::InitHuff()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ Place[i] = PlaceA[i] = PlaceB[i] = i;
+ PlaceC[i] = (~i + 1) & 0xff;
+ ChSet[i] = ChSetB[i] = i << 8;
+ ChSetA[i] = i;
+ ChSetC[i] = ((~i + 1) & 0xff) << 8;
+ }
+ memset(NToPl, 0, sizeof(NToPl));
+ memset(NToPlB, 0, sizeof(NToPlB));
+ memset(NToPlC, 0, sizeof(NToPlC));
+ CorrHuff(ChSetB, NToPlB);
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */)
+{
+ if (inSize == NULL || outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ m_UnpackSize = (Int64)*outSize;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(m_IsSolid);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+ InitData();
+ if (!m_IsSolid)
+ {
+ InitStructures();
+ InitHuff();
+ }
+ if (m_UnpackSize > 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 8;
+ }
+
+ while (m_UnpackSize > 0)
+ {
+ if (StMode)
+ {
+ RINOK(HuffDecode());
+ continue;
+ }
+
+ if (--FlagsCnt < 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt=7;
+ }
+
+ if (FlagBuf & 0x80)
+ {
+ FlagBuf <<= 1;
+ if (Nlzb > Nhfb)
+ {
+ RINOK(LongLZ());
+ }
+ else
+ {
+ RINOK(HuffDecode());
+ }
+ }
+ else
+ {
+ FlagBuf <<= 1;
+ if (--FlagsCnt < 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 7;
+ }
+ if (FlagBuf & 0x80)
+ {
+ FlagBuf <<= 1;
+ if (Nlzb > Nhfb)
+ {
+ RINOK(HuffDecode());
+ }
+ else
+ {
+ RINOK(LongLZ());
+ }
+ }
+ else
+ {
+ FlagBuf <<= 1;
+ RINOK(ShortLZ());
+ }
+ }
+ }
+ if (m_UnpackSize < 0)
+ return S_FALSE;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ m_IsSolid = (data[0] != 0);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Rar1Decoder.h b/src/libs/7zip/win/CPP/7zip/Compress/Rar1Decoder.h
new file mode 100644
index 000000000..f7c08b386
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Rar1Decoder.h
@@ -0,0 +1,88 @@
+// Rar1Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef __COMPRESS_RAR1_DECODER_H
+#define __COMPRESS_RAR1_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NRar1 {
+
+const UInt32 kNumRepDists = 4;
+
+typedef NBitm::CDecoder<CInBuffer> CBitDecoder;
+
+class CDecoder :
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+public:
+ CLzOutWindow m_OutWindowStream;
+ CBitDecoder m_InBitStream;
+
+ UInt32 m_RepDists[kNumRepDists];
+ UInt32 m_RepDistPtr;
+
+ UInt32 LastDist;
+ UInt32 LastLength;
+
+ Int64 m_UnpackSize;
+ bool m_IsSolid;
+
+ UInt32 ReadBits(int numBits);
+ HRESULT CopyBlock(UInt32 distance, UInt32 len);
+
+ UInt32 DecodeNum(const UInt32 *posTab);
+ HRESULT ShortLZ();
+ HRESULT LongLZ();
+ HRESULT HuffDecode();
+ void GetFlagsBuf();
+ void InitData();
+ void InitHuff();
+ void CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace);
+ void OldUnpWriteBuf();
+
+ UInt32 ChSet[256],ChSetA[256],ChSetB[256],ChSetC[256];
+ UInt32 Place[256],PlaceA[256],PlaceB[256],PlaceC[256];
+ UInt32 NToPl[256],NToPlB[256],NToPlC[256];
+ UInt32 FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3;
+ int Buf60,NumHuf,StMode,LCount,FlagsCnt;
+ UInt32 Nhfb,Nlzb,MaxDist3;
+
+ void InitStructures();
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+public:
+ CDecoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Rar2Decoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Rar2Decoder.cpp
new file mode 100644
index 000000000..4e669bd64
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Rar2Decoder.cpp
@@ -0,0 +1,391 @@
+// Rar2Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+#include "Rar2Decoder.h"
+
+namespace NCompress {
+namespace NRar2 {
+
+namespace NMultimedia {
+
+Byte CFilter::Decode(int &channelDelta, Byte deltaByte)
+{
+ D4 = D3;
+ D3 = D2;
+ D2 = LastDelta - D1;
+ D1 = LastDelta;
+ int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3);
+
+ Byte realValue = (Byte)(predictedValue - deltaByte);
+ int i = ((int)(signed char)deltaByte) << 3;
+
+ Dif[0] += abs(i);
+ Dif[1] += abs(i - D1);
+ Dif[2] += abs(i + D1);
+ Dif[3] += abs(i - D2);
+ Dif[4] += abs(i + D2);
+ Dif[5] += abs(i - D3);
+ Dif[6] += abs(i + D3);
+ Dif[7] += abs(i - D4);
+ Dif[8] += abs(i + D4);
+ Dif[9] += abs(i - channelDelta);
+ Dif[10] += abs(i + channelDelta);
+
+ channelDelta = LastDelta = (signed char)(realValue - LastChar);
+ LastChar = realValue;
+
+ if (((++ByteCount) & 0x1F) == 0)
+ {
+ UInt32 minDif = Dif[0];
+ UInt32 numMinDif = 0;
+ Dif[0] = 0;
+ for (i = 1; i < sizeof(Dif) / sizeof(Dif[0]); i++)
+ {
+ if (Dif[i] < minDif)
+ {
+ minDif = Dif[i];
+ numMinDif = i;
+ }
+ Dif[i] = 0;
+ }
+ switch(numMinDif)
+ {
+ case 1: if (K1 >= -16) K1--; break;
+ case 2: if (K1 < 16) K1++; break;
+ case 3: if (K2 >= -16) K2--; break;
+ case 4: if (K2 < 16) K2++; break;
+ case 5: if (K3 >= -16) K3--; break;
+ case 6: if (K3 < 16) K3++; break;
+ case 7: if (K4 >= -16) K4--; break;
+ case 8: if (K4 < 16) K4++; break;
+ case 9: if (K5 >= -16) K5--; break;
+ case 10:if (K5 < 16) K5++; break;
+ }
+ }
+ return realValue;
+}
+}
+
+static const char *kNumberErrorMessage = "Number error";
+
+static const UInt32 kHistorySize = 1 << 20;
+
+static const int kNumStats = 11;
+
+static const UInt32 kWindowReservSize = (1 << 22) + 256;
+
+CDecoder::CDecoder():
+ m_IsSolid(false)
+{
+}
+
+void CDecoder::InitStructures()
+{
+ m_MmFilter.Init();
+ for(int i = 0; i < kNumRepDists; i++)
+ m_RepDists[i] = 0;
+ m_RepDistPtr = 0;
+ m_LastLength = 0;
+ memset(m_LastLevels, 0, kMaxTableSize);
+}
+
+UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CDecoder::ReadTables(void)
+{
+ Byte levelLevels[kLevelTableSize];
+ Byte newLevels[kMaxTableSize];
+ m_AudioMode = (ReadBits(1) == 1);
+
+ if (ReadBits(1) == 0)
+ memset(m_LastLevels, 0, kMaxTableSize);
+ int numLevels;
+ if (m_AudioMode)
+ {
+ m_NumChannels = ReadBits(2) + 1;
+ if (m_MmFilter.CurrentChannel >= m_NumChannels)
+ m_MmFilter.CurrentChannel = 0;
+ numLevels = m_NumChannels * kMMTableSize;
+ }
+ else
+ numLevels = kHeapTablesSizesSum;
+
+ int i;
+ for (i = 0; i < kLevelTableSize; i++)
+ levelLevels[i] = (Byte)ReadBits(4);
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+ i = 0;
+ while (i < numLevels)
+ {
+ UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
+ if (number < kTableDirectLevels)
+ {
+ newLevels[i] = (Byte)((number + m_LastLevels[i]) & kLevelMask);
+ i++;
+ }
+ else
+ {
+ if (number == kTableLevelRepNumber)
+ {
+ int t = ReadBits(2) + 3;
+ for (int reps = t; reps > 0 && i < numLevels ; reps--, i++)
+ newLevels[i] = newLevels[i - 1];
+ }
+ else
+ {
+ int num;
+ if (number == kTableLevel0Number)
+ num = ReadBits(3) + 3;
+ else if (number == kTableLevel0Number2)
+ num = ReadBits(7) + 11;
+ else
+ return false;
+ for (;num > 0 && i < numLevels; num--)
+ newLevels[i++] = 0;
+ }
+ }
+ }
+ if (m_AudioMode)
+ for (i = 0; i < m_NumChannels; i++)
+ {
+ RIF(m_MMDecoders[i].SetCodeLengths(&newLevels[i * kMMTableSize]));
+ }
+ else
+ {
+ RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
+ RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
+ RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
+ }
+ memcpy(m_LastLevels, newLevels, kMaxTableSize);
+ return true;
+}
+
+bool CDecoder::ReadLastTables()
+{
+ // it differs a little from pure RAR sources;
+ // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2;
+ // + 2 works for: return 0xFF; in CInBuffer::ReadByte.
+ if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect;
+ // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
+ if (m_AudioMode)
+ {
+ UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
+ if (symbol == 256)
+ return ReadTables();
+ if (symbol >= kMMTableSize)
+ return false;
+ }
+ else
+ {
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ if (number == kReadTableNumber)
+ return ReadTables();
+ if (number >= kMainTableSize)
+ return false;
+ }
+ return true;
+}
+
+class CCoderReleaser
+{
+ CDecoder *m_Coder;
+public:
+ CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser()
+ {
+ m_Coder->ReleaseStreams();
+ }
+};
+
+bool CDecoder::DecodeMm(UInt32 pos)
+{
+ while (pos-- > 0)
+ {
+ UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
+ if (symbol == 256)
+ return true;
+ if (symbol >= kMMTableSize)
+ return false;
+ /*
+ Byte byPredict = m_Predictor.Predict();
+ Byte byReal = (Byte)(byPredict - (Byte)symbol);
+ m_Predictor.Update(byReal, byPredict);
+ */
+ Byte byReal = m_MmFilter.Decode((Byte)symbol);
+ m_OutWindowStream.PutByte(byReal);
+ if (++m_MmFilter.CurrentChannel == m_NumChannels)
+ m_MmFilter.CurrentChannel = 0;
+ }
+ return true;
+}
+
+bool CDecoder::DecodeLz(Int32 pos)
+{
+ while (pos > 0)
+ {
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
+ UInt32 length, distance;
+ if (number < 256)
+ {
+ m_OutWindowStream.PutByte(Byte(number));
+ pos--;
+ continue;
+ }
+ else if (number >= kMatchNumber)
+ {
+ number -= kMatchNumber;
+ length = kNormalMatchMinLen + UInt32(kLenStart[number]) +
+ m_InBitStream.ReadBits(kLenDirectBits[number]);
+ number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
+ if (number >= kDistTableSize)
+ return false;
+ distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
+ if (distance >= kDistLimit3)
+ {
+ length += 2 - ((distance - kDistLimit4) >> 31);
+ // length++;
+ // if (distance >= kDistLimit4)
+ // length++;
+ }
+ }
+ else if (number == kRepBothNumber)
+ {
+ length = m_LastLength;
+ if (length == 0)
+ return false;
+ distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
+ }
+ else if (number < kLen2Number)
+ {
+ distance = m_RepDists[(m_RepDistPtr - (number - kRepNumber + 1)) & 3];
+ number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
+ if (number >= kLenTableSize)
+ return false;
+ length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
+ if (distance >= kDistLimit2)
+ {
+ length++;
+ if (distance >= kDistLimit3)
+ {
+ length += 2 - ((distance - kDistLimit4) >> 31);
+ // length++;
+ // if (distance >= kDistLimit4)
+ // length++;
+ }
+ }
+ }
+ else if (number < kReadTableNumber)
+ {
+ number -= kLen2Number;
+ distance = kLen2DistStarts[number] +
+ m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
+ length = 2;
+ }
+ else if (number == kReadTableNumber)
+ return true;
+ else
+ return false;
+ m_RepDists[m_RepDistPtr++ & 3] = distance;
+ m_LastLength = length;
+ if (!m_OutWindowStream.CopyBlock(distance, length))
+ return false;
+ pos -= length;
+ }
+ return true;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (inSize == NULL || outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ m_PackSize = *inSize;
+
+ UInt64 pos = 0, unPackSize = *outSize;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(m_IsSolid);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+ if (!m_IsSolid)
+ {
+ InitStructures();
+ if (unPackSize == 0)
+ {
+ if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
+ if (!ReadTables())
+ return S_FALSE;
+ return S_OK;
+ }
+ if (!ReadTables())
+ return S_FALSE;
+ }
+
+ UInt64 startPos = m_OutWindowStream.GetProcessedSize();
+ while(pos < unPackSize)
+ {
+ UInt32 blockSize = 1 << 20;
+ if (blockSize > unPackSize - pos)
+ blockSize = (UInt32)(unPackSize - pos);
+ UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize();
+ if (m_AudioMode)
+ {
+ if (!DecodeMm(blockSize))
+ return S_FALSE;
+ }
+ else
+ {
+ if (!DecodeLz((Int32)blockSize))
+ return S_FALSE;
+ }
+ UInt64 globalPos = m_OutWindowStream.GetProcessedSize();
+ pos = globalPos - blockStartPos;
+ if (pos < blockSize)
+ if (!ReadTables())
+ return S_FALSE;
+ pos = globalPos - startPos;
+ if (progress != 0)
+ {
+ UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos));
+ }
+ }
+ if (pos > unPackSize)
+ return S_FALSE;
+
+ if (!ReadLastTables())
+ return S_FALSE;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ m_IsSolid = (data[0] != 0);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Rar2Decoder.h b/src/libs/7zip/win/CPP/7zip/Compress/Rar2Decoder.h
new file mode 100644
index 000000000..61a8b4dab
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Rar2Decoder.h
@@ -0,0 +1,174 @@
+// Rar2Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef __COMPRESS_RAR2_DECODER_H
+#define __COMPRESS_RAR2_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NRar2 {
+
+const UInt32 kNumRepDists = 4;
+const UInt32 kDistTableSize = 48;
+
+const int kMMTableSize = 256 + 1;
+
+const UInt32 kMainTableSize = 298;
+const UInt32 kLenTableSize = 28;
+
+const UInt32 kDistTableStart = kMainTableSize;
+const UInt32 kLenTableStart = kDistTableStart + kDistTableSize;
+
+const UInt32 kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize;
+
+const UInt32 kLevelTableSize = 19;
+
+const UInt32 kMMTablesSizesSum = kMMTableSize * 4;
+
+const UInt32 kMaxTableSize = kMMTablesSizesSum;
+
+const UInt32 kTableDirectLevels = 16;
+const UInt32 kTableLevelRepNumber = kTableDirectLevels;
+const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1;
+const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1;
+
+const UInt32 kLevelMask = 0xF;
+
+
+const UInt32 kRepBothNumber = 256;
+const UInt32 kRepNumber = kRepBothNumber + 1;
+const UInt32 kLen2Number = kRepNumber + 4;
+
+const UInt32 kLen2NumNumbers = 8;
+const UInt32 kReadTableNumber = kLen2Number + kLen2NumNumbers;
+const UInt32 kMatchNumber = kReadTableNumber + 1;
+
+const Byte kLenStart[kLenTableSize] = {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};
+const Byte kLenDirectBits[kLenTableSize] = {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};
+
+const UInt32 kDistStart[kDistTableSize] = {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
+const Byte kDistDirectBits[kDistTableSize] = {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, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
+
+const Byte kLevelDirectBits[kLevelTableSize] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
+
+const Byte kLen2DistStarts[kLen2NumNumbers]={0,4,8,16,32,64,128,192};
+const Byte kLen2DistDirectBits[kLen2NumNumbers]={2,2,3, 4, 5, 6, 6, 6};
+
+const UInt32 kDistLimit2 = 0x101 - 1;
+const UInt32 kDistLimit3 = 0x2000 - 1;
+const UInt32 kDistLimit4 = 0x40000 - 1;
+
+const UInt32 kMatchMaxLen = 255 + 2;
+const UInt32 kMatchMaxLenMax = 255 + 5;
+const UInt32 kNormalMatchMinLen = 3;
+
+namespace NMultimedia {
+
+struct CFilter
+{
+ int K1,K2,K3,K4,K5;
+ int D1,D2,D3,D4;
+ int LastDelta;
+ UInt32 Dif[11];
+ UInt32 ByteCount;
+ int LastChar;
+
+ Byte Decode(int &channelDelta, Byte delta);
+
+ void Init() { memset(this, 0, sizeof(*this)); }
+
+};
+
+const int kNumChanelsMax = 4;
+
+class CFilter2
+{
+public:
+ CFilter m_Filters[kNumChanelsMax];
+ int m_ChannelDelta;
+ int CurrentChannel;
+
+ void Init() { memset(this, 0, sizeof(*this)); }
+ Byte Decode(Byte delta)
+ {
+ return m_Filters[CurrentChannel].Decode(m_ChannelDelta, delta);
+ }
+
+};
+
+}
+
+typedef NBitm::CDecoder<CInBuffer> CBitDecoder;
+
+const int kNumHuffmanBits = 15;
+
+class CDecoder :
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ CLzOutWindow m_OutWindowStream;
+ CBitDecoder m_InBitStream;
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kMMTableSize> m_MMDecoders[NMultimedia::kNumChanelsMax];
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ bool m_AudioMode;
+
+ NMultimedia::CFilter2 m_MmFilter;
+ int m_NumChannels;
+
+ UInt32 m_RepDists[kNumRepDists];
+ UInt32 m_RepDistPtr;
+
+ UInt32 m_LastLength;
+
+ Byte m_LastLevels[kMaxTableSize];
+
+ UInt64 m_PackSize;
+ bool m_IsSolid;
+
+ void InitStructures();
+ UInt32 ReadBits(int numBits);
+ bool ReadTables();
+ bool ReadLastTables();
+
+ bool DecodeMm(UInt32 pos);
+ bool DecodeLz(Int32 pos);
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+public:
+ CDecoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InBitStream.ReleaseStream();
+ }
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Rar3Decoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Rar3Decoder.cpp
new file mode 100644
index 000000000..dde7c6de3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Rar3Decoder.cpp
@@ -0,0 +1,897 @@
+// Rar3Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Rar3Decoder.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
+static void SzBigFree(void *, void *address) { BigFree(address); }
+static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+static const UInt32 kNumAlignReps = 15;
+
+static const UInt32 kSymbolReadTable = 256;
+static const UInt32 kSymbolRep = 259;
+static const UInt32 kSymbolLen2 = kSymbolRep + kNumReps;
+
+static const Byte kLenStart[kLenTableSize] = {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};
+static const Byte kLenDirectBits[kLenTableSize] = {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};
+
+static const Byte kDistDirectBits[kDistTableSize] =
+ {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,15,15,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 18,18,18,18,18,18,18,18,18,18,18,18};
+
+static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192};
+static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6};
+
+static const UInt32 kDistLimit3 = 0x2000 - 2;
+static const UInt32 kDistLimit4 = 0x40000 - 2;
+
+static const UInt32 kNormalMatchMinLen = 3;
+
+static const UInt32 kVmDataSizeMax = 1 << 16;
+static const UInt32 kVmCodeSizeMax = 1 << 16;
+
+extern "C" {
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ return p->Code / (p->Range /= total);
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ start *= p->Range;
+ p->Low += start;
+ p->Code -= start;
+ p->Range *= size;
+ p->Normalize();
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CRangeDecoder *p = (CRangeDecoder *)pp;
+ if (p->Code / (p->Range >>= 14) < size0)
+ {
+ Range_Decode(p, 0, size0);
+ return 0;
+ }
+ else
+ {
+ Range_Decode(p, size0, (1 << 14) - size0);
+ return 1;
+ }
+}
+
+}
+
+CRangeDecoder::CRangeDecoder()
+{
+ s.GetThreshold = Range_GetThreshold;
+ s.Decode = Range_Decode;
+ s.DecodeBit = Range_DecodeBit;
+}
+
+CDecoder::CDecoder():
+ _window(0),
+ _winPos(0),
+ _wrPtr(0),
+ _lzSize(0),
+ _writtenFileSize(0),
+ _vmData(0),
+ _vmCode(0),
+ m_IsSolid(false)
+{
+ Ppmd7_Construct(&_ppmd);
+}
+
+CDecoder::~CDecoder()
+{
+ InitFilters();
+ ::MidFree(_vmData);
+ ::MidFree(_window);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
+{
+ return WriteStream(_outStream, data, size);
+}
+
+HRESULT CDecoder::WriteData(const Byte *data, UInt32 size)
+{
+ HRESULT res = S_OK;
+ if (_writtenFileSize < _unpackSize)
+ {
+ UInt32 curSize = size;
+ UInt64 remain = _unpackSize - _writtenFileSize;
+ if (remain < curSize)
+ curSize = (UInt32)remain;
+ res = WriteDataToStream(data, curSize);
+ }
+ _writtenFileSize += size;
+ return res;
+}
+
+HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr)
+{
+ if (startPtr <= endPtr)
+ return WriteData(_window + startPtr, endPtr - startPtr);
+ RINOK(WriteData(_window + startPtr, kWindowSize - startPtr));
+ return WriteData(_window, endPtr);
+}
+
+void CDecoder::ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef)
+{
+ CTempFilter *tempFilter = _tempFilters[tempFilterIndex];
+ tempFilter->InitR[6] = (UInt32)_writtenFileSize;
+ NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize);
+ NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32));
+ CFilter *filter = _filters[tempFilter->FilterIndex];
+ _vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData);
+ delete tempFilter;
+ _tempFilters[tempFilterIndex] = 0;
+}
+
+HRESULT CDecoder::WriteBuf()
+{
+ UInt32 writtenBorder = _wrPtr;
+ UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask;
+ for (int i = 0; i < _tempFilters.Size(); i++)
+ {
+ CTempFilter *filter = _tempFilters[i];
+ if (filter == NULL)
+ continue;
+ if (filter->NextWindow)
+ {
+ filter->NextWindow = false;
+ continue;
+ }
+ UInt32 blockStart = filter->BlockStart;
+ UInt32 blockSize = filter->BlockSize;
+ if (((blockStart - writtenBorder) & kWindowMask) < writeSize)
+ {
+ if (writtenBorder != blockStart)
+ {
+ RINOK(WriteArea(writtenBorder, blockStart));
+ writtenBorder = blockStart;
+ writeSize = (_winPos - writtenBorder) & kWindowMask;
+ }
+ if (blockSize <= writeSize)
+ {
+ UInt32 blockEnd = (blockStart + blockSize) & kWindowMask;
+ if (blockStart < blockEnd || blockEnd == 0)
+ _vm.SetMemory(0, _window + blockStart, blockSize);
+ else
+ {
+ UInt32 tailSize = kWindowSize - blockStart;
+ _vm.SetMemory(0, _window + blockStart, tailSize);
+ _vm.SetMemory(tailSize, _window, blockEnd);
+ }
+ NVm::CBlockRef outBlockRef;
+ ExecuteFilter(i, outBlockRef);
+ while (i + 1 < _tempFilters.Size())
+ {
+ CTempFilter *nextFilter = _tempFilters[i + 1];
+ if (nextFilter == NULL || nextFilter->BlockStart != blockStart ||
+ nextFilter->BlockSize != outBlockRef.Size || nextFilter->NextWindow)
+ break;
+ _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
+ ExecuteFilter(++i, outBlockRef);
+ }
+ WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
+ _writtenFileSize += outBlockRef.Size;
+ writtenBorder = blockEnd;
+ writeSize = (_winPos - writtenBorder) & kWindowMask;
+ }
+ else
+ {
+ for (int j = i; j < _tempFilters.Size(); j++)
+ {
+ CTempFilter *filter = _tempFilters[j];
+ if (filter != NULL && filter->NextWindow)
+ filter->NextWindow = false;
+ }
+ _wrPtr = writtenBorder;
+ return S_OK; // check it
+ }
+ }
+ }
+
+ _wrPtr = _winPos;
+ return WriteArea(writtenBorder, _winPos);
+}
+
+void CDecoder::InitFilters()
+{
+ _lastFilter = 0;
+ int i;
+ for (i = 0; i < _tempFilters.Size(); i++)
+ delete _tempFilters[i];
+ _tempFilters.Clear();
+ for (i = 0; i < _filters.Size(); i++)
+ delete _filters[i];
+ _filters.Clear();
+}
+
+bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
+{
+ CMemBitDecoder inp;
+ inp.Init(_vmData, codeSize);
+
+ UInt32 filterIndex;
+ if (firstByte & 0x80)
+ {
+ filterIndex = NVm::ReadEncodedUInt32(inp);
+ if (filterIndex == 0)
+ InitFilters();
+ else
+ filterIndex--;
+ }
+ else
+ filterIndex = _lastFilter;
+ if (filterIndex > (UInt32)_filters.Size())
+ return false;
+ _lastFilter = filterIndex;
+ bool newFilter = (filterIndex == (UInt32)_filters.Size());
+
+ CFilter *filter;
+ if (newFilter)
+ {
+ // check if too many filters
+ if (filterIndex > 1024)
+ return false;
+ filter = new CFilter;
+ _filters.Add(filter);
+ }
+ else
+ {
+ filter = _filters[filterIndex];
+ filter->ExecCount++;
+ }
+
+ int numEmptyItems = 0;
+ int i;
+ for (i = 0; i < _tempFilters.Size(); i++)
+ {
+ _tempFilters[i - numEmptyItems] = _tempFilters[i];
+ if (_tempFilters[i] == NULL)
+ numEmptyItems++;
+ if (numEmptyItems > 0)
+ _tempFilters[i] = NULL;
+ }
+ if (numEmptyItems == 0)
+ {
+ _tempFilters.Add(NULL);
+ numEmptyItems = 1;
+ }
+ CTempFilter *tempFilter = new CTempFilter;
+ _tempFilters[_tempFilters.Size() - numEmptyItems] = tempFilter;
+ tempFilter->FilterIndex = filterIndex;
+ tempFilter->ExecCount = filter->ExecCount;
+
+ UInt32 blockStart = NVm::ReadEncodedUInt32(inp);
+ if (firstByte & 0x40)
+ blockStart += 258;
+ tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask;
+ if (firstByte & 0x20)
+ filter->BlockSize = NVm::ReadEncodedUInt32(inp);
+ tempFilter->BlockSize = filter->BlockSize;
+ tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart;
+
+ memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR));
+ tempFilter->InitR[3] = NVm::kGlobalOffset;
+ tempFilter->InitR[4] = tempFilter->BlockSize;
+ tempFilter->InitR[5] = tempFilter->ExecCount;
+ if (firstByte & 0x10)
+ {
+ UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs);
+ for (int i = 0; i < NVm::kNumGpRegs; i++)
+ if (initMask & (1 << i))
+ tempFilter->InitR[i] = NVm::ReadEncodedUInt32(inp);
+ }
+ if (newFilter)
+ {
+ UInt32 vmCodeSize = NVm::ReadEncodedUInt32(inp);
+ if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0)
+ return false;
+ for (UInt32 i = 0; i < vmCodeSize; i++)
+ _vmCode[i] = (Byte)inp.ReadBits(8);
+ _vm.PrepareProgram(_vmCode, vmCodeSize, filter);
+ }
+
+ tempFilter->AllocateEmptyFixedGlobal();
+
+ Byte *globalData = &tempFilter->GlobalData[0];
+ for (i = 0; i < NVm::kNumGpRegs; i++)
+ NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]);
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize);
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why?
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], tempFilter->ExecCount);
+
+ if (firstByte & 8)
+ {
+ UInt32 dataSize = NVm::ReadEncodedUInt32(inp);
+ if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize)
+ return false;
+ CRecordVector<Byte> &globalData = tempFilter->GlobalData;
+ int requredSize = (int)(dataSize + NVm::kFixedGlobalSize);
+ if (globalData.Size() < requredSize)
+ {
+ globalData.Reserve(requredSize);
+ for (; globalData.Size() < requredSize; i++)
+ globalData.Add(0);
+ }
+ for (UInt32 i = 0; i < dataSize; i++)
+ globalData[NVm::kFixedGlobalSize + i] = (Byte)inp.ReadBits(8);
+ }
+ return true;
+}
+
+bool CDecoder::ReadVmCodeLZ()
+{
+ UInt32 firstByte = ReadBits(8);
+ UInt32 length = (firstByte & 7) + 1;
+ if (length == 7)
+ length = ReadBits(8) + 7;
+ else if (length == 8)
+ length = ReadBits(16);
+ if (length > kVmDataSizeMax)
+ return false;
+ for (UInt32 i = 0; i < length; i++)
+ _vmData[i] = (Byte)ReadBits(8);
+ return AddVmCode(firstByte, length);
+}
+
+bool CDecoder::ReadVmCodePPM()
+{
+ int firstByte = DecodePpmSymbol();
+ if (firstByte < 0)
+ return false;
+ UInt32 length = (firstByte & 7) + 1;
+ if (length == 7)
+ {
+ int b1 = DecodePpmSymbol();
+ if (b1 < 0)
+ return false;
+ length = b1 + 7;
+ }
+ else if (length == 8)
+ {
+ int b1 = DecodePpmSymbol();
+ if (b1 < 0)
+ return false;
+ int b2 = DecodePpmSymbol();
+ if (b2 < 0)
+ return false;
+ length = b1 * 256 + b2;
+ }
+ if (length > kVmDataSizeMax)
+ return false;
+ for (UInt32 i = 0; i < length; i++)
+ {
+ int b = DecodePpmSymbol();
+ if (b < 0)
+ return false;
+ _vmData[i] = (Byte)b;
+ }
+ return AddVmCode(firstByte, length);
+}
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.bitDecoder.ReadBits(numBits); }
+
+/////////////////////////////////////////////////
+// PPM
+
+HRESULT CDecoder::InitPPM()
+{
+ Byte maxOrder = (Byte)ReadBits(7);
+
+ bool reset = ((maxOrder & 0x20) != 0);
+ int maxMB = 0;
+ if (reset)
+ maxMB = (Byte)ReadBits(8);
+ else
+ {
+ if (PpmError || !Ppmd7_WasAllocated(&_ppmd))
+ return S_FALSE;
+ }
+ if (maxOrder & 0x40)
+ PpmEscChar = (Byte)ReadBits(8);
+ m_InBitStream.InitRangeCoder();
+ /*
+ if (m_InBitStream.m_BitPos != 0)
+ return S_FALSE;
+ */
+ if (reset)
+ {
+ PpmError = true;
+ maxOrder = (maxOrder & 0x1F) + 1;
+ if (maxOrder > 16)
+ maxOrder = 16 + (maxOrder - 16) * 3;
+ if (maxOrder == 1)
+ {
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+ return S_FALSE;
+ }
+ if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+ Ppmd7_Init(&_ppmd, maxOrder);
+ PpmError = false;
+ }
+ return S_OK;
+}
+
+int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.s); }
+
+HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
+{
+ keepDecompressing = false;
+ if (PpmError)
+ return S_FALSE;
+ do
+ {
+ if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
+ {
+ RINOK(WriteBuf());
+ if (_writtenFileSize > _unpackSize)
+ {
+ keepDecompressing = false;
+ return S_OK;
+ }
+ }
+ int c = DecodePpmSymbol();
+ if (c < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ if (c == PpmEscChar)
+ {
+ int nextCh = DecodePpmSymbol();
+ if (nextCh < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ if (nextCh == 0)
+ return ReadTables(keepDecompressing);
+ if (nextCh == 2 || nextCh == -1)
+ return S_OK;
+ if (nextCh == 3)
+ {
+ if (!ReadVmCodePPM())
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ continue;
+ }
+ if (nextCh == 4 || nextCh == 5)
+ {
+ UInt32 distance = 0;
+ UInt32 length = 4;
+ if (nextCh == 4)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ int c = DecodePpmSymbol();
+ if (c < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ distance = (distance << 8) + (Byte)c;
+ }
+ distance++;
+ length += 28;
+ }
+ int c = DecodePpmSymbol();
+ if (c < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ length += c;
+ if (distance >= _lzSize)
+ return S_FALSE;
+ CopyBlock(distance, length);
+ num -= (Int32)length;
+ continue;
+ }
+ }
+ PutByte((Byte)c);
+ num--;
+ }
+ while (num >= 0);
+ keepDecompressing = true;
+ return S_OK;
+}
+
+/////////////////////////////////////////////////
+// LZ
+
+HRESULT CDecoder::ReadTables(bool &keepDecompressing)
+{
+ keepDecompressing = true;
+ ReadBits((8 - m_InBitStream.bitDecoder.GetBitPosition()) & 7);
+ if (ReadBits(1) != 0)
+ {
+ _lzMode = false;
+ return InitPPM();
+ }
+
+ _lzMode = true;
+ PrevAlignBits = 0;
+ PrevAlignCount = 0;
+
+ Byte levelLevels[kLevelTableSize];
+ Byte newLevels[kTablesSizesSum];
+
+ if (ReadBits(1) == 0)
+ memset(m_LastLevels, 0, kTablesSizesSum);
+
+ int i;
+ for (i = 0; i < kLevelTableSize; i++)
+ {
+ UInt32 length = ReadBits(4);
+ if (length == 15)
+ {
+ UInt32 zeroCount = ReadBits(4);
+ if (zeroCount != 0)
+ {
+ zeroCount += 2;
+ while (zeroCount-- > 0 && i < kLevelTableSize)
+ levelLevels[i++]=0;
+ i--;
+ continue;
+ }
+ }
+ levelLevels[i] = (Byte)length;
+ }
+ RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
+ i = 0;
+ while (i < kTablesSizesSum)
+ {
+ UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number < 16)
+ {
+ newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
+ i++;
+ }
+ else if (number > kLevelTableSize)
+ return S_FALSE;
+ else
+ {
+ int num;
+ if (((number - 16) & 1) == 0)
+ num = ReadBits(3) + 3;
+ else
+ num = ReadBits(7) + 11;
+ if (number < 18)
+ {
+ if (i == 0)
+ return S_FALSE;
+ for (; num > 0 && i < kTablesSizesSum; num--, i++)
+ newLevels[i] = newLevels[i - 1];
+ }
+ else
+ {
+ for (; num > 0 && i < kTablesSizesSum; num--)
+ newLevels[i++] = 0;
+ }
+ }
+ }
+ TablesRead = true;
+
+ // original code has check here:
+ /*
+ if (InAddr > ReadTop)
+ {
+ keepDecompressing = false;
+ return true;
+ }
+ */
+
+ RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
+ RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
+ RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
+ RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
+
+ memcpy(m_LastLevels, newLevels, kTablesSizesSum);
+ return S_OK;
+}
+
+class CCoderReleaser
+{
+ CDecoder *m_Coder;
+public:
+ CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser()
+ {
+ m_Coder->ReleaseStreams();
+ }
+};
+
+HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
+{
+ if (ReadBits(1) != 0)
+ {
+ // old file
+ TablesRead = false;
+ return ReadTables(keepDecompressing);
+ }
+ // new file
+ keepDecompressing = false;
+ TablesRead = (ReadBits(1) == 0);
+ return S_OK;
+}
+
+UInt32 kDistStart[kDistTableSize];
+
+class CDistInit
+{
+public:
+ CDistInit() { Init(); }
+ void Init()
+ {
+ UInt32 start = 0;
+ for (UInt32 i = 0; i < kDistTableSize; i++)
+ {
+ kDistStart[i] = start;
+ start += (1 << kDistDirectBits[i]);
+ }
+ }
+} g_DistInit;
+
+HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
+{
+ UInt32 rep0 = _reps[0];
+ UInt32 rep1 = _reps[1];
+ UInt32 rep2 = _reps[2];
+ UInt32 rep3 = _reps[3];
+ UInt32 length = _lastLength;
+ for (;;)
+ {
+ if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
+ {
+ RINOK(WriteBuf());
+ if (_writtenFileSize > _unpackSize)
+ {
+ keepDecompressing = false;
+ return S_OK;
+ }
+ }
+ UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number < 256)
+ {
+ PutByte((Byte)number);
+ continue;
+ }
+ else if (number == kSymbolReadTable)
+ {
+ RINOK(ReadEndOfBlock(keepDecompressing));
+ break;
+ }
+ else if (number == 257)
+ {
+ if (!ReadVmCodeLZ())
+ return S_FALSE;
+ continue;
+ }
+ else if (number == 258)
+ {
+ if (length == 0)
+ return S_FALSE;
+ }
+ else if (number < kSymbolRep + 4)
+ {
+ if (number != kSymbolRep)
+ {
+ UInt32 distance;
+ if (number == kSymbolRep + 1)
+ distance = rep1;
+ else
+ {
+ if (number == kSymbolRep + 2)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+
+ UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number >= kLenTableSize)
+ return S_FALSE;
+ length = 2 + kLenStart[number] + m_InBitStream.bitDecoder.ReadBits(kLenDirectBits[number]);
+ }
+ else
+ {
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ if (number < 271)
+ {
+ number -= 263;
+ rep0 = kLen2DistStarts[number] + m_InBitStream.bitDecoder.ReadBits(kLen2DistDirectBits[number]);
+ length = 2;
+ }
+ else if (number < 299)
+ {
+ number -= 271;
+ length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.bitDecoder.ReadBits(kLenDirectBits[number]);
+ UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number >= kDistTableSize)
+ return S_FALSE;
+ rep0 = kDistStart[number];
+ int numBits = kDistDirectBits[number];
+ if (number >= (kNumAlignBits * 2) + 2)
+ {
+ if (numBits > kNumAlignBits)
+ rep0 += (m_InBitStream.bitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
+ if (PrevAlignCount > 0)
+ {
+ PrevAlignCount--;
+ rep0 += PrevAlignBits;
+ }
+ else
+ {
+ UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream.bitDecoder);
+ if (number < (1 << kNumAlignBits))
+ {
+ rep0 += number;
+ PrevAlignBits = number;
+ }
+ else if (number == (1 << kNumAlignBits))
+ {
+ PrevAlignCount = kNumAlignReps;
+ rep0 += PrevAlignBits;
+ }
+ else
+ return S_FALSE;
+ }
+ }
+ else
+ rep0 += m_InBitStream.bitDecoder.ReadBits(numBits);
+ length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
+ }
+ else
+ return S_FALSE;
+ }
+ if (rep0 >= _lzSize)
+ return S_FALSE;
+ CopyBlock(rep0, length);
+ }
+ _reps[0] = rep0;
+ _reps[1] = rep1;
+ _reps[2] = rep2;
+ _reps[3] = rep3;
+ _lastLength = length;
+
+ return S_OK;
+}
+
+HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
+{
+ _writtenFileSize = 0;
+ if (!m_IsSolid)
+ {
+ _lzSize = 0;
+ _winPos = 0;
+ _wrPtr = 0;
+ for (int i = 0; i < kNumReps; i++)
+ _reps[i] = 0;
+ _lastLength = 0;
+ memset(m_LastLevels, 0, kTablesSizesSum);
+ TablesRead = false;
+ PpmEscChar = 2;
+ PpmError = true;
+ InitFilters();
+ }
+ if (!m_IsSolid || !TablesRead)
+ {
+ bool keepDecompressing;
+ RINOK(ReadTables(keepDecompressing));
+ if (!keepDecompressing)
+ return S_OK;
+ }
+
+ for (;;)
+ {
+ bool keepDecompressing;
+ if (_lzMode)
+ {
+ RINOK(DecodeLZ(keepDecompressing))
+ }
+ else
+ {
+ RINOK(DecodePPM(1 << 18, keepDecompressing))
+ }
+ UInt64 packSize = m_InBitStream.bitDecoder.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
+ if (!keepDecompressing)
+ break;
+ }
+ RINOK(WriteBuf());
+ UInt64 packSize = m_InBitStream.bitDecoder.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
+ if (_writtenFileSize < _unpackSize)
+ return S_FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try
+ {
+ if (inSize == NULL || outSize == NULL)
+ return E_INVALIDARG;
+
+ if (_vmData == 0)
+ {
+ _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
+ if (_vmData == 0)
+ return E_OUTOFMEMORY;
+ _vmCode = _vmData + kVmDataSizeMax;
+ }
+
+ if (_window == 0)
+ {
+ _window = (Byte *)::MidAlloc(kWindowSize);
+ if (_window == 0)
+ return E_OUTOFMEMORY;
+ }
+ if (!m_InBitStream.bitDecoder.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!_vm.Create())
+ return E_OUTOFMEMORY;
+
+
+ m_InBitStream.bitDecoder.SetStream(inStream);
+ m_InBitStream.bitDecoder.Init();
+ _outStream = outStream;
+
+ CCoderReleaser coderReleaser(this);
+ _unpackSize = *outSize;
+ return CodeReal(progress);
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+ // CNewException is possible here. But probably CNewException is caused
+ // by error in data stream.
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ m_IsSolid = (data[0] != 0);
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Rar3Decoder.h b/src/libs/7zip/win/CPP/7zip/Compress/Rar3Decoder.h
new file mode 100644
index 000000000..99b647dc7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Rar3Decoder.h
@@ -0,0 +1,267 @@
+// Rar3Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#ifndef __COMPRESS_RAR3_DECODER_H
+#define __COMPRESS_RAR3_DECODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "Rar3Vm.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+const UInt32 kWindowSize = 1 << 22;
+const UInt32 kWindowMask = (kWindowSize - 1);
+
+const UInt32 kNumReps = 4;
+const UInt32 kNumLen2Symbols = 8;
+const UInt32 kLenTableSize = 28;
+const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize;
+const UInt32 kDistTableSize = 60;
+
+const int kNumAlignBits = 4;
+const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1;
+
+const UInt32 kLevelTableSize = 20;
+
+const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
+
+class CBitDecoder
+{
+ UInt32 m_Value;
+ unsigned m_BitPos;
+public:
+ CInBuffer m_Stream;
+ bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
+ void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);}
+ void ReleaseStream() { m_Stream.ReleaseStream();}
+
+ void Init()
+ {
+ m_Stream.Init();
+ m_BitPos = 0;
+ m_Value = 0;
+ }
+
+ UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - (m_BitPos) / 8; }
+ UInt32 GetBitPosition() const { return ((8 - m_BitPos) & 7); }
+
+ UInt32 GetValue(unsigned numBits)
+ {
+ if (m_BitPos < numBits)
+ {
+ m_BitPos += 8;
+ m_Value = (m_Value << 8) | m_Stream.ReadByte();
+ if (m_BitPos < numBits)
+ {
+ m_BitPos += 8;
+ m_Value = (m_Value << 8) | m_Stream.ReadByte();
+ }
+ }
+ return m_Value >> (m_BitPos - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ m_BitPos -= numBits;
+ m_Value = m_Value & ((1 << m_BitPos) - 1);
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ MovePos(numBits);
+ return res;
+ }
+};
+
+const UInt32 kTopValue = (1 << 24);
+const UInt32 kBot = (1 << 15);
+
+struct CRangeDecoder
+{
+ IPpmd7_RangeDec s;
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ CBitDecoder bitDecoder;
+ SRes Res;
+
+public:
+ void InitRangeCoder()
+ {
+ Code = 0;
+ Low = 0;
+ Range = 0xFFFFFFFF;
+ for (int i = 0; i < 4; i++)
+ Code = (Code << 8) | bitDecoder.ReadBits(8);
+ }
+
+ void Normalize()
+ {
+ while ((Low ^ (Low + Range)) < kTopValue ||
+ Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1))
+ {
+ Code = (Code << 8) | bitDecoder.m_Stream.ReadByte();
+ Range <<= 8;
+ Low <<= 8;
+ }
+ }
+
+ CRangeDecoder();
+};
+
+struct CFilter: public NVm::CProgram
+{
+ CRecordVector<Byte> GlobalData;
+ UInt32 BlockStart;
+ UInt32 BlockSize;
+ UInt32 ExecCount;
+ CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {}
+};
+
+struct CTempFilter: public NVm::CProgramInitState
+{
+ UInt32 BlockStart;
+ UInt32 BlockSize;
+ UInt32 ExecCount;
+ bool NextWindow;
+
+ UInt32 FilterIndex;
+};
+
+const int kNumHuffmanBits = 15;
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ CRangeDecoder m_InBitStream;
+ Byte *_window;
+ UInt32 _winPos;
+ UInt32 _wrPtr;
+ UInt64 _lzSize;
+ UInt64 _unpackSize;
+ UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written
+ CMyComPtr<ISequentialOutStream> _outStream;
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ UInt32 _reps[kNumReps];
+ UInt32 _lastLength;
+
+ Byte m_LastLevels[kTablesSizesSum];
+
+ Byte *_vmData;
+ Byte *_vmCode;
+ NVm::CVm _vm;
+ CRecordVector<CFilter *> _filters;
+ CRecordVector<CTempFilter *> _tempFilters;
+ UInt32 _lastFilter;
+
+ bool m_IsSolid;
+
+ bool _lzMode;
+
+ UInt32 PrevAlignBits;
+ UInt32 PrevAlignCount;
+
+ bool TablesRead;
+
+ CPpmd7 _ppmd;
+ int PpmEscChar;
+ bool PpmError;
+
+ HRESULT WriteDataToStream(const Byte *data, UInt32 size);
+ HRESULT WriteData(const Byte *data, UInt32 size);
+ HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr);
+ void ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef);
+ HRESULT WriteBuf();
+
+ void InitFilters();
+ bool AddVmCode(UInt32 firstByte, UInt32 codeSize);
+ bool ReadVmCodeLZ();
+ bool ReadVmCodePPM();
+
+ UInt32 ReadBits(int numBits);
+
+ HRESULT InitPPM();
+ int DecodePpmSymbol();
+ HRESULT DecodePPM(Int32 num, bool &keepDecompressing);
+
+ HRESULT ReadTables(bool &keepDecompressing);
+ HRESULT ReadEndOfBlock(bool &keepDecompressing);
+ HRESULT DecodeLZ(bool &keepDecompressing);
+ HRESULT CodeReal(ICompressProgressInfo *progress);
+public:
+ CDecoder();
+ ~CDecoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ void ReleaseStreams()
+ {
+ _outStream.Release();
+ m_InBitStream.bitDecoder.ReleaseStream();
+ }
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+ void CopyBlock(UInt32 distance, UInt32 len)
+ {
+ _lzSize += len;
+ UInt32 pos = (_winPos - distance - 1) & kWindowMask;
+ Byte *window = _window;
+ UInt32 winPos = _winPos;
+ if (kWindowSize - winPos > len && kWindowSize - pos > len)
+ {
+ const Byte *src = window + pos;
+ Byte *dest = window + winPos;
+ _winPos += len;
+ do
+ *dest++ = *src++;
+ while(--len != 0);
+ return;
+ }
+ do
+ {
+ window[winPos] = window[pos];
+ winPos = (winPos + 1) & kWindowMask;
+ pos = (pos + 1) & kWindowMask;
+ }
+ while(--len != 0);
+ _winPos = winPos;
+ }
+
+ void PutByte(Byte b)
+ {
+ _window[_winPos] = b;
+ _winPos = (_winPos + 1) & kWindowMask;
+ _lzSize++;
+ }
+
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Rar3Vm.cpp b/src/libs/7zip/win/CPP/7zip/Compress/Rar3Vm.cpp
new file mode 100644
index 000000000..74051dd79
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Rar3Vm.cpp
@@ -0,0 +1,1091 @@
+// Rar3Vm.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/*
+Note:
+ Due to performance considerations Rar VM may set Flags C incorrectly
+ for some operands (SHL x, 0, ... ).
+ Check implementation of concrete VM command
+ to see if it sets flags right.
+*/
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/Alloc.h"
+
+#include "Rar3Vm.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+UInt32 CMemBitDecoder::ReadBits(int numBits)
+{
+ UInt32 res = 0;
+ for (;;)
+ {
+ Byte b = _bitPos < _bitSize ? _data[_bitPos >> 3] : 0;
+ int avail = (int)(8 - (_bitPos & 7));
+ if (numBits <= avail)
+ {
+ _bitPos += numBits;
+ return res | (b >> (avail - numBits)) & ((1 << numBits) - 1);
+ }
+ numBits -= avail;
+ res |= (UInt32)(b & ((1 << avail) - 1)) << numBits;
+ _bitPos += avail;
+ }
+}
+
+UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }
+
+namespace NVm {
+
+static const UInt32 kStackRegIndex = kNumRegs - 1;
+
+static const UInt32 FLAG_C = 1;
+static const UInt32 FLAG_Z = 2;
+static const UInt32 FLAG_S = 0x80000000;
+
+static const Byte CF_OP0 = 0;
+static const Byte CF_OP1 = 1;
+static const Byte CF_OP2 = 2;
+static const Byte CF_OPMASK = 3;
+static const Byte CF_BYTEMODE = 4;
+static const Byte CF_JUMP = 8;
+static const Byte CF_PROC = 16;
+static const Byte CF_USEFLAGS = 32;
+static const Byte CF_CHFLAGS = 64;
+
+static Byte kCmdFlags[]=
+{
+ /* CMD_MOV */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JMP */ CF_OP1 | CF_JUMP,
+ /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_PUSH */ CF_OP1,
+ /* CMD_POP */ CF_OP1,
+ /* CMD_CALL */ CF_OP1 | CF_PROC,
+ /* CMD_RET */ CF_OP0 | CF_PROC,
+ /* CMD_NOT */ CF_OP1 | CF_BYTEMODE,
+ /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_PUSHA */ CF_OP0,
+ /* CMD_POPA */ CF_OP0,
+ /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS,
+ /* CMD_POPF */ CF_OP0 | CF_CHFLAGS,
+ /* CMD_MOVZX */ CF_OP2,
+ /* CMD_MOVSX */ CF_OP2,
+ /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_MUL */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_DIV */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
+ /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
+ /* CMD_PRINT */ CF_OP0
+};
+
+CVm::CVm(): Mem(NULL) {}
+
+bool CVm::Create()
+{
+ if (Mem == NULL)
+ Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
+ return (Mem != NULL);
+}
+
+CVm::~CVm()
+{
+ ::MyFree(Mem);
+}
+
+// CVm::Execute can change CProgram object: it clears progarm if VM returns error.
+
+bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
+ CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData)
+{
+ memcpy(R, initState->InitR, sizeof(initState->InitR));
+ R[kStackRegIndex] = kSpaceSize;
+ R[kNumRegs] = 0;
+ Flags = 0;
+
+ UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize);
+ if (globalSize != 0)
+ memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize);
+ UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize);
+ if (staticSize != 0)
+ memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);
+
+ bool res = true;
+ #ifdef RARVM_STANDARD_FILTERS
+ if (prg->StandardFilterIndex >= 0)
+ ExecuteStandardFilter(prg->StandardFilterIndex);
+ else
+ #endif
+ {
+ res = ExecuteCode(prg);
+ if (!res)
+ prg->Commands[0].OpCode = CMD_RET;
+ }
+ UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
+ UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
+ if (newBlockPos + newBlockSize >= kSpaceSize)
+ newBlockPos = newBlockSize = 0;
+ outBlockRef.Offset = newBlockPos;
+ outBlockRef.Size = newBlockSize;
+
+ outGlobalData.Clear();
+ UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize);
+ dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize);
+ if (dataSize != 0)
+ {
+ dataSize += kFixedGlobalSize;
+ outGlobalData.Reserve(dataSize);
+ for (UInt32 i = 0; i < dataSize; i++)
+ outGlobalData.Add(Mem[kGlobalOffset + i]);
+ }
+ return res;
+}
+
+
+#define SET_IP(IP) \
+ if ((IP) >= numCommands) return true; \
+ if (--maxOpCount <= 0) return false; \
+ cmd = commands + (IP);
+
+#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0)
+#define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); }
+#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S
+#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)
+
+UInt32 CVm::GetOperand32(const COperand *op) const
+{
+ switch(op->Type)
+ {
+ case OP_TYPE_REG: return R[op->Data];
+ case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
+ default: return op->Data;
+ }
+}
+
+void CVm::SetOperand32(const COperand *op, UInt32 val)
+{
+ switch(op->Type)
+ {
+ case OP_TYPE_REG: R[op->Data] = val; return;
+ case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
+ }
+}
+
+Byte CVm::GetOperand8(const COperand *op) const
+{
+ switch(op->Type)
+ {
+ case OP_TYPE_REG: return (Byte)R[op->Data];
+ case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];;
+ default: return (Byte)op->Data;
+ }
+}
+
+void CVm::SetOperand8(const COperand *op, Byte val)
+{
+ switch(op->Type)
+ {
+ case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
+ case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
+ }
+}
+
+UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
+{
+ if (byteMode)
+ return GetOperand8(op);
+ return GetOperand32(op);
+}
+
+void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val)
+{
+ if (byteMode)
+ SetOperand8(op, (Byte)(val & 0xFF));
+ else
+ SetOperand32(op, val);
+}
+
+bool CVm::ExecuteCode(const CProgram *prg)
+{
+ Int32 maxOpCount = 25000000;
+ const CCommand *commands = &prg->Commands[0];
+ const CCommand *cmd = commands;
+ UInt32 numCommands = prg->Commands.Size();
+ for (;;)
+ {
+ switch(cmd->OpCode)
+ {
+ #ifndef RARVM_NO_VM
+
+ case CMD_MOV:
+ SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
+ break;
+ case CMD_MOVB:
+ SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2));
+ break;
+ case CMD_CMP:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ UInt32 res = v1 - GetOperand32(&cmd->Op2);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_CMPB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ Byte res = v1 - GetOperand8(&cmd->Op2);
+ res &= 0xFF;
+ Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res);
+ }
+ break;
+ case CMD_ADD:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ UInt32 res = v1 + GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_ADDB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ Byte res = v1 + GetOperand8(&cmd->Op2);
+ res &= 0xFF;
+ SetOperand8(&cmd->Op1, (Byte)res);
+ Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res));
+ }
+ break;
+ case CMD_ADC:
+ {
+ UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ UInt32 FC = (Flags & FLAG_C);
+ UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC;
+ if (cmd->ByteMode)
+ res &= 0xFF;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_SUB:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ UInt32 res = v1 - GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_SUBB:
+ {
+ UInt32 v1 = GetOperand8(&cmd->Op1);
+ UInt32 res = v1 - GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, (Byte)res);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_SBB:
+ {
+ UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ UInt32 FC = (Flags & FLAG_C);
+ UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC;
+ // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S);
+ if (cmd->ByteMode)
+ res &= 0xFF;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_INC:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) + 1;
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_INCB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) + 1;
+ SetOperand8(&cmd->Op1, res);;
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_DEC:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) - 1;
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_DECB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) - 1;
+ SetOperand8(&cmd->Op1, res);;
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_XOR:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_XORB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_AND:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_ANDB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_OR:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_ORB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_TEST:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_TESTB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_NOT:
+ SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1));
+ break;
+ case CMD_NEG:
+ {
+ UInt32 res = 0 - GetOperand32(&cmd->Op1);
+ SetOperand32(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S);
+ }
+ break;
+ case CMD_NEGB:
+ {
+ Byte res = (Byte)(0 - GetOperand8(&cmd->Op1));
+ SetOperand8(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res);
+ }
+ break;
+
+ case CMD_SHL:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ int v2 = (int)GetOperand32(&cmd->Op2);
+ UInt32 res = v1 << v2;
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0);
+ }
+ break;
+ case CMD_SHLB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ int v2 = (int)GetOperand8(&cmd->Op2);
+ Byte res = (Byte)(v1 << v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0);
+ }
+ break;
+ case CMD_SHR:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ int v2 = (int)GetOperand32(&cmd->Op2);
+ UInt32 res = v1 >> v2;
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SHRB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ int v2 = (int)GetOperand8(&cmd->Op2);
+ Byte res = (Byte)(v1 >> v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SAR:
+ {
+ UInt32 v1 = GetOperand32(&cmd->Op1);
+ int v2 = (int)GetOperand32(&cmd->Op2);
+ UInt32 res = UInt32(((Int32)v1) >> v2);
+ SetOperand32(&cmd->Op1, res);
+ Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SARB:
+ {
+ Byte v1 = GetOperand8(&cmd->Op1);
+ int v2 = (int)GetOperand8(&cmd->Op2);
+ Byte res = (Byte)(((signed char)v1) >> v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+
+ case CMD_JMP:
+ SET_IP_OP1;
+ continue;
+ case CMD_JZ:
+ if ((Flags & FLAG_Z) != 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JNZ:
+ if ((Flags & FLAG_Z) == 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JS:
+ if ((Flags & FLAG_S) != 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JNS:
+ if ((Flags & FLAG_S) == 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JB:
+ if ((Flags & FLAG_C) != 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JBE:
+ if ((Flags & (FLAG_C | FLAG_Z)) != 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JA:
+ if ((Flags & (FLAG_C | FLAG_Z)) == 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+ case CMD_JAE:
+ if ((Flags & FLAG_C) == 0)
+ {
+ SET_IP_OP1;
+ continue;
+ }
+ break;
+
+ case CMD_PUSH:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1));
+ break;
+ case CMD_POP:
+ SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]));
+ R[kStackRegIndex] += 4;
+ break;
+ case CMD_CALL:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1));
+ SET_IP_OP1;
+ continue;
+
+ case CMD_PUSHA:
+ {
+ for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4)
+ SetValue32(&Mem[SP & kSpaceMask], R[i]);
+ R[kStackRegIndex] -= kNumRegs * 4;
+ }
+ break;
+ case CMD_POPA:
+ {
+ for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4)
+ R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]);
+ }
+ break;
+ case CMD_PUSHF:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags);
+ break;
+ case CMD_POPF:
+ Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
+ R[kStackRegIndex] += 4;
+ break;
+
+ case CMD_MOVZX:
+ SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2));
+ break;
+ case CMD_MOVSX:
+ SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2));
+ break;
+ case CMD_XCHG:
+ {
+ UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2));
+ SetOperand(cmd->ByteMode, &cmd->Op2, v1);
+ }
+ break;
+ case CMD_MUL:
+ {
+ UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ }
+ break;
+ case CMD_MULB:
+ {
+ Byte res = GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, res);
+ }
+ break;
+ case CMD_DIV:
+ {
+ UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2);
+ if (divider != 0)
+ {
+ UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ }
+ }
+ break;
+
+ #endif
+
+ case CMD_RET:
+ {
+ if (R[kStackRegIndex] >= kSpaceSize)
+ return true;
+ UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
+ SET_IP(ip);
+ R[kStackRegIndex] += 4;
+ continue;
+ }
+ case CMD_PRINT:
+ break;
+ }
+ cmd++;
+ --maxOpCount;
+ }
+}
+
+
+//////////////////////////////////////////////////////
+// Read program
+
+UInt32 ReadEncodedUInt32(CMemBitDecoder &inp)
+{
+ switch(inp.ReadBits(2))
+ {
+ case 0:
+ return inp.ReadBits(4);
+ case 1:
+ {
+ UInt32 v = inp.ReadBits(4);
+ if (v == 0)
+ return 0xFFFFFF00 | inp.ReadBits(8);
+ else
+ return (v << 4) | inp.ReadBits(4);
+ }
+ case 2:
+ return inp.ReadBits(16);
+ default:
+ return inp.ReadBits(32);
+ }
+}
+
+void CVm::DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode)
+{
+ if (inp.ReadBit())
+ {
+ op.Type = OP_TYPE_REG;
+ op.Data = inp.ReadBits(kNumRegBits);
+ }
+ else if (inp.ReadBit() == 0)
+ {
+ op.Type = OP_TYPE_INT;
+ if (byteMode)
+ op.Data = inp.ReadBits(8);
+ else
+ op.Data = ReadEncodedUInt32(inp);
+ }
+ else
+ {
+ op.Type = OP_TYPE_REGMEM;
+ if (inp.ReadBit() == 0)
+ {
+ op.Data = inp.ReadBits(kNumRegBits);
+ op.Base = 0;
+ }
+ else
+ {
+ if (inp.ReadBit() == 0)
+ op.Data = inp.ReadBits(kNumRegBits);
+ else
+ op.Data = kNumRegs;
+ op.Base = ReadEncodedUInt32(inp);
+ }
+ }
+}
+
+void CVm::ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
+{
+ CMemBitDecoder inp;
+ inp.Init(code, codeSize);
+
+ prg->StaticData.Clear();
+ if (inp.ReadBit())
+ {
+ UInt32 dataSize = ReadEncodedUInt32(inp) + 1;
+ for (UInt32 i = 0; inp.Avail() && i < dataSize; i++)
+ prg->StaticData.Add((Byte)inp.ReadBits(8));
+ }
+ while (inp.Avail())
+ {
+ prg->Commands.Add(CCommand());
+ CCommand *cmd = &prg->Commands.Back();
+ if (inp.ReadBit() == 0)
+ cmd->OpCode = (ECommand)inp.ReadBits(3);
+ else
+ cmd->OpCode = (ECommand)(8 + inp.ReadBits(5));
+ if (kCmdFlags[cmd->OpCode] & CF_BYTEMODE)
+ cmd->ByteMode = (inp.ReadBit()) ? true : false;
+ else
+ cmd->ByteMode = 0;
+ int opNum = (kCmdFlags[cmd->OpCode] & CF_OPMASK);
+ if (opNum > 0)
+ {
+ DecodeArg(inp, cmd->Op1, cmd->ByteMode);
+ if (opNum == 2)
+ DecodeArg(inp, cmd->Op2, cmd->ByteMode);
+ else
+ {
+ if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[cmd->OpCode] & (CF_JUMP | CF_PROC)))
+ {
+ int Distance = cmd->Op1.Data;
+ if (Distance >= 256)
+ Distance -= 256;
+ else
+ {
+ if (Distance >= 136)
+ Distance -= 264;
+ else if (Distance >= 16)
+ Distance -= 8;
+ else if (Distance >= 8)
+ Distance -= 16;
+ Distance += prg->Commands.Size() - 1;
+ }
+ cmd->Op1.Data = Distance;
+ }
+ }
+ }
+ if (cmd->ByteMode)
+ {
+ switch (cmd->OpCode)
+ {
+ case CMD_MOV: cmd->OpCode = CMD_MOVB; break;
+ case CMD_CMP: cmd->OpCode = CMD_CMPB; break;
+ case CMD_ADD: cmd->OpCode = CMD_ADDB; break;
+ case CMD_SUB: cmd->OpCode = CMD_SUBB; break;
+ case CMD_INC: cmd->OpCode = CMD_INCB; break;
+ case CMD_DEC: cmd->OpCode = CMD_DECB; break;
+ case CMD_XOR: cmd->OpCode = CMD_XORB; break;
+ case CMD_AND: cmd->OpCode = CMD_ANDB; break;
+ case CMD_OR: cmd->OpCode = CMD_ORB; break;
+ case CMD_TEST: cmd->OpCode = CMD_TESTB; break;
+ case CMD_NEG: cmd->OpCode = CMD_NEGB; break;
+ case CMD_SHL: cmd->OpCode = CMD_SHLB; break;
+ case CMD_SHR: cmd->OpCode = CMD_SHRB; break;
+ case CMD_SAR: cmd->OpCode = CMD_SARB; break;
+ case CMD_MUL: cmd->OpCode = CMD_MULB; break;
+ }
+ }
+ }
+}
+
+#ifdef RARVM_STANDARD_FILTERS
+
+enum EStandardFilter
+{
+ SF_E8,
+ SF_E8E9,
+ SF_ITANIUM,
+ SF_RGB,
+ SF_AUDIO,
+ SF_DELTA,
+ SF_UPCASE
+};
+
+struct StandardFilterSignature
+{
+ UInt32 Length;
+ UInt32 CRC;
+ EStandardFilter Type;
+}
+kStdFilters[]=
+{
+ { 53, 0xad576887, SF_E8 },
+ { 57, 0x3cd7e57e, SF_E8E9 },
+ { 120, 0x3769893f, SF_ITANIUM },
+ { 29, 0x0e06077d, SF_DELTA },
+ { 149, 0x1c2c5dc8, SF_RGB },
+ { 216, 0xbc85e701, SF_AUDIO },
+ { 40, 0x46b9c560, SF_UPCASE }
+};
+
+static int FindStandardFilter(const Byte *code, UInt32 codeSize)
+{
+ UInt32 crc = CrcCalc(code, codeSize);
+ for (int i = 0; i < sizeof(kStdFilters) / sizeof(kStdFilters[0]); i++)
+ {
+ StandardFilterSignature &sfs = kStdFilters[i];
+ if (sfs.CRC == crc && sfs.Length == codeSize)
+ return i;
+ }
+ return -1;
+}
+
+#endif
+
+void CVm::PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg)
+{
+ Byte xorSum = 0;
+ for (UInt32 i = 1; i < codeSize; i++)
+ xorSum ^= code[i];
+
+ prg->Commands.Clear();
+ #ifdef RARVM_STANDARD_FILTERS
+ prg->StandardFilterIndex = -1;
+ #endif
+
+ if (xorSum == code[0] && codeSize > 0)
+ {
+ #ifdef RARVM_STANDARD_FILTERS
+ prg->StandardFilterIndex = FindStandardFilter(code, codeSize);
+ if (prg->StandardFilterIndex >= 0)
+ return;
+ #endif
+ // 1 byte for checksum
+ ReadVmProgram(code + 1, codeSize - 1, prg);
+ }
+ prg->Commands.Add(CCommand());
+ CCommand *cmd = &prg->Commands.Back();
+ cmd->OpCode = CMD_RET;
+}
+
+void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize)
+{
+ if (pos < kSpaceSize && data != Mem + pos)
+ memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos));
+}
+
+#ifdef RARVM_STANDARD_FILTERS
+
+static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
+{
+ if (dataSize <= 4)
+ return;
+ dataSize -= 4;
+ const UInt32 kFileSize = 0x1000000;
+ Byte cmpByte2 = (e9 ? 0xE9 : 0xE8);
+ for (UInt32 curPos = 0; curPos < dataSize;)
+ {
+ Byte curByte = *(data++);
+ curPos++;
+ if (curByte == 0xE8 || curByte == cmpByte2)
+ {
+ UInt32 offset = curPos + fileOffset;
+ UInt32 addr = (Int32)GetValue32(data);
+ if (addr < kFileSize)
+ SetValue32(data, addr - offset);
+ else if ((Int32)addr < 0 && (Int32)(addr + offset) >= 0)
+ SetValue32(data, addr + kFileSize);
+ data += 4;
+ curPos += 4;
+ }
+ }
+}
+
+static inline UInt32 ItaniumGetOpType(const Byte *data, int bitPos)
+{
+ return (data[(unsigned int)bitPos >> 3] >> (bitPos & 7)) & 0xF;
+}
+
+
+static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
+{
+ UInt32 curPos = 0;
+ fileOffset >>= 4;
+ while (curPos < dataSize - 21)
+ {
+ int b = (data[0] & 0x1F) - 0x10;
+ if (b >= 0)
+ {
+ static Byte kCmdMasks[16] = {4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
+ Byte cmdMask = kCmdMasks[b];
+ if (cmdMask != 0)
+ for (int i = 0; i < 3; i++)
+ if (cmdMask & (1 << i))
+ {
+ int startPos = i * 41 + 18;
+ if (ItaniumGetOpType(data, startPos + 24) == 5)
+ {
+ const UInt32 kMask = 0xFFFFF;
+ Byte *p = data + ((unsigned int)startPos >> 3);
+ UInt32 bitField = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
+ int inBit = (startPos & 7);
+ UInt32 offset = (bitField >> inBit) & kMask;
+ UInt32 andMask = ~(kMask << inBit);
+ bitField = ((offset - fileOffset) & kMask) << inBit;
+ for (int j = 0; j < 3; j++)
+ {
+ p[j] &= andMask;
+ p[j] |= bitField;
+ andMask >>= 8;
+ bitField >>= 8;
+ }
+ }
+ }
+ }
+ data += 16;
+ curPos += 16;
+ fileOffset++;
+ }
+}
+
+static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels)
+{
+ UInt32 srcPos = 0;
+ UInt32 border = dataSize * 2;
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ Byte prevByte = 0;
+ for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels)
+ data[destPos] = (prevByte = prevByte - data[srcPos++]);
+ }
+}
+
+static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR)
+{
+ Byte *destData = srcData + dataSize;
+ const UInt32 numChannels = 3;
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ Byte prevByte = 0;
+
+ for (UInt32 i = curChannel; i < dataSize; i+= numChannels)
+ {
+ unsigned int predicted;
+ if (i < width)
+ predicted = prevByte;
+ else
+ {
+ unsigned int upperLeftByte = destData[i - width];
+ unsigned int upperByte = destData[i - width + 3];
+ predicted = prevByte + upperByte - upperLeftByte;
+ int pa = abs((int)(predicted - prevByte));
+ int pb = abs((int)(predicted - upperByte));
+ int pc = abs((int)(predicted - upperLeftByte));
+ if (pa <= pb && pa <= pc)
+ predicted = prevByte;
+ else
+ if (pb <= pc)
+ predicted = upperByte;
+ else
+ predicted = upperLeftByte;
+ }
+ destData[i] = prevByte = (Byte)(predicted - *(srcData++));
+ }
+ }
+ if (dataSize < 3)
+ return;
+ for (UInt32 i = posR, border = dataSize - 2; i < border; i += 3)
+ {
+ Byte g = destData[i + 1];
+ destData[i] = destData[i] + g;
+ destData[i + 2] = destData[i + 2] + g;
+ }
+}
+
+static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels)
+{
+ Byte *destData = srcData + dataSize;
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ UInt32 prevByte = 0, prevDelta = 0, dif[7];
+ Int32 D1 = 0, D2 = 0, D3;
+ Int32 K1 = 0, K2 = 0, K3 = 0;
+ memset(dif, 0, sizeof(dif));
+
+ for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++)
+ {
+ D3 = D2;
+ D2 = prevDelta - D1;
+ D1 = prevDelta;
+
+ UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3;
+ predicted = (predicted >> 3) & 0xFF;
+
+ UInt32 curByte = *(srcData++);
+
+ predicted -= curByte;
+ destData[i] = (Byte)predicted;
+ prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte);
+ prevByte = predicted;
+
+ Int32 D = ((Int32)(signed char)curByte) << 3;
+
+ dif[0] += abs(D);
+ dif[1] += abs(D - D1);
+ dif[2] += abs(D + D1);
+ dif[3] += abs(D - D2);
+ dif[4] += abs(D + D2);
+ dif[5] += abs(D - D3);
+ dif[6] += abs(D + D3);
+
+ if ((byteCount & 0x1F) == 0)
+ {
+ UInt32 minDif = dif[0], numMinDif = 0;
+ dif[0] = 0;
+ for (int j = 1; j < sizeof(dif) / sizeof(dif[0]); j++)
+ {
+ if (dif[j] < minDif)
+ {
+ minDif = dif[j];
+ numMinDif = j;
+ }
+ dif[j] = 0;
+ }
+ switch (numMinDif)
+ {
+ case 1: if (K1 >= -16) K1--; break;
+ case 2: if (K1 < 16) K1++; break;
+ case 3: if (K2 >= -16) K2--; break;
+ case 4: if (K2 < 16) K2++; break;
+ case 5: if (K3 >= -16) K3--; break;
+ case 6: if (K3 < 16) K3++; break;
+ }
+ }
+ }
+ }
+}
+
+static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
+{
+ UInt32 srcPos = 0, destPos = dataSize;
+ while (srcPos < dataSize)
+ {
+ Byte curByte = data[srcPos++];
+ if (curByte == 2 && (curByte = data[srcPos++]) != 2)
+ curByte -= 32;
+ data[destPos++] = curByte;
+ }
+ return destPos - dataSize;
+}
+
+void CVm::ExecuteStandardFilter(int filterIndex)
+{
+ UInt32 dataSize = R[4];
+ if (dataSize >= kGlobalOffset)
+ return;
+ EStandardFilter filterType = kStdFilters[filterIndex].Type;
+
+ switch (filterType)
+ {
+ case SF_E8:
+ case SF_E8E9:
+ E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9));
+ break;
+ case SF_ITANIUM:
+ ItaniumDecode(Mem, dataSize, R[6]);
+ break;
+ case SF_DELTA:
+ if (dataSize >= kGlobalOffset / 2)
+ break;
+ SetBlockPos(dataSize);
+ DeltaDecode(Mem, dataSize, R[0]);
+ break;
+ case SF_RGB:
+ if (dataSize >= kGlobalOffset / 2)
+ break;
+ {
+ UInt32 width = R[0];
+ if (width <= 3)
+ break;
+ SetBlockPos(dataSize);
+ RgbDecode(Mem, dataSize, width, R[1]);
+ }
+ break;
+ case SF_AUDIO:
+ if (dataSize >= kGlobalOffset / 2)
+ break;
+ SetBlockPos(dataSize);
+ AudioDecode(Mem, dataSize, R[0]);
+ break;
+ case SF_UPCASE:
+ if (dataSize >= kGlobalOffset / 2)
+ break;
+ UInt32 destSize = UpCaseDecode(Mem, dataSize);
+ SetBlockSize(destSize);
+ SetBlockPos(dataSize);
+ break;
+ }
+}
+
+#endif
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/Rar3Vm.h b/src/libs/7zip/win/CPP/7zip/Compress/Rar3Vm.h
new file mode 100644
index 000000000..c02534c61
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/Rar3Vm.h
@@ -0,0 +1,179 @@
+// Rar3Vm.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef __COMPRESS_RAR3_VM_H
+#define __COMPRESS_RAR3_VM_H
+
+#include "../../../C/CpuArch.h"
+
+#include "Common/MyVector.h"
+#include "Common/Types.h"
+
+#define RARVM_STANDARD_FILTERS
+
+namespace NCompress {
+namespace NRar3 {
+
+class CMemBitDecoder
+{
+ const Byte *_data;
+ UInt32 _bitSize;
+ UInt32 _bitPos;
+public:
+ void Init(const Byte *data, UInt32 byteSize)
+ {
+ _data = data;
+ _bitSize = (byteSize << 3);
+ _bitPos = 0;
+ }
+ UInt32 ReadBits(int numBits);
+ UInt32 ReadBit();
+ bool Avail() const { return (_bitPos < _bitSize); }
+};
+
+namespace NVm {
+
+inline UInt32 GetValue32(const void *addr) { return GetUi32(addr); }
+inline void SetValue32(void *addr, UInt32 value) { SetUi32(addr, value); }
+
+UInt32 ReadEncodedUInt32(CMemBitDecoder &inp);
+
+const int kNumRegBits = 3;
+const UInt32 kNumRegs = 1 << kNumRegBits;
+const UInt32 kNumGpRegs = kNumRegs - 1;
+
+const UInt32 kSpaceSize = 0x40000;
+const UInt32 kSpaceMask = kSpaceSize -1;
+const UInt32 kGlobalOffset = 0x3C000;
+const UInt32 kGlobalSize = 0x2000;
+const UInt32 kFixedGlobalSize = 64;
+
+namespace NGlobalOffset
+{
+ const UInt32 kBlockSize = 0x1C;
+ const UInt32 kBlockPos = 0x20;
+ const UInt32 kExecCount = 0x2C;
+ const UInt32 kGlobalMemOutSize = 0x30;
+}
+
+enum ECommand
+{
+ CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC,
+ CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB,
+ CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT,
+ CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF,
+ CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT,
+
+ CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB,
+ CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB,
+ CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB
+};
+
+enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE};
+
+// Addr in COperand object can link (point) to CVm object!!!
+
+struct COperand
+{
+ EOpType Type;
+ UInt32 Data;
+ UInt32 Base;
+ COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {}
+};
+
+struct CCommand
+{
+ ECommand OpCode;
+ bool ByteMode;
+ COperand Op1, Op2;
+};
+
+struct CBlockRef
+{
+ UInt32 Offset;
+ UInt32 Size;
+};
+
+struct CProgram
+{
+ CRecordVector<CCommand> Commands;
+ #ifdef RARVM_STANDARD_FILTERS
+ int StandardFilterIndex;
+ #endif
+ CRecordVector<Byte> StaticData;
+};
+
+struct CProgramInitState
+{
+ UInt32 InitR[kNumGpRegs];
+ CRecordVector<Byte> GlobalData;
+
+ void AllocateEmptyFixedGlobal()
+ {
+ GlobalData.Clear();
+ GlobalData.Reserve(NVm::kFixedGlobalSize);
+ for (UInt32 i = 0; i < NVm::kFixedGlobalSize; i++)
+ GlobalData.Add(0);
+ }
+};
+
+class CVm
+{
+ static UInt32 GetValue(bool byteMode, const void *addr)
+ {
+ if (byteMode)
+ return(*(const Byte *)addr);
+ else
+ return GetUi32(addr);
+ }
+
+ static void SetValue(bool byteMode, void *addr, UInt32 value)
+ {
+ if (byteMode)
+ *(Byte *)addr = (Byte)value;
+ else
+ SetUi32(addr, value);
+ }
+
+ UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); }
+
+ void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); }
+ void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); }
+public:
+ static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); }
+private:
+ UInt32 GetOperand32(const COperand *op) const;
+ void SetOperand32(const COperand *op, UInt32 val);
+ Byte GetOperand8(const COperand *op) const;
+ void SetOperand8(const COperand *op, Byte val);
+ UInt32 GetOperand(bool byteMode, const COperand *op) const;
+ void SetOperand(bool byteMode, const COperand *op, UInt32 val);
+
+ void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode);
+
+ bool ExecuteCode(const CProgram *prg);
+
+ #ifdef RARVM_STANDARD_FILTERS
+ void ExecuteStandardFilter(int filterIndex);
+ #endif
+
+ Byte *Mem;
+ UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization)
+ UInt32 Flags;
+ void ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg);
+public:
+ CVm();
+ ~CVm();
+ bool Create();
+ void PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg);
+ void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize);
+ bool Execute(CProgram *prg, const CProgramInitState *initState,
+ CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData);
+ const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; }
+
+};
+
+#endif
+
+}}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/RarCodecsRegister.cpp b/src/libs/7zip/win/CPP/7zip/Compress/RarCodecsRegister.cpp
new file mode 100644
index 000000000..e3f6a05c4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/RarCodecsRegister.cpp
@@ -0,0 +1,26 @@
+// RarCodecsRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Rar1Decoder.h"
+#include "Rar2Decoder.h"
+#include "Rar3Decoder.h"
+
+#define CREATE_CODEC(x) static void *CreateCodec ## x() { return (void *)(ICompressCoder *)(new NCompress::NRar ## x::CDecoder); }
+
+CREATE_CODEC(1)
+CREATE_CODEC(2)
+CREATE_CODEC(3)
+
+#define RAR_CODEC(x, name) { CreateCodec ## x, 0, 0x040300 + x, L"Rar" name, 1, false }
+
+static CCodecInfo g_CodecsInfo[] =
+{
+ RAR_CODEC(1, L"1"),
+ RAR_CODEC(2, L"2"),
+ RAR_CODEC(3, L"3"),
+};
+
+REGISTER_CODECS(Rar)
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ShrinkDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ShrinkDecoder.cpp
new file mode 100644
index 000000000..a89d323c6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ShrinkDecoder.cpp
@@ -0,0 +1,145 @@
+// ShrinkDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "BitlDecoder.h"
+#include "ShrinkDecoder.h"
+
+namespace NCompress {
+namespace NShrink {
+
+static const UInt32 kBufferSize = (1 << 20);
+static const int kNumMinBits = 9;
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ NBitl::CBaseDecoder<CInBuffer> inBuffer;
+ COutBuffer outBuffer;
+
+ if (!inBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ inBuffer.SetStream(inStream);
+ inBuffer.Init();
+
+ if (!outBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ outBuffer.SetStream(outStream);
+ outBuffer.Init();
+
+ UInt64 prevPos = 0;
+ int numBits = kNumMinBits;
+ UInt32 head = 257;
+ bool needPrev = false;
+ UInt32 lastSymbol = 0;
+
+ int i;
+ for (i = 0; i < kNumItems; i++)
+ _parents[i] = 0;
+ for (i = 0; i < kNumItems; i++)
+ _suffixes[i] = 0;
+ for (i = 0; i < 257; i++)
+ _isFree[i] = false;
+ for (; i < kNumItems; i++)
+ _isFree[i] = true;
+
+ for (;;)
+ {
+ UInt32 symbol = inBuffer.ReadBits(numBits);
+ if (inBuffer.ExtraBitsWereRead())
+ break;
+ if (_isFree[symbol])
+ return S_FALSE;
+ if (symbol == 256)
+ {
+ UInt32 symbol = inBuffer.ReadBits(numBits);
+ if (symbol == 1)
+ {
+ if (numBits < kNumMaxBits)
+ numBits++;
+ }
+ else if (symbol == 2)
+ {
+ if (needPrev)
+ _isFree[head - 1] = true;
+ for (i = 257; i < kNumItems; i++)
+ _isParent[i] = false;
+ for (i = 257; i < kNumItems; i++)
+ if (!_isFree[i])
+ _isParent[_parents[i]] = true;
+ for (i = 257; i < kNumItems; i++)
+ if (!_isParent[i])
+ _isFree[i] = true;
+ head = 257;
+ while (head < kNumItems && !_isFree[head])
+ head++;
+ if (head < kNumItems)
+ {
+ needPrev = true;
+ _isFree[head] = false;
+ _parents[head] = (UInt16)lastSymbol;
+ head++;
+ }
+ }
+ else
+ return S_FALSE;
+ continue;
+ }
+ UInt32 cur = symbol;
+ i = 0;
+ int corectionIndex = -1;
+ while (cur >= 256)
+ {
+ if (cur == head - 1)
+ corectionIndex = i;
+ _stack[i++] = _suffixes[cur];
+ cur = _parents[cur];
+ }
+ _stack[i++] = (Byte)cur;
+ if (needPrev)
+ {
+ _suffixes[head - 1] = (Byte)cur;
+ if (corectionIndex >= 0)
+ _stack[corectionIndex] = (Byte)cur;
+ }
+ while (i > 0)
+ outBuffer.WriteByte((_stack[--i]));
+ while (head < kNumItems && !_isFree[head])
+ head++;
+ if (head < kNumItems)
+ {
+ needPrev = true;
+ _isFree[head] = false;
+ _parents[head] = (UInt16)symbol;
+ head++;
+ }
+ else
+ needPrev = false;
+ lastSymbol = symbol;
+
+ UInt64 nowPos = outBuffer.GetProcessedSize();
+ if (progress != NULL && nowPos - prevPos > (1 << 18))
+ {
+ prevPos = nowPos;
+ UInt64 packSize = inBuffer.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &nowPos));
+ }
+ }
+ return outBuffer.Flush();
+}
+
+STDMETHODIMP CDecoder ::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ShrinkDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/ShrinkDecoder.h
new file mode 100644
index 000000000..9bbecd41b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ShrinkDecoder.h
@@ -0,0 +1,38 @@
+// ShrinkDecoder.h
+
+#ifndef __COMPRESS_SHRINK_DECODER_H
+#define __COMPRESS_SHRINK_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NShrink {
+
+const int kNumMaxBits = 13;
+const UInt32 kNumItems = 1 << kNumMaxBits;
+
+class CDecoder :
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ UInt16 _parents[kNumItems];
+ Byte _suffixes[kNumItems];
+ Byte _stack[kNumItems];
+ bool _isFree[kNumItems];
+ bool _isParent[kNumItems];
+
+public:
+ MY_UNKNOWN_IMP
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Compress/StdAfx.h
new file mode 100644
index 000000000..99a8aa46d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/MyWindows.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp
new file mode 100644
index 000000000..e28c64518
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.cpp
@@ -0,0 +1,159 @@
+// ZDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "ZDecoder.h"
+
+namespace NCompress {
+namespace NZ {
+
+static const UInt32 kBufferSize = (1 << 20);
+static const Byte kNumBitsMask = 0x1F;
+static const Byte kBlockModeMask = 0x80;
+static const int kNumMinBits = 9;
+static const int kNumMaxBits = 16;
+
+void CDecoder::Free()
+{
+ MyFree(_parents); _parents = 0;
+ MyFree(_suffixes); _suffixes = 0;
+ MyFree(_stack); _stack = 0;
+}
+
+CDecoder::~CDecoder() { Free(); }
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CInBuffer inBuffer;
+ COutBuffer outBuffer;
+
+ if (!inBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ inBuffer.SetStream(inStream);
+ inBuffer.Init();
+
+ if (!outBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ outBuffer.SetStream(outStream);
+ outBuffer.Init();
+
+ int maxbits = _properties & kNumBitsMask;
+ if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
+ return S_FALSE;
+ UInt32 numItems = 1 << maxbits;
+ bool blockMode = ((_properties & kBlockModeMask) != 0);
+
+ if (maxbits != _numMaxBits || _parents == 0 || _suffixes == 0 || _stack == 0)
+ {
+ Free();
+ _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (_parents == 0) return E_OUTOFMEMORY;
+ _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_suffixes == 0) return E_OUTOFMEMORY;
+ _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_stack == 0) return E_OUTOFMEMORY;
+ _numMaxBits = maxbits;
+ }
+
+ UInt64 prevPos = 0;
+ int numBits = kNumMinBits;
+ UInt32 head = blockMode ? 257 : 256;
+
+ bool needPrev = false;
+
+ unsigned bitPos = 0;
+ unsigned numBufBits = 0;
+
+ Byte buf[kNumMaxBits + 4];
+
+ _parents[256] = 0; // virus protection
+ _suffixes[256] = 0;
+
+ for (;;)
+ {
+ if (numBufBits == bitPos)
+ {
+ numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8;
+ bitPos = 0;
+ UInt64 nowPos = outBuffer.GetProcessedSize();
+ if (progress != NULL && nowPos - prevPos >= (1 << 18))
+ {
+ prevPos = nowPos;
+ UInt64 packSize = inBuffer.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &nowPos));
+ }
+ }
+ unsigned bytePos = bitPos >> 3;
+ UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16);
+ symbol >>= (bitPos & 7);
+ symbol &= (1 << numBits) - 1;
+ bitPos += numBits;
+ if (bitPos > numBufBits)
+ break;
+ if (symbol >= head)
+ return S_FALSE;
+ if (blockMode && symbol == 256)
+ {
+ numBufBits = bitPos = 0;
+ numBits = kNumMinBits;
+ head = 257;
+ needPrev = false;
+ continue;
+ }
+ UInt32 cur = symbol;
+ int i = 0;
+ while (cur >= 256)
+ {
+ _stack[i++] = _suffixes[cur];
+ cur = _parents[cur];
+ }
+ _stack[i++] = (Byte)cur;
+ if (needPrev)
+ {
+ _suffixes[head - 1] = (Byte)cur;
+ if (symbol == head - 1)
+ _stack[0] = (Byte)cur;
+ }
+ do
+ outBuffer.WriteByte((_stack[--i]));
+ while (i > 0);
+ if (head < numItems)
+ {
+ needPrev = true;
+ _parents[head++] = (UInt16)symbol;
+ if (head > ((UInt32)1 << numBits))
+ {
+ if (numBits < maxbits)
+ {
+ numBufBits = bitPos = 0;
+ numBits++;
+ }
+ }
+ }
+ else
+ needPrev = false;
+ }
+ return outBuffer.Flush();
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ _properties = data[0];
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.h
new file mode 100644
index 000000000..2bd83a177
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ZDecoder.h
@@ -0,0 +1,42 @@
+// ZDecoder.h
+
+#ifndef __COMPRESS_Z_DECODER_H
+#define __COMPRESS_Z_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NZ {
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ UInt16 *_parents;
+ Byte *_suffixes;
+ Byte *_stack;
+ Byte _properties;
+ int _numMaxBits;
+
+public:
+ CDecoder(): _parents(0), _suffixes(0), _stack(0), _properties(0), _numMaxBits(0) {};
+ ~CDecoder();
+ void Free();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ZlibDecoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ZlibDecoder.cpp
new file mode 100644
index 000000000..90d6715db
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ZlibDecoder.cpp
@@ -0,0 +1,89 @@
+// ZlibDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "ZlibDecoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } catch(...) { return S_FALSE; }
+
+#define ADLER_MOD 65521
+#define ADLER_LOOP_MAX 5550
+
+UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size)
+{
+ UInt32 a = adler & 0xFFFF;
+ UInt32 b = (adler >> 16) & 0xFFFF;
+ while (size > 0)
+ {
+ unsigned curSize = (size > ADLER_LOOP_MAX) ? ADLER_LOOP_MAX : (unsigned )size;
+ unsigned i;
+ for (i = 0; i < curSize; i++)
+ {
+ a += buf[i];
+ b += a;
+ }
+ buf += curSize;
+ size -= curSize;
+ a %= ADLER_MOD;
+ b %= ADLER_MOD;
+ }
+ return (b << 16) + a;
+}
+
+STDMETHODIMP COutStreamWithAdler::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = _stream->Write(data, size, &size);
+ _adler = Adler32_Update(_adler, (const Byte *)data, size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ DEFLATE_TRY_BEGIN
+ if (!AdlerStream)
+ AdlerStream = AdlerSpec = new COutStreamWithAdler;
+ if (!DeflateDecoder)
+ {
+ DeflateDecoderSpec = new NDeflate::NDecoder::CCOMCoder;
+ DeflateDecoderSpec->ZlibMode = true;
+ DeflateDecoder = DeflateDecoderSpec;
+ }
+
+ Byte buf[2];
+ RINOK(ReadStream_FALSE(inStream, buf, 2));
+ int method = buf[0] & 0xF;
+ if (method != 8)
+ return S_FALSE;
+ // int dicSize = buf[0] >> 4;
+ if ((((UInt32)buf[0] << 8) + buf[1]) % 31 != 0)
+ return S_FALSE;
+ if ((buf[1] & 0x20) != 0) // dictPresent
+ return S_FALSE;
+ // int level = (buf[1] >> 6);
+
+ AdlerSpec->SetStream(outStream);
+ AdlerSpec->Init();
+ HRESULT res = DeflateDecoder->Code(inStream, AdlerStream, inSize, outSize, progress);
+ AdlerSpec->ReleaseStream();
+
+ if (res == S_OK)
+ {
+ const Byte *p = DeflateDecoderSpec->ZlibFooter;
+ UInt32 adler = ((UInt32)p[0] << 24) | ((UInt32)p[1] << 16) | ((UInt32)p[2] << 8) | p[3];
+ if (adler != AdlerSpec->GetAdler())
+ return S_FALSE;
+ }
+ return res;
+ DEFLATE_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ZlibDecoder.h b/src/libs/7zip/win/CPP/7zip/Compress/ZlibDecoder.h
new file mode 100644
index 000000000..95c110022
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ZlibDecoder.h
@@ -0,0 +1,48 @@
+// ZlibDecoder.h
+
+#ifndef __ZLIB_DECODER_H
+#define __ZLIB_DECODER_H
+
+#include "DeflateDecoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+const UInt32 ADLER_INIT_VAL = 1;
+
+class COutStreamWithAdler:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt32 _adler;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _adler = ADLER_INIT_VAL; }
+ UInt32 GetAdler() const { return _adler; }
+};
+
+class CDecoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ COutStreamWithAdler *AdlerSpec;
+ CMyComPtr<ISequentialOutStream> AdlerStream;
+
+ NCompress::NDeflate::NDecoder::CCOMCoder *DeflateDecoderSpec;
+ CMyComPtr<ICompressCoder> DeflateDecoder;
+public:
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ UInt64 GetInputProcessedSize() const { return DeflateDecoderSpec->GetInputProcessedSize() + 2; }
+
+ MY_UNKNOWN_IMP
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ZlibEncoder.cpp b/src/libs/7zip/win/CPP/7zip/Compress/ZlibEncoder.cpp
new file mode 100644
index 000000000..09235c337
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ZlibEncoder.cpp
@@ -0,0 +1,61 @@
+// ZlibEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "ZlibEncoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } catch(...) { return S_FALSE; }
+
+UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size);
+
+STDMETHODIMP CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ HRESULT result = _stream->Read(data, size, &size);
+ _adler = Adler32_Update(_adler, (const Byte *)data, size);
+ _size += size;
+ if (processedSize != NULL)
+ *processedSize = size;
+ return result;
+}
+
+void CEncoder::Create()
+{
+ if (!DeflateEncoder)
+ DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder;
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ DEFLATE_TRY_BEGIN
+ if (!AdlerStream)
+ AdlerStream = AdlerSpec = new CInStreamWithAdler;
+ Create();
+
+ {
+ Byte buf[2] = { 0x78, 0xDA };
+ RINOK(WriteStream(outStream, buf, 2));
+ }
+
+ AdlerSpec->SetStream(inStream);
+ AdlerSpec->Init();
+ HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress);
+ AdlerSpec->ReleaseStream();
+
+ RINOK(res);
+
+ {
+ UInt32 a = AdlerSpec->GetAdler();
+ Byte buf[4] = { (Byte)(a >> 24), (Byte)(a >> 16), (Byte)(a >> 8), (Byte)(a) };
+ return WriteStream(outStream, buf, 4);
+ }
+ DEFLATE_TRY_END
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Compress/ZlibEncoder.h b/src/libs/7zip/win/CPP/7zip/Compress/ZlibEncoder.h
new file mode 100644
index 000000000..621cc1d08
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Compress/ZlibEncoder.h
@@ -0,0 +1,48 @@
+// ZlibEncoder.h
+
+#ifndef __ZLIB_ENCODER_H
+#define __ZLIB_ENCODER_H
+
+#include "DeflateEncoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+class CInStreamWithAdler:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt32 _adler;
+ UInt64 _size;
+public:
+ MY_UNKNOWN_IMP
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _adler = 1; _size = 0; } // ADLER_INIT_VAL
+ UInt32 GetAdler() const { return _adler; }
+ UInt64 GetSize() const { return _size; }
+};
+
+class CEncoder:
+ public ICompressCoder,
+ public CMyUnknownImp
+{
+ CInStreamWithAdler *AdlerSpec;
+ CMyComPtr<ISequentialInStream> AdlerStream;
+ CMyComPtr<ICompressCoder> DeflateEncoder;
+public:
+ NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec;
+
+ void Create();
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+ UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); }
+
+ MY_UNKNOWN_IMP
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/7zAes.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/7zAes.cpp
new file mode 100644
index 000000000..b686fb61f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/7zAes.cpp
@@ -0,0 +1,244 @@
+// 7zAes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Sha256.h"
+
+#include "Windows/Synchronization.h"
+
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "7zAes.h"
+#include "MyAes.h"
+
+#ifndef EXTRACT_ONLY
+#include "RandGen.h"
+#endif
+
+using namespace NWindows;
+
+namespace NCrypto {
+namespace NSevenZ {
+
+bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
+{
+ if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
+ return false;
+ for (UInt32 i = 0; i < SaltSize; i++)
+ if (Salt[i] != a.Salt[i])
+ return false;
+ return (Password == a.Password);
+}
+
+void CKeyInfo::CalculateDigest()
+{
+ if (NumCyclesPower == 0x3F)
+ {
+ UInt32 pos;
+ for (pos = 0; pos < SaltSize; pos++)
+ Key[pos] = Salt[pos];
+ for (UInt32 i = 0; i < Password.GetCapacity() && pos < kKeySize; i++)
+ Key[pos++] = Password[i];
+ for (; pos < kKeySize; pos++)
+ Key[pos] = 0;
+ }
+ else
+ {
+ CSha256 sha;
+ Sha256_Init(&sha);
+ const UInt64 numRounds = (UInt64)1 << NumCyclesPower;
+ Byte temp[8] = { 0,0,0,0,0,0,0,0 };
+ for (UInt64 round = 0; round < numRounds; round++)
+ {
+ Sha256_Update(&sha, Salt, (size_t)SaltSize);
+ Sha256_Update(&sha, Password, Password.GetCapacity());
+ Sha256_Update(&sha, temp, 8);
+ for (int i = 0; i < 8; i++)
+ if (++(temp[i]) != 0)
+ break;
+ }
+ Sha256_Final(&sha, Key);
+ }
+}
+
+bool CKeyInfoCache::Find(CKeyInfo &key)
+{
+ for (int i = 0; i < Keys.Size(); i++)
+ {
+ const CKeyInfo &cached = Keys[i];
+ if (key.IsEqualTo(cached))
+ {
+ for (int j = 0; j < kKeySize; j++)
+ key.Key[j] = cached.Key[j];
+ if (i != 0)
+ {
+ Keys.Insert(0, cached);
+ Keys.Delete(i+1);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void CKeyInfoCache::Add(CKeyInfo &key)
+{
+ if (Find(key))
+ return;
+ if (Keys.Size() >= Size)
+ Keys.DeleteBack();
+ Keys.Insert(0, key);
+}
+
+static CKeyInfoCache g_GlobalKeyCache(32);
+static NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
+
+CBase::CBase():
+ _cachedKeys(16),
+ _ivSize(0)
+{
+ for (int i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+}
+
+void CBase::CalculateDigest()
+{
+ NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
+ if (_cachedKeys.Find(_key))
+ g_GlobalKeyCache.Add(_key);
+ else
+ {
+ if (!g_GlobalKeyCache.Find(_key))
+ {
+ _key.CalculateDigest();
+ g_GlobalKeyCache.Add(_key);
+ }
+ _cachedKeys.Add(_key);
+ }
+}
+
+#ifndef EXTRACT_ONLY
+
+/*
+STDMETHODIMP CEncoder::ResetSalt()
+{
+ _key.SaltSize = 4;
+ g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
+ return S_OK;
+}
+*/
+
+STDMETHODIMP CEncoder::ResetInitVector()
+{
+ _ivSize = 8;
+ g_RandomGenerator.Generate(_iv, (unsigned)_ivSize);
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ // _key.Init();
+ for (UInt32 i = _ivSize; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+
+ UInt32 ivSize = _ivSize;
+
+ // _key.NumCyclesPower = 0x3F;
+ _key.NumCyclesPower = 19;
+
+ Byte firstByte = (Byte)(_key.NumCyclesPower |
+ (((_key.SaltSize == 0) ? 0 : 1) << 7) |
+ (((ivSize == 0) ? 0 : 1) << 6));
+ RINOK(outStream->Write(&firstByte, 1, NULL));
+ if (_key.SaltSize == 0 && ivSize == 0)
+ return S_OK;
+ Byte saltSizeSpec = (Byte)((_key.SaltSize == 0) ? 0 : (_key.SaltSize - 1));
+ Byte ivSizeSpec = (Byte)((ivSize == 0) ? 0 : (ivSize - 1));
+ Byte secondByte = (Byte)(((saltSizeSpec) << 4) | ivSizeSpec);
+ RINOK(outStream->Write(&secondByte, 1, NULL));
+ if (_key.SaltSize > 0)
+ {
+ RINOK(WriteStream(outStream, _key.Salt, _key.SaltSize));
+ }
+ if (ivSize > 0)
+ {
+ RINOK(WriteStream(outStream, _iv, ivSize));
+ }
+ return S_OK;
+}
+
+HRESULT CEncoder::CreateFilter()
+{
+ _aesFilter = new CAesCbcEncoder;
+ return S_OK;
+}
+
+#endif
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ _key.Init();
+ UInt32 i;
+ for (i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+ if (size == 0)
+ return S_OK;
+ UInt32 pos = 0;
+ Byte firstByte = data[pos++];
+
+ _key.NumCyclesPower = firstByte & 0x3F;
+ if ((firstByte & 0xC0) == 0)
+ return S_OK;
+ _key.SaltSize = (firstByte >> 7) & 1;
+ UInt32 ivSize = (firstByte >> 6) & 1;
+
+ if (pos >= size)
+ return E_INVALIDARG;
+ Byte secondByte = data[pos++];
+
+ _key.SaltSize += (secondByte >> 4);
+ ivSize += (secondByte & 0x0F);
+
+ if (pos + _key.SaltSize + ivSize > size)
+ return E_INVALIDARG;
+ for (i = 0; i < _key.SaltSize; i++)
+ _key.Salt[i] = data[pos++];
+ for (i = 0; i < ivSize; i++)
+ _iv[i] = data[pos++];
+ return (_key.NumCyclesPower <= 24) ? S_OK : E_NOTIMPL;
+}
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _key.Password.SetCapacity((size_t)size);
+ memcpy(_key.Password, data, (size_t)size);
+ return S_OK;
+}
+
+STDMETHODIMP CBaseCoder::Init()
+{
+ CalculateDigest();
+ if (_aesFilter == 0)
+ {
+ RINOK(CreateFilter());
+ }
+ CMyComPtr<ICryptoProperties> cp;
+ RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
+ RINOK(cp->SetKey(_key.Key, sizeof(_key.Key)));
+ RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
+{
+ return _aesFilter->Filter(data, size);
+}
+
+HRESULT CDecoder::CreateFilter()
+{
+ _aesFilter = new CAesCbcDecoder;
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/7zAes.h b/src/libs/7zip/win/CPP/7zip/Crypto/7zAes.h
new file mode 100644
index 000000000..79d723fae
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/7zAes.h
@@ -0,0 +1,117 @@
+// 7zAes.h
+
+#ifndef __CRYPTO_7Z_AES_H
+#define __CRYPTO_7Z_AES_H
+
+#include "Common/Buffer.h"
+#include "Common/MyCom.h"
+#include "Common/MyVector.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NSevenZ {
+
+const int kKeySize = 32;
+
+class CKeyInfo
+{
+public:
+ int NumCyclesPower;
+ UInt32 SaltSize;
+ Byte Salt[16];
+ CByteBuffer Password;
+ Byte Key[kKeySize];
+
+ bool IsEqualTo(const CKeyInfo &a) const;
+ void CalculateDigest();
+
+ CKeyInfo() { Init(); }
+ void Init()
+ {
+ NumCyclesPower = 0;
+ SaltSize = 0;
+ for (int i = 0; i < sizeof(Salt); i++)
+ Salt[i] = 0;
+ }
+};
+
+class CKeyInfoCache
+{
+ int Size;
+ CObjectVector<CKeyInfo> Keys;
+public:
+ CKeyInfoCache(int size): Size(size) {}
+ bool Find(CKeyInfo &key);
+ // HRESULT Calculate(CKeyInfo &key);
+ void Add(CKeyInfo &key);
+};
+
+class CBase
+{
+ CKeyInfoCache _cachedKeys;
+protected:
+ CKeyInfo _key;
+ Byte _iv[16];
+ UInt32 _ivSize;
+ void CalculateDigest();
+ CBase();
+};
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp,
+ public CBase
+{
+protected:
+ CMyComPtr<ICompressFilter> _aesFilter;
+
+ virtual HRESULT CreateFilter() = 0;
+ #ifndef CRYPTO_AES
+ HRESULT CreateFilterFromDLL(REFCLSID clsID);
+ #endif
+public:
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+#ifndef EXTRACT_ONLY
+
+class CEncoder:
+ public CBaseCoder,
+ public ICompressWriteCoderProperties,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector
+{
+ virtual HRESULT CreateFilter();
+public:
+ MY_UNKNOWN_IMP3(
+ ICryptoSetPassword,
+ ICompressWriteCoderProperties,
+ // ICryptoResetSalt,
+ ICryptoResetInitVector)
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+ // STDMETHOD(ResetSalt)();
+ STDMETHOD(ResetInitVector)();
+};
+#endif
+
+class CDecoder:
+ public CBaseCoder,
+ public ICompressSetDecoderProperties2
+{
+ virtual HRESULT CreateFilter();
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/7zAesRegister.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/7zAesRegister.cpp
new file mode 100644
index 000000000..5e57748f5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/7zAesRegister.cpp
@@ -0,0 +1,18 @@
+// 7zAesRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+#include "7zAes.h"
+
+static void *CreateCodec() { return (void *)(ICompressFilter *)(new NCrypto::NSevenZ::CDecoder()); }
+#ifndef EXTRACT_ONLY
+static void *CreateCodecOut() { return (void *)(ICompressFilter *)(new NCrypto::NSevenZ::CEncoder()); }
+#else
+#define CreateCodecOut 0
+#endif
+
+static CCodecInfo g_CodecInfo =
+ { CreateCodec, CreateCodecOut, 0x06F10701, L"7zAES", 1, true };
+
+REGISTER_CODEC(7zAES)
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/HmacSha1.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/HmacSha1.cpp
new file mode 100644
index 000000000..a66d62711
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/HmacSha1.cpp
@@ -0,0 +1,109 @@
+// HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void CHmac::SetKey(const Byte *key, size_t keySize)
+{
+ Byte keyTemp[kBlockSize];
+ size_t i;
+ for (i = 0; i < kBlockSize; i++)
+ keyTemp[i] = 0;
+ if(keySize > kBlockSize)
+ {
+ _sha.Init();
+ _sha.Update(key, keySize);
+ _sha.Final(keyTemp);
+ keySize = kDigestSize;
+ }
+ else
+ for (i = 0; i < keySize; i++)
+ keyTemp[i] = key[i];
+ for (i = 0; i < kBlockSize; i++)
+ keyTemp[i] ^= 0x36;
+ _sha.Init();
+ _sha.Update(keyTemp, kBlockSize);
+ for (i = 0; i < kBlockSize; i++)
+ keyTemp[i] ^= 0x36 ^ 0x5C;
+ _sha2.Init();
+ _sha2.Update(keyTemp, kBlockSize);
+}
+
+void CHmac::Final(Byte *mac, size_t macSize)
+{
+ Byte digest[kDigestSize];
+ _sha.Final(digest);
+ _sha2.Update(digest, kDigestSize);
+ _sha2.Final(digest);
+ for(size_t i = 0; i < macSize; i++)
+ mac[i] = digest[i];
+}
+
+
+void CHmac32::SetKey(const Byte *key, size_t keySize)
+{
+ UInt32 keyTemp[kBlockSizeInWords];
+ size_t i;
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] = 0;
+ if(keySize > kBlockSize)
+ {
+ CContext sha;
+ sha.Init();
+ sha.Update(key, keySize);
+ Byte digest[kDigestSize];
+ sha.Final(digest);
+
+ for (int i = 0 ; i < kDigestSizeInWords; i++)
+ keyTemp[i] =
+ ((UInt32)(digest[i * 4 + 0]) << 24) |
+ ((UInt32)(digest[i * 4 + 1]) << 16) |
+ ((UInt32)(digest[i * 4 + 2]) << 8) |
+ ((UInt32)(digest[i * 4 + 3]));
+ keySize = kDigestSizeInWords;
+ }
+ else
+ for (size_t i = 0; i < keySize; i++)
+ keyTemp[i / 4] |= (key[i] << (24 - 8 * (i & 3)));
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] ^= 0x36363636;
+ _sha.Init();
+ _sha.Update(keyTemp, kBlockSizeInWords);
+ for (i = 0; i < kBlockSizeInWords; i++)
+ keyTemp[i] ^= 0x36363636 ^ 0x5C5C5C5C;
+ _sha2.Init();
+ _sha2.Update(keyTemp, kBlockSizeInWords);
+}
+
+void CHmac32::Final(UInt32 *mac, size_t macSize)
+{
+ UInt32 digest[kDigestSizeInWords];
+ _sha.Final(digest);
+ _sha2.Update(digest, kDigestSizeInWords);
+ _sha2.Final(digest);
+ for(size_t i = 0; i < macSize; i++)
+ mac[i] = digest[i];
+}
+
+void CHmac32::GetLoopXorDigest(UInt32 *mac, UInt32 numIteration)
+{
+ UInt32 block[kBlockSizeInWords];
+ UInt32 block2[kBlockSizeInWords];
+ _sha.PrepareBlock(block, kDigestSizeInWords);
+ _sha2.PrepareBlock(block2, kDigestSizeInWords);
+ for(unsigned int s = 0; s < kDigestSizeInWords; s++)
+ block[s] = mac[s];
+ for(UInt32 i = 0; i < numIteration; i++)
+ {
+ _sha.GetBlockDigest(block, block2);
+ _sha2.GetBlockDigest(block2, block);
+ for (unsigned int s = 0; s < kDigestSizeInWords; s++)
+ mac[s] ^= block[s];
+ }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/HmacSha1.h b/src/libs/7zip/win/CPP/7zip/Crypto/HmacSha1.h
new file mode 100644
index 000000000..d7181329c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/HmacSha1.h
@@ -0,0 +1,39 @@
+// HmacSha1.h
+// Implements HMAC-SHA-1 (RFC2104, FIPS-198)
+
+#ifndef __CRYPTO_HMAC_SHA1_H
+#define __CRYPTO_HMAC_SHA1_H
+
+#include "Sha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+// Use: SetKey(key, keySize); for () Update(data, size); Final(mac, macSize);
+
+class CHmac
+{
+ CContext _sha;
+ CContext _sha2;
+public:
+ void SetKey(const Byte *key, size_t keySize);
+ void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); }
+ void Final(Byte *mac, size_t macSize = kDigestSize);
+};
+
+class CHmac32
+{
+ CContext32 _sha;
+ CContext32 _sha2;
+public:
+ void SetKey(const Byte *key, size_t keySize);
+ void Update(const UInt32 *data, size_t dataSize) { _sha.Update(data, dataSize); }
+ void Final(UInt32 *mac, size_t macSize = kDigestSizeInWords);
+
+ // It'sa for hmac function. in,out: mac[kDigestSizeInWords].
+ void GetLoopXorDigest(UInt32 *mac, UInt32 numIteration);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/MyAes.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/MyAes.cpp
new file mode 100644
index 000000000..70a7dccff
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/MyAes.cpp
@@ -0,0 +1,48 @@
+// Crypto/MyAes.cpp
+
+#include "StdAfx.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+
+struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;
+
+CAesCbcCoder::CAesCbcCoder()
+{
+ _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32);
+}
+
+STDMETHODIMP CAesCbcCoder::Init() { return S_OK; }
+
+STDMETHODIMP_(UInt32) CAesCbcCoder::Filter(Byte *data, UInt32 size)
+{
+ if (size == 0)
+ return 0;
+ if (size < AES_BLOCK_SIZE)
+ return AES_BLOCK_SIZE;
+ size >>= 4;
+ _codeFunc(_aes + _offset, data, size);
+ return size << 4;
+}
+
+STDMETHODIMP CAesCbcCoder::SetKey(const Byte *data, UInt32 size)
+{
+ if ((size & 0x7) != 0 || size < 16 || size > 32)
+ return E_INVALIDARG;
+ _setKeyFunc(_aes + _offset + 4, data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CAesCbcCoder::SetInitVector(const Byte *data, UInt32 size)
+{
+ if (size != AES_BLOCK_SIZE)
+ return E_INVALIDARG;
+ AesCbc_Init(_aes + _offset, data);
+ return S_OK;
+}
+
+CAesCbcEncoder::CAesCbcEncoder() { _codeFunc = g_AesCbc_Encode; _setKeyFunc = Aes_SetKey_Enc; }
+CAesCbcDecoder::CAesCbcDecoder() { _codeFunc = g_AesCbc_Decode; _setKeyFunc = Aes_SetKey_Dec; }
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/MyAes.h b/src/libs/7zip/win/CPP/7zip/Crypto/MyAes.h
new file mode 100644
index 000000000..60b13845f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/MyAes.h
@@ -0,0 +1,38 @@
+// Crypto/MyAes.h
+
+#ifndef __CRYPTO_MY_AES_H
+#define __CRYPTO_MY_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCrypto {
+
+class CAesCbcCoder:
+ public ICompressFilter,
+ public ICryptoProperties,
+ public CMyUnknownImp
+{
+protected:
+ AES_CODE_FUNC _codeFunc;
+ AES_SET_KEY_FUNC _setKeyFunc;
+ unsigned _offset;
+ UInt32 _aes[AES_NUM_IVMRK_WORDS + 3];
+public:
+ CAesCbcCoder();
+ MY_UNKNOWN_IMP1(ICryptoProperties)
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetKey)(const Byte *data, UInt32 size);
+ STDMETHOD(SetInitVector)(const Byte *data, UInt32 size);
+};
+
+struct CAesCbcEncoder: public CAesCbcCoder { CAesCbcEncoder(); };
+struct CAesCbcDecoder: public CAesCbcCoder { CAesCbcDecoder(); };
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
new file mode 100644
index 000000000..cbbdec89d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
@@ -0,0 +1,83 @@
+// Pbkdf2HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSize,
+ UInt32 numIterations, Byte *key, size_t keySize)
+{
+ CHmac baseCtx;
+ baseCtx.SetKey(pwd, pwdSize);
+ for (UInt32 i = 1; keySize > 0; i++)
+ {
+ CHmac ctx = baseCtx;
+ ctx.Update(salt, saltSize);
+ Byte u[kDigestSize] = { (Byte)(i >> 24), (Byte)(i >> 16), (Byte)(i >> 8), (Byte)(i) };
+ const unsigned int curSize = (keySize < kDigestSize) ? (unsigned int)keySize : kDigestSize;
+ ctx.Update(u, 4);
+ ctx.Final(u, kDigestSize);
+
+ unsigned int s;
+ for (s = 0; s < curSize; s++)
+ key[s] = u[s];
+
+ for (UInt32 j = numIterations; j > 1; j--)
+ {
+ ctx = baseCtx;
+ ctx.Update(u, kDigestSize);
+ ctx.Final(u, kDigestSize);
+ for (s = 0; s < curSize; s++)
+ key[s] ^= u[s];
+ }
+
+ key += curSize;
+ keySize -= curSize;
+ }
+}
+
+void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t saltSize,
+ UInt32 numIterations, UInt32 *key, size_t keySize)
+{
+ CHmac32 baseCtx;
+ baseCtx.SetKey(pwd, pwdSize);
+ for (UInt32 i = 1; keySize > 0; i++)
+ {
+ CHmac32 ctx = baseCtx;
+ ctx.Update(salt, saltSize);
+ UInt32 u[kDigestSizeInWords] = { i };
+ const unsigned int curSize = (keySize < kDigestSizeInWords) ? (unsigned int)keySize : kDigestSizeInWords;
+ ctx.Update(u, 1);
+ ctx.Final(u, kDigestSizeInWords);
+
+ // Speed-optimized code start
+ ctx = baseCtx;
+ ctx.GetLoopXorDigest(u, numIterations - 1);
+ // Speed-optimized code end
+
+ unsigned int s;
+ for (s = 0; s < curSize; s++)
+ key[s] = u[s];
+
+ /*
+ // Default code start
+ for (UInt32 j = numIterations; j > 1; j--)
+ {
+ ctx = baseCtx;
+ ctx.Update(u, kDigestSizeInWords);
+ ctx.Final(u, kDigestSizeInWords);
+ for (s = 0; s < curSize; s++)
+ key[s] ^= u[s];
+ }
+ // Default code end
+ */
+
+ key += curSize;
+ keySize -= curSize;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/Pbkdf2HmacSha1.h b/src/libs/7zip/win/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
new file mode 100644
index 000000000..bb90e1214
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
@@ -0,0 +1,21 @@
+// Pbkdf2HmacSha1.h
+// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1
+
+#ifndef __CRYPTO_PBKDF2_HMAC_SHA1_H
+#define __CRYPTO_PBKDF2_HMAC_SHA1_H
+
+#include <stddef.h>
+#include "../../Common/Types.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSize,
+ UInt32 numIterations, Byte *key, size_t keySize);
+
+void Pbkdf2Hmac32(const Byte *pwd, size_t pwdSize, const UInt32 *salt, size_t saltSize,
+ UInt32 numIterations, UInt32 *key, size_t keySize);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/RandGen.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/RandGen.cpp
new file mode 100644
index 000000000..e0e2e3abd
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/RandGen.cpp
@@ -0,0 +1,107 @@
+// RandGen.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+#include "Windows/Synchronization.h"
+#include "RandGen.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#endif
+#endif
+
+// This is not very good random number generator.
+// Please use it only for salt.
+// First generated data block depends from timer and processID.
+// Other generated data blocks depend from previous state
+// Maybe it's possible to restore original timer value from generated value.
+
+void CRandomGenerator::Init()
+{
+ NCrypto::NSha1::CContext hash;
+ hash.Init();
+
+ #ifdef _WIN32
+ DWORD w = ::GetCurrentProcessId();
+ hash.Update((const Byte *)&w, sizeof(w));
+ w = ::GetCurrentThreadId();
+ hash.Update((const Byte *)&w, sizeof(w));
+ #else
+ pid_t pid = getpid();
+ hash.Update((const Byte *)&pid, sizeof(pid));
+ pid = getppid();
+ hash.Update((const Byte *)&pid, sizeof(pid));
+ #endif
+
+ for (int i = 0; i < 1000; i++)
+ {
+ #ifdef _WIN32
+ LARGE_INTEGER v;
+ if (::QueryPerformanceCounter(&v))
+ hash.Update((const Byte *)&v.QuadPart, sizeof(v.QuadPart));
+ #endif
+
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ timeval v;
+ if (gettimeofday(&v, 0) == 0)
+ {
+ hash.Update((const Byte *)&v.tv_sec, sizeof(v.tv_sec));
+ hash.Update((const Byte *)&v.tv_usec, sizeof(v.tv_usec));
+ }
+ #endif
+ time_t v2 = time(NULL);
+ hash.Update((const Byte *)&v2, sizeof(v2));
+ #endif
+
+ DWORD tickCount = ::GetTickCount();
+ hash.Update((const Byte *)&tickCount, sizeof(tickCount));
+
+ for (int j = 0; j < 100; j++)
+ {
+ hash.Final(_buff);
+ hash.Init();
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ }
+ }
+ hash.Final(_buff);
+ _needInit = false;
+}
+
+static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
+
+void CRandomGenerator::Generate(Byte *data, unsigned int size)
+{
+ g_CriticalSection.Enter();
+ if (_needInit)
+ Init();
+ while (size > 0)
+ {
+ NCrypto::NSha1::CContext hash;
+
+ hash.Init();
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ hash.Final(_buff);
+
+ hash.Init();
+ UInt32 salt = 0xF672ABD1;
+ hash.Update((const Byte *)&salt, sizeof(salt));
+ hash.Update(_buff, NCrypto::NSha1::kDigestSize);
+ Byte buff[NCrypto::NSha1::kDigestSize];
+ hash.Final(buff);
+ for (unsigned int i = 0; i < NCrypto::NSha1::kDigestSize && size > 0; i++, size--)
+ *data++ = buff[i];
+ }
+ g_CriticalSection.Leave();
+}
+
+CRandomGenerator g_RandomGenerator;
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/RandGen.h b/src/libs/7zip/win/CPP/7zip/Crypto/RandGen.h
new file mode 100644
index 000000000..209445c43
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/RandGen.h
@@ -0,0 +1,21 @@
+// RandGen.h
+
+#ifndef __CRYPTO_RAND_GEN_H
+#define __CRYPTO_RAND_GEN_H
+
+#include "Sha1.h"
+
+class CRandomGenerator
+{
+ Byte _buff[NCrypto::NSha1::kDigestSize];
+ bool _needInit;
+
+ void Init();
+public:
+ CRandomGenerator(): _needInit(true) {};
+ void Generate(Byte *data, unsigned size);
+};
+
+extern CRandomGenerator g_RandomGenerator;
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/Rar20Crypto.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/Rar20Crypto.cpp
new file mode 100644
index 000000000..c2df0e527
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/Rar20Crypto.cpp
@@ -0,0 +1,133 @@
+// Crypto/Rar20Crypto.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/RotateDefs.h"
+
+#include "Rar20Crypto.h"
+
+namespace NCrypto {
+namespace NRar20 {
+
+static const int kNumRounds = 32;
+
+static const Byte InitSubstTable[256] = {
+ 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
+ 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
+ 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
+ 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
+ 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
+ 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
+ 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
+ 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
+ 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
+ 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
+ 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
+ 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
+ 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
+ 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
+ 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
+ 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
+};
+
+void CData::UpdateKeys(const Byte *data)
+{
+ for (int i = 0; i < 16; i += 4)
+ for (int j = 0; j < 4; j++)
+ Keys[j] ^= g_CrcTable[data[i + j]];
+}
+
+static void Swap(Byte *b1, Byte *b2)
+{
+ Byte b = *b1;
+ *b1 = *b2;
+ *b2 = b;
+}
+
+void CData::SetPassword(const Byte *password, UInt32 passwordLen)
+{
+ Keys[0] = 0xD3A3B879L;
+ Keys[1] = 0x3F6D12F7L;
+ Keys[2] = 0x7515A235L;
+ Keys[3] = 0xA4E7F123L;
+
+ Byte psw[256];
+ memset(psw, 0, sizeof(psw));
+ memcpy(psw, password, passwordLen);
+ memcpy(SubstTable, InitSubstTable, sizeof(SubstTable));
+
+ for (UInt32 j = 0; j < 256; j++)
+ for (UInt32 i = 0; i < passwordLen; i += 2)
+ {
+ UInt32 n2 = (Byte)g_CrcTable[(psw[i + 1] + j) & 0xFF];
+ UInt32 n1 = (Byte)g_CrcTable[(psw[i] - j) & 0xFF];
+ for (UInt32 k = 1; (n1 & 0xFF) != n2; n1++, k++)
+ Swap(&SubstTable[n1 & 0xFF], &SubstTable[(n1 + i + k) & 0xFF]);
+ }
+ for (UInt32 i = 0; i < passwordLen; i+= 16)
+ EncryptBlock(&psw[i]);
+}
+
+void CData::CryptBlock(Byte *buf, bool encrypt)
+{
+ Byte inBuf[16];
+ UInt32 A, B, C, D, T, TA, TB;
+
+ A = GetUi32(buf + 0) ^ Keys[0];
+ B = GetUi32(buf + 4) ^ Keys[1];
+ C = GetUi32(buf + 8) ^ Keys[2];
+ D = GetUi32(buf + 12) ^ Keys[3];
+
+ if (!encrypt)
+ memcpy(inBuf, buf, sizeof(inBuf));
+
+ for (int i = 0; i < kNumRounds; i++)
+ {
+ UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3];
+ T = ((C + rotlFixed(D, 11)) ^ key);
+ TA = A ^ SubstLong(T);
+ T = ((D ^ rotlFixed(C, 17)) + key);
+ TB = B ^ SubstLong(T);
+ A = C;
+ B = D;
+ C = TA;
+ D = TB;
+ }
+
+ SetUi32(buf + 0, C ^ Keys[0]);
+ SetUi32(buf + 4, D ^ Keys[1]);
+ SetUi32(buf + 8, A ^ Keys[2]);
+ SetUi32(buf + 12, B ^ Keys[3]);
+
+ UpdateKeys(encrypt ? buf : inBuf);
+}
+
+STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _cipher.SetPassword(data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Init()
+{
+ return S_OK;
+}
+
+static const UInt32 kBlockSize = 16;
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ if (size == 0)
+ return 0;
+ if (size < kBlockSize)
+ return kBlockSize;
+ UInt32 i;
+ size -= kBlockSize;
+ for (i = 0; i <= size; i += kBlockSize)
+ _cipher.DecryptBlock(data + i);
+ return i;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/Rar20Crypto.h b/src/libs/7zip/win/CPP/7zip/Crypto/Rar20Crypto.h
new file mode 100644
index 000000000..b9648f59d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/Rar20Crypto.h
@@ -0,0 +1,50 @@
+// Crypto/Rar20Crypto.h
+
+#ifndef __CRYPTO_RAR20_CRYPTO_H
+#define __CRYPTO_RAR20_CRYPTO_H
+
+#include "Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NRar20 {
+
+class CData
+{
+ Byte SubstTable[256];
+ UInt32 Keys[4];
+
+ UInt32 SubstLong(UInt32 t)
+ {
+ return (UInt32)SubstTable[(int)t & 255] |
+ ((UInt32)SubstTable[(int)(t >> 8) & 255] << 8) |
+ ((UInt32)SubstTable[(int)(t >> 16) & 255] << 16) |
+ ((UInt32)SubstTable[(int)(t >> 24) & 255] << 24);
+ }
+ void UpdateKeys(const Byte *data);
+ void CryptBlock(Byte *buf, bool encrypt);
+public:
+ void EncryptBlock(Byte *buf) { CryptBlock(buf, true); }
+ void DecryptBlock(Byte *buf) { CryptBlock(buf, false); }
+ void SetPassword(const Byte *password, UInt32 passwordLen);
+};
+
+class CDecoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+ CData _cipher;
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/RarAes.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/RarAes.cpp
new file mode 100644
index 000000000..b0f00ea85
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/RarAes.cpp
@@ -0,0 +1,134 @@
+// Crypto/RarAes.cpp
+// Note: you must include MyAes.cpp to project to initialize AES tables
+
+#include "StdAfx.h"
+
+#include "RarAes.h"
+#include "Sha1.h"
+
+namespace NCrypto {
+namespace NRar29 {
+
+CDecoder::CDecoder():
+ _thereIsSalt(false),
+ _needCalculate(true),
+ _rar350Mode(false)
+{
+ for (int i = 0; i < sizeof(_salt); i++)
+ _salt[i] = 0;
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ bool thereIsSaltPrev = _thereIsSalt;
+ _thereIsSalt = false;
+ if (size == 0)
+ return S_OK;
+ if (size < 8)
+ return E_INVALIDARG;
+ _thereIsSalt = true;
+ bool same = false;
+ if (_thereIsSalt == thereIsSaltPrev)
+ {
+ same = true;
+ if (_thereIsSalt)
+ {
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ if (_salt[i] != data[i])
+ {
+ same = false;
+ break;
+ }
+ }
+ }
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ _salt[i] = data[i];
+ if (!_needCalculate && !same)
+ _needCalculate = true;
+ return S_OK;
+}
+
+static const unsigned kMaxPasswordLength = 127 * 2;
+
+STDMETHODIMP CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ if (size > kMaxPasswordLength)
+ size = kMaxPasswordLength;
+ bool same = false;
+ if (size == buffer.GetCapacity())
+ {
+ same = true;
+ for (UInt32 i = 0; i < size; i++)
+ if (data[i] != buffer[i])
+ {
+ same = false;
+ break;
+ }
+ }
+ if (!_needCalculate && !same)
+ _needCalculate = true;
+ buffer.SetCapacity(size);
+ memcpy(buffer, data, size);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::Init()
+{
+ Calculate();
+ SetKey(aesKey, kRarAesKeySize);
+ AesCbc_Init(_aes + _offset, _aesInit);
+ return S_OK;
+}
+
+void CDecoder::Calculate()
+{
+ if (_needCalculate)
+ {
+ const unsigned kSaltSize = 8;
+
+ Byte rawPassword[kMaxPasswordLength + kSaltSize];
+
+ memcpy(rawPassword, buffer, buffer.GetCapacity());
+
+ size_t rawLength = buffer.GetCapacity();
+
+ if (_thereIsSalt)
+ {
+ memcpy(rawPassword + rawLength, _salt, kSaltSize);
+ rawLength += kSaltSize;
+ }
+
+ NSha1::CContext sha;
+ sha.Init();
+
+ // rar reverts hash for sha.
+ const unsigned kNumRounds = (1 << 18);
+ unsigned i;
+ for (i = 0; i < kNumRounds; i++)
+ {
+ sha.UpdateRar(rawPassword, rawLength, _rar350Mode);
+ Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
+ sha.UpdateRar(pswNum, 3, _rar350Mode);
+ if (i % (kNumRounds / 16) == 0)
+ {
+ NSha1::CContext shaTemp = sha;
+ Byte digest[NSha1::kDigestSize];
+ shaTemp.Final(digest);
+ _aesInit[i / (kNumRounds / 16)] = (Byte)digest[4 * 4 + 3];
+ }
+ }
+ /*
+ // it's test message for sha
+ const char *message = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+ sha.Update((const Byte *)message, strlen(message));
+ */
+ Byte digest[20];
+ sha.Final(digest);
+ for (i = 0; i < 4; i++)
+ for (unsigned j = 0; j < 4; j++)
+ aesKey[i * 4 + j] = (digest[i * 4 + 3 - j]);
+ }
+ _needCalculate = false;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/RarAes.h b/src/libs/7zip/win/CPP/7zip/Crypto/RarAes.h
new file mode 100644
index 000000000..119cc2336
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/RarAes.h
@@ -0,0 +1,47 @@
+// Crypto/RarAes.h
+
+#ifndef __CRYPTO_RAR_AES_H
+#define __CRYPTO_RAR_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "Common/Buffer.h"
+
+#include "../IPassword.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NRar29 {
+
+const UInt32 kRarAesKeySize = 16;
+
+class CDecoder:
+ public CAesCbcDecoder,
+ public ICompressSetDecoderProperties2,
+ public ICryptoSetPassword
+{
+ Byte _salt[8];
+ bool _thereIsSalt;
+ CByteBuffer buffer;
+ Byte aesKey[kRarAesKeySize];
+ Byte _aesInit[AES_BLOCK_SIZE];
+ bool _needCalculate;
+ bool _rar350Mode;
+
+ void Calculate();
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD(Init)();
+ STDMETHOD(CryptoSetPassword)(const Byte *aData, UInt32 aSize);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+
+ CDecoder();
+ void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/Sha1.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/Sha1.cpp
new file mode 100644
index 000000000..82ca986c7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/Sha1.cpp
@@ -0,0 +1,229 @@
+// Crypto/Sha1.cpp
+// This file is based on public domain
+// Steve Reid and Wei Dai's code from Crypto++
+
+#include "StdAfx.h"
+
+#include "../../../C/RotateDefs.h"
+
+#include "Sha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+// define it for speed optimization
+// #define _SHA1_UNROLL
+
+static const unsigned kNumW =
+ #ifdef _SHA1_UNROLL
+ 16;
+ #else
+ 80;
+ #endif
+
+
+#define w0(i) (W[(i)] = data[(i)])
+
+#ifdef _SHA1_UNROLL
+#define w1(i) (W[(i)&15] = rotlFixed(W[((i)-3)&15] ^ W[((i)-8)&15] ^ W[((i)-14)&15] ^ W[((i)-16)&15], 1))
+#else
+#define w1(i) (W[(i)] = rotlFixed(W[(i)-3] ^ W[(i)-8] ^ W[(i)-14] ^ W[(i)-16], 1))
+#endif
+
+#define f1(x,y,z) (z^(x&(y^z)))
+#define f2(x,y,z) (x^y^z)
+#define f3(x,y,z) ((x&y)|(z&(x|y)))
+#define f4(x,y,z) (x^y^z)
+
+#define RK1(a,b,c,d,e,i, f, w, k) e += f(b,c,d) + w(i) + k + rotlFixed(a,5); b = rotlFixed(b,30);
+
+#define R0(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f1, w0, 0x5A827999)
+#define R1(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f1, w1, 0x5A827999)
+#define R2(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f2, w1, 0x6ED9EBA1)
+#define R3(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f3, w1, 0x8F1BBCDC)
+#define R4(a,b,c,d,e,i) RK1(a,b,c,d,e,i, f4, w1, 0xCA62C1D6)
+
+#define RX_1_4(rx1, rx4, i) rx1(a,b,c,d,e,i); rx4(e,a,b,c,d,i+1); rx4(d,e,a,b,c,i+2); rx4(c,d,e,a,b,i+3); rx4(b,c,d,e,a,i+4);
+#define RX_5(rx, i) RX_1_4(rx, rx, i);
+
+void CContextBase::Init()
+{
+ _state[0] = 0x67452301;
+ _state[1] = 0xEFCDAB89;
+ _state[2] = 0x98BADCFE;
+ _state[3] = 0x10325476;
+ _state[4] = 0xC3D2E1F0;
+ _count = 0;
+}
+
+void CContextBase::GetBlockDigest(UInt32 *data, UInt32 *destDigest, bool returnRes)
+{
+ UInt32 a, b, c, d, e;
+ UInt32 W[kNumW];
+
+ a = _state[0];
+ b = _state[1];
+ c = _state[2];
+ d = _state[3];
+ e = _state[4];
+ #ifdef _SHA1_UNROLL
+ RX_5(R0, 0); RX_5(R0, 5); RX_5(R0, 10);
+ #else
+ int i;
+ for (i = 0; i < 15; i += 5) { RX_5(R0, i); }
+ #endif
+
+ RX_1_4(R0, R1, 15);
+
+
+ #ifdef _SHA1_UNROLL
+ RX_5(R2, 20); RX_5(R2, 25); RX_5(R2, 30); RX_5(R2, 35);
+ RX_5(R3, 40); RX_5(R3, 45); RX_5(R3, 50); RX_5(R3, 55);
+ RX_5(R4, 60); RX_5(R4, 65); RX_5(R4, 70); RX_5(R4, 75);
+ #else
+ i = 20;
+ for (; i < 40; i += 5) { RX_5(R2, i); }
+ for (; i < 60; i += 5) { RX_5(R3, i); }
+ for (; i < 80; i += 5) { RX_5(R4, i); }
+ #endif
+
+ destDigest[0] = _state[0] + a;
+ destDigest[1] = _state[1] + b;
+ destDigest[2] = _state[2] + c;
+ destDigest[3] = _state[3] + d;
+ destDigest[4] = _state[4] + e;
+
+ if (returnRes)
+ for (int i = 0 ; i < 16; i++)
+ data[i] = W[kNumW - 16 + i];
+
+ // Wipe variables
+ // a = b = c = d = e = 0;
+}
+
+void CContextBase::PrepareBlock(UInt32 *block, unsigned size) const
+{
+ unsigned curBufferPos = size & 0xF;
+ block[curBufferPos++] = 0x80000000;
+ while (curBufferPos != (16 - 2))
+ block[curBufferPos++] = 0;
+ const UInt64 lenInBits = (_count << 9) + ((UInt64)size << 5);
+ block[curBufferPos++] = (UInt32)(lenInBits >> 32);
+ block[curBufferPos++] = (UInt32)(lenInBits);
+}
+
+void CContext::Update(const Byte *data, size_t size)
+{
+ unsigned curBufferPos = _count2;
+ while (size--)
+ {
+ int pos = (int)(curBufferPos & 3);
+ if (pos == 0)
+ _buffer[curBufferPos >> 2] = 0;
+ _buffer[curBufferPos >> 2] |= ((UInt32)*data++) << (8 * (3 - pos));
+ if (++curBufferPos == kBlockSize)
+ {
+ curBufferPos = 0;
+ CContextBase::UpdateBlock(_buffer, false);
+ }
+ }
+ _count2 = curBufferPos;
+}
+
+void CContext::UpdateRar(Byte *data, size_t size, bool rar350Mode)
+{
+ bool returnRes = false;
+ unsigned curBufferPos = _count2;
+ while (size--)
+ {
+ int pos = (int)(curBufferPos & 3);
+ if (pos == 0)
+ _buffer[curBufferPos >> 2] = 0;
+ _buffer[curBufferPos >> 2] |= ((UInt32)*data++) << (8 * (3 - pos));
+ if (++curBufferPos == kBlockSize)
+ {
+ curBufferPos = 0;
+ CContextBase::UpdateBlock(_buffer, returnRes);
+ if (returnRes)
+ for (int i = 0; i < kBlockSizeInWords; i++)
+ {
+ UInt32 d = _buffer[i];
+ data[i * 4 + 0 - kBlockSize] = (Byte)(d);
+ data[i * 4 + 1 - kBlockSize] = (Byte)(d >> 8);
+ data[i * 4 + 2 - kBlockSize] = (Byte)(d >> 16);
+ data[i * 4 + 3 - kBlockSize] = (Byte)(d >> 24);
+ }
+ returnRes = rar350Mode;
+ }
+ }
+ _count2 = curBufferPos;
+}
+
+void CContext::Final(Byte *digest)
+{
+ const UInt64 lenInBits = (_count << 9) + ((UInt64)_count2 << 3);
+ unsigned curBufferPos = _count2;
+ int pos = (int)(curBufferPos & 3);
+ curBufferPos >>= 2;
+ if (pos == 0)
+ _buffer[curBufferPos] = 0;
+ _buffer[curBufferPos++] |= ((UInt32)0x80) << (8 * (3 - pos));
+
+ while (curBufferPos != (16 - 2))
+ {
+ curBufferPos &= 0xF;
+ if (curBufferPos == 0)
+ UpdateBlock();
+ _buffer[curBufferPos++] = 0;
+ }
+ _buffer[curBufferPos++] = (UInt32)(lenInBits >> 32);
+ _buffer[curBufferPos++] = (UInt32)(lenInBits);
+ UpdateBlock();
+
+ int i;
+ for (i = 0; i < kDigestSizeInWords; i++)
+ {
+ UInt32 state = _state[i] & 0xFFFFFFFF;
+ *digest++ = (Byte)(state >> 24);
+ *digest++ = (Byte)(state >> 16);
+ *digest++ = (Byte)(state >> 8);
+ *digest++ = (Byte)(state);
+ }
+ Init();
+}
+
+///////////////////////////
+// Words version
+
+void CContext32::Update(const UInt32 *data, size_t size)
+{
+ while (size--)
+ {
+ _buffer[_count2++] = *data++;
+ if (_count2 == kBlockSizeInWords)
+ {
+ _count2 = 0;
+ UpdateBlock();
+ }
+ }
+}
+
+void CContext32::Final(UInt32 *digest)
+{
+ const UInt64 lenInBits = (_count << 9) + ((UInt64)_count2 << 5);
+ unsigned curBufferPos = _count2;
+ _buffer[curBufferPos++] = 0x80000000;
+ while (curBufferPos != (16 - 2))
+ {
+ curBufferPos &= 0xF;
+ if (curBufferPos == 0)
+ UpdateBlock();
+ _buffer[curBufferPos++] = 0;
+ }
+ _buffer[curBufferPos++] = (UInt32)(lenInBits >> 32);
+ _buffer[curBufferPos++] = (UInt32)(lenInBits);
+ GetBlockDigest(_buffer, digest);
+ Init();
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/Sha1.h b/src/libs/7zip/win/CPP/7zip/Crypto/Sha1.h
new file mode 100644
index 000000000..1bad1f91f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/Sha1.h
@@ -0,0 +1,68 @@
+// Crypto/Sha1.h
+// This file is based on public domain
+// Steve Reid and Wei Dai's code from Crypto++
+
+#ifndef __CRYPTO_SHA1_H
+#define __CRYPTO_SHA1_H
+
+#include <stddef.h>
+#include "../../Common/Types.h"
+
+// Sha1 implementation in RAR before version 3.60 has bug:
+// it changes data bytes in some cases.
+// So this class supports both versions: normal_SHA and rar3Mode
+
+namespace NCrypto {
+namespace NSha1 {
+
+const unsigned kBlockSize = 64;
+const unsigned kDigestSize = 20;
+
+const unsigned kBlockSizeInWords = (kBlockSize >> 2);
+const unsigned kDigestSizeInWords = (kDigestSize >> 2);
+
+class CContextBase
+{
+protected:
+ UInt32 _state[5];
+ UInt64 _count;
+ void UpdateBlock(UInt32 *data, bool returnRes = false)
+ {
+ GetBlockDigest(data, _state, returnRes);
+ _count++;
+ }
+public:
+ void Init();
+ void GetBlockDigest(UInt32 *blockData, UInt32 *destDigest, bool returnRes = false);
+ // PrepareBlock can be used only when size <= 13. size in Words
+ void PrepareBlock(UInt32 *block, unsigned int size) const;
+};
+
+class CContextBase2: public CContextBase
+{
+protected:
+ unsigned _count2;
+ UInt32 _buffer[kBlockSizeInWords];
+ void UpdateBlock() { CContextBase::UpdateBlock(_buffer); }
+public:
+ void Init() { CContextBase::Init(); _count2 = 0; }
+};
+
+class CContext: public CContextBase2
+{
+public:
+ void Update(const Byte *data, size_t size);
+ void UpdateRar(Byte *data, size_t size, bool rar350Mode);
+ void Final(Byte *digest);
+};
+
+class CContext32: public CContextBase2
+{
+public:
+ void Update(const UInt32 *data, size_t size);
+ void Final(UInt32 *digest);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Crypto/StdAfx.h
new file mode 100644
index 000000000..99a8aa46d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/MyWindows.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/WzAes.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/WzAes.cpp
new file mode 100644
index 000000000..08a1818c0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/WzAes.cpp
@@ -0,0 +1,221 @@
+// Crypto/WzAes.cpp
+/*
+This code implements Brian Gladman's scheme
+specified in password Based File Encryption Utility.
+
+Note: you must include MyAes.cpp to project to initialize AES tables
+*/
+
+#include "StdAfx.h"
+
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "Pbkdf2HmacSha1.h"
+#include "RandGen.h"
+#include "WzAes.h"
+
+// define it if you don't want to use speed-optimized version of Pbkdf2HmacSha1
+// #define _NO_WZAES_OPTIMIZATIONS
+
+namespace NCrypto {
+namespace NWzAes {
+
+const unsigned kAesKeySizeMax = 32;
+
+static const UInt32 kNumKeyGenIterations = 1000;
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ if(size > kPasswordSizeMax)
+ return E_INVALIDARG;
+ _key.Password.SetCapacity(size);
+ memcpy(_key.Password, data, size);
+ return S_OK;
+}
+
+#ifndef _NO_WZAES_OPTIMIZATIONS
+
+static void BytesToBeUInt32s(const Byte *src, UInt32 *dest, unsigned destSize)
+{
+ for (unsigned i = 0; i < destSize; i++)
+ dest[i] =
+ ((UInt32)(src[i * 4 + 0]) << 24) |
+ ((UInt32)(src[i * 4 + 1]) << 16) |
+ ((UInt32)(src[i * 4 + 2]) << 8) |
+ ((UInt32)(src[i * 4 + 3]));
+}
+
+#endif
+
+STDMETHODIMP CBaseCoder::Init()
+{
+ UInt32 keySize = _key.GetKeySize();
+ UInt32 keysTotalSize = 2 * keySize + kPwdVerifCodeSize;
+ Byte buf[2 * kAesKeySizeMax + kPwdVerifCodeSize];
+
+ // for (unsigned ii = 0; ii < 1000; ii++)
+ {
+ #ifdef _NO_WZAES_OPTIMIZATIONS
+
+ NSha1::Pbkdf2Hmac(
+ _key.Password, _key.Password.GetCapacity(),
+ _key.Salt, _key.GetSaltSize(),
+ kNumKeyGenIterations,
+ buf, keysTotalSize);
+
+ #else
+
+ UInt32 buf32[(2 * kAesKeySizeMax + kPwdVerifCodeSize + 3) / 4];
+ UInt32 key32SizeTotal = (keysTotalSize + 3) / 4;
+ UInt32 salt[kSaltSizeMax * 4];
+ UInt32 saltSizeInWords = _key.GetSaltSize() / 4;
+ BytesToBeUInt32s(_key.Salt, salt, saltSizeInWords);
+ NSha1::Pbkdf2Hmac32(
+ _key.Password, _key.Password.GetCapacity(),
+ salt, saltSizeInWords,
+ kNumKeyGenIterations,
+ buf32, key32SizeTotal);
+ for (UInt32 j = 0; j < keysTotalSize; j++)
+ buf[j] = (Byte)(buf32[j / 4] >> (24 - 8 * (j & 3)));
+
+ #endif
+ }
+
+ _hmac.SetKey(buf + keySize, keySize);
+ memcpy(_key.PwdVerifComputed, buf + 2 * keySize, kPwdVerifCodeSize);
+
+ AesCtr2_Init(&_aes);
+ Aes_SetKey_Enc(_aes.aes + _aes.offset + 8, buf, keySize);
+ return S_OK;
+}
+
+HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
+{
+ UInt32 saltSize = _key.GetSaltSize();
+ g_RandomGenerator.Generate(_key.Salt, saltSize);
+ Init();
+ RINOK(WriteStream(outStream, _key.Salt, saltSize));
+ return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifCodeSize);
+}
+
+HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
+{
+ Byte mac[kMacSize];
+ _hmac.Final(mac, kMacSize);
+ return WriteStream(outStream, mac, kMacSize);
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size != 1)
+ return E_INVALIDARG;
+ _key.Init();
+ return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
+{
+ UInt32 saltSize = _key.GetSaltSize();
+ UInt32 extraSize = saltSize + kPwdVerifCodeSize;
+ Byte temp[kSaltSizeMax + kPwdVerifCodeSize];
+ RINOK(ReadStream_FAIL(inStream, temp, extraSize));
+ UInt32 i;
+ for (i = 0; i < saltSize; i++)
+ _key.Salt[i] = temp[i];
+ for (i = 0; i < kPwdVerifCodeSize; i++)
+ _pwdVerifFromArchive[i] = temp[saltSize + i];
+ return S_OK;
+}
+
+static bool CompareArrays(const Byte *p1, const Byte *p2, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ if (p1[i] != p2[i])
+ return false;
+ return true;
+}
+
+bool CDecoder::CheckPasswordVerifyCode()
+{
+ return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifCodeSize);
+}
+
+HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
+{
+ isOK = false;
+ Byte mac1[kMacSize];
+ RINOK(ReadStream_FAIL(inStream, mac1, kMacSize));
+ Byte mac2[kMacSize];
+ _hmac.Final(mac2, kMacSize);
+ isOK = CompareArrays(mac1, mac2, kMacSize);
+ return S_OK;
+}
+
+CAesCtr2::CAesCtr2()
+{
+ offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32);
+}
+
+void AesCtr2_Init(CAesCtr2 *p)
+{
+ UInt32 *ctr = p->aes + p->offset + 4;
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ ctr[i] = 0;
+ p->pos = AES_BLOCK_SIZE;
+}
+
+void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
+{
+ unsigned pos = p->pos;
+ UInt32 *buf32 = p->aes + p->offset;
+ if (size == 0)
+ return;
+ if (pos != AES_BLOCK_SIZE)
+ {
+ const Byte *buf = (const Byte *)buf32;
+ do
+ *data++ ^= buf[pos++];
+ while (--size != 0 && pos != AES_BLOCK_SIZE);
+ }
+ if (size >= 16)
+ {
+ SizeT size2 = size >> 4;
+ g_AesCtr_Code(buf32 + 4, data, size2);
+ size2 <<= 4;
+ data += size2;
+ size -= size2;
+ pos = AES_BLOCK_SIZE;
+ }
+ if (size != 0)
+ {
+ unsigned j;
+ const Byte *buf;
+ for (j = 0; j < 4; j++)
+ buf32[j] = 0;
+ g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1);
+ buf = (const Byte *)buf32;
+ pos = 0;
+ do
+ *data++ ^= buf[pos++];
+ while (--size != 0 && pos != AES_BLOCK_SIZE);
+ }
+ p->pos = pos;
+}
+
+STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
+{
+ AesCtr2_Code(&_aes, data, size);
+ _hmac.Update(data, size);
+ return size;
+}
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ _hmac.Update(data, size);
+ AesCtr2_Code(&_aes, data, size);
+ return size;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/WzAes.h b/src/libs/7zip/win/CPP/7zip/Crypto/WzAes.h
new file mode 100644
index 000000000..f37fe6440
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/WzAes.h
@@ -0,0 +1,125 @@
+// Crypto/WzAes.h
+/*
+This code implements Brian Gladman's scheme
+specified in password Based File Encryption Utility:
+ - AES encryption (128,192,256-bit) in Counter (CTR) mode.
+ - HMAC-SHA1 authentication for encrypted data (10 bytes)
+ - Keys are derived by PPKDF2(RFC2898)-HMAC-SHA1 from ASCII password and
+ Salt (saltSize = aesKeySize / 2).
+ - 2 bytes contain Password Verifier's Code
+*/
+
+#ifndef __CRYPTO_WZ_AES_H
+#define __CRYPTO_WZ_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "Common/Buffer.h"
+#include "Common/MyCom.h"
+#include "Common/MyVector.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NWzAes {
+
+const unsigned kSaltSizeMax = 16;
+const unsigned kMacSize = 10;
+
+const UInt32 kPasswordSizeMax = 99; // 128;
+
+// Password Verification Code Size
+const unsigned kPwdVerifCodeSize = 2;
+
+enum EKeySizeMode
+{
+ kKeySizeMode_AES128 = 1,
+ kKeySizeMode_AES192 = 2,
+ kKeySizeMode_AES256 = 3
+};
+
+class CKeyInfo
+{
+public:
+ EKeySizeMode KeySizeMode;
+ Byte Salt[kSaltSizeMax];
+ Byte PwdVerifComputed[kPwdVerifCodeSize];
+
+ CByteBuffer Password;
+
+ UInt32 GetKeySize() const { return (8 * (KeySizeMode & 3) + 8); }
+ UInt32 GetSaltSize() const { return (4 * (KeySizeMode & 3) + 4); }
+
+ CKeyInfo() { Init(); }
+ void Init() { KeySizeMode = kKeySizeMode_AES256; }
+};
+
+struct CAesCtr2
+{
+ unsigned pos;
+ unsigned offset;
+ UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3];
+ CAesCtr2();
+};
+
+void AesCtr2_Init(CAesCtr2 *p);
+void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size);
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+protected:
+ CKeyInfo _key;
+ NSha1::CHmac _hmac;
+ Byte _pwdVerifFromArchive[kPwdVerifCodeSize];
+ CAesCtr2 _aes;
+
+public:
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) = 0;
+
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+
+ UInt32 GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifCodeSize; }
+ bool SetKeyMode(unsigned mode)
+ {
+ if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256)
+ return false;
+ _key.KeySizeMode = (EKeySizeMode)mode;
+ return true;
+ }
+};
+
+class CEncoder:
+ public CBaseCoder
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ HRESULT WriteHeader(ISequentialOutStream *outStream);
+ HRESULT WriteFooter(ISequentialOutStream *outStream);
+};
+
+class CDecoder:
+ public CBaseCoder,
+ public ICompressSetDecoderProperties2
+{
+public:
+ MY_UNKNOWN_IMP2(
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ HRESULT ReadHeader(ISequentialInStream *inStream);
+ bool CheckPasswordVerifyCode();
+ HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/ZipCrypto.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/ZipCrypto.cpp
new file mode 100644
index 000000000..baaaf98e3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/ZipCrypto.cpp
@@ -0,0 +1,88 @@
+// Crypto/ZipCrypto.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "RandGen.h"
+#include "ZipCrypto.h"
+
+namespace NCrypto {
+namespace NZip {
+
+void CCipher::UpdateKeys(Byte b)
+{
+ Keys[0] = CRC_UPDATE_BYTE(Keys[0], b);
+ Keys[1] = (Keys[1] + (Keys[0] & 0xFF)) * 0x8088405 + 1;
+ Keys[2] = CRC_UPDATE_BYTE(Keys[2], (Byte)(Keys[1] >> 24));
+}
+
+STDMETHODIMP CCipher::CryptoSetPassword(const Byte *password, UInt32 passwordLen)
+{
+ Keys[0] = 0x12345678;
+ Keys[1] = 0x23456789;
+ Keys[2] = 0x34567890;
+ UInt32 i;
+ for (i = 0; i < passwordLen; i++)
+ UpdateKeys(password[i]);
+ for (i = 0; i < 3; i++)
+ Keys2[i] = Keys[i];
+ return S_OK;
+}
+
+STDMETHODIMP CCipher::Init()
+{
+ return S_OK;
+}
+
+Byte CCipher::DecryptByteSpec()
+{
+ UInt32 temp = Keys[2] | 2;
+ return (Byte)((temp * (temp ^ 1)) >> 8);
+}
+
+HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream, UInt32 crc)
+{
+ Byte h[kHeaderSize];
+ g_RandomGenerator.Generate(h, kHeaderSize - 2);
+ h[kHeaderSize - 1] = (Byte)(crc >> 24);
+ h[kHeaderSize - 2] = (Byte)(crc >> 16);
+ RestoreKeys();
+ Filter(h, kHeaderSize);
+ return WriteStream(outStream, h, kHeaderSize);
+}
+
+STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte b = data[i];
+ data[i] = (Byte)(b ^ DecryptByteSpec());;
+ UpdateKeys(b);
+ }
+ return size;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
+{
+ Byte h[kHeaderSize];
+ RINOK(ReadStream_FAIL(inStream, h, kHeaderSize));
+ RestoreKeys();
+ Filter(h, kHeaderSize);
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte c = (Byte)(data[i] ^ DecryptByteSpec());
+ UpdateKeys(c);
+ data[i] = c;
+ }
+ return size;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/ZipCrypto.h b/src/libs/7zip/win/CPP/7zip/Crypto/ZipCrypto.h
new file mode 100644
index 000000000..6f104beb4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/ZipCrypto.h
@@ -0,0 +1,56 @@
+// Crypto/ZipCrypto.h
+
+#ifndef __CRYPTO_ZIP_CRYPTO_H
+#define __CRYPTO_ZIP_CRYPTO_H
+
+#include "Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NZip {
+
+const unsigned kHeaderSize = 12;
+
+class CCipher:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+ UInt32 Keys[3];
+ UInt32 Keys2[3];
+
+protected:
+ void UpdateKeys(Byte b);
+ Byte DecryptByteSpec();
+ void RestoreKeys()
+ {
+ for (int i = 0; i < 3; i++)
+ Keys[i] = Keys2[i];
+ }
+
+public:
+ STDMETHOD(Init)();
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+class CEncoder: public CCipher
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ HRESULT WriteHeader(ISequentialOutStream *outStream, UInt32 crc);
+};
+
+class CDecoder: public CCipher
+{
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+ HRESULT ReadHeader(ISequentialInStream *inStream);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/ZipStrong.cpp b/src/libs/7zip/win/CPP/7zip/Crypto/ZipStrong.cpp
new file mode 100644
index 000000000..1554b3489
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/ZipStrong.cpp
@@ -0,0 +1,164 @@
+// Crypto/ZipStrong.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "MyAes.h"
+#include "Sha1.h"
+#include "ZipStrong.h"
+
+namespace NCrypto {
+namespace NZipStrong {
+
+static const UInt16 kAES128 = 0x660E;
+
+// DeriveKey* function is similar to CryptDeriveKey() from Windows.
+// But MSDN tells that we need such scheme only if
+// "the required key length is longer than the hash value"
+// but ZipStrong uses it always.
+
+static void DeriveKey2(const Byte *digest, Byte c, Byte *dest)
+{
+ Byte buf[64];
+ memset(buf, c, 64);
+ for (unsigned i = 0; i < NSha1::kDigestSize; i++)
+ buf[i] ^= digest[i];
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(buf, 64);
+ sha.Final(dest);
+}
+
+static void DeriveKey(NSha1::CContext &sha, Byte *key)
+{
+ Byte digest[NSha1::kDigestSize];
+ sha.Final(digest);
+ Byte temp[NSha1::kDigestSize * 2];
+ DeriveKey2(digest, 0x36, temp);
+ DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize);
+ memcpy(key, temp, 32);
+}
+
+void CKeyInfo::SetPassword(const Byte *data, UInt32 size)
+{
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(data, size);
+ DeriveKey(sha, MasterKey);
+}
+
+STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
+{
+ _key.SetPassword(data, size);
+ return S_OK;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 /* crc */, UInt64 /* unpackSize */)
+{
+ Byte temp[4];
+ RINOK(ReadStream_FALSE(inStream, temp, 2));
+ _ivSize = GetUi16(temp);
+ if (_ivSize == 0)
+ {
+ return E_NOTIMPL;
+ /*
+ SetUi32(_iv, crc);
+ for (int i = 0; i < 8; i++)
+ _iv[4 + i] = (Byte)(unpackSize >> (8 * i));
+ SetUi32(_iv + 12, 0);
+ */
+ }
+ else if (_ivSize == 16)
+ {
+ RINOK(ReadStream_FALSE(inStream, _iv, _ivSize));
+ }
+ else
+ return E_NOTIMPL;
+ RINOK(ReadStream_FALSE(inStream, temp, 4));
+ _remSize = GetUi32(temp);
+ const UInt32 kAlign = 16;
+ if (_remSize < 16 || _remSize > (1 << 18))
+ return E_NOTIMPL;
+ if (_remSize + kAlign > _buf.GetCapacity())
+ {
+ _buf.Free();
+ _buf.SetCapacity(_remSize + kAlign);
+ _bufAligned = (Byte *)((ptrdiff_t)((Byte *)_buf + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1));
+ }
+ return ReadStream_FALSE(inStream, _bufAligned, _remSize);
+}
+
+HRESULT CDecoder::CheckPassword(bool &passwOK)
+{
+ passwOK = false;
+ if (_remSize < 16)
+ return E_NOTIMPL;
+ Byte *p = _bufAligned;
+ UInt16 format = GetUi16(p);
+ if (format != 3)
+ return E_NOTIMPL;
+ UInt16 algId = GetUi16(p + 2);
+ if (algId < kAES128)
+ return E_NOTIMPL;
+ algId -= kAES128;
+ if (algId > 2)
+ return E_NOTIMPL;
+ UInt16 bitLen = GetUi16(p + 4);
+ UInt16 flags = GetUi16(p + 6);
+ if (algId * 64 + 128 != bitLen)
+ return E_NOTIMPL;
+ _key.KeySize = 16 + algId * 8;
+ if ((flags & 1) == 0)
+ return E_NOTIMPL;
+ if ((flags & 0x4000) != 0)
+ {
+ // Use 3DES
+ return E_NOTIMPL;
+ }
+
+ UInt32 rdSize = GetUi16(p + 8);
+ if ((rdSize & 0xF) != 0 || rdSize + 16 > _remSize)
+ return E_NOTIMPL;
+ memmove(p, p + 10, rdSize);
+ Byte *validData = p + rdSize + 16;
+ if (GetUi32(validData - 6) != 0) // reserved
+ return E_NOTIMPL;
+ UInt32 validSize = GetUi16(validData - 2);
+ if ((validSize & 0xF) != 0 || 16 + rdSize + validSize != _remSize)
+ return E_NOTIMPL;
+
+
+ {
+ RINOK(SetKey(_key.MasterKey, _key.KeySize));
+ RINOK(SetInitVector(_iv, 16));
+ Init();
+ Filter(p, rdSize);
+ }
+
+ Byte fileKey[32];
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(_iv, 16);
+ sha.Update(p, rdSize - 16); // we don't use last 16 bytes (PAD bytes)
+ DeriveKey(sha, fileKey);
+
+ RINOK(SetKey(fileKey, _key.KeySize));
+ RINOK(SetInitVector(_iv, 16));
+ Init();
+ Filter(validData, validSize);
+
+ if (validSize < 4)
+ return E_NOTIMPL;
+ validSize -= 4;
+ if (GetUi32(validData + validSize) != CrcCalc(validData, validSize))
+ return S_OK;
+ passwOK = true;
+ Init();
+ return S_OK;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/7zip/Crypto/ZipStrong.h b/src/libs/7zip/win/CPP/7zip/Crypto/ZipStrong.h
new file mode 100644
index 000000000..151677ea6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Crypto/ZipStrong.h
@@ -0,0 +1,47 @@
+// Crypto/ZipStrong.h
+
+#ifndef __CRYPTO_ZIP_STRONG_H
+#define __CRYPTO_ZIP_STRONG_H
+
+#include "Common/Buffer.h"
+
+#include "../IPassword.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NZipStrong {
+
+struct CKeyInfo
+{
+ Byte MasterKey[32];
+ UInt32 KeySize;
+ void SetPassword(const Byte *data, UInt32 size);
+};
+
+class CBaseCoder:
+ public CAesCbcDecoder,
+ public ICryptoSetPassword
+{
+protected:
+ CKeyInfo _key;
+ CByteBuffer _buf;
+ Byte *_bufAligned;
+public:
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
+};
+
+class CDecoder: public CBaseCoder
+{
+ UInt32 _ivSize;
+ Byte _iv[16];
+ UInt32 _remSize;
+public:
+ MY_UNKNOWN_IMP1(ICryptoSetPassword)
+ HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize);
+ HRESULT CheckPassword(bool &passwOK);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/Guid.txt b/src/libs/7zip/win/CPP/7zip/Guid.txt
new file mode 100644
index 000000000..59a743b96
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/Guid.txt
@@ -0,0 +1,170 @@
+{23170F69-40C1-278A-0000-00yy00xx0000}
+
+00 IProgress.h
+
+ 05 IProgress
+
+01 IFolderArchive.h
+
+ 05 IArchiveFolder
+ // 06 IInFolderArchive // old
+ 07 IFileExtractCallback.h::IFolderArchiveExtractCallback
+ 0A IOutFolderArchive
+ 0B IFolderArchiveUpdateCallback
+ 0C Agent.h::IArchiveFolderInternal
+ 0D
+ 0E IInFolderArchive
+
+03 IStream.h
+
+ 01 ISequentialInStream
+ 02 ISequentialOutStream
+ 03 IInStream
+ 04 IOutStream
+ 06 IStreamGetSize
+ 07 IOutStreamFlush
+
+
+04 ICoder.h
+
+ 04 ICompressProgressInfo
+ 05 ICompressCoder
+ 18 ICompressCoder2
+ 20 ICompressSetCoderProperties
+ 21 ICompressSetDecoderProperties //
+ 22 ICompressSetDecoderProperties2
+ 23 ICompressWriteCoderProperties
+ 24 ICompressGetInStreamProcessedSize
+ 25 ICompressSetCoderMt
+ 30 ICompressGetSubStreamSize
+ 31 ICompressSetInStream
+ 32 ICompressSetOutStream
+ 33 ICompressSetInStreamSize
+ 34 ICompressSetOutStreamSize
+ 35 ICompressSetBufSize
+ 40 ICompressFilter
+ 60 ICompressCodecsInfo
+ 61 ISetCompressCodecsInfo
+ 80 ICryptoProperties
+ 88 ICryptoResetSalt
+ 8C ICryptoResetInitVector
+ 90 ICryptoSetPassword
+ A0 ICryptoSetCRC
+
+
+05 IPassword.h
+
+ 10 ICryptoGetTextPassword
+ 11 ICryptoGetTextPassword2
+
+
+06 IArchive.h
+
+ 03 ISetProperties
+
+ 10 IArchiveOpenCallback
+ 20 IArchiveExtractCallback
+ 30 IArchiveOpenVolumeCallback
+ 40 IInArchiveGetStream
+ 50 IArchiveOpenSetSubArchiveName
+ 60 IInArchive
+ 61 IArchiveOpenSeq
+
+ 80 IArchiveUpdateCallback
+ 82 IArchiveUpdateCallback2
+ A0 IOutArchive
+
+
+
+08 IFolder.h
+
+ 00 IFolderFolder
+ 01 IEnumProperties
+ 02 IFolderGetTypeID
+ 03 IFolderGetPath
+ 04 IFolderWasChanged
+ 05 // IFolderReload
+ 06 IFolderOperations
+ 07 IFolderGetSystemIconIndex
+ 08 IFolderGetItemFullSize
+ 09 IFolderClone
+ 0A IFolderSetFlatMode
+ 0B IFolderOperationsExtractCallback
+ 0C //
+ 0D //
+ 0E IFolderProperties
+ 0F
+ 10 IFolderArcProps
+ 11 IGetFolderArcProps
+
+
+09 IFolder.h :: FOLDER_MANAGER_INTERFACE
+
+ 00 - 04 // old IFolderManager
+ 05 IFolderManager
+
+
+// 0A PluginInterface.h
+ 00 IInitContextMenu
+ 01 IPluginOptionsCallback
+ 02 IPluginOptions
+
+
+Handler GUIDs:
+
+{23170F69-40C1-278A-1000-000110xx0000}
+
+ 01 Zip
+ 02 BZip2
+ 03 Rar
+ 04 Arj
+ 05 Z
+ 06 Lzh
+ 07 7z
+ 08 Cab
+ 09 Nsis
+ 0A lzma
+ 0B lzma86
+ 0C xz
+ 0D ppmd
+
+ D2 SquashFS
+ D3 CramFS
+ D4 APM
+ D5 Mslz
+ D6 Flv
+ D7 Swf
+ D8 Swfc
+ D9 Ntfs
+ DA Fat
+ DB Mbr
+ DC Vhd
+ DD Pe
+ DE Elf
+ DF Mach-O
+ E0 Udf
+ E1 Xar
+ E2 Mub
+ E3 Hfs
+ E4 Dmg
+ E5 Compound
+ E6 Wim
+ E7 Iso
+ E8 Bkf
+ E9 Chm
+ EA Split
+ EB Rpm
+ EC Deb
+ ED Cpio
+ EE Tar
+ EF GZip
+
+{23170F69-40C1-278A-1000-000100030000} CAgentArchiveHandle
+{23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu
+
+{23170F69-40C1-278B- old codecs clsids
+
+{23170F69-40C1-278D-1000-000100020000} OptionsDialog.h::CLSID_CSevenZipOptions
+
+{23170F69-40C1-2790-id} Codec Decoders
+{23170F69-40C1-2791-id} Codec Encoders
diff --git a/src/libs/7zip/win/CPP/7zip/ICoder.h b/src/libs/7zip/win/CPP/7zip/ICoder.h
new file mode 100644
index 000000000..a518de463
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/ICoder.h
@@ -0,0 +1,186 @@
+// ICoder.h
+
+#ifndef __ICODER_H
+#define __ICODER_H
+
+#include "IStream.h"
+
+#define CODER_INTERFACE(i, x) DECL_INTERFACE(i, 4, x)
+
+CODER_INTERFACE(ICompressProgressInfo, 0x04)
+{
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE;
+};
+
+CODER_INTERFACE(ICompressCoder, 0x05)
+{
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress) PURE;
+};
+
+CODER_INTERFACE(ICompressCoder2, 0x18)
+{
+ STDMETHOD(Code)(ISequentialInStream **inStreams, const UInt64 **inSizes, UInt32 numInStreams,
+ ISequentialOutStream **outStreams, const UInt64 **outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress) PURE;
+};
+
+namespace NCoderPropID
+{
+ enum EEnum
+ {
+ kDefaultProp = 0,
+ kDictionarySize,
+ kUsedMemorySize,
+ kOrder,
+ kBlockSize,
+ kPosStateBits,
+ kLitContextBits,
+ kLitPosBits,
+ kNumFastBytes,
+ kMatchFinder,
+ kMatchFinderCycles,
+ kNumPasses,
+ kAlgorithm,
+ kNumThreads,
+ kEndMarker
+ };
+}
+
+CODER_INTERFACE(ICompressSetCoderProperties, 0x20)
+{
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) PURE;
+};
+
+/*
+CODER_INTERFACE(ICompressSetCoderProperties, 0x21)
+{
+ STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE;
+};
+*/
+
+CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22)
+{
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICompressWriteCoderProperties, 0x23)
+{
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream) PURE;
+};
+
+CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24)
+{
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE;
+};
+
+CODER_INTERFACE(ICompressSetCoderMt, 0x25)
+{
+ STDMETHOD(SetNumberOfThreads)(UInt32 numThreads) PURE;
+};
+
+CODER_INTERFACE(ICompressGetSubStreamSize, 0x30)
+{
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE;
+};
+
+CODER_INTERFACE(ICompressSetInStream, 0x31)
+{
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE;
+ STDMETHOD(ReleaseInStream)() PURE;
+};
+
+CODER_INTERFACE(ICompressSetOutStream, 0x32)
+{
+ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE;
+ STDMETHOD(ReleaseOutStream)() PURE;
+};
+
+CODER_INTERFACE(ICompressSetInStreamSize, 0x33)
+{
+ STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE;
+};
+
+CODER_INTERFACE(ICompressSetOutStreamSize, 0x34)
+{
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE;
+};
+
+CODER_INTERFACE(ICompressSetBufSize, 0x35)
+{
+ STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size) PURE;
+ STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICompressFilter, 0x40)
+{
+ STDMETHOD(Init)() PURE;
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) PURE;
+ // Filter converts as most as possible bytes
+ // Filter return outSize (UInt32)
+ // if (outSize <= size): Filter have converted outSize bytes
+ // if (outSize > size): Filter have not converted anything.
+ // and it needs at least outSize bytes to convert one block
+ // (it's for crypto block algorithms).
+};
+
+CODER_INTERFACE(ICompressCodecsInfo, 0x60)
+{
+ STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods) PURE;
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE;
+ STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder) PURE;
+ STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder) PURE;
+};
+CODER_INTERFACE(ISetCompressCodecsInfo, 0x61)
+{
+ STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo) PURE;
+};
+
+CODER_INTERFACE(ICryptoProperties, 0x80)
+{
+ STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE;
+ STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE;
+};
+
+/*
+CODER_INTERFACE(ICryptoResetSalt, 0x88)
+{
+ STDMETHOD(ResetSalt)() PURE;
+};
+*/
+
+CODER_INTERFACE(ICryptoResetInitVector, 0x8C)
+{
+ STDMETHOD(ResetInitVector)() PURE;
+};
+
+CODER_INTERFACE(ICryptoSetPassword, 0x90)
+{
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICryptoSetCRC, 0xA0)
+{
+ STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE;
+};
+
+//////////////////////
+// It's for DLL file
+namespace NMethodPropID
+{
+ enum EEnum
+ {
+ kID,
+ kName,
+ kDecoder,
+ kEncoder,
+ kInStreams,
+ kOutStreams,
+ kDescription,
+ kDecoderIsAssigned,
+ kEncoderIsAssigned
+ };
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/IDecl.h b/src/libs/7zip/win/CPP/7zip/IDecl.h
new file mode 100644
index 000000000..8316eb3ac
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/IDecl.h
@@ -0,0 +1,15 @@
+// IDecl.h
+
+#ifndef __IDECL_H
+#define __IDECL_H
+
+#include "../Common/MyUnknown.h"
+
+#define DECL_INTERFACE_SUB(i, base, groupId, subId) \
+DEFINE_GUID(IID_ ## i, \
+0x23170F69, 0x40C1, 0x278A, 0, 0, 0, (groupId), 0, (subId), 0, 0); \
+struct i: public base
+
+#define DECL_INTERFACE(i, groupId, subId) DECL_INTERFACE_SUB(i, IUnknown, groupId, subId)
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/IPassword.h b/src/libs/7zip/win/CPP/7zip/IPassword.h
new file mode 100644
index 000000000..3ca7b090e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/IPassword.h
@@ -0,0 +1,24 @@
+// IPassword.h
+
+#ifndef __IPASSWORD_H
+#define __IPASSWORD_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+#define PASSWORD_INTERFACE(i, x) DECL_INTERFACE(i, 5, x)
+
+PASSWORD_INTERFACE(ICryptoGetTextPassword, 0x10)
+{
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE;
+};
+
+PASSWORD_INTERFACE(ICryptoGetTextPassword2, 0x11)
+{
+ STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password) PURE;
+};
+
+#endif
+
diff --git a/src/libs/7zip/win/CPP/7zip/IProgress.h b/src/libs/7zip/win/CPP/7zip/IProgress.h
new file mode 100644
index 000000000..d6093f173
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/IProgress.h
@@ -0,0 +1,33 @@
+// Interface/IProgress.h
+
+#ifndef __IPROGRESS_H
+#define __IPROGRESS_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+#define INTERFACE_IProgress(x) \
+ STDMETHOD(SetTotal)(UInt64 total) x; \
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue) x; \
+
+DECL_INTERFACE(IProgress, 0, 5)
+{
+ INTERFACE_IProgress(PURE)
+};
+
+/*
+// {23170F69-40C1-278A-0000-000000050002}
+DEFINE_GUID(IID_IProgress2,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050002")
+IProgress2: public IUnknown
+{
+public:
+ STDMETHOD(SetTotal)(const UInt64 *total) PURE;
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE;
+};
+*/
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/IStream.h b/src/libs/7zip/win/CPP/7zip/IStream.h
new file mode 100644
index 000000000..165e8baad
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/IStream.h
@@ -0,0 +1,58 @@
+// IStream.h
+
+#ifndef __ISTREAM_H
+#define __ISTREAM_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+#include "IDecl.h"
+
+#define STREAM_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 3, x)
+#define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x)
+
+STREAM_INTERFACE(ISequentialInStream, 0x01)
+{
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE;
+ /*
+ Out: if size != 0, return_value = S_OK and (*processedSize == 0),
+ then there are no more bytes in stream.
+ if (size > 0) && there are bytes in stream,
+ this function must read at least 1 byte.
+ This function is allowed to read less than number of remaining bytes in stream.
+ You must call Read function in loop, if you need exact amount of data
+ */
+};
+
+STREAM_INTERFACE(ISequentialOutStream, 0x02)
+{
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE;
+ /*
+ if (size > 0) this function must write at least 1 byte.
+ This function is allowed to write less than "size".
+ You must call Write function in loop, if you need to write exact amount of data
+ */
+};
+
+STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03)
+{
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
+};
+
+STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04)
+{
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
+ STDMETHOD(SetSize)(UInt64 newSize) PURE;
+};
+
+STREAM_INTERFACE(IStreamGetSize, 0x06)
+{
+ STDMETHOD(GetSize)(UInt64 *size) PURE;
+};
+
+STREAM_INTERFACE(IOutStreamFlush, 0x07)
+{
+ STDMETHOD(Flush)() PURE;
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/MyVersion.h b/src/libs/7zip/win/CPP/7zip/MyVersion.h
new file mode 100644
index 000000000..eda88db08
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/MyVersion.h
@@ -0,0 +1,8 @@
+#define MY_VER_MAJOR 9
+#define MY_VER_MINOR 20
+#define MY_VER_BUILD 0
+#define MY_VERSION "9.20"
+#define MY_7ZIP_VERSION "7-Zip 9.20"
+#define MY_DATE "2010-11-18"
+#define MY_COPYRIGHT "Copyright (c) 1999-2010 Igor Pavlov"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " " MY_DATE
diff --git a/src/libs/7zip/win/CPP/7zip/PropID.h b/src/libs/7zip/win/CPP/7zip/PropID.h
new file mode 100644
index 000000000..8f8885263
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/PropID.h
@@ -0,0 +1,76 @@
+// PropID.h
+
+#ifndef __7ZIP_PROPID_H
+#define __7ZIP_PROPID_H
+
+enum
+{
+ kpidNoProperty = 0,
+ kpidMainSubfile = 1,
+ kpidHandlerItemIndex = 2,
+ kpidPath,
+ kpidName,
+ kpidExtension,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidAttrib,
+ kpidCTime,
+ kpidATime,
+ kpidMTime,
+ kpidSolid,
+ kpidCommented,
+ kpidEncrypted,
+ kpidSplitBefore,
+ kpidSplitAfter,
+ kpidDictionarySize,
+ kpidCRC,
+ kpidType,
+ kpidIsAnti,
+ kpidMethod,
+ kpidHostOS,
+ kpidFileSystem,
+ kpidUser,
+ kpidGroup,
+ kpidBlock,
+ kpidComment,
+ kpidPosition,
+ kpidPrefix,
+ kpidNumSubDirs,
+ kpidNumSubFiles,
+ kpidUnpackVer,
+ kpidVolume,
+ kpidIsVolume,
+ kpidOffset,
+ kpidLinks,
+ kpidNumBlocks,
+ kpidNumVolumes,
+ kpidTimeType,
+ kpidBit64,
+ kpidBigEndian,
+ kpidCpu,
+ kpidPhySize,
+ kpidHeadersSize,
+ kpidChecksum,
+ kpidCharacts,
+ kpidVa,
+ kpidId,
+ kpidShortName,
+ kpidCreatorApp,
+ kpidSectorSize,
+ kpidPosixAttrib,
+ kpidLink,
+ kpidError,
+
+ kpidTotalSize = 0x1100,
+ kpidFreeSpace,
+ kpidClusterSize,
+ kpidVolumeName,
+
+ kpidLocalName = 0x1200,
+ kpidProvider,
+
+ kpidUserDefined = 0x10000
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
new file mode 100644
index 000000000..8ae2e15e8
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -0,0 +1,1042 @@
+// ArchiveCommandLine.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+#include <io.h>
+#endif
+#endif
+#include <stdio.h>
+
+#include "Common/ListFileUtils.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileName.h"
+#ifdef _WIN32
+#include "Windows/FileMapping.h"
+#include "Windows/Synchronization.h"
+#endif
+
+#include "ArchiveCommandLine.h"
+#include "EnumDirItems.h"
+#include "SortUtils.h"
+#include "Update.h"
+#include "UpdateAction.h"
+
+extern bool g_CaseSensitive;
+
+#ifdef UNDER_CE
+
+#define MY_IS_TERMINAL(x) false;
+
+#else
+
+#if _MSC_VER >= 1400
+#define MY_isatty_fileno(x) _isatty(_fileno(x))
+#else
+#define MY_isatty_fileno(x) isatty(fileno(x))
+#endif
+
+#define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
+
+#endif
+
+using namespace NCommandLineParser;
+using namespace NWindows;
+using namespace NFile;
+
+int g_CodePage = -1;
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kHelp3,
+ kDisableHeaders,
+ kDisablePercents,
+ kArchiveType,
+ kYes,
+ #ifndef _NO_CRYPTO
+ kPassword,
+ #endif
+ kProperty,
+ kOutputDir,
+ kWorkingDir,
+ kInclude,
+ kExclude,
+ kArInclude,
+ kArExclude,
+ kNoArName,
+ kUpdate,
+ kVolume,
+ kRecursed,
+ kSfx,
+ kStdIn,
+ kStdOut,
+ kOverwrite,
+ kEmail,
+ kShowDialog,
+ kLargePages,
+ kListfileCharSet,
+ kConsoleCharSet,
+ kTechMode,
+ kShareForWrite,
+ kCaseSensitive,
+ kCalcCrc
+};
+
+}
+
+
+static const wchar_t kRecursedIDChar = 'R';
+static const wchar_t *kRecursedPostCharSet = L"0-";
+
+namespace NRecursedPostCharIndex {
+ enum EEnum
+ {
+ kWildCardRecursionOnly = 0,
+ kNoRecursion = 1
+ };
+}
+
+static const char kImmediateNameID = '!';
+static const char kMapNameID = '#';
+static const char kFileListID = '@';
+
+static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
+static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
+
+static const wchar_t *kOverwritePostCharSet = L"asut";
+
+NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
+{
+ NExtract::NOverwriteMode::kWithoutPrompt,
+ NExtract::NOverwriteMode::kSkipExisting,
+ NExtract::NOverwriteMode::kAutoRename,
+ NExtract::NOverwriteMode::kAutoRenameExisting
+};
+
+static const CSwitchForm kSwitchForms[] =
+ {
+ { L"?", NSwitchType::kSimple, false },
+ { L"H", NSwitchType::kSimple, false },
+ { L"-HELP", NSwitchType::kSimple, false },
+ { L"BA", NSwitchType::kSimple, false },
+ { L"BD", NSwitchType::kSimple, false },
+ { L"T", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"Y", NSwitchType::kSimple, false },
+ #ifndef _NO_CRYPTO
+ { L"P", NSwitchType::kUnLimitedPostString, false, 0 },
+ #endif
+ { L"M", NSwitchType::kUnLimitedPostString, true, 1 },
+ { L"O", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"W", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"I", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"X", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AI", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AX", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSize},
+ { L"AN", NSwitchType::kSimple, false },
+ { L"U", NSwitchType::kUnLimitedPostString, true, 1},
+ { L"V", NSwitchType::kUnLimitedPostString, true, 1},
+ { L"R", NSwitchType::kPostChar, false, 0, 0, kRecursedPostCharSet },
+ { L"SFX", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"SI", NSwitchType::kUnLimitedPostString, false, 0 },
+ { L"SO", NSwitchType::kSimple, false, 0 },
+ { L"AO", NSwitchType::kPostChar, false, 1, 1, kOverwritePostCharSet},
+ { L"SEML", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"AD", NSwitchType::kSimple, false },
+ { L"SLP", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"SCS", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"SCC", NSwitchType::kUnLimitedPostString, false, 0},
+ { L"SLT", NSwitchType::kSimple, false },
+ { L"SSW", NSwitchType::kSimple, false },
+ { L"SSC", NSwitchType::kPostChar, false, 0, 0, L"-" },
+ { L"SCRC", NSwitchType::kSimple, false }
+ };
+
+static const CCommandForm g_CommandForms[] =
+{
+ { L"A", false },
+ { L"U", false },
+ { L"D", false },
+ { L"T", false },
+ { L"E", false },
+ { L"X", false },
+ { L"L", false },
+ { L"B", false },
+ { L"I", false }
+};
+
+static const int kNumCommandForms = sizeof(g_CommandForms) / sizeof(g_CommandForms[0]);
+
+static const wchar_t *kUniversalWildcard = L"*";
+static const int kMinNonSwitchWords = 1;
+static const int kCommandIndex = 0;
+
+// ---------------------------
+// exception messages
+
+static const char *kUserErrorMessage = "Incorrect command line";
+static const char *kCannotFindListFile = "Cannot find listfile";
+static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
+static const char *kIncorrectWildCardInListFile = "Incorrect wildcard in listfile";
+static const char *kIncorrectWildCardInCommandLine = "Incorrect wildcard in command line";
+static const char *kTerminalOutError = "I won't write compressed data to a terminal";
+static const char *kSameTerminalError = "I won't write data and program's messages to same terminal";
+static const char *kEmptyFilePath = "Empty file path";
+
+static void ThrowException(const char *errorMessage)
+{
+ throw CArchiveCommandLineException(errorMessage);
+}
+
+static void ThrowUserErrorException()
+{
+ ThrowException(kUserErrorMessage);
+}
+
+// ---------------------------
+
+bool CArchiveCommand::IsFromExtractGroup() const
+{
+ switch(CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kExtract:
+ case NCommandType::kFullExtract:
+ return true;
+ default:
+ return false;
+ }
+}
+
+NExtract::NPathMode::EEnum CArchiveCommand::GetPathMode() const
+{
+ switch(CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kFullExtract:
+ return NExtract::NPathMode::kFullPathnames;
+ default:
+ return NExtract::NPathMode::kNoPathnames;
+ }
+}
+
+bool CArchiveCommand::IsFromUpdateGroup() const
+{
+ return (CommandType == NCommandType::kAdd ||
+ CommandType == NCommandType::kUpdate ||
+ CommandType == NCommandType::kDelete);
+}
+
+static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
+{
+ switch (index)
+ {
+ case NRecursedPostCharIndex::kWildCardRecursionOnly:
+ return NRecursedType::kWildCardOnlyRecursed;
+ case NRecursedPostCharIndex::kNoRecursion:
+ return NRecursedType::kNonRecursed;
+ default:
+ return NRecursedType::kRecursed;
+ }
+}
+
+static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command)
+{
+ UString commandStringUpper = commandString;
+ commandStringUpper.MakeUpper();
+ UString postString;
+ int commandIndex = ParseCommand(kNumCommandForms, g_CommandForms, commandStringUpper,
+ postString) ;
+ if (commandIndex < 0)
+ return false;
+ command.CommandType = (NCommandType::EEnum)commandIndex;
+ return true;
+}
+
+// ------------------------------------------------------------------
+// filenames functions
+
+static void AddNameToCensor(NWildcard::CCensor &wildcardCensor,
+ const UString &name, bool include, NRecursedType::EEnum type)
+{
+ bool recursed = false;
+
+ switch (type)
+ {
+ case NRecursedType::kWildCardOnlyRecursed:
+ recursed = DoesNameContainWildCard(name);
+ break;
+ case NRecursedType::kRecursed:
+ recursed = true;
+ break;
+ }
+ wildcardCensor.AddItem(include, name, recursed);
+}
+
+static void AddToCensorFromListFile(NWildcard::CCensor &wildcardCensor,
+ LPCWSTR fileName, bool include, NRecursedType::EEnum type, UINT codePage)
+{
+ UStringVector names;
+ if (!NFind::DoesFileExist(fileName))
+ throw kCannotFindListFile;
+ if (!ReadNamesFromListFile(fileName, names, codePage))
+ throw kIncorrectListFile;
+ for (int i = 0; i < names.Size(); i++)
+ AddNameToCensor(wildcardCensor, names[i], include, type);
+}
+
+static void AddToCensorFromNonSwitchesStrings(
+ int startIndex,
+ NWildcard::CCensor &wildcardCensor,
+ const UStringVector &nonSwitchStrings, NRecursedType::EEnum type,
+ bool thereAreSwitchIncludes, UINT codePage)
+{
+ if (nonSwitchStrings.Size() == startIndex && (!thereAreSwitchIncludes))
+ AddNameToCensor(wildcardCensor, kUniversalWildcard, true, type);
+ for (int i = startIndex; i < nonSwitchStrings.Size(); i++)
+ {
+ const UString &s = nonSwitchStrings[i];
+ if (s.IsEmpty())
+ throw kEmptyFilePath;
+ if (s[0] == kFileListID)
+ AddToCensorFromListFile(wildcardCensor, s.Mid(1), true, type, codePage);
+ else
+ AddNameToCensor(wildcardCensor, s, true, type);
+ }
+}
+
+#ifdef _WIN32
+static void ParseMapWithPaths(NWildcard::CCensor &wildcardCensor,
+ const UString &switchParam, bool include,
+ NRecursedType::EEnum commonRecursedType)
+{
+ int splitPos = switchParam.Find(L':');
+ if (splitPos < 0)
+ ThrowUserErrorException();
+ UString mappingName = switchParam.Left(splitPos);
+
+ UString switchParam2 = switchParam.Mid(splitPos + 1);
+ splitPos = switchParam2.Find(L':');
+ if (splitPos < 0)
+ ThrowUserErrorException();
+
+ UString mappingSize = switchParam2.Left(splitPos);
+ UString eventName = switchParam2.Mid(splitPos + 1);
+
+ UInt64 dataSize64 = ConvertStringToUInt64(mappingSize, NULL);
+ UInt32 dataSize = (UInt32)dataSize64;
+ {
+ CFileMapping fileMapping;
+ if (fileMapping.Open(FILE_MAP_READ, GetSystemString(mappingName)) != 0)
+ ThrowException("Can not open mapping");
+ LPVOID data = fileMapping.Map(FILE_MAP_READ, 0, dataSize);
+ if (data == NULL)
+ ThrowException("MapViewOfFile error");
+ try
+ {
+ const wchar_t *curData = (const wchar_t *)data;
+ if (*curData != 0)
+ ThrowException("Incorrect mapping data");
+ UInt32 numChars = dataSize / sizeof(wchar_t);
+ UString name;
+ for (UInt32 i = 1; i < numChars; i++)
+ {
+ wchar_t c = curData[i];
+ if (c == L'\0')
+ {
+ AddNameToCensor(wildcardCensor, name, include, commonRecursedType);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ if (!name.IsEmpty())
+ ThrowException("data error");
+ }
+ catch(...)
+ {
+ UnmapViewOfFile(data);
+ throw;
+ }
+ UnmapViewOfFile(data);
+ }
+
+ {
+ NSynchronization::CManualResetEvent event;
+ if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(eventName)) == S_OK)
+ event.Set();
+ }
+}
+#endif
+
+static void AddSwitchWildCardsToCensor(NWildcard::CCensor &wildcardCensor,
+ const UStringVector &strings, bool include,
+ NRecursedType::EEnum commonRecursedType, UINT codePage)
+{
+ for (int i = 0; i < strings.Size(); i++)
+ {
+ const UString &name = strings[i];
+ NRecursedType::EEnum recursedType;
+ int pos = 0;
+ if (name.Length() < kSomeCludePostStringMinSize)
+ ThrowUserErrorException();
+ if (::MyCharUpper(name[pos]) == kRecursedIDChar)
+ {
+ pos++;
+ int index = UString(kRecursedPostCharSet).Find(name[pos]);
+ recursedType = GetRecursedTypeFromIndex(index);
+ if (index >= 0)
+ pos++;
+ }
+ else
+ recursedType = commonRecursedType;
+ if (name.Length() < pos + kSomeCludeAfterRecursedPostStringMinSize)
+ ThrowUserErrorException();
+ UString tail = name.Mid(pos + 1);
+ if (name[pos] == kImmediateNameID)
+ AddNameToCensor(wildcardCensor, tail, include, recursedType);
+ else if (name[pos] == kFileListID)
+ AddToCensorFromListFile(wildcardCensor, tail, include, recursedType, codePage);
+ #ifdef _WIN32
+ else if (name[pos] == kMapNameID)
+ ParseMapWithPaths(wildcardCensor, tail, include, recursedType);
+ #endif
+ else
+ ThrowUserErrorException();
+ }
+}
+
+#ifdef _WIN32
+
+// This code converts all short file names to long file names.
+
+static void ConvertToLongName(const UString &prefix, UString &name)
+{
+ if (name.IsEmpty() || DoesNameContainWildCard(name))
+ return;
+ NFind::CFileInfoW fi;
+ if (fi.Find(prefix + name))
+ name = fi.Name;
+}
+
+static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::CItem> &items)
+{
+ for (int i = 0; i < items.Size(); i++)
+ {
+ NWildcard::CItem &item = items[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ continue;
+ ConvertToLongName(prefix, item.PathParts.Front());
+ }
+}
+
+static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node)
+{
+ ConvertToLongNames(prefix, node.IncludeItems);
+ ConvertToLongNames(prefix, node.ExcludeItems);
+ int i;
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ ConvertToLongName(prefix, node.SubNodes[i].Name);
+ // mix folders with same name
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ NWildcard::CCensorNode &nextNode1 = node.SubNodes[i];
+ for (int j = i + 1; j < node.SubNodes.Size();)
+ {
+ const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j];
+ if (nextNode1.Name.CompareNoCase(nextNode2.Name) == 0)
+ {
+ nextNode1.IncludeItems += nextNode2.IncludeItems;
+ nextNode1.ExcludeItems += nextNode2.ExcludeItems;
+ node.SubNodes.Delete(j);
+ }
+ else
+ j++;
+ }
+ }
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ NWildcard::CCensorNode &nextNode = node.SubNodes[i];
+ ConvertToLongNames(prefix + nextNode.Name + wchar_t(NFile::NName::kDirDelimiter), nextNode);
+ }
+}
+
+static void ConvertToLongNames(NWildcard::CCensor &censor)
+{
+ for (int i = 0; i < censor.Pairs.Size(); i++)
+ {
+ NWildcard::CPair &pair = censor.Pairs[i];
+ ConvertToLongNames(pair.Prefix, pair.Head);
+ }
+}
+
+#endif
+
+static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
+{
+ switch(i)
+ {
+ case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
+ case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
+ case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
+ case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
+ }
+ throw 98111603;
+}
+
+const UString kUpdatePairStateIDSet = L"PQRXYZW";
+const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
+
+const UString kUpdatePairActionIDSet = L"0123"; //Ignore, Copy, Compress, Create Anti
+
+const wchar_t *kUpdateIgnoreItselfPostStringID = L"-";
+const wchar_t kUpdateNewArchivePostCharID = '!';
+
+
+static bool ParseUpdateCommandString2(const UString &command,
+ NUpdateArchive::CActionSet &actionSet, UString &postString)
+{
+ for (int i = 0; i < command.Length();)
+ {
+ wchar_t c = MyCharUpper(command[i]);
+ int statePos = kUpdatePairStateIDSet.Find(c);
+ if (statePos < 0)
+ {
+ postString = command.Mid(i);
+ return true;
+ }
+ i++;
+ if (i >= command.Length())
+ return false;
+ int actionPos = kUpdatePairActionIDSet.Find(::MyCharUpper(command[i]));
+ if (actionPos < 0)
+ return false;
+ actionSet.StateActions[statePos] = GetUpdatePairActionType(actionPos);
+ if (kUpdatePairStateNotSupportedActions[statePos] == actionPos)
+ return false;
+ i++;
+ }
+ postString.Empty();
+ return true;
+}
+
+static void ParseUpdateCommandString(CUpdateOptions &options,
+ const UStringVector &updatePostStrings,
+ const NUpdateArchive::CActionSet &defaultActionSet)
+{
+ for (int i = 0; i < updatePostStrings.Size(); i++)
+ {
+ const UString &updateString = updatePostStrings[i];
+ if (updateString.CompareNoCase(kUpdateIgnoreItselfPostStringID) == 0)
+ {
+ if (options.UpdateArchiveItself)
+ {
+ options.UpdateArchiveItself = false;
+ options.Commands.Delete(0);
+ }
+ }
+ else
+ {
+ NUpdateArchive::CActionSet actionSet = defaultActionSet;
+
+ UString postString;
+ if (!ParseUpdateCommandString2(updateString, actionSet, postString))
+ ThrowUserErrorException();
+ if (postString.IsEmpty())
+ {
+ if (options.UpdateArchiveItself)
+ options.Commands[0].ActionSet = actionSet;
+ }
+ else
+ {
+ if (MyCharUpper(postString[0]) != kUpdateNewArchivePostCharID)
+ ThrowUserErrorException();
+ CUpdateArchiveCommand uc;
+ UString archivePath = postString.Mid(1);
+ if (archivePath.IsEmpty())
+ ThrowUserErrorException();
+ uc.UserArchivePath = archivePath;
+ uc.ActionSet = actionSet;
+ options.Commands.Add(uc);
+ }
+ }
+ }
+}
+
+static const char kByteSymbol = 'B';
+static const char kKiloSymbol = 'K';
+static const char kMegaSymbol = 'M';
+static const char kGigaSymbol = 'G';
+
+static bool ParseComplexSize(const UString &src, UInt64 &result)
+{
+ UString s = src;
+ s.MakeUpper();
+
+ const wchar_t *start = s;
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(start, &end);
+ int numDigits = (int)(end - start);
+ if (numDigits == 0 || s.Length() > numDigits + 1)
+ return false;
+ if (s.Length() == numDigits)
+ {
+ result = number;
+ return true;
+ }
+ int numBits;
+ switch (s[numDigits])
+ {
+ case kByteSymbol:
+ result = number;
+ return true;
+ case kKiloSymbol:
+ numBits = 10;
+ break;
+ case kMegaSymbol:
+ numBits = 20;
+ break;
+ case kGigaSymbol:
+ numBits = 30;
+ break;
+ default:
+ return false;
+ }
+ if (number >= ((UInt64)1 << (64 - numBits)))
+ return false;
+ result = number << numBits;
+ return true;
+}
+
+static void SetAddCommandOptions(
+ NCommandType::EEnum commandType,
+ const CParser &parser,
+ CUpdateOptions &options)
+{
+ NUpdateArchive::CActionSet defaultActionSet;
+ switch(commandType)
+ {
+ case NCommandType::kAdd:
+ defaultActionSet = NUpdateArchive::kAddActionSet;
+ break;
+ case NCommandType::kDelete:
+ defaultActionSet = NUpdateArchive::kDeleteActionSet;
+ break;
+ default:
+ defaultActionSet = NUpdateArchive::kUpdateActionSet;
+ }
+
+ options.UpdateArchiveItself = true;
+
+ options.Commands.Clear();
+ CUpdateArchiveCommand updateMainCommand;
+ updateMainCommand.ActionSet = defaultActionSet;
+ options.Commands.Add(updateMainCommand);
+ if (parser[NKey::kUpdate].ThereIs)
+ ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
+ defaultActionSet);
+ if (parser[NKey::kWorkingDir].ThereIs)
+ {
+ const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
+ if (postString.IsEmpty())
+ NDirectory::MyGetTempPath(options.WorkingDir);
+ else
+ options.WorkingDir = postString;
+ }
+ options.SfxMode = parser[NKey::kSfx].ThereIs;
+ if (options.SfxMode)
+ options.SfxModule = parser[NKey::kSfx].PostStrings[0];
+
+ if (parser[NKey::kVolume].ThereIs)
+ {
+ const UStringVector &sv = parser[NKey::kVolume].PostStrings;
+ for (int i = 0; i < sv.Size(); i++)
+ {
+ UInt64 size;
+ if (!ParseComplexSize(sv[i], size))
+ ThrowException("Incorrect volume size");
+ options.VolumesSizes.Add(size);
+ }
+ }
+}
+
+static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
+{
+ if (parser[NKey::kProperty].ThereIs)
+ {
+ // options.MethodMode.Properties.Clear();
+ for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++)
+ {
+ CProperty property;
+ const UString &postString = parser[NKey::kProperty].PostStrings[i];
+ int index = postString.Find(L'=');
+ if (index < 0)
+ property.Name = postString;
+ else
+ {
+ property.Name = postString.Left(index);
+ property.Value = postString.Mid(index + 1);
+ }
+ properties.Add(property);
+ }
+ }
+}
+
+CArchiveCommandLineParser::CArchiveCommandLineParser():
+ parser(sizeof(kSwitchForms) / sizeof(kSwitchForms[0])) {}
+
+void CArchiveCommandLineParser::Parse1(const UStringVector &commandStrings,
+ CArchiveCommandLineOptions &options)
+{
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ }
+ catch(...)
+ {
+ ThrowUserErrorException();
+ }
+
+ options.IsInTerminal = MY_IS_TERMINAL(stdin);
+ options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
+ options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
+ options.StdInMode = parser[NKey::kStdIn].ThereIs;
+ options.StdOutMode = parser[NKey::kStdOut].ThereIs;
+ options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
+ options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs;
+
+ #ifdef _WIN32
+ options.LargePages = false;
+ if (parser[NKey::kLargePages].ThereIs)
+ {
+ const UString &postString = parser[NKey::kLargePages].PostStrings.Front();
+ if (postString.IsEmpty())
+ options.LargePages = true;
+ }
+ #endif
+}
+
+struct CCodePagePair
+{
+ const wchar_t *Name;
+ UINT CodePage;
+};
+
+static CCodePagePair g_CodePagePairs[] =
+{
+ { L"UTF-8", CP_UTF8 },
+ { L"WIN", CP_ACP },
+ { L"DOS", CP_OEMCP }
+};
+
+static int FindCharset(const NCommandLineParser::CParser &parser, int keyIndex, int defaultVal)
+{
+ if (!parser[keyIndex].ThereIs)
+ return defaultVal;
+
+ UString name = parser[keyIndex].PostStrings.Back();
+ name.MakeUpper();
+ int i;
+ for (i = 0; i < sizeof(g_CodePagePairs) / sizeof(g_CodePagePairs[0]); i++)
+ {
+ const CCodePagePair &pair = g_CodePagePairs[i];
+ if (name.Compare(pair.Name) == 0)
+ return pair.CodePage;
+ }
+ if (i == sizeof(g_CodePagePairs) / sizeof(g_CodePagePairs[0]))
+ ThrowUserErrorException();
+ return -1;
+}
+
+static bool ConvertStringToUInt32(const wchar_t *s, UInt32 &v)
+{
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(s, &end);
+ if (*end != 0)
+ return false;
+ if (number > (UInt32)0xFFFFFFFF)
+ return false;
+ v = (UInt32)number;
+ return true;
+}
+
+void EnumerateDirItemsAndSort(NWildcard::CCensor &wildcardCensor,
+ UStringVector &sortedPaths,
+ UStringVector &sortedFullPaths)
+{
+ UStringVector paths;
+ {
+ CDirItems dirItems;
+ {
+ UStringVector errorPaths;
+ CRecordVector<DWORD> errorCodes;
+ HRESULT res = EnumerateItems(wildcardCensor, dirItems, NULL, errorPaths, errorCodes);
+ if (res != S_OK || errorPaths.Size() > 0)
+ throw "cannot find archive";
+ }
+ for (int i = 0; i < dirItems.Items.Size(); i++)
+ {
+ const CDirItem &dirItem = dirItems.Items[i];
+ if (!dirItem.IsDir())
+ paths.Add(dirItems.GetPhyPath(i));
+ }
+ }
+
+ if (paths.Size() == 0)
+ throw "there is no such archive";
+
+ UStringVector fullPaths;
+
+ int i;
+ for (i = 0; i < paths.Size(); i++)
+ {
+ UString fullPath;
+ NFile::NDirectory::MyGetFullPathName(paths[i], fullPath);
+ fullPaths.Add(fullPath);
+ }
+ CIntVector indices;
+ SortFileNames(fullPaths, indices);
+ sortedPaths.Reserve(indices.Size());
+ sortedFullPaths.Reserve(indices.Size());
+ for (i = 0; i < indices.Size(); i++)
+ {
+ int index = indices[i];
+ sortedPaths.Add(paths[index]);
+ sortedFullPaths.Add(fullPaths[index]);
+ }
+}
+
+void CArchiveCommandLineParser::Parse2(CArchiveCommandLineOptions &options)
+{
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+ int numNonSwitchStrings = nonSwitchStrings.Size();
+ if (numNonSwitchStrings < kMinNonSwitchWords)
+ ThrowUserErrorException();
+
+ if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
+ ThrowUserErrorException();
+
+ options.TechMode = parser[NKey::kTechMode].ThereIs;
+ options.CalcCrc = parser[NKey::kCalcCrc].ThereIs;
+
+ if (parser[NKey::kCaseSensitive].ThereIs)
+ g_CaseSensitive = (parser[NKey::kCaseSensitive].PostCharIndex < 0);
+
+ NRecursedType::EEnum recursedType;
+ if (parser[NKey::kRecursed].ThereIs)
+ recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
+ else
+ recursedType = NRecursedType::kNonRecursed;
+
+ g_CodePage = FindCharset(parser, NKey::kConsoleCharSet, -1);
+ UINT codePage = FindCharset(parser, NKey::kListfileCharSet, CP_UTF8);
+
+ bool thereAreSwitchIncludes = false;
+ if (parser[NKey::kInclude].ThereIs)
+ {
+ thereAreSwitchIncludes = true;
+ AddSwitchWildCardsToCensor(options.WildcardCensor,
+ parser[NKey::kInclude].PostStrings, true, recursedType, codePage);
+ }
+ if (parser[NKey::kExclude].ThereIs)
+ AddSwitchWildCardsToCensor(options.WildcardCensor,
+ parser[NKey::kExclude].PostStrings, false, recursedType, codePage);
+
+ int curCommandIndex = kCommandIndex + 1;
+ bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
+ options.Command.CommandType != NCommandType::kBenchmark &&
+ options.Command.CommandType != NCommandType::kInfo;
+
+ bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+ bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
+
+ if (isExtractOrList && options.StdInMode)
+ thereIsArchiveName = false;
+
+ if (thereIsArchiveName)
+ {
+ if (curCommandIndex >= numNonSwitchStrings)
+ ThrowUserErrorException();
+ options.ArchiveName = nonSwitchStrings[curCommandIndex++];
+ if (options.ArchiveName.IsEmpty())
+ ThrowUserErrorException();
+ }
+
+ AddToCensorFromNonSwitchesStrings(
+ curCommandIndex, options.WildcardCensor,
+ nonSwitchStrings, recursedType, thereAreSwitchIncludes, codePage);
+
+ options.YesToAll = parser[NKey::kYes].ThereIs;
+
+
+ #ifndef _NO_CRYPTO
+ options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
+ if (options.PasswordEnabled)
+ options.Password = parser[NKey::kPassword].PostStrings[0];
+ #endif
+
+ options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
+
+ if (parser[NKey::kArchiveType].ThereIs)
+ options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
+
+ if (isExtractOrList)
+ {
+ if (!options.WildcardCensor.AllAreRelative())
+ ThrowException("Cannot use absolute pathnames for this command");
+
+ NWildcard::CCensor archiveWildcardCensor;
+
+ if (parser[NKey::kArInclude].ThereIs)
+ AddSwitchWildCardsToCensor(archiveWildcardCensor,
+ parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, codePage);
+ if (parser[NKey::kArExclude].ThereIs)
+ AddSwitchWildCardsToCensor(archiveWildcardCensor,
+ parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, codePage);
+
+ if (thereIsArchiveName)
+ AddNameToCensor(archiveWildcardCensor, options.ArchiveName, true, NRecursedType::kNonRecursed);
+
+ #ifdef _WIN32
+ ConvertToLongNames(archiveWildcardCensor);
+ #endif
+
+ archiveWildcardCensor.ExtendExclude();
+
+ if (options.StdInMode)
+ {
+ UString arcName = parser[NKey::kStdIn].PostStrings.Front();
+ options.ArchivePathsSorted.Add(arcName);
+ options.ArchivePathsFullSorted.Add(arcName);
+ }
+ else
+ {
+ EnumerateDirItemsAndSort(archiveWildcardCensor,
+ options.ArchivePathsSorted,
+ options.ArchivePathsFullSorted);
+ }
+
+ if (isExtractGroupCommand)
+ {
+ SetMethodOptions(parser, options.ExtractProperties);
+ if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerminal)
+ throw kSameTerminalError;
+ if (parser[NKey::kOutputDir].ThereIs)
+ {
+ options.OutputDir = parser[NKey::kOutputDir].PostStrings[0];
+ NFile::NName::NormalizeDirPathPrefix(options.OutputDir);
+ }
+
+ options.OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
+ if (parser[NKey::kOverwrite].ThereIs)
+ options.OverwriteMode = k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex];
+ else if (options.YesToAll)
+ options.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
+ }
+ }
+ else if (options.Command.IsFromUpdateGroup())
+ {
+ CUpdateOptions &updateOptions = options.UpdateOptions;
+
+ SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
+
+ SetMethodOptions(parser, updateOptions.MethodMode.Properties);
+
+ if (parser[NKey::kShareForWrite].ThereIs)
+ updateOptions.OpenShareForWrite = true;
+
+ options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs;
+
+ if (options.EnablePercents)
+ {
+ if ((options.StdOutMode && !options.IsStdErrTerminal) ||
+ (!options.StdOutMode && !options.IsStdOutTerminal))
+ options.EnablePercents = false;
+ }
+
+ updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
+ if (updateOptions.EMailMode)
+ {
+ updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
+ if (updateOptions.EMailAddress.Length() > 0)
+ if (updateOptions.EMailAddress[0] == L'.')
+ {
+ updateOptions.EMailRemoveAfter = true;
+ updateOptions.EMailAddress.Delete(0);
+ }
+ }
+
+ updateOptions.StdOutMode = options.StdOutMode;
+ updateOptions.StdInMode = options.StdInMode;
+
+ if (updateOptions.StdOutMode && updateOptions.EMailMode)
+ throw "stdout mode and email mode cannot be combined";
+ if (updateOptions.StdOutMode && options.IsStdOutTerminal)
+ throw kTerminalOutError;
+ if (updateOptions.StdInMode)
+ updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
+
+ #ifdef _WIN32
+ ConvertToLongNames(options.WildcardCensor);
+ #endif
+ }
+ else if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ options.NumThreads = (UInt32)-1;
+ options.DictionarySize = (UInt32)-1;
+ options.NumIterations = 1;
+ if (curCommandIndex < numNonSwitchStrings)
+ {
+ if (!ConvertStringToUInt32(nonSwitchStrings[curCommandIndex++], options.NumIterations))
+ ThrowUserErrorException();
+ }
+ for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++)
+ {
+ UString postString = parser[NKey::kProperty].PostStrings[i];
+ postString.MakeUpper();
+ if (postString.Length() < 2)
+ ThrowUserErrorException();
+ if (postString[0] == 'D')
+ {
+ int pos = 1;
+ if (postString[pos] == '=')
+ pos++;
+ UInt32 logSize;
+ if (!ConvertStringToUInt32((const wchar_t *)postString + pos, logSize))
+ ThrowUserErrorException();
+ if (logSize > 31)
+ ThrowUserErrorException();
+ options.DictionarySize = 1 << logSize;
+ }
+ else if (postString[0] == 'M' && postString[1] == 'T' )
+ {
+ int pos = 2;
+ if (postString[pos] == '=')
+ pos++;
+ if (postString[pos] != 0)
+ if (!ConvertStringToUInt32((const wchar_t *)postString + pos, options.NumThreads))
+ ThrowUserErrorException();
+ }
+ else if (postString[0] == 'M' && postString[1] == '=' )
+ {
+ int pos = 2;
+ if (postString[pos] != 0)
+ options.Method = postString.Mid(2);
+ }
+ else
+ ThrowUserErrorException();
+ }
+ }
+ else if (options.Command.CommandType == NCommandType::kInfo)
+ {
+ }
+ else
+ ThrowUserErrorException();
+ options.WildcardCensor.ExtendExclude();
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h
new file mode 100644
index 000000000..e8f601df4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveCommandLine.h
@@ -0,0 +1,111 @@
+// ArchiveCommandLine.h
+
+#ifndef __ARCHIVE_COMMAND_LINE_H
+#define __ARCHIVE_COMMAND_LINE_H
+
+#include "Common/CommandLineParser.h"
+#include "Common/Wildcard.h"
+
+#include "Extract.h"
+#include "Update.h"
+
+struct CArchiveCommandLineException: public AString
+{
+ CArchiveCommandLineException(const char *errorMessage): AString(errorMessage) {}
+};
+
+namespace NCommandType { enum EEnum
+{
+ kAdd = 0,
+ kUpdate,
+ kDelete,
+ kTest,
+ kExtract,
+ kFullExtract,
+ kList,
+ kBenchmark,
+ kInfo
+};}
+
+namespace NRecursedType { enum EEnum
+{
+ kRecursed,
+ kWildCardOnlyRecursed,
+ kNonRecursed
+};}
+
+struct CArchiveCommand
+{
+ NCommandType::EEnum CommandType;
+ bool IsFromExtractGroup() const;
+ bool IsFromUpdateGroup() const;
+ bool IsTestMode() const { return CommandType == NCommandType::kTest; }
+ NExtract::NPathMode::EEnum GetPathMode() const;
+};
+
+struct CArchiveCommandLineOptions
+{
+ bool HelpMode;
+
+ #ifdef _WIN32
+ bool LargePages;
+ #endif
+
+ bool IsInTerminal;
+ bool IsStdOutTerminal;
+ bool IsStdErrTerminal;
+ bool StdInMode;
+ bool StdOutMode;
+ bool EnableHeaders;
+
+ bool YesToAll;
+ bool ShowDialog;
+ // NWildcard::CCensor ArchiveWildcardCensor;
+ NWildcard::CCensor WildcardCensor;
+
+ CArchiveCommand Command;
+ UString ArchiveName;
+
+ #ifndef _NO_CRYPTO
+ bool PasswordEnabled;
+ UString Password;
+ #endif
+
+ bool TechMode;
+ // Extract
+ bool CalcCrc;
+ bool AppendName;
+ UString OutputDir;
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+ UStringVector ArchivePathsSorted;
+ UStringVector ArchivePathsFullSorted;
+ CObjectVector<CProperty> ExtractProperties;
+
+ CUpdateOptions UpdateOptions;
+ UString ArcType;
+ bool EnablePercents;
+
+ // Benchmark
+ UInt32 NumIterations;
+ UInt32 NumThreads;
+ UInt32 DictionarySize;
+ UString Method;
+
+
+ CArchiveCommandLineOptions(): StdInMode(false), StdOutMode(false) {};
+};
+
+class CArchiveCommandLineParser
+{
+ NCommandLineParser::CParser parser;
+public:
+ CArchiveCommandLineParser();
+ void Parse1(const UStringVector &commandStrings, CArchiveCommandLineOptions &options);
+ void Parse2(CArchiveCommandLineOptions &options);
+};
+
+void EnumerateDirItemsAndSort(NWildcard::CCensor &wildcardCensor,
+ UStringVector &sortedPaths,
+ UStringVector &sortedFullPaths);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
new file mode 100644
index 000000000..4c0cc90b5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -0,0 +1,488 @@
+// ArchiveExtractCallback.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "ArchiveExtractCallback.h"
+
+using namespace NWindows;
+
+static const wchar_t *kCantAutoRename = L"ERROR: Can not create file with auto name";
+static const wchar_t *kCantRenameFile = L"ERROR: Can not rename existing file ";
+static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file ";
+
+void CArchiveExtractCallback::Init(
+ const NWildcard::CCensorNode *wildcardCensor,
+ const CArc *arc,
+ IFolderArchiveExtractCallback *extractCallback2,
+ bool stdOutMode, bool testMode, bool crcMode,
+ const UString &directoryPath,
+ const UStringVector &removePathParts,
+ UInt64 packSize)
+{
+ _wildcardCensor = wildcardCensor;
+
+ _stdOutMode = stdOutMode;
+ _testMode = testMode;
+ _crcMode = crcMode;
+ _unpTotal = 1;
+ _packTotal = packSize;
+
+ _extractCallback2 = extractCallback2;
+ _compressProgress.Release();
+ _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
+
+ LocalProgressSpec->Init(extractCallback2, true);
+ LocalProgressSpec->SendProgress = false;
+
+
+ _removePathParts = removePathParts;
+ _arc = arc;
+ _directoryPath = directoryPath;
+ NFile::NName::NormalizeDirPathPrefix(_directoryPath);
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
+{
+ COM_TRY_BEGIN
+ _unpTotal = size;
+ if (!_multiArchives && _extractCallback2)
+ return _extractCallback2->SetTotal(size);
+ return S_OK;
+ COM_TRY_END
+}
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ const UInt64 kMax = (UInt64)1 << 31;
+ while (v1 > kMax)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)
+{
+ NormalizeVals(packTotal, unpTotal);
+ NormalizeVals(unpCur, unpTotal);
+ if (unpTotal == 0)
+ unpTotal = 1;
+ return unpCur * packTotal / unpTotal;
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
+{
+ COM_TRY_BEGIN
+ if (!_extractCallback2)
+ return S_OK;
+
+ if (_multiArchives)
+ {
+ if (completeValue != NULL)
+ {
+ UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal);
+ return _extractCallback2->SetCompleted(&packCur);
+ }
+ }
+ return _extractCallback2->SetCompleted(completeValue);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ COM_TRY_BEGIN
+ return _localProgress->SetRatioInfo(inSize, outSize);
+ COM_TRY_END
+}
+
+void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath)
+{
+ fullPath = _directoryPath;
+ for (int i = 0; i < dirPathParts.Size(); i++)
+ {
+ if (i > 0)
+ fullPath += wchar_t(NFile::NName::kDirDelimiter);
+ fullPath += dirPathParts[i];
+ NFile::NDirectory::MyCreateDirectory(fullPath);
+ }
+}
+
+HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
+{
+ filetimeIsDefined = false;
+ NCOM::CPropVariant prop;
+ RINOK(_arc->Archive->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ {
+ filetime = prop.filetime;
+ filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT CArchiveExtractCallback::GetUnpackSize()
+{
+ NCOM::CPropVariant prop;
+ RINOK(_arc->Archive->GetProperty(_index, kpidSize, &prop));
+ _curSizeDefined = (prop.vt != VT_EMPTY);
+ if (_curSizeDefined)
+ _curSize = ConvertPropVariantToUInt64(prop);
+ return S_OK;
+}
+
+STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
+{
+ COM_TRY_BEGIN
+ _crcStream.Release();
+ *outStream = 0;
+ _outFileStream.Release();
+
+ _encrypted = false;
+ _isSplit = false;
+ _curSize = 0;
+ _curSizeDefined = false;
+ _index = index;
+
+ UString fullPath;
+
+ IInArchive *archive = _arc->Archive;
+ RINOK(_arc->GetItemPath(index, fullPath));
+ RINOK(IsArchiveItemFolder(archive, index, _fi.IsDir));
+
+ _filePath = fullPath;
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidPosition, &prop));
+ if (prop.vt != VT_EMPTY)
+ {
+ if (prop.vt != VT_UI8)
+ return E_FAIL;
+ _position = prop.uhVal.QuadPart;
+ _isSplit = true;
+ }
+ }
+
+ RINOK(GetArchiveItemBoolProp(archive, index, kpidEncrypted, _encrypted));
+
+ RINOK(GetUnpackSize());
+
+ if (_wildcardCensor)
+ {
+ if (!_wildcardCensor->CheckPath(fullPath, !_fi.IsDir))
+ return S_OK;
+ }
+
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
+ {
+ if (_stdOutMode)
+ {
+ CMyComPtr<ISequentialOutStream> outStreamLoc = new CStdOutFileStream;
+ *outStream = outStreamLoc.Detach();
+ return S_OK;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidAttrib, &prop));
+ if (prop.vt == VT_UI4)
+ {
+ _fi.Attrib = prop.ulVal;
+ _fi.AttribDefined = true;
+ }
+ else if (prop.vt == VT_EMPTY)
+ _fi.AttribDefined = false;
+ else
+ return E_FAIL;
+ }
+
+ RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined));
+ RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined));
+ RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined));
+
+ bool isAnti = false;
+ RINOK(_arc->IsItemAnti(index, isAnti));
+
+ UStringVector pathParts;
+ SplitPathToParts(fullPath, pathParts);
+
+ if (pathParts.IsEmpty())
+ return E_FAIL;
+ int numRemovePathParts = 0;
+ switch(_pathMode)
+ {
+ case NExtract::NPathMode::kFullPathnames:
+ break;
+ case NExtract::NPathMode::kCurrentPathnames:
+ {
+ numRemovePathParts = _removePathParts.Size();
+ if (pathParts.Size() <= numRemovePathParts)
+ return E_FAIL;
+ for (int i = 0; i < numRemovePathParts; i++)
+ if (_removePathParts[i].CompareNoCase(pathParts[i]) != 0)
+ return E_FAIL;
+ break;
+ }
+ case NExtract::NPathMode::kNoPathnames:
+ {
+ numRemovePathParts = pathParts.Size() - 1;
+ break;
+ }
+ }
+ pathParts.Delete(0, numRemovePathParts);
+ MakeCorrectPath(pathParts);
+ UString processedPath = MakePathNameFromParts(pathParts);
+ if (!isAnti)
+ {
+ if (!_fi.IsDir)
+ {
+ if (!pathParts.IsEmpty())
+ pathParts.DeleteBack();
+ }
+
+ if (!pathParts.IsEmpty())
+ {
+ UString fullPathNew;
+ CreateComplexDirectory(pathParts, fullPathNew);
+ if (_fi.IsDir)
+ NFile::NDirectory::SetDirTime(fullPathNew,
+ (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
+ (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
+ (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ }
+ }
+
+
+ UString fullProcessedPath = _directoryPath + processedPath;
+
+ if (_fi.IsDir)
+ {
+ _diskFilePath = fullProcessedPath;
+ if (isAnti)
+ NFile::NDirectory::MyRemoveDirectory(_diskFilePath);
+ return S_OK;
+ }
+
+ if (!_isSplit)
+ {
+ NFile::NFind::CFileInfoW fileInfo;
+ if (fileInfo.Find(fullProcessedPath))
+ {
+ switch(_overwriteMode)
+ {
+ case NExtract::NOverwriteMode::kSkipExisting:
+ return S_OK;
+ case NExtract::NOverwriteMode::kAskBefore:
+ {
+ Int32 overwiteResult;
+ RINOK(_extractCallback2->AskOverwrite(
+ fullProcessedPath, &fileInfo.MTime, &fileInfo.Size, fullPath,
+ _fi.MTimeDefined ? &_fi.MTime : NULL,
+ _curSizeDefined ? &_curSize : NULL,
+ &overwiteResult))
+
+ switch(overwiteResult)
+ {
+ case NOverwriteAnswer::kCancel:
+ return E_ABORT;
+ case NOverwriteAnswer::kNo:
+ return S_OK;
+ case NOverwriteAnswer::kNoToAll:
+ _overwriteMode = NExtract::NOverwriteMode::kSkipExisting;
+ return S_OK;
+ case NOverwriteAnswer::kYesToAll:
+ _overwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
+ break;
+ case NOverwriteAnswer::kYes:
+ break;
+ case NOverwriteAnswer::kAutoRename:
+ _overwriteMode = NExtract::NOverwriteMode::kAutoRename;
+ break;
+ default:
+ return E_FAIL;
+ }
+ }
+ }
+ if (_overwriteMode == NExtract::NOverwriteMode::kAutoRename)
+ {
+ if (!AutoRenamePath(fullProcessedPath))
+ {
+ UString message = UString(kCantAutoRename) + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ }
+ else if (_overwriteMode == NExtract::NOverwriteMode::kAutoRenameExisting)
+ {
+ UString existPath = fullProcessedPath;
+ if (!AutoRenamePath(existPath))
+ {
+ UString message = kCantAutoRename + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ if (!NFile::NDirectory::MyMoveFile(fullProcessedPath, existPath))
+ {
+ UString message = UString(kCantRenameFile) + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return E_FAIL;
+ }
+ }
+ else
+ if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath))
+ {
+ UString message = UString(kCantDeleteOutputFile) + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return S_OK;
+ // return E_FAIL;
+ }
+ }
+ }
+ if (!isAnti)
+ {
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+ if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+ {
+ // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
+ {
+ UString message = L"can not open output file " + fullProcessedPath;
+ RINOK(_extractCallback2->MessageError(message));
+ return S_OK;
+ }
+ }
+ if (_isSplit)
+ {
+ RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
+ }
+ _outFileStream = outStreamLoc;
+ *outStream = outStreamLoc.Detach();
+ }
+ _diskFilePath = fullProcessedPath;
+ }
+ else
+ {
+ *outStream = NULL;
+ }
+ if (_crcMode)
+ {
+ _crcStreamSpec = new COutStreamWithCRC;
+ _crcStream = _crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> crcStream = _crcStreamSpec;
+ _crcStreamSpec->SetStream(*outStream);
+ if (*outStream)
+ (*outStream)->Release();
+ *outStream = crcStream.Detach();
+ _crcStreamSpec->Init(true);
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
+{
+ COM_TRY_BEGIN
+ _extractMode = false;
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract:
+ if (_testMode)
+ askExtractMode = NArchive::NExtract::NAskMode::kTest;
+ else
+ _extractMode = true;
+ break;
+ };
+ return _extractCallback2->PrepareOperation(_filePath, _fi.IsDir,
+ askExtractMode, _isSplit ? &_position: 0);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
+{
+ COM_TRY_BEGIN
+ switch(operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ case NArchive::NExtract::NOperationResult::kDataError:
+ break;
+ default:
+ _outFileStream.Release();
+ return E_FAIL;
+ }
+ if (_crcStream)
+ {
+ CrcSum += _crcStreamSpec->GetCRC();
+ _curSize = _crcStreamSpec->GetSize();
+ _curSizeDefined = true;
+ _crcStream.Release();
+ }
+ if (_outFileStream)
+ {
+ _outFileStreamSpec->SetTime(
+ (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
+ (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
+ (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ _curSize = _outFileStreamSpec->ProcessedSize;
+ _curSizeDefined = true;
+ RINOK(_outFileStreamSpec->Close());
+ _outFileStream.Release();
+ }
+ if (!_curSizeDefined)
+ GetUnpackSize();
+ if (_curSizeDefined)
+ UnpackSize += _curSize;
+ if (_fi.IsDir)
+ NumFolders++;
+ else
+ NumFiles++;
+
+ if (_extractMode && _fi.AttribDefined)
+ NFile::NDirectory::MySetFileAttributes(_diskFilePath, _fi.Attrib);
+ RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted));
+ return S_OK;
+ COM_TRY_END
+}
+
+/*
+STDMETHODIMP CArchiveExtractCallback::GetInStream(
+ const wchar_t *name, ISequentialInStream **inStream)
+{
+ COM_TRY_BEGIN
+ CInFileStream *inFile = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamTemp = inFile;
+ if (!inFile->Open(_srcDirectoryPrefix + name))
+ return ::GetLastError();
+ *inStream = inStreamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+*/
+
+STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ if (!_cryptoGetTextPassword)
+ {
+ RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,
+ &_cryptoGetTextPassword));
+ }
+ return _cryptoGetTextPassword->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h
new file mode 100644
index 000000000..367e4b07d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -0,0 +1,143 @@
+// ArchiveExtractCallback.h
+
+#ifndef __ARCHIVE_EXTRACT_CALLBACK_H
+#define __ARCHIVE_EXTRACT_CALLBACK_H
+
+#include "Common/MyCom.h"
+#include "Common/Wildcard.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../../Archive/Common/OutStreamWithCRC.h"
+
+#include "ExtractMode.h"
+#include "IFileExtractCallback.h"
+#include "OpenArchive.h"
+
+class CArchiveExtractCallback:
+ public IArchiveExtractCallback,
+ // public IArchiveVolumeExtractCallback,
+ public ICryptoGetTextPassword,
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ const CArc *_arc;
+ const NWildcard::CCensorNode *_wildcardCensor;
+ CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
+ CMyComPtr<ICompressProgressInfo> _compressProgress;
+ CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
+ UString _directoryPath;
+ NExtract::NPathMode::EEnum _pathMode;
+ NExtract::NOverwriteMode::EEnum _overwriteMode;
+
+ UString _diskFilePath;
+ UString _filePath;
+ UInt64 _position;
+ bool _isSplit;
+
+ bool _extractMode;
+
+ bool WriteCTime;
+ bool WriteATime;
+ bool WriteMTime;
+
+ bool _encrypted;
+
+ struct CProcessedFileInfo
+ {
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ UInt32 Attrib;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+ bool AttribDefined;
+
+ bool IsDir;
+ } _fi;
+
+ UInt32 _index;
+ UInt64 _curSize;
+ bool _curSizeDefined;
+ COutFileStream *_outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outFileStream;
+
+ COutStreamWithCRC *_crcStreamSpec;
+ CMyComPtr<ISequentialOutStream> _crcStream;
+
+ UStringVector _removePathParts;
+
+ bool _stdOutMode;
+ bool _testMode;
+ bool _crcMode;
+ bool _multiArchives;
+
+ CMyComPtr<ICompressProgressInfo> _localProgress;
+ UInt64 _packTotal;
+ UInt64 _unpTotal;
+
+ void CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath);
+ HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
+ HRESULT GetUnpackSize();
+
+public:
+
+ CLocalProgress *LocalProgressSpec;
+
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+ UInt64 UnpackSize;
+ UInt32 CrcSum;
+
+ MY_UNKNOWN_IMP2(ICryptoGetTextPassword, ICompressProgressInfo)
+ // COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback)
+
+ INTERFACE_IArchiveExtractCallback(;)
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+
+ // IArchiveVolumeExtractCallback
+ // STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream);
+
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+ CArchiveExtractCallback():
+ WriteCTime(true),
+ WriteATime(true),
+ WriteMTime(true),
+ _multiArchives(false)
+ {
+ LocalProgressSpec = new CLocalProgress();
+ _localProgress = LocalProgressSpec;
+ }
+
+ void InitForMulti(bool multiArchives,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode)
+ {
+ _multiArchives = multiArchives;
+ _pathMode = pathMode;
+ _overwriteMode = overwriteMode;
+ NumFolders = NumFiles = UnpackSize = 0;
+ CrcSum = 0;
+ }
+
+ void Init(
+ const NWildcard::CCensorNode *wildcardCensor,
+ const CArc *arc,
+ IFolderArchiveExtractCallback *extractCallback2,
+ bool stdOutMode, bool testMode, bool crcMode,
+ const UString &directoryPath,
+ const UStringVector &removePathParts,
+ UInt64 packSize);
+
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp
new file mode 100644
index 000000000..c3684def8
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.cpp
@@ -0,0 +1,54 @@
+// ArchiveName.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+
+#include "ExtractingFilePath.h"
+
+using namespace NWindows;
+
+static UString CreateArchiveName2(const UString &srcName, bool fromPrev, bool keepName)
+{
+ UString resultName = L"Archive";
+ if (fromPrev)
+ {
+ UString dirPrefix;
+ if (NFile::NDirectory::GetOnlyDirPrefix(srcName, dirPrefix))
+ {
+ if (dirPrefix.Length() > 0)
+ if (dirPrefix[dirPrefix.Length() - 1] == WCHAR_PATH_SEPARATOR)
+ {
+ dirPrefix.Delete(dirPrefix.Length() - 1);
+ NFile::NFind::CFileInfoW fileInfo;
+ if (fileInfo.Find(dirPrefix))
+ resultName = fileInfo.Name;
+ }
+ }
+ }
+ else
+ {
+ NFile::NFind::CFileInfoW fileInfo;
+ if (!fileInfo.Find(srcName))
+ // return resultName;
+ return srcName;
+ resultName = fileInfo.Name;
+ if (!fileInfo.IsDir() && !keepName)
+ {
+ int dotPos = resultName.ReverseFind('.');
+ if (dotPos > 0)
+ {
+ UString archiveName2 = resultName.Left(dotPos);
+ if (archiveName2.ReverseFind('.') < 0)
+ resultName = archiveName2;
+ }
+ }
+ }
+ return resultName;
+}
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName)
+{
+ return GetCorrectFsPath(CreateArchiveName2(srcName, fromPrev, keepName));
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h
new file mode 100644
index 000000000..9513fb2ba
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveName.h
@@ -0,0 +1,10 @@
+// ArchiveName.h
+
+#ifndef __ARCHIVENAME_H
+#define __ARCHIVENAME_H
+
+#include "Common/MyString.h"
+
+UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
new file mode 100644
index 000000000..e7e617131
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
@@ -0,0 +1,133 @@
+// ArchiveOpenCallback.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StringConvert.h"
+#include "Common/ComTry.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "ArchiveOpenCallback.h"
+
+using namespace NWindows;
+
+STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ return ReOpenCallback->SetTotal(files, bytes);
+ if (!Callback)
+ return S_OK;
+ return Callback->Open_SetTotal(files, bytes);
+ COM_TRY_END
+}
+
+STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ return ReOpenCallback->SetCompleted(files, bytes);
+ if (!Callback)
+ return S_OK;
+ return Callback->Open_SetCompleted(files, bytes);
+ COM_TRY_END
+}
+
+STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (_subArchiveMode)
+ switch(propID)
+ {
+ case kpidName: prop = _subArchiveName; break;
+ }
+ else
+ switch(propID)
+ {
+ case kpidName: prop = _fileInfo.Name; break;
+ case kpidIsDir: prop = _fileInfo.IsDir(); break;
+ case kpidSize: prop = _fileInfo.Size; break;
+ case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break;
+ case kpidCTime: prop = _fileInfo.CTime; break;
+ case kpidATime: prop = _fileInfo.ATime; break;
+ case kpidMTime: prop = _fileInfo.MTime; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+int COpenCallbackImp::FindName(const UString &name)
+{
+ for (int i = 0; i < FileNames.Size(); i++)
+ if (name.CompareNoCase(FileNames[i]) == 0)
+ return i;
+ return -1;
+}
+
+struct CInFileStreamVol: public CInFileStream
+{
+ UString Name;
+ COpenCallbackImp *OpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
+ ~CInFileStreamVol()
+ {
+ if (OpenCallbackRef)
+ {
+ int index = OpenCallbackImp->FindName(Name);
+ if (index >= 0)
+ OpenCallbackImp->FileNames.Delete(index);
+ }
+ }
+};
+
+STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)
+{
+ COM_TRY_BEGIN
+ if (_subArchiveMode)
+ return S_FALSE;
+ if (Callback)
+ {
+ RINOK(Callback->Open_CheckBreak());
+ }
+ *inStream = NULL;
+ UString fullPath = _folderPrefix + name;
+ if (!_fileInfo.Find(fullPath))
+ return S_FALSE;
+ if (_fileInfo.IsDir())
+ return S_FALSE;
+ CInFileStreamVol *inFile = new CInFileStreamVol;
+ CMyComPtr<IInStream> inStreamTemp = inFile;
+ if (!inFile->Open(fullPath))
+ return ::GetLastError();
+ *inStream = inStreamTemp.Detach();
+ inFile->Name = name;
+ inFile->OpenCallbackImp = this;
+ inFile->OpenCallbackRef = this;
+ FileNames.Add(name);
+ TotalSize += _fileInfo.Size;
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifndef _NO_CRYPTO
+STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ {
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ if (getTextPassword)
+ return getTextPassword->CryptoGetTextPassword(password);
+ }
+ if (!Callback)
+ return E_NOTIMPL;
+ return Callback->Open_CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+#endif
+
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h
new file mode 100644
index 000000000..c6651e8f9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveOpenCallback.h
@@ -0,0 +1,103 @@
+// ArchiveOpenCallback.h
+
+#ifndef __ARCHIVE_OPEN_CALLBACK_H
+#define __ARCHIVE_OPEN_CALLBACK_H
+
+#include "Common/MyCom.h"
+#include "Common/MyString.h"
+
+#include "Windows/FileFind.h"
+
+#ifndef _NO_CRYPTO
+#include "../../IPassword.h"
+#endif
+#include "../../Archive/IArchive.h"
+
+#ifdef _NO_CRYPTO
+
+#define INTERFACE_IOpenCallbackUI_Crypto(x)
+
+#else
+
+#define INTERFACE_IOpenCallbackUI_Crypto(x) \
+ virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x; \
+ virtual HRESULT Open_GetPasswordIfAny(UString &password) x; \
+ virtual bool Open_WasPasswordAsked() x; \
+ virtual void Open_ClearPasswordWasAskedFlag() x; \
+
+#endif
+
+#define INTERFACE_IOpenCallbackUI(x) \
+ virtual HRESULT Open_CheckBreak() x; \
+ virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x; \
+ virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x; \
+ INTERFACE_IOpenCallbackUI_Crypto(x)
+
+struct IOpenCallbackUI
+{
+ INTERFACE_IOpenCallbackUI(=0)
+};
+
+class COpenCallbackImp:
+ public IArchiveOpenCallback,
+ public IArchiveOpenVolumeCallback,
+ public IArchiveOpenSetSubArchiveName,
+ #ifndef _NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ #ifndef _NO_CRYPTO
+ MY_UNKNOWN_IMP3(
+ IArchiveOpenVolumeCallback,
+ ICryptoGetTextPassword,
+ IArchiveOpenSetSubArchiveName
+ )
+ #else
+ MY_UNKNOWN_IMP2(
+ IArchiveOpenVolumeCallback,
+ IArchiveOpenSetSubArchiveName
+ )
+ #endif
+
+ INTERFACE_IArchiveOpenCallback(;)
+ INTERFACE_IArchiveOpenVolumeCallback(;)
+
+ #ifndef _NO_CRYPTO
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+ #endif
+
+ STDMETHOD(SetSubArchiveName(const wchar_t *name))
+ {
+ _subArchiveMode = true;
+ _subArchiveName = name;
+ TotalSize = 0;
+ return S_OK;
+ }
+
+private:
+ UString _folderPrefix;
+ NWindows::NFile::NFind::CFileInfoW _fileInfo;
+ bool _subArchiveMode;
+ UString _subArchiveName;
+public:
+ UStringVector FileNames;
+ IOpenCallbackUI *Callback;
+ CMyComPtr<IArchiveOpenCallback> ReOpenCallback;
+ UInt64 TotalSize;
+
+ COpenCallbackImp(): Callback(NULL) {}
+ void Init(const UString &folderPrefix, const UString &fileName)
+ {
+ _folderPrefix = folderPrefix;
+ if (!_fileInfo.Find(_folderPrefix + fileName))
+ throw 1;
+ FileNames.Clear();
+ _subArchiveMode = false;
+ TotalSize = 0;
+ }
+ int FindName(const UString &name);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp
new file mode 100644
index 000000000..282f405f1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.cpp
@@ -0,0 +1,1028 @@
+// Bench.cpp
+
+#include "StdAfx.h"
+
+#include "Bench.h"
+
+#ifndef _WIN32
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#endif
+#endif
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/Alloc.h"
+
+#ifndef _7ZIP_ST
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/Thread.h"
+#endif
+
+#include "../../../Windows/PropVariant.h"
+
+static const UInt32 kUncompressMinBlockSize =
+#ifdef UNDER_CE
+1 << 24;
+#else
+1 << 26;
+#endif
+
+static const UInt32 kCrcBlockSize =
+#ifdef UNDER_CE
+1 << 25;
+#else
+1 << 30;
+#endif
+
+static const UInt32 kAdditionalSize = (1 << 16);
+static const UInt32 kCompressedAdditionalSize = (1 << 10);
+static const UInt32 kMaxLzmaPropSize = 5;
+
+class CBaseRandomGenerator
+{
+ UInt32 A1;
+ UInt32 A2;
+public:
+ CBaseRandomGenerator() { Init(); }
+ void Init() { A1 = 362436069; A2 = 521288629;}
+ UInt32 GetRnd()
+ {
+ return
+ ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
+ ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
+ }
+};
+
+class CBenchBuffer
+{
+public:
+ size_t BufferSize;
+ Byte *Buffer;
+ CBenchBuffer(): Buffer(0) {}
+ virtual ~CBenchBuffer() { Free(); }
+ void Free()
+ {
+ ::MidFree(Buffer);
+ Buffer = 0;
+ }
+ bool Alloc(size_t bufferSize)
+ {
+ if (Buffer != 0 && BufferSize == bufferSize)
+ return true;
+ Free();
+ Buffer = (Byte *)::MidAlloc(bufferSize);
+ BufferSize = bufferSize;
+ return (Buffer != 0);
+ }
+};
+
+class CBenchRandomGenerator: public CBenchBuffer
+{
+ CBaseRandomGenerator *RG;
+public:
+ void Set(CBaseRandomGenerator *rg) { RG = rg; }
+ UInt32 GetVal(UInt32 &res, int numBits)
+ {
+ UInt32 val = res & (((UInt32)1 << numBits) - 1);
+ res >>= numBits;
+ return val;
+ }
+ UInt32 GetLen(UInt32 &res)
+ {
+ UInt32 len = GetVal(res, 2);
+ return GetVal(res, 1 + len);
+ }
+ void Generate()
+ {
+ UInt32 pos = 0;
+ UInt32 rep0 = 1;
+ while (pos < BufferSize)
+ {
+ UInt32 res = RG->GetRnd();
+ res >>= 1;
+ if (GetVal(res, 1) == 0 || pos < 1024)
+ Buffer[pos++] = (Byte)(res & 0xFF);
+ else
+ {
+ UInt32 len;
+ len = 1 + GetLen(res);
+ if (GetVal(res, 3) != 0)
+ {
+ len += GetLen(res);
+ do
+ {
+ UInt32 ppp = GetVal(res, 5) + 6;
+ res = RG->GetRnd();
+ if (ppp > 30)
+ continue;
+ rep0 = /* (1 << ppp) +*/ GetVal(res, ppp);
+ res = RG->GetRnd();
+ }
+ while (rep0 >= pos);
+ rep0++;
+ }
+
+ for (UInt32 i = 0; i < len && pos < BufferSize; i++, pos++)
+ Buffer[pos] = Buffer[pos - rep0];
+ }
+ }
+ }
+};
+
+
+class CBenchmarkInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ const Byte *Data;
+ size_t Pos;
+ size_t Size;
+public:
+ MY_UNKNOWN_IMP
+ void Init(const Byte *data, size_t size)
+ {
+ Data = data;
+ Size = size;
+ Pos = 0;
+ }
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t remain = Size - Pos;
+ UInt32 kMaxBlockSize = (1 << 20);
+ if (size > kMaxBlockSize)
+ size = kMaxBlockSize;
+ if (size > remain)
+ size = (UInt32)remain;
+ for (UInt32 i = 0; i < size; i++)
+ ((Byte *)data)[i] = Data[Pos + i];
+ Pos += size;
+ if(processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+class CBenchmarkOutStream:
+ public ISequentialOutStream,
+ public CBenchBuffer,
+ public CMyUnknownImp
+{
+ // bool _overflow;
+public:
+ UInt32 Pos;
+ // CBenchmarkOutStream(): _overflow(false) {}
+ void Init()
+ {
+ // _overflow = false;
+ Pos = 0;
+ }
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ size_t curSize = BufferSize - Pos;
+ if (curSize > size)
+ curSize = size;
+ memcpy(Buffer + Pos, data, curSize);
+ Pos += (UInt32)curSize;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)curSize;
+ if (curSize != size)
+ {
+ // _overflow = true;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+class CCrcOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ UInt32 Crc;
+ MY_UNKNOWN_IMP
+ void Init() { Crc = CRC_INIT_VAL; }
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ Crc = CrcUpdate(Crc, data, size);
+ if (processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+static UInt64 GetTimeCount()
+{
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ timeval v;
+ if (gettimeofday(&v, 0) == 0)
+ return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec;
+ return (UInt64)time(NULL) * 1000000;
+ #else
+ return time(NULL);
+ #endif
+ #else
+ /*
+ LARGE_INTEGER value;
+ if (::QueryPerformanceCounter(&value))
+ return value.QuadPart;
+ */
+ return GetTickCount();
+ #endif
+}
+
+static UInt64 GetFreq()
+{
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ return 1000000;
+ #else
+ return 1;
+ #endif
+ #else
+ /*
+ LARGE_INTEGER value;
+ if (::QueryPerformanceFrequency(&value))
+ return value.QuadPart;
+ */
+ return 1000;
+ #endif
+}
+
+#ifndef USE_POSIX_TIME
+static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
+#endif
+
+static UInt64 GetUserTime()
+{
+ #ifdef USE_POSIX_TIME
+ return clock();
+ #else
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ if (
+ #ifdef UNDER_CE
+ ::GetThreadTimes(::GetCurrentThread()
+ #else
+ ::GetProcessTimes(::GetCurrentProcess()
+ #endif
+ , &creationTime, &exitTime, &kernelTime, &userTime) != 0)
+ return GetTime64(userTime) + GetTime64(kernelTime);
+ return (UInt64)GetTickCount() * 10000;
+ #endif
+}
+
+static UInt64 GetUserFreq()
+{
+ #ifdef USE_POSIX_TIME
+ return CLOCKS_PER_SEC;
+ #else
+ return 10000000;
+ #endif
+}
+
+class CBenchProgressStatus
+{
+ #ifndef _7ZIP_ST
+ NWindows::NSynchronization::CCriticalSection CS;
+ #endif
+public:
+ HRESULT Res;
+ bool EncodeMode;
+ void SetResult(HRESULT res)
+ {
+ #ifndef _7ZIP_ST
+ NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+ #endif
+ Res = res;
+ }
+ HRESULT GetResult()
+ {
+ #ifndef _7ZIP_ST
+ NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+ #endif
+ return Res;
+ }
+};
+
+class CBenchProgressInfo:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ CBenchProgressStatus *Status;
+ CBenchInfo BenchInfo;
+ HRESULT Res;
+ IBenchCallback *callback;
+ CBenchProgressInfo(): callback(0) {}
+ MY_UNKNOWN_IMP
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+static void SetStartTime(CBenchInfo &bi)
+{
+ bi.GlobalFreq = GetFreq();
+ bi.UserFreq = GetUserFreq();
+ bi.GlobalTime = ::GetTimeCount();
+ bi.UserTime = ::GetUserTime();
+}
+
+static void SetFinishTime(const CBenchInfo &biStart, CBenchInfo &dest)
+{
+ dest.GlobalFreq = GetFreq();
+ dest.UserFreq = GetUserFreq();
+ dest.GlobalTime = ::GetTimeCount() - biStart.GlobalTime;
+ dest.UserTime = ::GetUserTime() - biStart.UserTime;
+}
+
+STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ HRESULT res = Status->GetResult();
+ if (res != S_OK)
+ return res;
+ if (!callback)
+ return res;
+ CBenchInfo info = BenchInfo;
+ SetFinishTime(BenchInfo, info);
+ if (Status->EncodeMode)
+ {
+ info.UnpackSize = *inSize;
+ info.PackSize = *outSize;
+ res = callback->SetEncodeResult(info, false);
+ }
+ else
+ {
+ info.PackSize = BenchInfo.PackSize + *inSize;
+ info.UnpackSize = BenchInfo.UnpackSize + *outSize;
+ res = callback->SetDecodeResult(info, false);
+ }
+ if (res != S_OK)
+ Status->SetResult(res);
+ return res;
+}
+
+static const int kSubBits = 8;
+
+static UInt32 GetLogSize(UInt32 size)
+{
+ for (int i = kSubBits; i < 32; i++)
+ for (UInt32 j = 0; j < (1 << kSubBits); j++)
+ if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
+ return (i << kSubBits) + j;
+ return (32 << kSubBits);
+}
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ while (v1 > 1000000)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+UInt64 GetUsage(const CBenchInfo &info)
+{
+ UInt64 userTime = info.UserTime;
+ UInt64 userFreq = info.UserFreq;
+ UInt64 globalTime = info.GlobalTime;
+ UInt64 globalFreq = info.GlobalFreq;
+ NormalizeVals(userTime, userFreq);
+ NormalizeVals(globalFreq, globalTime);
+ if (userFreq == 0)
+ userFreq = 1;
+ if (globalTime == 0)
+ globalTime = 1;
+ return userTime * globalFreq * 1000000 / userFreq / globalTime;
+}
+
+UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating)
+{
+ UInt64 userTime = info.UserTime;
+ UInt64 userFreq = info.UserFreq;
+ UInt64 globalTime = info.GlobalTime;
+ UInt64 globalFreq = info.GlobalFreq;
+ NormalizeVals(userFreq, userTime);
+ NormalizeVals(globalTime, globalFreq);
+ if (globalFreq == 0)
+ globalFreq = 1;
+ if (userTime == 0)
+ userTime = 1;
+ return userFreq * globalTime / globalFreq * rating / userTime;
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
+{
+ UInt64 elTime = elapsedTime;
+ NormalizeVals(freq, elTime);
+ if (elTime == 0)
+ elTime = 1;
+ return value * freq / elTime;
+}
+
+UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
+{
+ UInt64 t = GetLogSize(dictionarySize) - (kBenchMinDicLogSize << kSubBits);
+ UInt64 numCommandsForOne = 870 + ((t * t * 5) >> (2 * kSubBits));
+ UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
+ return MyMultDiv64(numCommands, elapsedTime, freq);
+}
+
+UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations)
+{
+ UInt64 numCommands = (inSize * 200 + outSize * 4) * numIterations;
+ return MyMultDiv64(numCommands, elapsedTime, freq);
+}
+
+struct CEncoderInfo;
+
+struct CEncoderInfo
+{
+ #ifndef _7ZIP_ST
+ NWindows::CThread thread[2];
+ #endif
+ CMyComPtr<ICompressCoder> encoder;
+ CBenchProgressInfo *progressInfoSpec[2];
+ CMyComPtr<ICompressProgressInfo> progressInfo[2];
+ UInt32 NumIterations;
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+
+ struct CDecoderInfo
+ {
+ CEncoderInfo *Encoder;
+ UInt32 DecoderIndex;
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+ bool CallbackMode;
+ };
+ CDecoderInfo decodersInfo[2];
+
+ CMyComPtr<ICompressCoder> decoders[2];
+ HRESULT Results[2];
+ CBenchmarkOutStream *outStreamSpec;
+ CMyComPtr<ISequentialOutStream> outStream;
+ IBenchCallback *callback;
+ UInt32 crc;
+ UInt32 kBufferSize;
+ UInt32 compressedSize;
+ CBenchRandomGenerator rg;
+ CBenchmarkOutStream *propStreamSpec;
+ CMyComPtr<ISequentialOutStream> propStream;
+ HRESULT Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rg);
+ HRESULT Encode();
+ HRESULT Decode(UInt32 decoderIndex);
+
+ CEncoderInfo(): outStreamSpec(0), callback(0), propStreamSpec(0) {}
+
+ #ifndef _7ZIP_ST
+ static THREAD_FUNC_DECL EncodeThreadFunction(void *param)
+ {
+ CEncoderInfo *encoder = (CEncoderInfo *)param;
+ #ifdef USE_ALLOCA
+ alloca(encoder->AllocaSize);
+ #endif
+ HRESULT res = encoder->Encode();
+ encoder->Results[0] = res;
+ if (res != S_OK)
+ encoder->progressInfoSpec[0]->Status->SetResult(res);
+
+ return 0;
+ }
+ static THREAD_FUNC_DECL DecodeThreadFunction(void *param)
+ {
+ CDecoderInfo *decoder = (CDecoderInfo *)param;
+ #ifdef USE_ALLOCA
+ alloca(decoder->AllocaSize);
+ #endif
+ CEncoderInfo *encoder = decoder->Encoder;
+ encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);
+ return 0;
+ }
+
+ HRESULT CreateEncoderThread()
+ {
+ return thread[0].Create(EncodeThreadFunction, this);
+ }
+
+ HRESULT CreateDecoderThread(int index, bool callbackMode
+ #ifdef USE_ALLOCA
+ , size_t allocaSize
+ #endif
+ )
+ {
+ CDecoderInfo &decoder = decodersInfo[index];
+ decoder.DecoderIndex = index;
+ decoder.Encoder = this;
+ #ifdef USE_ALLOCA
+ decoder.AllocaSize = allocaSize;
+ #endif
+ decoder.CallbackMode = callbackMode;
+ return thread[index].Create(DecodeThreadFunction, &decoder);
+ }
+ #endif
+};
+
+HRESULT CEncoderInfo::Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rgLoc)
+{
+ rg.Set(rgLoc);
+ kBufferSize = dictionarySize + kAdditionalSize;
+ UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
+ if (!rg.Alloc(kBufferSize))
+ return E_OUTOFMEMORY;
+ rg.Generate();
+ crc = CrcCalc(rg.Buffer, rg.BufferSize);
+
+ outStreamSpec = new CBenchmarkOutStream;
+ if (!outStreamSpec->Alloc(kCompressedBufferSize))
+ return E_OUTOFMEMORY;
+
+ outStream = outStreamSpec;
+
+ propStreamSpec = 0;
+ if (!propStream)
+ {
+ propStreamSpec = new CBenchmarkOutStream;
+ propStream = propStreamSpec;
+ }
+ if (!propStreamSpec->Alloc(kMaxLzmaPropSize))
+ return E_OUTOFMEMORY;
+ propStreamSpec->Init();
+
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumThreads
+ };
+ const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ PROPVARIANT props[kNumProps];
+ props[0].vt = VT_UI4;
+ props[0].ulVal = dictionarySize;
+
+ props[1].vt = VT_UI4;
+ props[1].ulVal = numThreads;
+
+ {
+ CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
+ RINOK(encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties));
+ if (!setCoderProperties)
+ return E_FAIL;
+ RINOK(setCoderProperties->SetCoderProperties(propIDs, props, kNumProps));
+
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
+ encoder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProperties);
+ if (writeCoderProperties)
+ {
+ RINOK(writeCoderProperties->WriteCoderProperties(propStream));
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CEncoderInfo::Encode()
+{
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ inStreamSpec->Init(rg.Buffer, rg.BufferSize);
+ outStreamSpec->Init();
+
+ RINOK(encoder->Code(inStream, outStream, 0, 0, progressInfo[0]));
+ compressedSize = outStreamSpec->Pos;
+ encoder.Release();
+ return S_OK;
+}
+
+HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)
+{
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ CMyComPtr<ICompressCoder> &decoder = decoders[decoderIndex];
+
+ CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
+ decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &compressSetDecoderProperties);
+ if (!compressSetDecoderProperties)
+ return E_FAIL;
+
+ CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
+ CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
+
+ CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
+ pi->BenchInfo.UnpackSize = 0;
+ pi->BenchInfo.PackSize = 0;
+
+ for (UInt32 j = 0; j < NumIterations; j++)
+ {
+ inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
+ crcOutStreamSpec->Init();
+
+ RINOK(compressSetDecoderProperties->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos));
+ UInt64 outSize = kBufferSize;
+ RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex]));
+ if (CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc)
+ return S_FALSE;
+ pi->BenchInfo.UnpackSize += kBufferSize;
+ pi->BenchInfo.PackSize += compressedSize;
+ }
+ decoder.Release();
+ return S_OK;
+}
+
+static const UInt32 kNumThreadsMax = (1 << 16);
+
+struct CBenchEncoders
+{
+ CEncoderInfo *encoders;
+ CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; }
+ ~CBenchEncoders() { delete []encoders; }
+};
+
+HRESULT LzmaBench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback)
+{
+ UInt32 numEncoderThreads =
+ #ifndef _7ZIP_ST
+ (numThreads > 1 ? numThreads / 2 : 1);
+ #else
+ 1;
+ #endif
+ UInt32 numSubDecoderThreads =
+ #ifndef _7ZIP_ST
+ (numThreads > 1 ? 2 : 1);
+ #else
+ 1;
+ #endif
+ if (dictionarySize < (1 << kBenchMinDicLogSize) || numThreads < 1 || numEncoderThreads > kNumThreadsMax)
+ {
+ return E_INVALIDARG;
+ }
+
+ CBenchEncoders encodersSpec(numEncoderThreads);
+ CEncoderInfo *encoders = encodersSpec.encoders;
+
+
+ UInt32 i;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.callback = (i == 0) ? callback : 0;
+
+ const UInt32 kLzmaId = 0x030101;
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS kLzmaId, encoder.encoder, true));
+ if (!encoder.encoder)
+ return E_NOTIMPL;
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS kLzmaId, encoder.decoders[j], false));
+ if (!encoder.decoders[j])
+ return E_NOTIMPL;
+ }
+ }
+
+ CBaseRandomGenerator rg;
+ rg.Init();
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ RINOK(encoders[i].Init(dictionarySize, numThreads, &rg));
+ }
+
+ CBenchProgressStatus status;
+ status.Res = S_OK;
+ status.EncodeMode = true;
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ for (int j = 0; j < 2; j++)
+ {
+ encoder.progressInfo[j] = encoder.progressInfoSpec[j] = new CBenchProgressInfo;
+ encoder.progressInfoSpec[j]->Status = &status;
+ }
+ if (i == 0)
+ {
+ encoder.progressInfoSpec[0]->callback = callback;
+ encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numEncoderThreads;
+ SetStartTime(encoder.progressInfoSpec[0]->BenchInfo);
+ }
+
+ #ifndef _7ZIP_ST
+ if (numEncoderThreads > 1)
+ {
+ #ifdef USE_ALLOCA
+ encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
+ #endif
+ RINOK(encoder.CreateEncoderThread())
+ }
+ else
+ #endif
+ {
+ RINOK(encoder.Encode());
+ }
+ }
+ #ifndef _7ZIP_ST
+ if (numEncoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ encoders[i].thread[0].Wait();
+ #endif
+
+ RINOK(status.Res);
+
+ CBenchInfo info;
+
+ SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info);
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = 1; // progressInfoSpec->NumIterations;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ info.UnpackSize += encoder.kBufferSize;
+ info.PackSize += encoder.compressedSize;
+ }
+ RINOK(callback->SetEncodeResult(info, true));
+
+
+ status.Res = S_OK;
+ status.EncodeMode = false;
+
+ UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.NumIterations = 2 + kUncompressMinBlockSize / encoder.kBufferSize;
+
+ if (i == 0)
+ {
+ encoder.progressInfoSpec[0]->callback = callback;
+ encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numDecoderThreads;
+ SetStartTime(encoder.progressInfoSpec[0]->BenchInfo);
+ }
+
+ #ifndef _7ZIP_ST
+ if (numDecoderThreads > 1)
+ {
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
+ #ifdef USE_ALLOCA
+ , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
+ #endif
+ );
+ RINOK(res);
+ }
+ }
+ else
+ #endif
+ {
+ RINOK(encoder.Decode(0));
+ }
+ }
+ #ifndef _7ZIP_ST
+ HRESULT res = S_OK;
+ if (numDecoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.thread[j].Wait();
+ if (encoder.Results[j] != S_OK)
+ res = encoder.Results[j];
+ }
+ RINOK(res);
+ #endif
+ RINOK(status.Res);
+ SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info);
+ #ifndef _7ZIP_ST
+ #ifdef UNDER_CE
+ if (numDecoderThreads > 1)
+ for (i = 0; i < numEncoderThreads; i++)
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0)
+ info.UserTime += GetTime64(userTime) + GetTime64(kernelTime);
+ }
+ #endif
+ #endif
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ info.UnpackSize += encoder.kBufferSize;
+ info.PackSize += encoder.compressedSize;
+ }
+ RINOK(callback->SetDecodeResult(info, false));
+ RINOK(callback->SetDecodeResult(info, true));
+ return S_OK;
+}
+
+
+inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)
+{
+ UInt32 hs = dictionary - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ hs |= 0xFFFF;
+ if (hs > (1 << 24))
+ hs >>= 1;
+ hs++;
+ return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 +
+ (1 << 20) + (multiThread ? (6 << 20) : 0);
+}
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary)
+{
+ const UInt32 kBufferSize = dictionary;
+ const UInt32 kCompressedBufferSize = (kBufferSize / 2);
+ UInt32 numSubThreads = (numThreads > 1) ? 2 : 1;
+ UInt32 numBigThreads = numThreads / numSubThreads;
+ return (kBufferSize + kCompressedBufferSize +
+ GetLZMAUsage((numThreads > 1), dictionary) + (2 << 20)) * numBigThreads;
+}
+
+static bool CrcBig(const void *data, UInt32 size, UInt32 numCycles, UInt32 crcBase)
+{
+ for (UInt32 i = 0; i < numCycles; i++)
+ if (CrcCalc(data, size) != crcBase)
+ return false;
+ return true;
+}
+
+#ifndef _7ZIP_ST
+struct CCrcInfo
+{
+ NWindows::CThread Thread;
+ const Byte *Data;
+ UInt32 Size;
+ UInt32 NumCycles;
+ UInt32 Crc;
+ bool Res;
+ void Wait()
+ {
+ Thread.Wait();
+ Thread.Close();
+ }
+};
+
+static THREAD_FUNC_DECL CrcThreadFunction(void *param)
+{
+ CCrcInfo *p = (CCrcInfo *)param;
+ p->Res = CrcBig(p->Data, p->Size, p->NumCycles, p->Crc);
+ return 0;
+}
+
+struct CCrcThreads
+{
+ UInt32 NumThreads;
+ CCrcInfo *Items;
+ CCrcThreads(): Items(0), NumThreads(0) {}
+ void WaitAll()
+ {
+ for (UInt32 i = 0; i < NumThreads; i++)
+ Items[i].Wait();
+ NumThreads = 0;
+ }
+ ~CCrcThreads()
+ {
+ WaitAll();
+ delete []Items;
+ }
+};
+#endif
+
+static UInt32 CrcCalc1(const Byte *buf, UInt32 size)
+{
+ UInt32 crc = CRC_INIT_VAL;;
+ for (UInt32 i = 0; i < size; i++)
+ crc = CRC_UPDATE_BYTE(crc, buf[i]);
+ return CRC_GET_DIGEST(crc);
+}
+
+static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+ for (UInt32 i = 0; i < size; i++)
+ buf[i] = (Byte)RG.GetRnd();
+}
+
+static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
+{
+ RandGen(buf, size, RG);
+ return CrcCalc1(buf, size);
+}
+
+bool CrcInternalTest()
+{
+ CBenchBuffer buffer;
+ const UInt32 kBufferSize0 = (1 << 8);
+ const UInt32 kBufferSize1 = (1 << 10);
+ const UInt32 kCheckSize = (1 << 5);
+ if (!buffer.Alloc(kBufferSize0 + kBufferSize1))
+ return false;
+ Byte *buf = buffer.Buffer;
+ UInt32 i;
+ for (i = 0; i < kBufferSize0; i++)
+ buf[i] = (Byte)i;
+ UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
+ if (crc1 != 0x29058C73)
+ return false;
+ CBaseRandomGenerator RG;
+ RandGen(buf + kBufferSize0, kBufferSize1, RG);
+ for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
+ for (UInt32 j = 0; j < kCheckSize; j++)
+ if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
+ return false;
+ return true;
+}
+
+HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed)
+{
+ if (numThreads == 0)
+ numThreads = 1;
+
+ CBenchBuffer buffer;
+ size_t totalSize = (size_t)bufferSize * numThreads;
+ if (totalSize / numThreads != bufferSize)
+ return E_OUTOFMEMORY;
+ if (!buffer.Alloc(totalSize))
+ return E_OUTOFMEMORY;
+
+ Byte *buf = buffer.Buffer;
+ CBaseRandomGenerator RG;
+ UInt32 numCycles = (kCrcBlockSize) / ((bufferSize >> 2) + 1) + 1;
+
+ UInt64 timeVal;
+ #ifndef _7ZIP_ST
+ CCrcThreads threads;
+ if (numThreads > 1)
+ {
+ threads.Items = new CCrcInfo[numThreads];
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &info = threads.Items[i];
+ Byte *data = buf + (size_t)bufferSize * i;
+ info.Data = data;
+ info.NumCycles = numCycles;
+ info.Size = bufferSize;
+ info.Crc = RandGenCrc(data, bufferSize, RG);
+ }
+ timeVal = GetTimeCount();
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &info = threads.Items[i];
+ RINOK(info.Thread.Create(CrcThreadFunction, &info));
+ threads.NumThreads++;
+ }
+ threads.WaitAll();
+ for (i = 0; i < numThreads; i++)
+ if (!threads.Items[i].Res)
+ return S_FALSE;
+ }
+ else
+ #endif
+ {
+ UInt32 crc = RandGenCrc(buf, bufferSize, RG);
+ timeVal = GetTimeCount();
+ if (!CrcBig(buf, bufferSize, numCycles, crc))
+ return S_FALSE;
+ }
+ timeVal = GetTimeCount() - timeVal;
+ if (timeVal == 0)
+ timeVal = 1;
+
+ UInt64 size = (UInt64)numCycles * totalSize;
+ speed = MyMultDiv64(size, timeVal, GetFreq());
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h b/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h
new file mode 100644
index 000000000..a8d02a19b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Bench.h
@@ -0,0 +1,42 @@
+// Bench.h
+
+#ifndef __7ZIP_BENCH_H
+#define __7ZIP_BENCH_H
+
+#include "../../Common/CreateCoder.h"
+
+struct CBenchInfo
+{
+ UInt64 GlobalTime;
+ UInt64 GlobalFreq;
+ UInt64 UserTime;
+ UInt64 UserFreq;
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt32 NumIterations;
+ CBenchInfo(): NumIterations(0) {}
+};
+
+struct IBenchCallback
+{
+ virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0;
+ virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0;
+};
+
+UInt64 GetUsage(const CBenchInfo &benchOnfo);
+UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating);
+UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
+UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations);
+
+HRESULT LzmaBench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback);
+
+const int kBenchMinDicLogSize = 18;
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary);
+
+bool CrcInternalTest();
+HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.cpp
new file mode 100644
index 000000000..c2685f798
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.cpp
@@ -0,0 +1,246 @@
+// CompressCall.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/Random.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileMapping.h"
+#include "Windows/Process.h"
+#include "Windows/Synchronization.h"
+
+#include "../FileManager/ProgramLocation.h"
+#include "../FileManager/RegistryUtils.h"
+
+#include "CompressCall.h"
+
+using namespace NWindows;
+
+#define MY_TRY_BEGIN try {
+#define MY_TRY_FINISH } \
+ catch(...) { ErrorMessageHRESULT(E_FAIL); return E_FAIL; }
+
+static LPCWSTR kShowDialogSwitch = L" -ad";
+static LPCWSTR kEmailSwitch = L" -seml.";
+static LPCWSTR kIncludeSwitch = L" -i";
+static LPCWSTR kArchiveTypeSwitch = L" -t";
+static LPCWSTR kArcIncludeSwitches = L" -an -ai";
+static LPCWSTR kStopSwitchParsing = L" --";
+static LPCWSTR kLargePagesDisable = L" -slp-";
+
+UString GetQuotedString(const UString &s)
+{
+ return UString(L'\"') + s + UString(L'\"');
+}
+static void ErrorMessage(LPCWSTR message)
+{
+ MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR | MB_OK);
+}
+
+static void ErrorMessageHRESULT(HRESULT res, LPCWSTR s = NULL)
+{
+ UString s2 = HResultToMessage(res);
+ if (s)
+ {
+ s2 += L'\n';
+ s2 += s;
+ }
+ ErrorMessage(s2);
+}
+
+static HRESULT MyCreateProcess(LPCWSTR imageName, const UString &params,
+ LPCWSTR curDir, bool waitFinish,
+ NSynchronization::CBaseEvent *event)
+{
+ CProcess process;
+ WRes res = process.Create(imageName, params, curDir);
+ if (res != 0)
+ {
+ ErrorMessageHRESULT(res, imageName);
+ return res;
+ }
+ if (waitFinish)
+ process.Wait();
+ else if (event != NULL)
+ {
+ HANDLE handles[] = { process, *event };
+ ::WaitForMultipleObjects(sizeof(handles) / sizeof(handles[0]), handles, FALSE, INFINITE);
+ }
+ return S_OK;
+}
+
+static void AddLagePagesSwitch(UString &params)
+{
+ if (!ReadLockMemoryEnable())
+ params += kLargePagesDisable;
+}
+
+static UString Get7zGuiPath()
+{
+ UString path;
+ GetProgramFolderPath(path);
+ return path + L"7zG.exe";
+}
+
+class CRandNameGenerator
+{
+ CRandom _random;
+public:
+ CRandNameGenerator() { _random.Init(); }
+ UString GenerateName()
+ {
+ wchar_t temp[16];
+ ConvertUInt32ToString((UInt32)_random.Generate(), temp);
+ return temp;
+ }
+};
+
+static HRESULT CreateMap(const UStringVector &names,
+ CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event,
+ UString &params)
+{
+ UInt32 totalSize = 1;
+ for (int i = 0; i < names.Size(); i++)
+ totalSize += (names[i].Length() + 1);
+ totalSize *= sizeof(wchar_t);
+
+ CRandNameGenerator random;
+
+ UString mappingName;
+ for (;;)
+ {
+ mappingName = L"7zMap" + random.GenerateName();
+
+ WRes res = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName));
+ if (fileMapping.IsCreated() && res == 0)
+ break;
+ if (res != ERROR_ALREADY_EXISTS)
+ return res;
+ fileMapping.Close();
+ }
+
+ UString eventName;
+ for (;;)
+ {
+ eventName = L"7zEvent" + random.GenerateName();
+ WRes res = event.CreateWithName(false, GetSystemString(eventName));
+ if (event.IsCreated() && res == 0)
+ break;
+ if (res != ERROR_ALREADY_EXISTS)
+ return res;
+ event.Close();
+ }
+
+ params += L'#';
+ params += mappingName;
+ params += L':';
+ wchar_t temp[16];
+ ConvertUInt32ToString(totalSize, temp);
+ params += temp;
+
+ params += L':';
+ params += eventName;
+
+ LPVOID data = fileMapping.Map(FILE_MAP_WRITE, 0, totalSize);
+ if (data == NULL)
+ return E_FAIL;
+ CFileUnmapper unmapper(data);
+ {
+ wchar_t *cur = (wchar_t *)data;
+ *cur++ = 0;
+ for (int i = 0; i < names.Size(); i++)
+ {
+ const UString &s = names[i];
+ int len = s.Length() + 1;
+ memcpy(cur, (const wchar_t *)s, len * sizeof(wchar_t));
+ cur += len;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CompressFiles(
+ const UString &arcPathPrefix,
+ const UString &arcName,
+ const UString &arcType,
+ const UStringVector &names,
+ bool email, bool showDialog, bool waitFinish)
+{
+ MY_TRY_BEGIN
+ UString params = L'a';
+
+ CFileMapping fileMapping;
+ NSynchronization::CManualResetEvent event;
+ params += kIncludeSwitch;
+ RINOK(CreateMap(names, fileMapping, event, params));
+
+ if (!arcType.IsEmpty())
+ {
+ params += kArchiveTypeSwitch;
+ params += arcType;
+ }
+
+ if (email)
+ params += kEmailSwitch;
+
+ if (showDialog)
+ params += kShowDialogSwitch;
+
+ AddLagePagesSwitch(params);
+
+ params += kStopSwitchParsing;
+ params += L' ';
+
+ params += GetQuotedString(
+ #ifdef UNDER_CE
+ arcPathPrefix +
+ #endif
+ arcName);
+
+ return MyCreateProcess(Get7zGuiPath(), params,
+ (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix), waitFinish, &event);
+ MY_TRY_FINISH
+}
+
+static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, UString &params)
+{
+ AddLagePagesSwitch(params);
+ params += kArcIncludeSwitches;
+ CFileMapping fileMapping;
+ NSynchronization::CManualResetEvent event;
+ RINOK(CreateMap(arcPaths, fileMapping, event, params));
+ return MyCreateProcess(Get7zGuiPath(), params, 0, false, &event);
+}
+
+HRESULT ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog)
+{
+ MY_TRY_BEGIN
+ UString params = L'x';
+ if (!outFolder.IsEmpty())
+ {
+ params += L" -o";
+ params += GetQuotedString(outFolder);
+ }
+ if (showDialog)
+ params += kShowDialogSwitch;
+ return ExtractGroupCommand(arcPaths, params);
+ MY_TRY_FINISH
+}
+
+HRESULT TestArchives(const UStringVector &arcPaths)
+{
+ MY_TRY_BEGIN
+ UString params = L't';
+ return ExtractGroupCommand(arcPaths, params);
+ MY_TRY_FINISH
+}
+
+HRESULT Benchmark()
+{
+ MY_TRY_BEGIN
+ return MyCreateProcess(Get7zGuiPath(), L'b', 0, false, NULL);
+ MY_TRY_FINISH
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.h b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.h
new file mode 100644
index 000000000..fc18df57c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall.h
@@ -0,0 +1,24 @@
+// CompressCall.h
+
+#ifndef __COMPRESS_CALL_H
+#define __COMPRESS_CALL_H
+
+#include "Common/MyString.h"
+
+UString GetQuotedString(const UString &s);
+
+extern HWND g_HWND;
+UString HResultToMessage(HRESULT errorCode);
+
+HRESULT CompressFiles(
+ const UString &arcPathPrefix,
+ const UString &arcName,
+ const UString &arcType,
+ const UStringVector &names,
+ bool email, bool showDialog, bool waitFinish);
+
+HRESULT ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog);
+HRESULT TestArchives(const UStringVector &arcPaths);
+HRESULT Benchmark();
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp
new file mode 100644
index 000000000..473f7d933
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/CompressCall2.cpp
@@ -0,0 +1,178 @@
+// CompressCall.cpp
+
+#include "StdAfx.h"
+
+#include "Common/MyException.h"
+
+#include "../../UI/common/ArchiveCommandLine.h"
+
+#include "../../UI/GUI/BenchmarkDialog.h"
+#include "../../UI/GUI/ExtractGUI.h"
+#include "../../UI/GUI/UpdateGUI.h"
+
+#include "../../UI/GUI/ExtractRes.h"
+
+#include "CompressCall.h"
+
+#define MY_TRY_BEGIN try {
+#define MY_TRY_FINISH } \
+ catch(CSystemException &e) { result = e.ErrorCode; } \
+ catch(...) { result = E_FAIL; } \
+ if (result != S_OK && result != E_ABORT) \
+ ErrorMessageHRESULT(result);
+
+#define CREATE_CODECS \
+ CCodecs *codecs = new CCodecs; \
+ CMyComPtr<IUnknown> compressCodecsInfo = codecs; \
+ result = codecs->Load(); \
+ if (result != S_OK) \
+ throw CSystemException(result);
+
+UString GetQuotedString(const UString &s)
+{
+ return UString(L'\"') + s + UString(L'\"');
+}
+
+static void ErrorMessage(LPCWSTR message)
+{
+ MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR);
+}
+
+static void ErrorMessageHRESULT(HRESULT res)
+{
+ ErrorMessage(HResultToMessage(res));
+}
+
+static void ErrorLangMessage(UINT resourceID, UInt32 langID)
+{
+ ErrorMessage(LangString(resourceID, langID));
+}
+
+HRESULT CompressFiles(
+ const UString &arcPathPrefix,
+ const UString &arcName,
+ const UString &arcType,
+ const UStringVector &names,
+ bool email, bool showDialog, bool /* waitFinish */)
+{
+ HRESULT result;
+ MY_TRY_BEGIN
+ CREATE_CODECS
+
+ CUpdateCallbackGUI callback;
+
+ callback.Init();
+
+ CUpdateOptions uo;
+ uo.EMailMode = email;
+ uo.SetAddActionCommand();
+
+ CIntVector formatIndices;
+ if (!codecs->FindFormatForArchiveType(arcType, formatIndices))
+ {
+ ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE, 0x0200060D);
+ return E_FAIL;
+ }
+ if (!uo.Init(codecs, formatIndices, arcPathPrefix + arcName))
+ {
+ ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED, 0x02000601);
+ return E_FAIL;
+ }
+
+ NWildcard::CCensor censor;
+ for (int i = 0; i < names.Size(); i++)
+ censor.AddItem(true, names[i], false);
+
+ bool messageWasDisplayed = false;
+ result = UpdateGUI(codecs, censor, uo, showDialog, messageWasDisplayed, &callback, g_HWND);
+
+ if (result != S_OK)
+ {
+ if (result != E_ABORT && messageWasDisplayed)
+ return E_FAIL;
+ throw CSystemException(result);
+ }
+ if (callback.FailedFiles.Size() > 0)
+ {
+ if (!messageWasDisplayed)
+ throw CSystemException(E_FAIL);
+ return E_FAIL;
+ }
+ MY_TRY_FINISH
+ return S_OK;
+}
+
+static HRESULT ExtractGroupCommand(const UStringVector &arcPaths,
+ bool showDialog, const UString &outFolder, bool testMode)
+{
+ HRESULT result;
+ MY_TRY_BEGIN
+ CREATE_CODECS
+
+ CExtractOptions eo;
+ eo.OutputDir = outFolder;
+ eo.TestMode = testMode;
+
+ CExtractCallbackImp *ecs = new CExtractCallbackImp;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+ ecs->Init();
+
+ // eo.CalcCrc = options.CalcCrc;
+
+ UStringVector arcPathsSorted;
+ UStringVector arcFullPathsSorted;
+ {
+ NWildcard::CCensor acrCensor;
+ for (int i = 0; i < arcPaths.Size(); i++)
+ acrCensor.AddItem(true, arcPaths[i], false);
+ EnumerateDirItemsAndSort(acrCensor, arcPathsSorted, arcFullPathsSorted);
+ }
+
+ CIntVector formatIndices;
+
+ NWildcard::CCensor censor;
+ censor.AddItem(true, L"*", false);
+
+ bool messageWasDisplayed = false;
+ result = ExtractGUI(codecs, formatIndices, arcPathsSorted, arcFullPathsSorted,
+ censor.Pairs.Front().Head, eo, showDialog, messageWasDisplayed, ecs, g_HWND);
+ if (result != S_OK)
+ {
+ if (result != E_ABORT && messageWasDisplayed)
+ return E_FAIL;
+ throw CSystemException(result);
+ }
+ return ecs->IsOK() ? S_OK : E_FAIL;
+ MY_TRY_FINISH
+ return result;
+}
+
+HRESULT ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog)
+{
+ return ExtractGroupCommand(arcPaths, showDialog, outFolder, false);
+}
+
+HRESULT TestArchives(const UStringVector &arcPaths)
+{
+ return ExtractGroupCommand(arcPaths, true, UString(), true);
+}
+
+HRESULT Benchmark()
+{
+ HRESULT result;
+ MY_TRY_BEGIN
+ CREATE_CODECS
+
+ #ifdef EXTERNAL_CODECS
+ CObjectVector<CCodecInfoEx> externalCodecs;
+ RINOK(LoadExternalCodecs(codecs, externalCodecs));
+ #endif
+ result = Benchmark(
+ #ifdef EXTERNAL_CODECS
+ codecs, &externalCodecs,
+ #endif
+ (UInt32)-1, (UInt32)-1, g_HWND);
+ MY_TRY_FINISH
+ return result;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp
new file mode 100644
index 000000000..4335e2731
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.cpp
@@ -0,0 +1,35 @@
+// DefaultName.cpp
+
+#include "StdAfx.h"
+
+#include "DefaultName.h"
+
+static UString GetDefaultName3(const UString &fileName,
+ const UString &extension, const UString &addSubExtension)
+{
+ int extLength = extension.Length();
+ int fileNameLength = fileName.Length();
+ if (fileNameLength > extLength + 1)
+ {
+ int dotPos = fileNameLength - (extLength + 1);
+ if (fileName[dotPos] == '.')
+ if (extension.CompareNoCase(fileName.Mid(dotPos + 1)) == 0)
+ return fileName.Left(dotPos) + addSubExtension;
+ }
+ int dotPos = fileName.ReverseFind(L'.');
+ if (dotPos > 0)
+ return fileName.Left(dotPos) + addSubExtension;
+
+ if (addSubExtension.IsEmpty())
+ return fileName + L"~";
+ else
+ return fileName + addSubExtension;
+}
+
+UString GetDefaultName2(const UString &fileName,
+ const UString &extension, const UString &addSubExtension)
+{
+ UString name = GetDefaultName3(fileName, extension, addSubExtension);
+ name.TrimRight();
+ return name;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h b/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h
new file mode 100644
index 000000000..9764ff871
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/DefaultName.h
@@ -0,0 +1,11 @@
+// DefaultName.h
+
+#ifndef __DEFAULTNAME_H
+#define __DEFAULTNAME_H
+
+#include "Common/MyString.h"
+
+UString GetDefaultName2(const UString &fileName,
+ const UString &extension, const UString &addSubExtension);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h b/src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h
new file mode 100644
index 000000000..29cc60d93
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/DirItem.h
@@ -0,0 +1,69 @@
+// DirItem.h
+
+#ifndef __DIR_ITEM_H
+#define __DIR_ITEM_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+#include "../../Archive/IArchive.h"
+
+struct CDirItem
+{
+ UInt64 Size;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ UString Name;
+ UInt32 Attrib;
+ int PhyParent;
+ int LogParent;
+
+ CDirItem(): PhyParent(-1), LogParent(-1) {}
+ bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
+};
+
+class CDirItems
+{
+ UStringVector Prefixes;
+ CIntVector PhyParents;
+ CIntVector LogParents;
+
+ UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const;
+public:
+ CObjectVector<CDirItem> Items;
+
+ int GetNumFolders() const { return Prefixes.Size(); }
+ UString GetPhyPath(int index) const;
+ UString GetLogPath(int index) const;
+
+ int AddPrefix(int phyParent, int logParent, const UString &prefix);
+ void DeleteLastPrefix();
+
+ void EnumerateDirectory(int phyParent, int logParent, const UString &phyPrefix,
+ UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes);
+
+ void EnumerateDirItems2(
+ const UString &phyPrefix,
+ const UString &logPrefix,
+ const UStringVector &filePaths,
+ UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes);
+
+ void ReserveDown();
+};
+
+struct CArcItem
+{
+ UInt64 Size;
+ FILETIME MTime;
+ UString Name;
+ bool IsDir;
+ bool SizeDefined;
+ bool MTimeDefined;
+ bool Censored;
+ UInt32 IndexInServer;
+ int TimeType;
+
+ CArcItem(): IsDir(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {}
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp
new file mode 100644
index 000000000..ba03ea35c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -0,0 +1,361 @@
+// EnumDirItems.cpp
+
+#include "StdAfx.h"
+
+#include "EnumDirItems.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+void AddDirFileInfo(int phyParent, int logParent,
+ const NFind::CFileInfoW &fi, CObjectVector<CDirItem> &dirItems)
+{
+ CDirItem di;
+ di.Size = fi.Size;
+ di.CTime = fi.CTime;
+ di.ATime = fi.ATime;
+ di.MTime = fi.MTime;
+ di.Attrib = fi.Attrib;
+ di.PhyParent = phyParent;
+ di.LogParent = logParent;
+ di.Name = fi.Name;
+ dirItems.Add(di);
+}
+
+UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
+{
+ UString path;
+ int len = name.Length();
+ int i;
+ for (i = index; i >= 0; i = parents[i])
+ len += Prefixes[i].Length();
+ int totalLen = len;
+ wchar_t *p = path.GetBuffer(len);
+ p[len] = 0;
+ len -= name.Length();
+ memcpy(p + len, (const wchar_t *)name, name.Length() * sizeof(wchar_t));
+ for (i = index; i >= 0; i = parents[i])
+ {
+ const UString &s = Prefixes[i];
+ len -= s.Length();
+ memcpy(p + len, (const wchar_t *)s, s.Length() * sizeof(wchar_t));
+ }
+ path.ReleaseBuffer(totalLen);
+ return path;
+}
+
+UString CDirItems::GetPhyPath(int index) const
+{
+ const CDirItem &di = Items[index];
+ return GetPrefixesPath(PhyParents, di.PhyParent, di.Name);
+}
+
+UString CDirItems::GetLogPath(int index) const
+{
+ const CDirItem &di = Items[index];
+ return GetPrefixesPath(LogParents, di.LogParent, di.Name);
+}
+
+void CDirItems::ReserveDown()
+{
+ Prefixes.ReserveDown();
+ PhyParents.ReserveDown();
+ LogParents.ReserveDown();
+ Items.ReserveDown();
+}
+
+int CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)
+{
+ PhyParents.Add(phyParent);
+ LogParents.Add(logParent);
+ return Prefixes.Add(prefix);
+}
+
+void CDirItems::DeleteLastPrefix()
+{
+ PhyParents.DeleteBack();
+ LogParents.DeleteBack();
+ Prefixes.DeleteBack();
+}
+
+void CDirItems::EnumerateDirectory(int phyParent, int logParent, const UString &phyPrefix,
+ UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes)
+{
+ NFind::CEnumeratorW enumerator(phyPrefix + (wchar_t)kAnyStringWildcard);
+ for (;;)
+ {
+ NFind::CFileInfoW fi;
+ bool found;
+ if (!enumerator.Next(fi, found))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(phyPrefix);
+ return;
+ }
+ if (!found)
+ break;
+ AddDirFileInfo(phyParent, logParent, fi, Items);
+ if (fi.IsDir())
+ {
+ const UString name2 = fi.Name + (wchar_t)kDirDelimiter;
+ int parent = AddPrefix(phyParent, logParent, name2);
+ EnumerateDirectory(parent, parent, phyPrefix + name2, errorPaths, errorCodes);
+ }
+ }
+}
+
+void CDirItems::EnumerateDirItems2(const UString &phyPrefix, const UString &logPrefix,
+ const UStringVector &filePaths, UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes)
+{
+ int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, phyPrefix);
+ int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);
+
+ for (int i = 0; i < filePaths.Size(); i++)
+ {
+ const UString &filePath = filePaths[i];
+ NFind::CFileInfoW fi;
+ const UString phyPath = phyPrefix + filePath;
+ if (!fi.Find(phyPath))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(phyPath);
+ continue;
+ }
+ int delimiter = filePath.ReverseFind((wchar_t)kDirDelimiter);
+ UString phyPrefixCur;
+ int phyParentCur = phyParent;
+ if (delimiter >= 0)
+ {
+ phyPrefixCur = filePath.Left(delimiter + 1);
+ phyParentCur = AddPrefix(phyParent, logParent, phyPrefixCur);
+ }
+ AddDirFileInfo(phyParentCur, logParent, fi, Items);
+ if (fi.IsDir())
+ {
+ const UString name2 = fi.Name + (wchar_t)kDirDelimiter;
+ int parent = AddPrefix(phyParentCur, logParent, name2);
+ EnumerateDirectory(parent, parent, phyPrefix + phyPrefixCur + name2, errorPaths, errorCodes);
+ }
+ }
+ ReserveDown();
+}
+
+static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const UString &phyPrefix,
+ const UStringVector &addArchivePrefix,
+ CDirItems &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes);
+
+static HRESULT EnumerateDirItems_Spec(const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const UString &curFolderName,
+ const UString &phyPrefix,
+ const UStringVector &addArchivePrefix,
+ CDirItems &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+
+{
+ const UString name2 = curFolderName + (wchar_t)kDirDelimiter;
+ int parent = dirItems.AddPrefix(phyParent, logParent, name2);
+ int numItems = dirItems.Items.Size();
+ HRESULT res = EnumerateDirItems(curNode, parent, parent, phyPrefix + name2,
+ addArchivePrefix, dirItems, enterToSubFolders, callback, errorPaths, errorCodes);
+ if (numItems == dirItems.Items.Size())
+ dirItems.DeleteLastPrefix();
+ return res;
+}
+
+
+static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode,
+ int phyParent, int logParent, const UString &phyPrefix,
+ const UStringVector &addArchivePrefix, // prefix from curNode
+ CDirItems &dirItems,
+ bool enterToSubFolders,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ if (!enterToSubFolders)
+ if (curNode.NeedCheckSubDirs())
+ enterToSubFolders = true;
+ if (callback)
+ RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix));
+
+ // try direct_names case at first
+ if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
+ {
+ // check that all names are direct
+ int i;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ break;
+ const UString &name = item.PathParts.Front();
+ if (name.IsEmpty() || DoesNameContainWildCard(name))
+ break;
+ }
+ if (i == curNode.IncludeItems.Size())
+ {
+ // all names are direct (no wildcards)
+ // so we don't need file_system's dir enumerator
+ CRecordVector<bool> needEnterVector;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ const UString &name = item.PathParts.Front();
+ const UString fullPath = phyPrefix + name;
+ NFind::CFileInfoW fi;
+ if (!fi.Find(fullPath))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ bool isDir = fi.IsDir();
+ if (isDir && !item.ForDir || !isDir && !item.ForFile)
+ {
+ errorCodes.Add((DWORD)E_FAIL);
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ {
+ UStringVector pathParts;
+ pathParts.Add(fi.Name);
+ if (curNode.CheckPathToRoot(false, pathParts, !isDir))
+ continue;
+ }
+ AddDirFileInfo(phyParent, logParent, fi, dirItems.Items);
+ if (!isDir)
+ continue;
+
+ UStringVector addArchivePrefixNew;
+ const NWildcard::CCensorNode *nextNode = 0;
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ {
+ for (int t = needEnterVector.Size(); t <= index; t++)
+ needEnterVector.Add(true);
+ needEnterVector[index] = false;
+ nextNode = &curNode.SubNodes[index];
+ }
+ else
+ {
+ nextNode = &curNode;
+ addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support
+ }
+
+ RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,
+ addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
+ }
+ for (i = 0; i < curNode.SubNodes.Size(); i++)
+ {
+ if (i < needEnterVector.Size())
+ if (!needEnterVector[i])
+ continue;
+ const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
+ const UString fullPath = phyPrefix + nextNode.Name;
+ NFind::CFileInfoW fi;
+ if (!fi.Find(fullPath))
+ {
+ if (!nextNode.AreThereIncludeItems())
+ continue;
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(fullPath);
+ continue;
+ }
+ if (!fi.IsDir())
+ {
+ errorCodes.Add((DWORD)E_FAIL);
+ errorPaths.Add(fullPath);
+ continue;
+ }
+
+ RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
+ UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+ }
+ }
+
+
+ NFind::CEnumeratorW enumerator(phyPrefix + wchar_t(kAnyStringWildcard));
+ for (int ttt = 0; ; ttt++)
+ {
+ NFind::CFileInfoW fi;
+ bool found;
+ if (!enumerator.Next(fi, found))
+ {
+ errorCodes.Add(::GetLastError());
+ errorPaths.Add(phyPrefix);
+ break;
+ }
+ if (!found)
+ break;
+
+ if (callback && (ttt & 0xFF) == 0xFF)
+ RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix));
+ const UString &name = fi.Name;
+ bool enterToSubFolders2 = enterToSubFolders;
+ UStringVector addArchivePrefixNew = addArchivePrefix;
+ addArchivePrefixNew.Add(name);
+ {
+ UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
+ if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))
+ continue;
+ }
+ if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
+ {
+ AddDirFileInfo(phyParent, logParent, fi, dirItems.Items);
+ if (fi.IsDir())
+ enterToSubFolders2 = true;
+ }
+ if (!fi.IsDir())
+ continue;
+
+ const NWildcard::CCensorNode *nextNode = 0;
+ if (addArchivePrefix.IsEmpty())
+ {
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ nextNode = &curNode.SubNodes[index];
+ }
+ if (!enterToSubFolders2 && nextNode == 0)
+ continue;
+
+ addArchivePrefixNew = addArchivePrefix;
+ if (nextNode == 0)
+ {
+ nextNode = &curNode;
+ addArchivePrefixNew.Add(name);
+ }
+
+ RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, name, phyPrefix,
+ addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
+ }
+ return S_OK;
+}
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ CDirItems &dirItems,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes)
+{
+ for (int i = 0; i < censor.Pairs.Size(); i++)
+ {
+ const NWildcard::CPair &pair = censor.Pairs[i];
+ int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);
+ RINOK(EnumerateDirItems(pair.Head, phyParent, -1, pair.Prefix, UStringVector(), dirItems, false,
+ callback, errorPaths, errorCodes));
+ }
+ dirItems.ReserveDown();
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h b/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h
new file mode 100644
index 000000000..d0ce950e3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/EnumDirItems.h
@@ -0,0 +1,25 @@
+// EnumDirItems.h
+
+#ifndef __ENUM_DIR_ITEMS_H
+#define __ENUM_DIR_ITEMS_H
+
+#include "Common/Wildcard.h"
+#include "Windows/FileFind.h"
+#include "DirItem.h"
+
+void AddDirFileInfo(int phyParent, int logParent,
+ const NWindows::NFile::NFind::CFileInfoW &fi, CObjectVector<CDirItem> &dirItems);
+
+struct IEnumDirItemCallback
+{
+ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) = 0;
+};
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ CDirItems &dirItems,
+ IEnumDirItemCallback *callback,
+ UStringVector &errorPaths,
+ CRecordVector<DWORD> &errorCodes);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ExitCode.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ExitCode.h
new file mode 100644
index 000000000..b6d7d4dfc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ExitCode.h
@@ -0,0 +1,27 @@
+// ExitCode.h
+
+#ifndef __EXIT_CODE_H
+#define __EXIT_CODE_H
+
+namespace NExitCode {
+
+enum EEnum {
+
+ kSuccess = 0, // Successful operation
+ kWarning = 1, // Non fatal error(s) occurred
+ kFatalError = 2, // A fatal error occurred
+ // kCRCError = 3, // A CRC error occurred when unpacking
+ // kLockedArchive = 4, // Attempt to modify an archive previously locked
+ // kWriteError = 5, // Write to disk error
+ // kOpenError = 6, // Open file error
+ kUserError = 7, // Command line option error
+ kMemoryError = 8, // Not enough memory for operation
+ // kCreateFileError = 9, // Create file error
+
+ kUserBreak = 255 // User stopped the process
+
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp
new file mode 100644
index 000000000..ca2c8c73d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.cpp
@@ -0,0 +1,263 @@
+// Extract.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "Extract.h"
+#include "SetProperties.h"
+
+using namespace NWindows;
+
+static HRESULT DecompressArchive(
+ const CArc &arc,
+ UInt64 packSize,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IExtractCallbackUI *callback,
+ CArchiveExtractCallback *extractCallbackSpec,
+ UString &errorMessage,
+ UInt64 &stdInProcessed)
+{
+ stdInProcessed = 0;
+ IInArchive *archive = arc.Archive;
+ CRecordVector<UInt32> realIndices;
+ if (!options.StdInMode)
+ {
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ UString filePath;
+ RINOK(arc.GetItemPath(i, filePath));
+ bool isFolder;
+ RINOK(IsArchiveItemFolder(archive, i, isFolder));
+ if (!wildcardCensor.CheckPath(filePath, !isFolder))
+ continue;
+ realIndices.Add(i);
+ }
+ if (realIndices.Size() == 0)
+ {
+ callback->ThereAreNoFiles();
+ return S_OK;
+ }
+ }
+
+ UStringVector removePathParts;
+
+ UString outDir = options.OutputDir;
+ outDir.Replace(L"*", GetCorrectFsPath(arc.DefaultName));
+ #ifdef _WIN32
+ // GetCorrectFullFsPath doesn't like "..".
+ // outDir.TrimRight();
+ // outDir = GetCorrectFullFsPath(outDir);
+ #endif
+
+ if (!outDir.IsEmpty())
+ if (!NFile::NDirectory::CreateComplexDirectory(outDir))
+ {
+ HRESULT res = ::GetLastError();
+ if (res == S_OK)
+ res = E_FAIL;
+ errorMessage = ((UString)L"Can not create output directory ") + outDir;
+ return res;
+ }
+
+ extractCallbackSpec->Init(
+ options.StdInMode ? &wildcardCensor : NULL,
+ &arc,
+ callback,
+ options.StdOutMode, options.TestMode, options.CalcCrc,
+ outDir,
+ removePathParts,
+ packSize);
+
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ RINOK(SetProperties(archive, options.Properties));
+ #endif
+
+ HRESULT result;
+ Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0;
+ if (options.StdInMode)
+ {
+ result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec);
+ NCOM::CPropVariant prop;
+ if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
+ if (prop.vt == VT_UI8 || prop.vt == VT_UI4)
+ stdInProcessed = ConvertPropVariantToUInt64(prop);
+ }
+ else
+ result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec);
+
+ return callback->ExtractResult(result);
+}
+
+HRESULT DecompressArchives(
+ CCodecs *codecs, const CIntVector &formatIndices,
+ UStringVector &arcPaths, UStringVector &arcPathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ UString &errorMessage,
+ CDecompressStat &stat)
+{
+ stat.Clear();
+ int i;
+ UInt64 totalPackSize = 0;
+ CRecordVector<UInt64> archiveSizes;
+
+ int numArcs = options.StdInMode ? 1 : arcPaths.Size();
+
+ for (i = 0; i < numArcs; i++)
+ {
+ NFile::NFind::CFileInfoW fi;
+ fi.Size = 0;
+ if (!options.StdInMode)
+ {
+ const UString &arcPath = arcPaths[i];
+ if (!fi.Find(arcPath))
+ throw "there is no such archive";
+ if (fi.IsDir())
+ throw "can't decompress folder";
+ }
+ archiveSizes.Add(fi.Size);
+ totalPackSize += fi.Size;
+ }
+ CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);
+ bool multi = (numArcs > 1);
+ extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);
+ if (multi)
+ {
+ RINOK(extractCallback->SetTotal(totalPackSize));
+ }
+ for (i = 0; i < numArcs; i++)
+ {
+ const UString &arcPath = arcPaths[i];
+ NFile::NFind::CFileInfoW fi;
+ if (options.StdInMode)
+ {
+ fi.Size = 0;
+ fi.Attrib = 0;
+ }
+ else
+ {
+ if (!fi.Find(arcPath) || fi.IsDir())
+ throw "there is no such archive";
+ }
+
+ #ifndef _NO_CRYPTO
+ openCallback->Open_ClearPasswordWasAskedFlag();
+ #endif
+
+ RINOK(extractCallback->BeforeOpen(arcPath));
+ CArchiveLink archiveLink;
+
+ CIntVector formatIndices2 = formatIndices;
+ #ifndef _SFX
+ if (formatIndices.IsEmpty())
+ {
+ int pos = arcPath.ReverseFind(L'.');
+ if (pos >= 0)
+ {
+ UString s = arcPath.Mid(pos + 1);
+ int index = codecs->FindFormatForExtension(s);
+ if (index >= 0 && s == L"001")
+ {
+ s = arcPath.Left(pos);
+ pos = s.ReverseFind(L'.');
+ if (pos >= 0)
+ {
+ int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1));
+ if (index2 >= 0 && s.CompareNoCase(L"rar") != 0)
+ {
+ formatIndices2.Add(index2);
+ formatIndices2.Add(index);
+ }
+ }
+ }
+ }
+ }
+ #endif
+ HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback);
+ if (result == E_ABORT)
+ return result;
+
+ bool crypted = false;
+ #ifndef _NO_CRYPTO
+ crypted = openCallback->Open_WasPasswordAsked();
+ #endif
+
+ RINOK(extractCallback->OpenResult(arcPath, result, crypted));
+ if (result != S_OK)
+ continue;
+
+ if (!options.StdInMode)
+ for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+ {
+ int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+ if (index >= 0 && index > i)
+ {
+ arcPaths.Delete(index);
+ arcPathsFull.Delete(index);
+ totalPackSize -= archiveSizes[index];
+ archiveSizes.Delete(index);
+ numArcs = arcPaths.Size();
+ }
+ }
+ if (archiveLink.VolumePaths.Size() != 0)
+ {
+ totalPackSize += archiveLink.VolumesSize;
+ RINOK(extractCallback->SetTotal(totalPackSize));
+ }
+
+ #ifndef _NO_CRYPTO
+ UString password;
+ RINOK(openCallback->Open_GetPasswordIfAny(password));
+ if (!password.IsEmpty())
+ {
+ RINOK(extractCallback->SetPassword(password));
+ }
+ #endif
+
+ for (int v = 0; v < archiveLink.Arcs.Size(); v++)
+ {
+ const UString &s = archiveLink.Arcs[v].ErrorMessage;
+ if (!s.IsEmpty())
+ {
+ RINOK(extractCallback->MessageError(s));
+ }
+ }
+
+ CArc &arc = archiveLink.Arcs.Back();
+ arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice);
+ arc.MTime = fi.MTime;
+
+ UInt64 packProcessed;
+ RINOK(DecompressArchive(arc,
+ fi.Size + archiveLink.VolumesSize,
+ wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage, packProcessed));
+ if (!options.StdInMode)
+ packProcessed = fi.Size + archiveLink.VolumesSize;
+ extractCallbackSpec->LocalProgressSpec->InSize += packProcessed;
+ extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;
+ if (!errorMessage.IsEmpty())
+ return E_FAIL;
+ }
+ stat.NumFolders = extractCallbackSpec->NumFolders;
+ stat.NumFiles = extractCallbackSpec->NumFiles;
+ stat.UnpackSize = extractCallbackSpec->UnpackSize;
+ stat.CrcSum = extractCallbackSpec->CrcSum;
+
+ stat.NumArchives = arcPaths.Size();
+ stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h
new file mode 100644
index 000000000..5a939ed23
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Extract.h
@@ -0,0 +1,76 @@
+// Extract.h
+
+#ifndef __EXTRACT_H
+#define __EXTRACT_H
+
+#include "Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ArchiveExtractCallback.h"
+#include "ArchiveOpenCallback.h"
+#include "ExtractMode.h"
+#include "Property.h"
+
+#include "../Common/LoadCodecs.h"
+
+struct CExtractOptions
+{
+ bool StdInMode;
+ bool StdOutMode;
+ bool YesToAll;
+ bool TestMode;
+ bool CalcCrc;
+ NExtract::NPathMode::EEnum PathMode;
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+ UString OutputDir;
+
+ // bool ShowDialog;
+ // bool PasswordEnabled;
+ // UString Password;
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ CObjectVector<CProperty> Properties;
+ #endif
+
+ #ifdef EXTERNAL_CODECS
+ CCodecs *Codecs;
+ #endif
+
+ CExtractOptions():
+ StdInMode(false),
+ StdOutMode(false),
+ YesToAll(false),
+ TestMode(false),
+ CalcCrc(false),
+ PathMode(NExtract::NPathMode::kFullPathnames),
+ OverwriteMode(NExtract::NOverwriteMode::kAskBefore)
+ {}
+};
+
+struct CDecompressStat
+{
+ UInt64 NumArchives;
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+ UInt32 CrcSum;
+
+ void Clear()
+ {
+ NumArchives = UnpackSize = PackSize = NumFolders = NumFiles = 0;
+ CrcSum = 0;
+ }
+};
+
+HRESULT DecompressArchives(
+ CCodecs *codecs, const CIntVector &formatIndices,
+ UStringVector &archivePaths, UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ UString &errorMessage,
+ CDecompressStat &stat);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h
new file mode 100644
index 000000000..b448fb30a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractMode.h
@@ -0,0 +1,31 @@
+// ExtractMode.h
+
+#ifndef __EXTRACT_MODE_H
+#define __EXTRACT_MODE_H
+
+namespace NExtract {
+
+ namespace NPathMode
+ {
+ enum EEnum
+ {
+ kFullPathnames,
+ kCurrentPathnames,
+ kNoPathnames
+ };
+ }
+
+ namespace NOverwriteMode
+ {
+ enum EEnum
+ {
+ kAskBefore,
+ kWithoutPrompt,
+ kSkipExisting,
+ kAutoRename,
+ kAutoRenameExisting
+ };
+ }
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp
new file mode 100644
index 000000000..8f31708b6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -0,0 +1,142 @@
+// ExtractingFilePath.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Types.h"
+
+#include "Common/Wildcard.h"
+
+#include "ExtractingFilePath.h"
+
+static UString ReplaceIncorrectChars(const UString &s)
+{
+ #ifdef _WIN32
+ UString res;
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ if (c < 0x20 || c == '*' || c == '?' || c == '<' || c == '>' || c == '|' || c == ':' || c == '"')
+ c = '_';
+ res += c;
+ }
+ res.TrimRight();
+ while (!res.IsEmpty() && res[res.Length() - 1] == '.')
+ res.Delete(res.Length() - 1);
+ return res;
+ #else
+ return s;
+ #endif
+}
+
+#ifdef _WIN32
+static const wchar_t *g_ReservedNames[] =
+{
+ L"CON", L"PRN", L"AUX", L"NUL"
+};
+
+static bool CheckTail(const UString &name, int len)
+{
+ int dotPos = name.Find(L'.');
+ if (dotPos < 0)
+ dotPos = name.Length();
+ UString s = name.Left(dotPos);
+ s.TrimRight();
+ return (s.Length() != len);
+}
+
+static bool CheckNameNum(const UString &name, const wchar_t *reservedName)
+{
+ int len = MyStringLen(reservedName);
+ if (name.Length() <= len)
+ return true;
+ if (name.Left(len).CompareNoCase(reservedName) != 0)
+ return true;
+ wchar_t c = name[len];
+ if (c < L'0' || c > L'9')
+ return true;
+ return CheckTail(name, len + 1);
+}
+
+static bool IsSupportedName(const UString &name)
+{
+ for (int i = 0; i < sizeof(g_ReservedNames) / sizeof(g_ReservedNames[0]); i++)
+ {
+ const wchar_t *reservedName = g_ReservedNames[i];
+ int len = MyStringLen(reservedName);
+ if (name.Length() < len)
+ continue;
+ if (name.Left(len).CompareNoCase(reservedName) != 0)
+ continue;
+ if (!CheckTail(name, len))
+ return false;
+ }
+ if (!CheckNameNum(name, L"COM"))
+ return false;
+ return CheckNameNum(name, L"LPT");
+}
+#endif
+
+static UString GetCorrectFileName(const UString &path)
+{
+ if (path == L".." || path == L".")
+ return UString();
+ return ReplaceIncorrectChars(path);
+}
+
+void MakeCorrectPath(UStringVector &pathParts)
+{
+ for (int i = 0; i < pathParts.Size();)
+ {
+ UString &s = pathParts[i];
+ s = GetCorrectFileName(s);
+ if (s.IsEmpty())
+ pathParts.Delete(i);
+ else
+ {
+ #ifdef _WIN32
+ if (!IsSupportedName(s))
+ s = (UString)L"_" + s;
+ #endif
+ i++;
+ }
+ }
+}
+
+UString MakePathNameFromParts(const UStringVector &parts)
+{
+ UString result;
+ for (int i = 0; i < parts.Size(); i++)
+ {
+ if (i != 0)
+ result += WCHAR_PATH_SEPARATOR;
+ result += parts[i];
+ }
+ return result;
+}
+
+UString GetCorrectFsPath(const UString &path)
+{
+ UString res = GetCorrectFileName(path);
+ #ifdef _WIN32
+ if (!IsSupportedName(res))
+ res = (UString)L"_" + res;
+ #endif
+ return res;
+}
+
+UString GetCorrectFullFsPath(const UString &path)
+{
+ UStringVector parts;
+ SplitPathToParts(path, parts);
+ for (int i = 0; i < parts.Size(); i++)
+ {
+ UString &s = parts[i];
+ #ifdef _WIN32
+ while (!s.IsEmpty() && s[s.Length() - 1] == '.')
+ s.Delete(s.Length() - 1);
+ if (!IsSupportedName(s))
+ s = (UString)L"_" + s;
+ #endif
+ }
+ return MakePathNameFromParts(parts);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h
new file mode 100644
index 000000000..da28bfc23
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ExtractingFilePath.h
@@ -0,0 +1,13 @@
+// ExtractingFilePath.h
+
+#ifndef __EXTRACTING_FILE_PATH_H
+#define __EXTRACTING_FILE_PATH_H
+
+#include "Common/MyString.h"
+
+UString MakePathNameFromParts(const UStringVector &parts);
+void MakeCorrectPath(UStringVector &pathParts);
+UString GetCorrectFsPath(const UString &path);
+UString GetCorrectFullFsPath(const UString &path);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h b/src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h
new file mode 100644
index 000000000..e8dcdce5f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/IFileExtractCallback.h
@@ -0,0 +1,46 @@
+// IFileExtractCallback.h
+
+#ifndef __IFILEEXTRACTCALLBACK_H
+#define __IFILEEXTRACTCALLBACK_H
+
+#include "Common/MyString.h"
+#include "../../IDecl.h"
+
+namespace NOverwriteAnswer
+{
+ enum EEnum
+ {
+ kYes,
+ kYesToAll,
+ kNo,
+ kNoToAll,
+ kAutoRename,
+ kCancel
+ };
+}
+
+DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07)
+{
+public:
+ STDMETHOD(AskOverwrite)(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer) PURE;
+ STDMETHOD(PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position) PURE;
+ STDMETHOD(MessageError)(const wchar_t *message) PURE;
+ STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted) PURE;
+};
+
+struct IExtractCallbackUI: IFolderArchiveExtractCallback
+{
+ virtual HRESULT BeforeOpen(const wchar_t *name) = 0;
+ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted) = 0;
+ virtual HRESULT ThereAreNoFiles() = 0;
+ virtual HRESULT ExtractResult(HRESULT result) = 0;
+
+ #ifndef _NO_CRYPTO
+ virtual HRESULT SetPassword(const UString &password) = 0;
+ #endif
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp
new file mode 100644
index 000000000..856e47fbc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.cpp
@@ -0,0 +1,681 @@
+// LoadCodecs.cpp
+
+#include "StdAfx.h"
+
+#include "LoadCodecs.h"
+
+#include "../../../Common/MyCom.h"
+#ifdef NEW_FOLDER_INTERFACE
+#include "../../../Common/StringToInt.h"
+#endif
+#include "../../../Windows/PropVariant.h"
+
+#include "../../ICoder.h"
+#include "../../Common/RegisterArc.h"
+
+#ifdef EXTERNAL_CODECS
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/DLL.h"
+#ifdef NEW_FOLDER_INTERFACE
+#include "../../../Windows/ResourceString.h"
+static const UINT kIconTypesResId = 100;
+#endif
+
+#ifdef _WIN32
+#include "Windows/Registry.h"
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+
+#ifdef _WIN32
+extern HINSTANCE g_hInstance;
+#endif
+
+static CSysString GetLibraryFolderPrefix()
+{
+ #ifdef _WIN32
+ TCHAR fullPath[MAX_PATH + 1];
+ ::GetModuleFileName(g_hInstance, fullPath, MAX_PATH);
+ CSysString path = fullPath;
+ int pos = path.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+ return path.Left(pos + 1);
+ #else
+ return CSysString(); // FIX IT
+ #endif
+}
+
+#define kCodecsFolderName TEXT("Codecs")
+#define kFormatsFolderName TEXT("Formats")
+static const TCHAR *kMainDll = TEXT("7z.dll");
+
+#ifdef _WIN32
+static LPCTSTR kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
+static LPCTSTR kProgramPathValue = TEXT("Path");
+static bool ReadPathFromRegistry(HKEY baseKey, CSysString &path)
+{
+ NRegistry::CKey key;
+ if(key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
+ if (key.QueryValue(kProgramPathValue, path) == ERROR_SUCCESS)
+ {
+ NName::NormalizeDirPathPrefix(path);
+ return true;
+ }
+ return false;
+}
+
+#endif
+
+CSysString GetBaseFolderPrefixFromRegistry()
+{
+ CSysString moduleFolderPrefix = GetLibraryFolderPrefix();
+ #ifdef _WIN32
+ if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) &&
+ !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) &&
+ !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName))
+ {
+ CSysString path;
+ if (ReadPathFromRegistry(HKEY_CURRENT_USER, path))
+ return path;
+ if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path))
+ return path;
+ }
+ #endif
+ return moduleFolderPrefix;
+}
+
+typedef UInt32 (WINAPI *GetNumberOfMethodsFunc)(UInt32 *numMethods);
+typedef UInt32 (WINAPI *GetNumberOfFormatsFunc)(UInt32 *numFormats);
+typedef UInt32 (WINAPI *GetHandlerPropertyFunc)(PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *GetHandlerPropertyFunc2)(UInt32 index, PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *iid, void **outObject);
+typedef UInt32 (WINAPI *SetLargePageModeFunc)();
+
+
+static HRESULT GetCoderClass(GetMethodPropertyFunc getMethodProperty, UInt32 index,
+ PROPID propId, CLSID &clsId, bool &isAssigned)
+{
+ NWindows::NCOM::CPropVariant prop;
+ isAssigned = false;
+ RINOK(getMethodProperty(index, propId, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ isAssigned = true;
+ clsId = *(const GUID *)prop.bstrVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT CCodecs::LoadCodecs()
+{
+ CCodecLib &lib = Libs.Back();
+ lib.GetMethodProperty = (GetMethodPropertyFunc)lib.Lib.GetProc("GetMethodProperty");
+ if (lib.GetMethodProperty == NULL)
+ return S_OK;
+
+ UInt32 numMethods = 1;
+ GetNumberOfMethodsFunc getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)lib.Lib.GetProc("GetNumberOfMethods");
+ if (getNumberOfMethodsFunc != NULL)
+ {
+ RINOK(getNumberOfMethodsFunc(&numMethods));
+ }
+
+ for(UInt32 i = 0; i < numMethods; i++)
+ {
+ CDllCodecInfo info;
+ info.LibIndex = Libs.Size() - 1;
+ info.CodecIndex = i;
+
+ RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
+ RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
+
+ Codecs.Add(info);
+ }
+ return S_OK;
+}
+
+static HRESULT ReadProp(
+ GetHandlerPropertyFunc getProp,
+ GetHandlerPropertyFunc2 getProp2,
+ UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
+{
+ if (getProp2)
+ return getProp2(index, propID, &prop);;
+ return getProp(propID, &prop);
+}
+
+static HRESULT ReadBoolProp(
+ GetHandlerPropertyFunc getProp,
+ GetHandlerPropertyFunc2 getProp2,
+ UInt32 index, PROPID propID, bool &res)
+{
+ NCOM::CPropVariant prop;
+ RINOK(ReadProp(getProp, getProp2, index, propID, prop));
+ if (prop.vt == VT_BOOL)
+ res = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+static HRESULT ReadStringProp(
+ GetHandlerPropertyFunc getProp,
+ GetHandlerPropertyFunc2 getProp2,
+ UInt32 index, PROPID propID, UString &res)
+{
+ NCOM::CPropVariant prop;
+ RINOK(ReadProp(getProp, getProp2, index, propID, prop));
+ if (prop.vt == VT_BSTR)
+ res = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+#endif
+
+static const unsigned int kNumArcsMax = 48;
+static unsigned int g_NumArcs = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax];
+void RegisterArc(const CArcInfo *arcInfo)
+{
+ if (g_NumArcs < kNumArcsMax)
+ g_Arcs[g_NumArcs++] = arcInfo;
+}
+
+static void SplitString(const UString &srcString, UStringVector &destStrings)
+{
+ destStrings.Clear();
+ UString s;
+ int len = srcString.Length();
+ if (len == 0)
+ return;
+ for (int i = 0; i < len; i++)
+ {
+ wchar_t c = srcString[i];
+ if (c == L' ')
+ {
+ if (!s.IsEmpty())
+ {
+ destStrings.Add(s);
+ s.Empty();
+ }
+ }
+ else
+ s += c;
+ }
+ if (!s.IsEmpty())
+ destStrings.Add(s);
+}
+
+void CArcInfoEx::AddExts(const wchar_t *ext, const wchar_t *addExt)
+{
+ UStringVector exts, addExts;
+ if (ext != 0)
+ SplitString(ext, exts);
+ if (addExt != 0)
+ SplitString(addExt, addExts);
+ for (int i = 0; i < exts.Size(); i++)
+ {
+ CArcExtInfo extInfo;
+ extInfo.Ext = exts[i];
+ if (i < addExts.Size())
+ {
+ extInfo.AddExt = addExts[i];
+ if (extInfo.AddExt == L"*")
+ extInfo.AddExt.Empty();
+ }
+ Exts.Add(extInfo);
+ }
+}
+
+#ifdef EXTERNAL_CODECS
+
+HRESULT CCodecs::LoadFormats()
+{
+ const NDLL::CLibrary &lib = Libs.Back().Lib;
+ GetHandlerPropertyFunc getProp = 0;
+ GetHandlerPropertyFunc2 getProp2 = (GetHandlerPropertyFunc2)lib.GetProc("GetHandlerProperty2");
+ if (getProp2 == NULL)
+ {
+ getProp = (GetHandlerPropertyFunc)lib.GetProc("GetHandlerProperty");
+ if (getProp == NULL)
+ return S_OK;
+ }
+
+ UInt32 numFormats = 1;
+ GetNumberOfFormatsFunc getNumberOfFormats = (GetNumberOfFormatsFunc)lib.GetProc("GetNumberOfFormats");
+ if (getNumberOfFormats != NULL)
+ {
+ RINOK(getNumberOfFormats(&numFormats));
+ }
+ if (getProp2 == NULL)
+ numFormats = 1;
+
+ for(UInt32 i = 0; i < numFormats; i++)
+ {
+ CArcInfoEx item;
+ item.LibIndex = Libs.Size() - 1;
+ item.FormatIndex = i;
+
+ RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kName, item.Name));
+
+ NCOM::CPropVariant prop;
+ if (ReadProp(getProp, getProp2, i, NArchive::kClassID, prop) != S_OK)
+ continue;
+ if (prop.vt != VT_BSTR)
+ continue;
+ item.ClassID = *(const GUID *)prop.bstrVal;
+ prop.Clear();
+
+ UString ext, addExt;
+ RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kExtension, ext));
+ RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kAddExtension, addExt));
+ item.AddExts(ext, addExt);
+
+ ReadBoolProp(getProp, getProp2, i, NArchive::kUpdate, item.UpdateEnabled);
+ if (item.UpdateEnabled)
+ ReadBoolProp(getProp, getProp2, i, NArchive::kKeepName, item.KeepName);
+
+ if (ReadProp(getProp, getProp2, i, NArchive::kStartSignature, prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ {
+ UINT len = ::SysStringByteLen(prop.bstrVal);
+ item.StartSignature.SetCapacity(len);
+ memmove(item.StartSignature, prop.bstrVal, len);
+ }
+ Formats.Add(item);
+ }
+ return S_OK;
+}
+
+#ifdef NEW_FOLDER_INTERFACE
+void CCodecIcons::LoadIcons(HMODULE m)
+{
+ UString iconTypes = MyLoadStringW(m, kIconTypesResId);
+ UStringVector pairs;
+ SplitString(iconTypes, pairs);
+ for (int i = 0; i < pairs.Size(); i++)
+ {
+ const UString &s = pairs[i];
+ int pos = s.Find(L':');
+ CIconPair iconPair;
+ iconPair.IconIndex = -1;
+ if (pos < 0)
+ pos = s.Length();
+ else
+ {
+ UString num = s.Mid(pos + 1);
+ if (!num.IsEmpty())
+ {
+ const wchar_t *end;
+ iconPair.IconIndex = (UInt32)ConvertStringToUInt64(num, &end);
+ if (*end != L'\0')
+ continue;
+ }
+ }
+ iconPair.Ext = s.Left(pos);
+ IconPairs.Add(iconPair);
+ }
+}
+
+bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
+{
+ iconIndex = -1;
+ for (int i = 0; i < IconPairs.Size(); i++)
+ {
+ const CIconPair &pair = IconPairs[i];
+ if (ext.CompareNoCase(pair.Ext) == 0)
+ {
+ iconIndex = pair.IconIndex;
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+#ifdef _7ZIP_LARGE_PAGES
+extern "C"
+{
+ extern SIZE_T g_LargePageSize;
+}
+#endif
+
+HRESULT CCodecs::LoadDll(const CSysString &dllPath, bool needCheckDll)
+{
+ if (needCheckDll)
+ {
+ NDLL::CLibrary library;
+ if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
+ return S_OK;
+ }
+ Libs.Add(CCodecLib());
+ CCodecLib &lib = Libs.Back();
+ #ifdef NEW_FOLDER_INTERFACE
+ lib.Path = dllPath;
+ #endif
+ bool used = false;
+ HRESULT res = S_OK;
+ if (lib.Lib.Load(dllPath))
+ {
+ #ifdef NEW_FOLDER_INTERFACE
+ lib.LoadIcons();
+ #endif
+
+ #ifdef _7ZIP_LARGE_PAGES
+ if (g_LargePageSize != 0)
+ {
+ SetLargePageModeFunc setLargePageMode = (SetLargePageModeFunc)lib.Lib.GetProc("SetLargePageMode");
+ if (setLargePageMode != 0)
+ setLargePageMode();
+ }
+ #endif
+
+ lib.CreateObject = (CreateObjectFunc)lib.Lib.GetProc("CreateObject");
+ if (lib.CreateObject != 0)
+ {
+ int startSize = Codecs.Size();
+ res = LoadCodecs();
+ used = (Codecs.Size() != startSize);
+ if (res == S_OK)
+ {
+ startSize = Formats.Size();
+ res = LoadFormats();
+ used = used || (Formats.Size() != startSize);
+ }
+ }
+ }
+ if (!used)
+ Libs.DeleteBack();
+ return res;
+}
+
+HRESULT CCodecs::LoadDllsFromFolder(const CSysString &folderPrefix)
+{
+ NFile::NFind::CEnumerator enumerator(folderPrefix + CSysString(TEXT("*")));
+ NFile::NFind::CFileInfo fi;
+ while (enumerator.Next(fi))
+ {
+ if (fi.IsDir())
+ continue;
+ RINOK(LoadDll(folderPrefix + fi.Name, true));
+ }
+ return S_OK;
+}
+
+#endif
+
+#ifndef _SFX
+static inline void SetBuffer(CByteBuffer &bb, const Byte *data, int size)
+{
+ bb.SetCapacity(size);
+ memmove((Byte *)bb, data, size);
+}
+#endif
+
+HRESULT CCodecs::Load()
+{
+ #ifdef NEW_FOLDER_INTERFACE
+ InternalIcons.LoadIcons(g_hInstance);
+ #endif
+
+ Formats.Clear();
+ #ifdef EXTERNAL_CODECS
+ Codecs.Clear();
+ #endif
+ for (UInt32 i = 0; i < g_NumArcs; i++)
+ {
+ const CArcInfo &arc = *g_Arcs[i];
+ CArcInfoEx item;
+ item.Name = arc.Name;
+ item.CreateInArchive = arc.CreateInArchive;
+ item.CreateOutArchive = arc.CreateOutArchive;
+ item.AddExts(arc.Ext, arc.AddExt);
+ item.UpdateEnabled = (arc.CreateOutArchive != 0);
+ item.KeepName = arc.KeepName;
+
+ #ifndef _SFX
+ SetBuffer(item.StartSignature, arc.Signature, arc.SignatureSize);
+ #endif
+ Formats.Add(item);
+ }
+ #ifdef EXTERNAL_CODECS
+ const CSysString baseFolder = GetBaseFolderPrefixFromRegistry();
+ RINOK(LoadDll(baseFolder + kMainDll, false));
+ RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName TEXT(STRING_PATH_SEPARATOR)));
+ RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName TEXT(STRING_PATH_SEPARATOR)));
+ #endif
+ return S_OK;
+}
+
+#ifndef _SFX
+
+int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
+{
+ int slashPos1 = arcPath.ReverseFind(WCHAR_PATH_SEPARATOR);
+ int slashPos2 = arcPath.ReverseFind(L'.');
+ int dotPos = arcPath.ReverseFind(L'.');
+ if (dotPos < 0 || dotPos < slashPos1 || dotPos < slashPos2)
+ return -1;
+ UString ext = arcPath.Mid(dotPos + 1);
+ for (int i = 0; i < Formats.Size(); i++)
+ {
+ const CArcInfoEx &arc = Formats[i];
+ if (!arc.UpdateEnabled)
+ continue;
+ if (arc.FindExtension(ext) >= 0)
+ return i;
+ }
+ return -1;
+}
+
+int CCodecs::FindFormatForExtension(const UString &ext) const
+{
+ if (ext.IsEmpty())
+ return -1;
+ for (int i = 0; i < Formats.Size(); i++)
+ if (Formats[i].FindExtension(ext) >= 0)
+ return i;
+ return -1;
+}
+
+int CCodecs::FindFormatForArchiveType(const UString &arcType) const
+{
+ for (int i = 0; i < Formats.Size(); i++)
+ if (Formats[i].Name.CompareNoCase(arcType) == 0)
+ return i;
+ return -1;
+}
+
+bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const
+{
+ formatIndices.Clear();
+ for (int pos = 0; pos < arcType.Length();)
+ {
+ int pos2 = arcType.Find('.', pos);
+ if (pos2 < 0)
+ pos2 = arcType.Length();
+ const UString name = arcType.Mid(pos, pos2 - pos);
+ int index = FindFormatForArchiveType(name);
+ if (index < 0 && name != L"*")
+ {
+ formatIndices.Clear();
+ return false;
+ }
+ formatIndices.Add(index);
+ pos = pos2 + 1;
+ }
+ return true;
+}
+
+#endif
+
+#ifdef EXTERNAL_CODECS
+
+#ifdef EXPORT_CODECS
+extern unsigned int g_NumCodecs;
+STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject);
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
+// STDAPI GetNumberOfMethods(UInt32 *numCodecs);
+#endif
+
+STDMETHODIMP CCodecs::GetNumberOfMethods(UInt32 *numMethods)
+{
+ *numMethods =
+ #ifdef EXPORT_CODECS
+ g_NumCodecs +
+ #endif
+ Codecs.Size();
+ return S_OK;
+}
+
+STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return GetMethodProperty(index, propID, value);
+ #endif
+
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+
+ if (propID == NMethodPropID::kDecoderIsAssigned)
+ {
+ NWindows::NCOM::CPropVariant propVariant;
+ propVariant = ci.DecoderIsAssigned;
+ propVariant.Detach(value);
+ return S_OK;
+ }
+ if (propID == NMethodPropID::kEncoderIsAssigned)
+ {
+ NWindows::NCOM::CPropVariant propVariant;
+ propVariant = ci.EncoderIsAssigned;
+ propVariant.Detach(value);
+ return S_OK;
+ }
+ return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value);
+}
+
+STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return CreateCoder2(false, index, iid, coder);
+ #endif
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+ if (ci.DecoderIsAssigned)
+ return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder);
+ return S_OK;
+}
+
+STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return CreateCoder2(true, index, iid, coder);
+ #endif
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+ if (ci.EncoderIsAssigned)
+ return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder);
+ return S_OK;
+}
+
+HRESULT CCodecs::CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const
+{
+ for (int i = 0; i < Codecs.Size(); i++)
+ {
+ const CDllCodecInfo &codec = Codecs[i];
+ if (encode && !codec.EncoderIsAssigned || !encode && !codec.DecoderIsAssigned)
+ continue;
+ const CCodecLib &lib = Libs[codec.LibIndex];
+ UString res;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(lib.GetMethodProperty(codec.CodecIndex, NMethodPropID::kName, &prop));
+ if (prop.vt == VT_BSTR)
+ res = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ continue;
+ if (name.CompareNoCase(res) == 0)
+ return lib.CreateObject(encode ? &codec.Encoder : &codec.Decoder, &IID_ICompressCoder, (void **)&coder);
+ }
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+int CCodecs::GetCodecLibIndex(UInt32 index)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return -1;
+ #endif
+ #ifdef EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+ return ci.LibIndex;
+ #else
+ return -1;
+ #endif
+}
+
+bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ {
+ NWindows::NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK)
+ if (prop.vt != VT_EMPTY)
+ return true;
+ return false;
+ }
+ #endif
+ #ifdef EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index
+ #ifdef EXPORT_CODECS
+ - g_NumCodecs
+ #endif
+ ];
+ return ci.EncoderIsAssigned;
+ #else
+ return false;
+ #endif
+}
+
+HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id)
+{
+ UString s;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(GetProperty(index, NMethodPropID::kID, &prop));
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ id = prop.uhVal.QuadPart;
+ return S_OK;
+}
+
+UString CCodecs::GetCodecName(UInt32 index)
+{
+ UString s;
+ NWindows::NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ s = prop.bstrVal;
+ return s;
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h b/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h
new file mode 100644
index 000000000..a633dd2e1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/LoadCodecs.h
@@ -0,0 +1,235 @@
+// LoadCodecs.h
+
+#ifndef __LOADCODECS_H
+#define __LOADCODECS_H
+
+#include "../../../Common/Types.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/Buffer.h"
+#include "../../ICoder.h"
+
+#ifdef EXTERNAL_CODECS
+#include "../../../Windows/DLL.h"
+#endif
+
+struct CDllCodecInfo
+{
+ CLSID Encoder;
+ CLSID Decoder;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+ int LibIndex;
+ UInt32 CodecIndex;
+};
+
+#include "../../Archive/IArchive.h"
+
+typedef IInArchive * (*CreateInArchiveP)();
+typedef IOutArchive * (*CreateOutArchiveP)();
+
+struct CArcExtInfo
+{
+ UString Ext;
+ UString AddExt;
+ CArcExtInfo() {}
+ CArcExtInfo(const UString &ext): Ext(ext) {}
+ CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
+};
+
+
+struct CArcInfoEx
+{
+ #ifdef EXTERNAL_CODECS
+ int LibIndex;
+ UInt32 FormatIndex;
+ CLSID ClassID;
+ #endif
+ bool UpdateEnabled;
+ CreateInArchiveP CreateInArchive;
+ CreateOutArchiveP CreateOutArchive;
+ UString Name;
+ CObjectVector<CArcExtInfo> Exts;
+ #ifndef _SFX
+ CByteBuffer StartSignature;
+ // CByteBuffer FinishSignature;
+ #ifdef NEW_FOLDER_INTERFACE
+ UStringVector AssociateExts;
+ #endif
+ #endif
+ bool KeepName;
+ UString GetMainExt() const
+ {
+ if (Exts.IsEmpty())
+ return UString();
+ return Exts[0].Ext;
+ }
+ int FindExtension(const UString &ext) const
+ {
+ for (int i = 0; i < Exts.Size(); i++)
+ if (ext.CompareNoCase(Exts[i].Ext) == 0)
+ return i;
+ return -1;
+ }
+ UString GetAllExtensions() const
+ {
+ UString s;
+ for (int i = 0; i < Exts.Size(); i++)
+ {
+ if (i > 0)
+ s += ' ';
+ s += Exts[i].Ext;
+ }
+ return s;
+ }
+
+ void AddExts(const wchar_t* ext, const wchar_t* addExt);
+
+ CArcInfoEx():
+ #ifdef EXTERNAL_CODECS
+ LibIndex(-1),
+ #endif
+ UpdateEnabled(false),
+ CreateInArchive(0), CreateOutArchive(0),
+ KeepName(false)
+ #ifndef _SFX
+ #endif
+ {}
+};
+
+#ifdef EXTERNAL_CODECS
+typedef UInt32 (WINAPI *GetMethodPropertyFunc)(UInt32 index, PROPID propID, PROPVARIANT *value);
+typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *interfaceID, void **outObject);
+
+
+#ifdef NEW_FOLDER_INTERFACE
+struct CCodecIcons
+{
+ struct CIconPair
+ {
+ UString Ext;
+ int IconIndex;
+ };
+ CObjectVector<CIconPair> IconPairs;
+ void LoadIcons(HMODULE m);
+ bool FindIconIndex(const UString &ext, int &iconIndex) const;
+};
+#endif
+
+struct CCodecLib
+#ifdef NEW_FOLDER_INTERFACE
+: public CCodecIcons
+#endif
+{
+ NWindows::NDLL::CLibrary Lib;
+ GetMethodPropertyFunc GetMethodProperty;
+ CreateObjectFunc CreateObject;
+ #ifdef NEW_FOLDER_INTERFACE
+ CSysString Path;
+ void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }
+ #endif
+ CCodecLib(): GetMethodProperty(0) {}
+};
+#endif
+
+class CCodecs:
+ #ifdef EXTERNAL_CODECS
+ public ICompressCodecsInfo,
+ #else
+ public IUnknown,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ #ifdef EXTERNAL_CODECS
+ CObjectVector<CCodecLib> Libs;
+ CObjectVector<CDllCodecInfo> Codecs;
+
+ #ifdef NEW_FOLDER_INTERFACE
+ CCodecIcons InternalIcons;
+ #endif
+
+ HRESULT LoadCodecs();
+ HRESULT LoadFormats();
+ HRESULT LoadDll(const CSysString &path, bool needCheckDll);
+ HRESULT LoadDllsFromFolder(const CSysString &folderPrefix);
+
+ HRESULT CreateArchiveHandler(const CArcInfoEx &ai, void **archive, bool outHandler) const
+ {
+ return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
+ }
+ #endif
+
+public:
+ CObjectVector<CArcInfoEx> Formats;
+ HRESULT Load();
+
+ #ifndef _SFX
+ int FindFormatForArchiveName(const UString &arcPath) const;
+ int FindFormatForExtension(const UString &ext) const;
+ int FindFormatForArchiveType(const UString &arcType) const;
+ bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
+ #endif
+
+ MY_UNKNOWN_IMP
+
+ #ifdef EXTERNAL_CODECS
+ STDMETHOD(GetNumberOfMethods)(UInt32 *numMethods);
+ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
+ STDMETHOD(CreateDecoder)(UInt32 index, const GUID *interfaceID, void **coder);
+ STDMETHOD(CreateEncoder)(UInt32 index, const GUID *interfaceID, void **coder);
+ #endif
+
+ int GetCodecLibIndex(UInt32 index);
+ bool GetCodecEncoderIsAssigned(UInt32 index);
+ HRESULT GetCodecId(UInt32 index, UInt64 &id);
+ UString GetCodecName(UInt32 index);
+
+ HRESULT CreateInArchive(int formatIndex, CMyComPtr<IInArchive> &archive) const
+ {
+ const CArcInfoEx &ai = Formats[formatIndex];
+ #ifdef EXTERNAL_CODECS
+ if (ai.LibIndex < 0)
+ #endif
+ {
+ archive = ai.CreateInArchive();
+ return S_OK;
+ }
+ #ifdef EXTERNAL_CODECS
+ return CreateArchiveHandler(ai, (void **)&archive, false);
+ #endif
+ }
+ HRESULT CreateOutArchive(int formatIndex, CMyComPtr<IOutArchive> &archive) const
+ {
+ const CArcInfoEx &ai = Formats[formatIndex];
+ #ifdef EXTERNAL_CODECS
+ if (ai.LibIndex < 0)
+ #endif
+ {
+ archive = ai.CreateOutArchive();
+ return S_OK;
+ }
+ #ifdef EXTERNAL_CODECS
+ return CreateArchiveHandler(ai, (void **)&archive, true);
+ #endif
+ }
+ int FindOutFormatFromName(const UString &name) const
+ {
+ for (int i = 0; i < Formats.Size(); i++)
+ {
+ const CArcInfoEx &arc = Formats[i];
+ if (!arc.UpdateEnabled)
+ continue;
+ if (arc.Name.CompareNoCase(name) == 0)
+ return i;
+ }
+ return -1;
+ }
+
+ #ifdef EXTERNAL_CODECS
+ HRESULT CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const;
+ #endif
+
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp
new file mode 100644
index 000000000..56a630467
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.cpp
@@ -0,0 +1,536 @@
+// OpenArchive.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "DefaultName.h"
+#include "OpenArchive.h"
+
+using namespace NWindows;
+
+// Static-SFX (for Linux) can be big.
+const UInt64 kMaxCheckStartPosition = 1 << 22;
+
+HRESULT GetArchiveItemBoolProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
+{
+ NCOM::CPropVariant prop;
+ result = false;
+ RINOK(archive->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_BOOL)
+ result = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
+{
+ return GetArchiveItemBoolProp(archive, index, kpidIsDir, result);
+}
+
+HRESULT CArc::GetItemPath(UInt32 index, UString &result) const
+{
+ {
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidPath, &prop));
+ if (prop.vt == VT_BSTR)
+ result = prop.bstrVal;
+ else if (prop.vt == VT_EMPTY)
+ result.Empty();
+ else
+ return E_FAIL;
+ }
+ if (result.IsEmpty())
+ {
+ result = DefaultName;
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidExtension, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ result += L'.';
+ result += prop.bstrVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const
+{
+ NCOM::CPropVariant prop;
+ defined = false;
+ ft.dwHighDateTime = ft.dwLowDateTime = 0;
+ RINOK(Archive->GetProperty(index, kpidMTime, &prop));
+ if (prop.vt == VT_FILETIME)
+ {
+ ft = prop.filetime;
+ defined = true;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ else if (MTimeDefined)
+ {
+ ft = MTime;
+ defined = true;
+ }
+ return S_OK;
+}
+
+#ifndef _SFX
+static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ if (p1[i] != p2[i])
+ return false;
+ return true;
+}
+#endif
+
+#ifdef UNDER_CE
+static const int kNumHashBytes = 1;
+#define HASH_VAL(buf, pos) ((buf)[pos])
+#else
+static const int kNumHashBytes = 2;
+#define HASH_VAL(buf, pos) ((buf)[pos] | ((UInt32)(buf)[pos + 1] << 8))
+#endif
+
+
+HRESULT CArc::OpenStream(
+ CCodecs *codecs,
+ int formatIndex,
+ IInStream *stream,
+ ISequentialInStream *seqStream,
+ IArchiveOpenCallback *callback)
+{
+ Archive.Release();
+ ErrorMessage.Empty();
+ const UString fileName = ExtractFileNameFromPath(Path);
+ UString extension;
+ {
+ int dotPos = fileName.ReverseFind(L'.');
+ if (dotPos >= 0)
+ extension = fileName.Mid(dotPos + 1);
+ }
+ CIntVector orderIndices;
+ if (formatIndex >= 0)
+ orderIndices.Add(formatIndex);
+ else
+ {
+
+ int i;
+ int numFinded = 0;
+ for (i = 0; i < codecs->Formats.Size(); i++)
+ if (codecs->Formats[i].FindExtension(extension) >= 0)
+ orderIndices.Insert(numFinded++, i);
+ else
+ orderIndices.Add(i);
+
+ if (!stream)
+ {
+ if (numFinded != 1)
+ return E_NOTIMPL;
+ orderIndices.DeleteFrom(1);
+ }
+
+ #ifndef _SFX
+ if (orderIndices.Size() >= 2 && (numFinded == 0 || extension.CompareNoCase(L"exe") == 0))
+ {
+ CIntVector orderIndices2;
+ CByteBuffer byteBuffer;
+ const size_t kBufferSize = (1 << 21);
+ byteBuffer.SetCapacity(kBufferSize);
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ size_t processedSize = kBufferSize;
+ RINOK(ReadStream(stream, byteBuffer, &processedSize));
+ if (processedSize == 0)
+ return S_FALSE;
+
+ const Byte *buf = byteBuffer;
+ CByteBuffer hashBuffer;
+ const UInt32 kNumVals = 1 << (kNumHashBytes * 8);
+ hashBuffer.SetCapacity(kNumVals);
+ Byte *hash = hashBuffer;
+ memset(hash, 0xFF, kNumVals);
+ Byte prevs[256];
+ if (orderIndices.Size() >= 256)
+ return S_FALSE;
+ int i;
+ for (i = 0; i < orderIndices.Size(); i++)
+ {
+ const CArcInfoEx &ai = codecs->Formats[orderIndices[i]];
+ const CByteBuffer &sig = ai.StartSignature;
+ if (sig.GetCapacity() < kNumHashBytes)
+ continue;
+ UInt32 v = HASH_VAL(sig, 0);
+ prevs[i] = hash[v];
+ hash[v] = (Byte)i;
+ }
+
+ processedSize -= (kNumHashBytes - 1);
+ for (UInt32 pos = 0; pos < processedSize; pos++)
+ {
+ for (; pos < processedSize && hash[HASH_VAL(buf, pos)] == 0xFF; pos++);
+ if (pos == processedSize)
+ break;
+ UInt32 v = HASH_VAL(buf, pos);
+ Byte *ptr = &hash[v];
+ int i = *ptr;
+ do
+ {
+ int index = orderIndices[i];
+ const CArcInfoEx &ai = codecs->Formats[index];
+ const CByteBuffer &sig = ai.StartSignature;
+ if (sig.GetCapacity() != 0 && pos + sig.GetCapacity() <= processedSize + (kNumHashBytes - 1) &&
+ TestSignature(buf + pos, sig, sig.GetCapacity()))
+ {
+ orderIndices2.Add(index);
+ orderIndices[i] = 0xFF;
+ *ptr = prevs[i];
+ }
+ else
+ ptr = &prevs[i];
+ i = *ptr;
+ }
+ while (i != 0xFF);
+ }
+
+ for (i = 0; i < orderIndices.Size(); i++)
+ {
+ int val = orderIndices[i];
+ if (val != 0xFF)
+ orderIndices2.Add(val);
+ }
+ orderIndices = orderIndices2;
+ }
+ else if (extension == L"000" || extension == L"001")
+ {
+ CByteBuffer byteBuffer;
+ const size_t kBufferSize = (1 << 10);
+ byteBuffer.SetCapacity(kBufferSize);
+ Byte *buffer = byteBuffer;
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ size_t processedSize = kBufferSize;
+ RINOK(ReadStream(stream, buffer, &processedSize));
+ if (processedSize >= 16)
+ {
+ Byte kRarHeader[] = {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
+ if (TestSignature(buffer, kRarHeader, 7) && buffer[9] == 0x73 && (buffer[10] & 1) != 0)
+ {
+ for (int i = 0; i < orderIndices.Size(); i++)
+ {
+ int index = orderIndices[i];
+ const CArcInfoEx &ai = codecs->Formats[index];
+ if (ai.Name.CompareNoCase(L"rar") != 0)
+ continue;
+ orderIndices.Delete(i--);
+ orderIndices.Insert(0, index);
+ break;
+ }
+ }
+ }
+ }
+ if (orderIndices.Size() >= 2)
+ {
+ int isoIndex = codecs->FindFormatForArchiveType(L"iso");
+ int udfIndex = codecs->FindFormatForArchiveType(L"udf");
+ int iIso = -1;
+ int iUdf = -1;
+ for (int i = 0; i < orderIndices.Size(); i++)
+ {
+ if (orderIndices[i] == isoIndex) iIso = i;
+ if (orderIndices[i] == udfIndex) iUdf = i;
+ }
+ if (iUdf > iIso && iIso >= 0)
+ {
+ orderIndices[iUdf] = isoIndex;
+ orderIndices[iIso] = udfIndex;
+ }
+ }
+
+ #endif
+ }
+
+ for (int i = 0; i < orderIndices.Size(); i++)
+ {
+ if (stream)
+ {
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ }
+ CMyComPtr<IInArchive> archive;
+
+ FormatIndex = orderIndices[i];
+ RINOK(codecs->CreateInArchive(FormatIndex, archive));
+ if (!archive)
+ continue;
+
+ #ifdef EXTERNAL_CODECS
+ {
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
+ }
+ }
+ #endif
+
+ // OutputDebugStringW(codecs->Formats[FormatIndex].Name);
+
+ HRESULT result;
+ if (stream)
+ result = archive->Open(stream, &kMaxCheckStartPosition, callback);
+ else
+ {
+ CMyComPtr<IArchiveOpenSeq> openSeq;
+ archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq);
+ if (!openSeq)
+ return E_NOTIMPL;
+ result = openSeq->OpenSeq(seqStream);
+ }
+
+ if (result == S_FALSE)
+ continue;
+ RINOK(result);
+
+ {
+ NCOM::CPropVariant prop;
+ archive->GetArchiveProperty(kpidError, &prop);
+ if (prop.vt != VT_EMPTY)
+ ErrorMessage = (prop.vt == VT_BSTR) ? prop.bstrVal : L"Unknown error";
+ }
+
+ Archive = archive;
+ const CArcInfoEx &format = codecs->Formats[FormatIndex];
+ if (format.Exts.Size() == 0)
+ DefaultName = GetDefaultName2(fileName, L"", L"");
+ else
+ {
+ int subExtIndex = format.FindExtension(extension);
+ if (subExtIndex < 0)
+ subExtIndex = 0;
+ const CArcExtInfo &extInfo = format.Exts[subExtIndex];
+ DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt);
+ }
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+HRESULT CArc::OpenStreamOrFile(
+ CCodecs *codecs,
+ int formatIndex,
+ bool stdInMode,
+ IInStream *stream,
+ IArchiveOpenCallback *callback)
+{
+ CMyComPtr<IInStream> fileStream;
+ CMyComPtr<ISequentialInStream> seqStream;
+ if (stdInMode)
+ seqStream = new CStdInFileStream;
+ else if (!stream)
+ {
+ CInFileStream *fileStreamSpec = new CInFileStream;
+ fileStream = fileStreamSpec;
+ if (!fileStreamSpec->Open(Path))
+ return GetLastError();
+ stream = fileStream;
+ }
+
+ /*
+ if (callback)
+ {
+ UInt64 fileSize;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize));
+ RINOK(callback->SetTotal(NULL, &fileSize))
+ }
+ */
+
+ return OpenStream(codecs, formatIndex, stream, seqStream, callback);
+}
+
+HRESULT CArchiveLink::Close()
+{
+ for (int i = Arcs.Size() - 1; i >= 0; i--)
+ {
+ RINOK(Arcs[i].Archive->Close());
+ }
+ IsOpen = false;
+ return S_OK;
+}
+
+void CArchiveLink::Release()
+{
+ while (!Arcs.IsEmpty())
+ Arcs.DeleteBack();
+}
+
+HRESULT CArchiveLink::Open(
+ CCodecs *codecs,
+ const CIntVector &formatIndices,
+ bool stdInMode,
+ IInStream *stream,
+ const UString &filePath,
+ IArchiveOpenCallback *callback)
+{
+ Release();
+ if (formatIndices.Size() >= 32)
+ return E_NOTIMPL;
+
+ HRESULT resSpec;
+
+ for (;;)
+ {
+ resSpec = S_OK;
+ int formatIndex = -1;
+ if (formatIndices.Size() >= 1)
+ {
+ if (Arcs.Size() >= formatIndices.Size())
+ break;
+ formatIndex = formatIndices[formatIndices.Size() - Arcs.Size() - 1];
+ }
+ else if (Arcs.Size() >= 32)
+ break;
+
+ if (Arcs.IsEmpty())
+ {
+ CArc arc;
+ arc.Path = filePath;
+ arc.SubfileIndex = (UInt32)(Int32)-1;
+ RINOK(arc.OpenStreamOrFile(codecs, formatIndex, stdInMode, stream, callback));
+ Arcs.Add(arc);
+ continue;
+ }
+
+ const CArc &arc = Arcs.Back();
+
+ resSpec = (formatIndices.Size() == 0 ? S_OK : E_NOTIMPL);
+
+ UInt32 mainSubfile;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop));
+ if (prop.vt == VT_UI4)
+ mainSubfile = prop.ulVal;
+ else
+ break;
+ UInt32 numItems;
+ RINOK(arc.Archive->GetNumberOfItems(&numItems));
+ if (mainSubfile >= numItems)
+ break;
+ }
+
+
+ CMyComPtr<IInArchiveGetStream> getStream;
+ if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream)
+ break;
+
+ CMyComPtr<ISequentialInStream> subSeqStream;
+ if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream)
+ break;
+
+ CMyComPtr<IInStream> subStream;
+ if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream)
+ break;
+
+ CArc arc2;
+ RINOK(arc.GetItemPath(mainSubfile, arc2.Path));
+
+ CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
+ callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
+ if (setSubArchiveName)
+ setSubArchiveName->SetSubArchiveName(arc2.Path);
+
+ arc2.SubfileIndex = mainSubfile;
+ HRESULT result = arc2.OpenStream(codecs, formatIndex, subStream, NULL, callback);
+ resSpec = (formatIndices.Size() == 0 ? S_OK : S_FALSE);
+ if (result == S_FALSE)
+ break;
+ RINOK(result);
+ RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined));
+ Arcs.Add(arc2);
+ }
+ IsOpen = !Arcs.IsEmpty();
+ return S_OK;
+}
+
+static void SetCallback(const UString &filePath,
+ IOpenCallbackUI *callbackUI,
+ IArchiveOpenCallback *reOpenCallback,
+ CMyComPtr<IArchiveOpenCallback> &callback)
+{
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ callback = openCallbackSpec;
+ openCallbackSpec->Callback = callbackUI;
+ openCallbackSpec->ReOpenCallback = reOpenCallback;
+
+ UString fullName;
+ int fileNamePartStartIndex;
+ NFile::NDirectory::MyGetFullPathName(filePath, fullName, fileNamePartStartIndex);
+ openCallbackSpec->Init(
+ fullName.Left(fileNamePartStartIndex),
+ fullName.Mid(fileNamePartStartIndex));
+}
+
+HRESULT CArchiveLink::Open2(CCodecs *codecs,
+ const CIntVector &formatIndices,
+ bool stdInMode,
+ IInStream *stream,
+ const UString &filePath,
+ IOpenCallbackUI *callbackUI)
+{
+ VolumesSize = 0;
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec;
+ openCallbackSpec->Callback = callbackUI;
+
+ UString fullName, prefix, name;
+ if (!stream && !stdInMode)
+ {
+ int fileNamePartStartIndex;
+ if (!NFile::NDirectory::MyGetFullPathName(filePath, fullName, fileNamePartStartIndex))
+ return GetLastError();
+ prefix = fullName.Left(fileNamePartStartIndex);
+ name = fullName.Mid(fileNamePartStartIndex);
+ openCallbackSpec->Init(prefix, name);
+ }
+ else
+ {
+ openCallbackSpec->SetSubArchiveName(filePath);
+ }
+
+ RINOK(Open(codecs, formatIndices, stdInMode, stream, filePath, callback));
+ VolumePaths.Add(prefix + name);
+ for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
+ VolumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
+ VolumesSize = openCallbackSpec->TotalSize;
+ return S_OK;
+}
+
+HRESULT CArchiveLink::ReOpen(CCodecs *codecs, const UString &filePath,
+ IArchiveOpenCallback *callback)
+{
+ if (Arcs.Size() > 1)
+ return E_NOTIMPL;
+
+ if (Arcs.Size() == 0)
+ return Open2(codecs, CIntVector(), false, NULL, filePath, 0);
+
+ CMyComPtr<IArchiveOpenCallback> openCallbackNew;
+ SetCallback(filePath, NULL, callback, openCallbackNew);
+
+ CInFileStream *fileStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> stream(fileStreamSpec);
+ if (!fileStreamSpec->Open(filePath))
+ return GetLastError();
+ HRESULT res = GetArchive()->Open(stream, &kMaxCheckStartPosition, callback);
+ IsOpen = (res == S_OK);
+ return res;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h b/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h
new file mode 100644
index 000000000..4a003ee63
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/OpenArchive.h
@@ -0,0 +1,87 @@
+// OpenArchive.h
+
+#ifndef __OPEN_ARCHIVE_H
+#define __OPEN_ARCHIVE_H
+
+#include "Common/MyString.h"
+
+#include "Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ArchiveOpenCallback.h"
+#include "LoadCodecs.h"
+
+HRESULT GetArchiveItemBoolProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result);
+HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result);
+
+struct CArc
+{
+ CMyComPtr<IInArchive> Archive;
+ UString Path;
+ UString DefaultName;
+ int FormatIndex;
+ int SubfileIndex;
+ FILETIME MTime;
+ bool MTimeDefined;
+ UString ErrorMessage;
+
+ CArc(): MTimeDefined(false) {}
+
+ HRESULT GetItemPath(UInt32 index, UString &result) const;
+ HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const;
+ HRESULT IsItemAnti(UInt32 index, bool &result) const
+ { return GetArchiveItemBoolProp(Archive, index, kpidIsAnti, result); }
+
+ HRESULT OpenStream(
+ CCodecs *codecs,
+ int formatIndex,
+ IInStream *stream,
+ ISequentialInStream *seqStream,
+ IArchiveOpenCallback *callback);
+
+ HRESULT OpenStreamOrFile(
+ CCodecs *codecs,
+ int formatIndex,
+ bool stdInMode,
+ IInStream *stream,
+ IArchiveOpenCallback *callback);
+};
+
+struct CArchiveLink
+{
+ CObjectVector<CArc> Arcs;
+ UStringVector VolumePaths;
+ UInt64 VolumesSize;
+ bool IsOpen;
+
+ CArchiveLink(): VolumesSize(0), IsOpen(false) {}
+ HRESULT Close();
+ void Release();
+ ~CArchiveLink() { Release(); }
+
+ IInArchive *GetArchive() const { return Arcs.Back().Archive; }
+
+ HRESULT Open(
+ CCodecs *codecs,
+ const CIntVector &formatIndices,
+ bool stdInMode,
+ IInStream *stream,
+ const UString &filePath,
+ IArchiveOpenCallback *callback);
+
+ HRESULT Open2(
+ CCodecs *codecs,
+ const CIntVector &formatIndices,
+ bool stdInMode,
+ IInStream *stream,
+ const UString &filePath,
+ IOpenCallbackUI *callbackUI);
+
+ HRESULT ReOpen(
+ CCodecs *codecs,
+ const UString &filePath,
+ IArchiveOpenCallback *callback);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp
new file mode 100644
index 000000000..dacaca5f9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.cpp
@@ -0,0 +1,120 @@
+// PropIDUtils.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+
+#include "Windows/FileFind.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../PropID.h"
+
+#include "PropIDUtils.h"
+
+using namespace NWindows;
+
+void ConvertUInt32ToHex(UInt32 value, wchar_t *s)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ int t = value & 0xF;
+ value >>= 4;
+ s[7 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));
+ }
+ s[8] = L'\0';
+}
+
+static const char g_WinAttrib[17] = "RHS8DAdNTsrCOnE_";
+/*
+0 READONLY
+1 HIDDEN
+3 SYSTEM
+
+4 DIRECTORY
+5 ARCHIVE
+6 DEVICE
+7 NORMAL
+8 TEMPORARY
+9 SPARSE_FILE
+10 REPARSE_POINT
+11 COMPRESSED
+12 OFFLINE
+13 NOT_CONTENT_INDEXED
+14 ENCRYPTED
+
+16 VIRTUAL
+*/
+
+static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
+#define MY_ATTR_CHAR(a, n, c) ((a )& (1 << (n))) ? c : L'-';
+
+UString ConvertPropertyToString(const PROPVARIANT &prop, PROPID propID, bool full)
+{
+ switch(propID)
+ {
+ case kpidCTime:
+ case kpidATime:
+ case kpidMTime:
+ {
+ if (prop.vt != VT_FILETIME)
+ break;
+ FILETIME localFileTime;
+ if ((prop.filetime.dwHighDateTime == 0 &&
+ prop.filetime.dwLowDateTime == 0) ||
+ !::FileTimeToLocalFileTime(&prop.filetime, &localFileTime))
+ return UString();
+ return ConvertFileTimeToString(localFileTime, true, full);
+ }
+ case kpidCRC:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ wchar_t temp[12];
+ ConvertUInt32ToHex(prop.ulVal, temp);
+ return temp;
+ }
+ case kpidAttrib:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ UInt32 a = prop.ulVal;
+ wchar_t sz[32];
+ int pos = 0;
+ for (int i = 0; i < 16; i++)
+ if (a & (1 << i) && i != 7)
+ sz[pos++] = g_WinAttrib[i];
+ sz[pos] = '\0';
+ return sz;
+ }
+ case kpidPosixAttrib:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ UString res;
+ UInt32 a = prop.ulVal;
+ wchar_t temp[16];
+
+ temp[0] = kPosixTypes[(a >> 12) & 0xF];
+ for (int i = 6; i >= 0; i -= 3)
+ {
+ temp[7 - i] = MY_ATTR_CHAR(a, i + 2, L'r');
+ temp[8 - i] = MY_ATTR_CHAR(a, i + 1, L'w');
+ temp[9 - i] = MY_ATTR_CHAR(a, i + 0, L'x');
+ }
+ if ((a & 0x800) != 0) temp[3] = ((a & (1 << 6)) ? 's' : 'S');
+ if ((a & 0x400) != 0) temp[6] = ((a & (1 << 3)) ? 's' : 'S');
+ if ((a & 0x200) != 0) temp[9] = ((a & (1 << 0)) ? 't' : 'T');
+ temp[10] = 0;
+ res = temp;
+
+ a &= ~(UInt32)0xFFFF;
+ if (a != 0)
+ {
+ ConvertUInt32ToHex(a, temp);
+ res = UString(temp) + L' ' + res;
+ }
+ return res;
+ }
+ }
+ return ConvertPropVariantToString(prop);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h b/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h
new file mode 100644
index 000000000..ca14d091d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/PropIDUtils.h
@@ -0,0 +1,12 @@
+// PropIDUtils.h
+
+#ifndef __PROPID_UTILS_H
+#define __PROPID_UTILS_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+void ConvertUInt32ToHex(UInt32 value, wchar_t *s);
+UString ConvertPropertyToString(const PROPVARIANT &propVariant, PROPID propID, bool full = true);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Property.h b/src/libs/7zip/win/CPP/7zip/UI/Common/Property.h
new file mode 100644
index 000000000..9fd340cbc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Property.h
@@ -0,0 +1,14 @@
+// Property.h
+
+#ifndef __PROPERTY_H
+#define __PROPERTY_H
+
+#include "Common/MyString.h"
+
+struct CProperty
+{
+ UString Name;
+ UString Value;
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp
new file mode 100644
index 000000000..4827f2a78
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.cpp
@@ -0,0 +1,79 @@
+// SetProperties.cpp
+
+#include "StdAfx.h"
+
+#include "SetProperties.h"
+
+#include "Windows/PropVariant.h"
+#include "Common/MyString.h"
+#include "Common/StringToInt.h"
+#include "Common/MyCom.h"
+
+#include "../../Archive/IArchive.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
+{
+ const wchar_t *endPtr;
+ UInt64 result = ConvertStringToUInt64(s, &endPtr);
+ if (endPtr - (const wchar_t *)s != s.Length())
+ prop = s;
+ else if (result <= 0xFFFFFFFF)
+ prop = (UInt32)result;
+ else
+ prop = result;
+}
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
+{
+ if (properties.IsEmpty())
+ return S_OK;
+ CMyComPtr<ISetProperties> setProperties;
+ unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);
+ if (!setProperties)
+ return S_OK;
+
+ UStringVector realNames;
+ CPropVariant *values = new CPropVariant[properties.Size()];
+ try
+ {
+ int i;
+ for(i = 0; i < properties.Size(); i++)
+ {
+ const CProperty &property = properties[i];
+ NCOM::CPropVariant propVariant;
+ UString name = property.Name;
+ if (property.Value.IsEmpty())
+ {
+ if (!name.IsEmpty())
+ {
+ wchar_t c = name[name.Length() - 1];
+ if (c == L'-')
+ propVariant = false;
+ else if (c == L'+')
+ propVariant = true;
+ if (propVariant.vt != VT_EMPTY)
+ name = name.Left(name.Length() - 1);
+ }
+ }
+ else
+ ParseNumberString(property.Value, propVariant);
+ realNames.Add(name);
+ values[i] = propVariant;
+ }
+ CRecordVector<const wchar_t *> names;
+ for(i = 0; i < realNames.Size(); i++)
+ names.Add((const wchar_t *)realNames[i]);
+
+ RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
+ }
+ catch(...)
+ {
+ delete []values;
+ throw;
+ }
+ delete []values;
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.h b/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.h
new file mode 100644
index 000000000..892f1a210
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/SetProperties.h
@@ -0,0 +1,10 @@
+// SetProperties.h
+
+#ifndef __SETPROPERTIES_H
+#define __SETPROPERTIES_H
+
+#include "Property.h"
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp
new file mode 100644
index 000000000..061e77730
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.cpp
@@ -0,0 +1,22 @@
+// SortUtils.cpp
+
+#include "StdAfx.h"
+
+#include "SortUtils.h"
+#include "Common/Wildcard.h"
+
+static int CompareStrings(const int *p1, const int *p2, void *param)
+{
+ const UStringVector &strings = *(const UStringVector *)param;
+ return CompareFileNames(strings[*p1], strings[*p2]);
+}
+
+void SortFileNames(const UStringVector &strings, CIntVector &indices)
+{
+ indices.Clear();
+ int numItems = strings.Size();
+ indices.Reserve(numItems);
+ for(int i = 0; i < numItems; i++)
+ indices.Add(i);
+ indices.Sort(CompareStrings, (void *)&strings);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h b/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h
new file mode 100644
index 000000000..e15224611
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/SortUtils.h
@@ -0,0 +1,10 @@
+// SortUtils.h
+
+#ifndef __SORTUTLS_H
+#define __SORTUTLS_H
+
+#include "Common/MyString.h"
+
+void SortFileNames(const UStringVector &strings, CIntVector &indices);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h b/src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h
new file mode 100644
index 000000000..9a8e7d21a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/StdAfx.h
@@ -0,0 +1,9 @@
+// stdafx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp
new file mode 100644
index 000000000..eeaec1802
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.cpp
@@ -0,0 +1,22 @@
+// TempFiles.cpp
+
+#include "StdAfx.h"
+
+#include "TempFiles.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileIO.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+void CTempFiles::Clear()
+{
+ while(!Paths.IsEmpty())
+ {
+ NDirectory::DeleteFileAlways((LPCWSTR)Paths.Back());
+ Paths.DeleteBack();
+ }
+}
+
+
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h b/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h
new file mode 100644
index 000000000..eb474a760
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/TempFiles.h
@@ -0,0 +1,16 @@
+// TempFiles.h
+
+#ifndef __TEMPFILES_H
+#define __TEMPFILES_H
+
+#include "Common/MyString.h"
+
+class CTempFiles
+{
+ void Clear();
+public:
+ UStringVector Paths;
+ ~CTempFiles() { Clear(); }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp
new file mode 100644
index 000000000..a57ec2a6b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Update.cpp
@@ -0,0 +1,910 @@
+// Update.cpp
+
+#include "StdAfx.h"
+
+#include "Update.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#ifdef _WIN32
+#include "Windows/DLL.h"
+#endif
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/FileName.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+#include "Windows/Time.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/DirItem.h"
+#include "../Common/EnumDirItems.h"
+#include "../Common/OpenArchive.h"
+#include "../Common/UpdateProduce.h"
+
+#include "EnumDirItems.h"
+#include "SetProperties.h"
+#include "TempFiles.h"
+#include "UpdateCallback.h"
+
+static const char *kUpdateIsNotSupoorted =
+ "update operations are not supported for this archive";
+
+using namespace NWindows;
+using namespace NCOM;
+using namespace NFile;
+using namespace NName;
+
+static const wchar_t *kTempFolderPrefix = L"7zE";
+
+using namespace NUpdateArchive;
+
+class COutMultiVolStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+ int _streamIndex; // required stream
+ UInt64 _offsetPos; // offset from start of _streamIndex index
+ UInt64 _absPos;
+ UInt64 _length;
+
+ struct CSubStreamInfo
+ {
+ COutFileStream *StreamSpec;
+ CMyComPtr<IOutStream> Stream;
+ UString Name;
+ UInt64 Pos;
+ UInt64 RealSize;
+ };
+ CObjectVector<CSubStreamInfo> Streams;
+public:
+ // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ CRecordVector<UInt64> Sizes;
+ UString Prefix;
+ CTempFiles *TempFiles;
+
+ void Init()
+ {
+ _streamIndex = 0;
+ _offsetPos = 0;
+ _absPos = 0;
+ _length = 0;
+ }
+
+ HRESULT Close();
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(UInt64 newSize);
+};
+
+// static NSynchronization::CCriticalSection g_TempPathsCS;
+
+HRESULT COutMultiVolStream::Close()
+{
+ HRESULT res = S_OK;
+ for (int i = 0; i < Streams.Size(); i++)
+ {
+ CSubStreamInfo &s = Streams[i];
+ if (s.StreamSpec)
+ {
+ HRESULT res2 = s.StreamSpec->Close();
+ if (res2 != S_OK)
+ res = res2;
+ }
+ }
+ return res;
+}
+
+STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != NULL)
+ *processedSize = 0;
+ while(size > 0)
+ {
+ if (_streamIndex >= Streams.Size())
+ {
+ CSubStreamInfo subStream;
+
+ wchar_t temp[16];
+ ConvertUInt32ToString(_streamIndex + 1, temp);
+ UString res = temp;
+ while (res.Length() < 3)
+ res = UString(L'0') + res;
+ UString name = Prefix + res;
+ subStream.StreamSpec = new COutFileStream;
+ subStream.Stream = subStream.StreamSpec;
+ if (!subStream.StreamSpec->Create(name, false))
+ return ::GetLastError();
+ {
+ // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);
+ TempFiles->Paths.Add(name);
+ }
+
+ subStream.Pos = 0;
+ subStream.RealSize = 0;
+ subStream.Name = name;
+ Streams.Add(subStream);
+ continue;
+ }
+ CSubStreamInfo &subStream = Streams[_streamIndex];
+
+ int index = _streamIndex;
+ if (index >= Sizes.Size())
+ index = Sizes.Size() - 1;
+ UInt64 volSize = Sizes[index];
+
+ if (_offsetPos >= volSize)
+ {
+ _offsetPos -= volSize;
+ _streamIndex++;
+ continue;
+ }
+ if (_offsetPos != subStream.Pos)
+ {
+ // CMyComPtr<IOutStream> outStream;
+ // RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
+ RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
+ subStream.Pos = _offsetPos;
+ }
+
+ UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos);
+ UInt32 realProcessed;
+ RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
+ data = (void *)((Byte *)data + realProcessed);
+ size -= realProcessed;
+ subStream.Pos += realProcessed;
+ _offsetPos += realProcessed;
+ _absPos += realProcessed;
+ if (_absPos > _length)
+ _length = _absPos;
+ if (_offsetPos > subStream.RealSize)
+ subStream.RealSize = _offsetPos;
+ if (processedSize != NULL)
+ *processedSize += realProcessed;
+ if (subStream.Pos == volSize)
+ {
+ _streamIndex++;
+ _offsetPos = 0;
+ }
+ if (realProcessed == 0 && curSize != 0)
+ return E_FAIL;
+ break;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ if (seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+ switch(seekOrigin)
+ {
+ case STREAM_SEEK_SET:
+ _absPos = offset;
+ break;
+ case STREAM_SEEK_CUR:
+ _absPos += offset;
+ break;
+ case STREAM_SEEK_END:
+ _absPos = _length + offset;
+ break;
+ }
+ _offsetPos = _absPos;
+ if (newPosition != NULL)
+ *newPosition = _absPos;
+ _streamIndex = 0;
+ return S_OK;
+}
+
+STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize)
+{
+ if (newSize < 0)
+ return E_INVALIDARG;
+ int i = 0;
+ while (i < Streams.Size())
+ {
+ CSubStreamInfo &subStream = Streams[i++];
+ if ((UInt64)newSize < subStream.RealSize)
+ {
+ RINOK(subStream.Stream->SetSize(newSize));
+ subStream.RealSize = newSize;
+ break;
+ }
+ newSize -= subStream.RealSize;
+ }
+ while (i < Streams.Size())
+ {
+ {
+ CSubStreamInfo &subStream = Streams.Back();
+ subStream.Stream.Release();
+ NDirectory::DeleteFileAlways(subStream.Name);
+ }
+ Streams.DeleteBack();
+ }
+ _offsetPos = _absPos;
+ _streamIndex = 0;
+ _length = newSize;
+ return S_OK;
+}
+
+static const wchar_t *kDefaultArchiveType = L"7z";
+static const wchar_t *kSFXExtension =
+ #ifdef _WIN32
+ L"exe";
+ #else
+ L"";
+ #endif
+
+bool CUpdateOptions::Init(const CCodecs *codecs, const CIntVector &formatIndices, const UString &arcPath)
+{
+ if (formatIndices.Size() > 1)
+ return false;
+ int arcTypeIndex = -1;
+ if (formatIndices.Size() != 0)
+ arcTypeIndex = formatIndices[0];
+ if (arcTypeIndex >= 0)
+ MethodMode.FormatIndex = arcTypeIndex;
+ else
+ {
+ MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath);
+ // It works incorrectly for update command if archive has some non-default extension!
+ if (MethodMode.FormatIndex < 0)
+ MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveType);
+ }
+ if (MethodMode.FormatIndex < 0)
+ return false;
+ const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex];
+ if (!arcInfo.UpdateEnabled)
+ return false;
+ UString typeExt = arcInfo.GetMainExt();
+ UString ext = typeExt;
+ if (SfxMode)
+ ext = kSFXExtension;
+ ArchivePath.BaseExtension = ext;
+ ArchivePath.VolExtension = typeExt;
+ ArchivePath.ParseFromPath(arcPath);
+ for (int i = 0; i < Commands.Size(); i++)
+ {
+ CUpdateArchiveCommand &uc = Commands[i];
+ uc.ArchivePath.BaseExtension = ext;
+ uc.ArchivePath.VolExtension = typeExt;
+ uc.ArchivePath.ParseFromPath(uc.UserArchivePath);
+ }
+ return true;
+}
+
+/*
+struct CUpdateProduceCallbackImp: public IUpdateProduceCallback
+{
+ const CObjectVector<CArcItem> *_arcItems;
+ IUpdateCallbackUI *_callback;
+
+ CUpdateProduceCallbackImp(const CObjectVector<CArcItem> *a,
+ IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {}
+ virtual HRESULT ShowDeleteFile(int arcIndex);
+};
+
+HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex)
+{
+ return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name);
+}
+*/
+
+static HRESULT Compress(
+ CCodecs *codecs,
+ const CActionSet &actionSet,
+ IInArchive *archive,
+ const CCompressionMethodMode &compressionMethod,
+ CArchivePath &archivePath,
+ const CObjectVector<CArcItem> &arcItems,
+ bool shareForWrite,
+ bool stdInMode,
+ /* const UString & stdInFileName, */
+ bool stdOutMode,
+ const CDirItems &dirItems,
+ bool sfxMode,
+ const UString &sfxModule,
+ const CRecordVector<UInt64> &volumesSizes,
+ CTempFiles &tempFiles,
+ CUpdateErrorInfo &errorInfo,
+ IUpdateCallbackUI *callback)
+{
+ CMyComPtr<IOutArchive> outArchive;
+ if (archive != NULL)
+ {
+ CMyComPtr<IInArchive> archive2 = archive;
+ HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
+ if (result != S_OK)
+ throw kUpdateIsNotSupoorted;
+ }
+ else
+ {
+ RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive));
+
+ #ifdef EXTERNAL_CODECS
+ {
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
+ }
+ }
+ #endif
+ }
+ if (outArchive == 0)
+ throw kUpdateIsNotSupoorted;
+
+ NFileTimeType::EEnum fileTimeType;
+ UInt32 value;
+ RINOK(outArchive->GetFileTimeType(&value));
+
+ switch(value)
+ {
+ case NFileTimeType::kWindows:
+ case NFileTimeType::kUnix:
+ case NFileTimeType::kDOS:
+ fileTimeType = (NFileTimeType::EEnum)value;
+ break;
+ default:
+ return E_FAIL;
+ }
+
+ CRecordVector<CUpdatePair2> updatePairs2;
+
+ {
+ CRecordVector<CUpdatePair> updatePairs;
+ GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!!
+ // CUpdateProduceCallbackImp upCallback(&arcItems, callback);
+ UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */);
+ }
+
+ UInt32 numFiles = 0;
+ for (int i = 0; i < updatePairs2.Size(); i++)
+ if (updatePairs2[i].NewData)
+ numFiles++;
+
+ RINOK(callback->SetNumFiles(numFiles));
+
+
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ updateCallbackSpec->ShareForWrite = shareForWrite;
+ updateCallbackSpec->StdInMode = stdInMode;
+ updateCallbackSpec->Callback = callback;
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->ArcItems = &arcItems;
+ updateCallbackSpec->UpdatePairs = &updatePairs2;
+
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ if (!stdOutMode)
+ {
+ UString resultPath;
+ int pos;
+ if (!NFile::NDirectory::MyGetFullPathName(archivePath.GetFinalPath(), resultPath, pos))
+ throw 1417161;
+ NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
+ }
+
+ COutFileStream *outStreamSpec = NULL;
+ COutMultiVolStream *volStreamSpec = NULL;
+
+ if (volumesSizes.Size() == 0)
+ {
+ if (stdOutMode)
+ outStream = new CStdOutFileStream;
+ else
+ {
+ outStreamSpec = new COutFileStream;
+ outStream = outStreamSpec;
+ bool isOK = false;
+ UString realPath;
+ for (int i = 0; i < (1 << 16); i++)
+ {
+ if (archivePath.Temp)
+ {
+ if (i > 0)
+ {
+ wchar_t s[16];
+ ConvertUInt32ToString(i, s);
+ archivePath.TempPostfix = s;
+ }
+ realPath = archivePath.GetTempPath();
+ }
+ else
+ realPath = archivePath.GetFinalPath();
+ if (outStreamSpec->Create(realPath, false))
+ {
+ tempFiles.Paths.Add(realPath);
+ isOK = true;
+ break;
+ }
+ if (::GetLastError() != ERROR_FILE_EXISTS)
+ break;
+ if (!archivePath.Temp)
+ break;
+ }
+ if (!isOK)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.FileName = realPath;
+ errorInfo.Message = L"7-Zip cannot open file";
+ return E_FAIL;
+ }
+ }
+ }
+ else
+ {
+ if (stdOutMode)
+ return E_FAIL;
+ volStreamSpec = new COutMultiVolStream;
+ outStream = volStreamSpec;
+ volStreamSpec->Sizes = volumesSizes;
+ volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L".");
+ volStreamSpec->TempFiles = &tempFiles;
+ volStreamSpec->Init();
+
+ /*
+ updateCallbackSpec->VolumesSizes = volumesSizes;
+ updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
+ if (!archivePath.VolExtension.IsEmpty())
+ updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
+ */
+ }
+
+ RINOK(SetProperties(outArchive, compressionMethod.Properties));
+
+ if (sfxMode)
+ {
+ CInFileStream *sfxStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+ if (!sfxStreamSpec->Open(sfxModule))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot open SFX module";
+ errorInfo.FileName = sfxModule;
+ return E_FAIL;
+ }
+
+ CMyComPtr<ISequentialOutStream> sfxOutStream;
+ COutFileStream *outStreamSpec = NULL;
+ if (volumesSizes.Size() == 0)
+ sfxOutStream = outStream;
+ else
+ {
+ outStreamSpec = new COutFileStream;
+ sfxOutStream = outStreamSpec;
+ UString realPath = archivePath.GetFinalPath();
+ if (!outStreamSpec->Create(realPath, false))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.FileName = realPath;
+ errorInfo.Message = L"7-Zip cannot open file";
+ return E_FAIL;
+ }
+ }
+ RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL));
+ if (outStreamSpec)
+ {
+ RINOK(outStreamSpec->Close());
+ }
+ }
+
+ HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updateCallback);
+ callback->Finilize();
+ RINOK(result);
+ if (outStreamSpec)
+ result = outStreamSpec->Close();
+ else if (volStreamSpec)
+ result = volStreamSpec->Close();
+ return result;
+}
+
+HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
+ const CArc &arc,
+ CObjectVector<CArcItem> &arcItems)
+{
+ arcItems.Clear();
+ UInt32 numItems;
+ IInArchive *archive = arc.Archive;
+ RINOK(archive->GetNumberOfItems(&numItems));
+ arcItems.Reserve(numItems);
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CArcItem ai;
+
+ RINOK(arc.GetItemPath(i, ai.Name));
+ RINOK(IsArchiveItemFolder(archive, i, ai.IsDir));
+ ai.Censored = censor.CheckPath(ai.Name, !ai.IsDir);
+ RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined));
+
+ {
+ CPropVariant prop;
+ RINOK(archive->GetProperty(i, kpidSize, &prop));
+ ai.SizeDefined = (prop.vt != VT_EMPTY);
+ if (ai.SizeDefined)
+ ai.Size = ConvertPropVariantToUInt64(prop);
+ }
+
+ {
+ CPropVariant prop;
+ RINOK(archive->GetProperty(i, kpidTimeType, &prop));
+ if (prop.vt == VT_UI4)
+ {
+ ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal;
+ switch(ai.TimeType)
+ {
+ case NFileTimeType::kWindows:
+ case NFileTimeType::kUnix:
+ case NFileTimeType::kDOS:
+ break;
+ default:
+ return E_FAIL;
+ }
+ }
+ }
+
+ ai.IndexInServer = i;
+ arcItems.Add(ai);
+ }
+ return S_OK;
+}
+
+
+static HRESULT UpdateWithItemLists(
+ CCodecs *codecs,
+ CUpdateOptions &options,
+ IInArchive *archive,
+ const CObjectVector<CArcItem> &arcItems,
+ CDirItems &dirItems,
+ CTempFiles &tempFiles,
+ CUpdateErrorInfo &errorInfo,
+ IUpdateCallbackUI2 *callback)
+{
+ for(int i = 0; i < options.Commands.Size(); i++)
+ {
+ CUpdateArchiveCommand &command = options.Commands[i];
+ if (options.StdOutMode)
+ {
+ RINOK(callback->StartArchive(L"stdout", archive != 0));
+ }
+ else
+ {
+ RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(),
+ i == 0 && options.UpdateArchiveItself && archive != 0));
+ }
+
+ RINOK(Compress(
+ codecs,
+ command.ActionSet, archive,
+ options.MethodMode,
+ command.ArchivePath,
+ arcItems,
+ options.OpenShareForWrite,
+ options.StdInMode,
+ /* options.StdInFileName, */
+ options.StdOutMode,
+ dirItems,
+ options.SfxMode, options.SfxModule,
+ options.VolumesSizes,
+ tempFiles,
+ errorInfo, callback));
+
+ RINOK(callback->FinishArchive());
+ }
+ return S_OK;
+}
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+class CCurrentDirRestorer
+{
+ UString _path;
+public:
+ CCurrentDirRestorer() { NFile::NDirectory::MyGetCurrentDirectory(_path); }
+ ~CCurrentDirRestorer() { RestoreDirectory();}
+ bool RestoreDirectory() { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(_path)); }
+};
+#endif
+
+struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
+{
+ IUpdateCallbackUI2 *Callback;
+ HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path)
+ {
+ return Callback->ScanProgress(numFolders, numFiles, path);
+ }
+};
+
+#ifdef _WIN32
+typedef ULONG (FAR PASCAL MY_MAPISENDDOCUMENTS)(
+ ULONG_PTR ulUIParam,
+ LPSTR lpszDelimChar,
+ LPSTR lpszFilePaths,
+ LPSTR lpszFileNames,
+ ULONG ulReserved
+);
+typedef MY_MAPISENDDOCUMENTS FAR *MY_LPMAPISENDDOCUMENTS;
+#endif
+
+HRESULT UpdateArchive(
+ CCodecs *codecs,
+ const NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ CUpdateErrorInfo &errorInfo,
+ IOpenCallbackUI *openCallback,
+ IUpdateCallbackUI2 *callback)
+{
+ if (options.StdOutMode && options.EMailMode)
+ return E_FAIL;
+
+ if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode))
+ return E_NOTIMPL;
+
+ if (options.SfxMode)
+ {
+ CProperty property;
+ property.Name = L"rsfx";
+ property.Value = L"on";
+ options.MethodMode.Properties.Add(property);
+ if (options.SfxModule.IsEmpty())
+ {
+ errorInfo.Message = L"SFX file is not specified";
+ return E_FAIL;
+ }
+ UString name = options.SfxModule;
+ #ifdef UNDER_CE
+ if (!NFind::DoesFileExist(name))
+ #else
+ if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule))
+ #endif
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot find specified SFX module";
+ errorInfo.FileName = name;
+ return E_FAIL;
+ }
+ }
+
+
+ CArchiveLink arcLink;
+ const UString arcPath = options.ArchivePath.GetFinalPath();
+
+ if (!options.ArchivePath.OriginalPath.IsEmpty())
+ {
+ NFind::CFileInfoW fi;
+ if (fi.Find(arcPath))
+ {
+ if (fi.IsDir())
+ throw "there is no such archive";
+ if (options.VolumesSizes.Size() > 0)
+ return E_NOTIMPL;
+ CIntVector formatIndices;
+ if (options.MethodMode.FormatIndex >= 0)
+ formatIndices.Add(options.MethodMode.FormatIndex);
+ HRESULT result = arcLink.Open2(codecs, formatIndices, false, NULL, arcPath, openCallback);
+ if (result == E_ABORT)
+ return result;
+ RINOK(callback->OpenResult(arcPath, result));
+ RINOK(result);
+ if (arcLink.VolumePaths.Size() > 1)
+ {
+ errorInfo.SystemError = (DWORD)E_NOTIMPL;
+ errorInfo.Message = L"Updating for multivolume archives is not implemented";
+ return E_NOTIMPL;
+ }
+
+ CArc &arc = arcLink.Arcs.Back();
+ arc.MTimeDefined = !fi.IsDevice;
+ arc.MTime = fi.MTime;
+ }
+ }
+ else
+ {
+ /*
+ if (archiveType.IsEmpty())
+ throw "type of archive is not specified";
+ */
+ }
+
+ CDirItems dirItems;
+ if (options.StdInMode)
+ {
+ CDirItem di;
+ di.Name = options.StdInFileName;
+ di.Size = (UInt64)(Int64)-1;
+ di.Attrib = 0;
+ NTime::GetCurUtcFileTime(di.MTime);
+ di.CTime = di.ATime = di.MTime;
+ dirItems.Items.Add(di);
+ }
+ else
+ {
+ bool needScanning = false;
+ for(int i = 0; i < options.Commands.Size(); i++)
+ if (options.Commands[i].ActionSet.NeedScanning())
+ needScanning = true;
+ if (needScanning)
+ {
+ CEnumDirItemUpdateCallback enumCallback;
+ enumCallback.Callback = callback;
+ RINOK(callback->StartScanning());
+ UStringVector errorPaths;
+ CRecordVector<DWORD> errorCodes;
+ HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths, errorCodes);
+ for (int i = 0; i < errorPaths.Size(); i++)
+ {
+ RINOK(callback->CanNotFindError(errorPaths[i], errorCodes[i]));
+ }
+ if (res != S_OK)
+ {
+ if (res != E_ABORT)
+ errorInfo.Message = L"Scanning error";
+ return res;
+ }
+ RINOK(callback->FinishScanning());
+ }
+ }
+
+ UString tempDirPrefix;
+ bool usesTempDir = false;
+
+ #ifdef _WIN32
+ NDirectory::CTempDirectoryW tempDirectory;
+ if (options.EMailMode && options.EMailRemoveAfter)
+ {
+ tempDirectory.Create(kTempFolderPrefix);
+ tempDirPrefix = tempDirectory.GetPath();
+ NormalizeDirPathPrefix(tempDirPrefix);
+ usesTempDir = true;
+ }
+ #endif
+
+ CTempFiles tempFiles;
+
+ bool createTempFile = false;
+
+ bool thereIsInArchive = arcLink.IsOpen;
+
+ if (!options.StdOutMode && options.UpdateArchiveItself)
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ ap = options.ArchivePath;
+ // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
+ if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
+ {
+ createTempFile = true;
+ ap.Temp = true;
+ if (!options.WorkingDir.IsEmpty())
+ {
+ ap.TempPrefix = options.WorkingDir;
+ NormalizeDirPathPrefix(ap.TempPrefix);
+ }
+ }
+ }
+
+ for(int i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ if (usesTempDir)
+ {
+ // Check it
+ ap.Prefix = tempDirPrefix;
+ // ap.Temp = true;
+ // ap.TempPrefix = tempDirPrefix;
+ }
+ if (!options.StdOutMode &&
+ (i > 0 || !createTempFile))
+ {
+ const UString &path = ap.GetFinalPath();
+ if (NFind::DoesFileOrDirExist(path))
+ {
+ errorInfo.SystemError = 0;
+ errorInfo.Message = L"The file already exists";
+ errorInfo.FileName = path;
+ return E_FAIL;
+ }
+ }
+ }
+
+ CObjectVector<CArcItem> arcItems;
+ if (thereIsInArchive)
+ {
+ RINOK(EnumerateInArchiveItems(censor, arcLink.Arcs.Back(), arcItems));
+ }
+
+ RINOK(UpdateWithItemLists(codecs, options,
+ thereIsInArchive ? arcLink.GetArchive() : 0,
+ arcItems, dirItems,
+ tempFiles, errorInfo, callback));
+
+ if (thereIsInArchive)
+ {
+ RINOK(arcLink.Close());
+ arcLink.Release();
+ }
+
+ tempFiles.Paths.Clear();
+ if (createTempFile)
+ {
+ try
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ const UString &tempPath = ap.GetTempPath();
+ if (thereIsInArchive)
+ if (!NDirectory::DeleteFileAlways(arcPath))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot delete the file";
+ errorInfo.FileName = arcPath;
+ return E_FAIL;
+ }
+ if (!NDirectory::MyMoveFile(tempPath, arcPath))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot move the file";
+ errorInfo.FileName = tempPath;
+ errorInfo.FileName2 = arcPath;
+ return E_FAIL;
+ }
+ }
+ catch(...)
+ {
+ throw;
+ }
+ }
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (options.EMailMode)
+ {
+ NDLL::CLibrary mapiLib;
+ if (!mapiLib.Load(TEXT("Mapi32.dll")))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot load Mapi32.dll";
+ return E_FAIL;
+ }
+ MY_LPMAPISENDDOCUMENTS fnSend = (MY_LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments");
+ if (fnSend == 0)
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"7-Zip cannot find MAPISendDocuments function";
+ return E_FAIL;
+ }
+ UStringVector fullPaths;
+ int i;
+ for(i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ UString arcPath;
+ if (!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath))
+ {
+ errorInfo.SystemError = ::GetLastError();
+ errorInfo.Message = L"GetFullPathName error";
+ return E_FAIL;
+ }
+ fullPaths.Add(arcPath);
+ }
+ CCurrentDirRestorer curDirRestorer;
+ for(i = 0; i < fullPaths.Size(); i++)
+ {
+ UString arcPath = fullPaths[i];
+ UString fileName = ExtractFileNameFromPath(arcPath);
+ AString path = GetAnsiString(arcPath);
+ AString name = GetAnsiString(fileName);
+ // Warning!!! MAPISendDocuments function changes Current directory
+ fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
+ }
+ }
+ #endif
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/Update.h b/src/libs/7zip/win/CPP/7zip/UI/Common/Update.h
new file mode 100644
index 000000000..49af0092a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/Update.h
@@ -0,0 +1,175 @@
+// Update.h
+
+#ifndef __COMMON_UPDATE_H
+#define __COMMON_UPDATE_H
+
+#include "Common/Wildcard.h"
+
+#include "ArchiveOpenCallback.h"
+#include "LoadCodecs.h"
+#include "Property.h"
+#include "UpdateAction.h"
+#include "UpdateCallback.h"
+
+struct CArchivePath
+{
+ UString OriginalPath;
+
+ UString Prefix; // path(folder) prefix including slash
+ UString Name; // base name
+ UString BaseExtension; // archive type extension or "exe" extension
+ UString VolExtension; // archive type extension for volumes
+
+ bool Temp;
+ UString TempPrefix; // path(folder) for temp location
+ UString TempPostfix;
+
+ CArchivePath(): Temp(false) {};
+
+ void ParseFromPath(const UString &path)
+ {
+ OriginalPath = path;
+
+ SplitPathToParts(path, Prefix, Name);
+ int dotPos = Name.ReverseFind(L'.');
+ if (dotPos < 0)
+ return;
+ if (dotPos == Name.Length() - 1)
+ {
+ Name = Name.Left(dotPos);
+ BaseExtension.Empty();
+ return;
+ }
+ if (BaseExtension.CompareNoCase(Name.Mid(dotPos + 1)) == 0)
+ {
+ BaseExtension = Name.Mid(dotPos + 1);
+ Name = Name.Left(dotPos);
+ }
+ else
+ BaseExtension.Empty();
+ }
+
+ UString GetPathWithoutExt() const
+ {
+ return Prefix + Name;
+ }
+
+ UString GetFinalPath() const
+ {
+ UString path = GetPathWithoutExt();
+ if (!BaseExtension.IsEmpty())
+ path += UString(L'.') + BaseExtension;
+ return path;
+ }
+
+
+ UString GetTempPath() const
+ {
+ UString path = TempPrefix + Name;
+ if (!BaseExtension.IsEmpty())
+ path += UString(L'.') + BaseExtension;
+ path += L".tmp";
+ path += TempPostfix;
+ return path;
+ }
+};
+
+struct CUpdateArchiveCommand
+{
+ UString UserArchivePath;
+ CArchivePath ArchivePath;
+ NUpdateArchive::CActionSet ActionSet;
+};
+
+struct CCompressionMethodMode
+{
+ int FormatIndex;
+ CObjectVector<CProperty> Properties;
+ CCompressionMethodMode(): FormatIndex(-1) {}
+};
+
+struct CUpdateOptions
+{
+ CCompressionMethodMode MethodMode;
+
+ CObjectVector<CUpdateArchiveCommand> Commands;
+ bool UpdateArchiveItself;
+ CArchivePath ArchivePath;
+
+ bool SfxMode;
+ UString SfxModule;
+
+ bool OpenShareForWrite;
+
+ bool StdInMode;
+ UString StdInFileName;
+ bool StdOutMode;
+
+ bool EMailMode;
+ bool EMailRemoveAfter;
+ UString EMailAddress;
+
+ UString WorkingDir;
+
+ bool Init(const CCodecs *codecs, const CIntVector &formatIndices, const UString &arcPath);
+
+ CUpdateOptions():
+ UpdateArchiveItself(true),
+ SfxMode(false),
+ StdInMode(false),
+ StdOutMode(false),
+ EMailMode(false),
+ EMailRemoveAfter(false),
+ OpenShareForWrite(false)
+ {};
+
+ void SetAddActionCommand()
+ {
+ Commands.Clear();
+ CUpdateArchiveCommand c;
+ c.ActionSet = NUpdateArchive::kAddActionSet;
+ Commands.Add(c);
+ }
+
+ CRecordVector<UInt64> VolumesSizes;
+};
+
+struct CErrorInfo
+{
+ DWORD SystemError;
+ UString FileName;
+ UString FileName2;
+ UString Message;
+ // UStringVector ErrorPaths;
+ // CRecordVector<DWORD> ErrorCodes;
+ CErrorInfo(): SystemError(0) {};
+};
+
+struct CUpdateErrorInfo: public CErrorInfo
+{
+};
+
+#define INTERFACE_IUpdateCallbackUI2(x) \
+ INTERFACE_IUpdateCallbackUI(x) \
+ virtual HRESULT OpenResult(const wchar_t *name, HRESULT result) x; \
+ virtual HRESULT StartScanning() x; \
+ virtual HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) x; \
+ virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \
+ virtual HRESULT FinishScanning() x; \
+ virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \
+ virtual HRESULT FinishArchive() x; \
+
+struct IUpdateCallbackUI2: public IUpdateCallbackUI
+{
+ INTERFACE_IUpdateCallbackUI2(=0)
+};
+
+HRESULT UpdateArchive(
+ CCodecs *codecs,
+ const NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ CUpdateErrorInfo &errorInfo,
+ IOpenCallbackUI *openCallback,
+ IUpdateCallbackUI2 *callback);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp
new file mode 100644
index 000000000..879a49c57
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.cpp
@@ -0,0 +1,64 @@
+// UpdateAction.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateAction.h"
+
+namespace NUpdateArchive {
+
+const CActionSet kAddActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress
+}};
+
+const CActionSet kUpdateActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress
+}};
+
+const CActionSet kFreshActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress
+}};
+
+const CActionSet kSynchronizeActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+}};
+
+const CActionSet kDeleteActionSet =
+{{
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore
+}};
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.h b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.h
new file mode 100644
index 000000000..0ac1c1080
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateAction.h
@@ -0,0 +1,57 @@
+// UpdateAction.h
+
+#ifndef __UPDATE_ACTION_H
+#define __UPDATE_ACTION_H
+
+namespace NUpdateArchive {
+
+ namespace NPairState
+ {
+ const int kNumValues = 7;
+ enum EEnum
+ {
+ kNotMasked = 0,
+ kOnlyInArchive,
+ kOnlyOnDisk,
+ kNewInArchive,
+ kOldInArchive,
+ kSameFiles,
+ kUnknowNewerFiles
+ };
+ }
+
+ namespace NPairAction
+ {
+ enum EEnum
+ {
+ kIgnore = 0,
+ kCopy,
+ kCompress,
+ kCompressAsAnti
+ };
+ }
+
+ struct CActionSet
+ {
+ NPairAction::EEnum StateActions[NPairState::kNumValues];
+ bool NeedScanning() const
+ {
+ int i;
+ for (i = 0; i < NPairState::kNumValues; i++)
+ if (StateActions[i] == NPairAction::kCompress)
+ return true;
+ for (i = 1; i < NPairState::kNumValues; i++)
+ if (StateActions[i] != NPairAction::kIgnore)
+ return true;
+ return false;
+ }
+ };
+
+ extern const CActionSet kAddActionSet;
+ extern const CActionSet kUpdateActionSet;
+ extern const CActionSet kFreshActionSet;
+ extern const CActionSet kSynchronizeActionSet;
+ extern const CActionSet kDeleteActionSet;
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp
new file mode 100644
index 000000000..0f229058c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -0,0 +1,249 @@
+// UpdateCallback.cpp
+
+#include "StdAfx.h"
+
+#include "Common/ComTry.h"
+#include "Common/Defs.h"
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "UpdateCallback.h"
+
+using namespace NWindows;
+
+CArchiveUpdateCallback::CArchiveUpdateCallback():
+ Callback(0),
+ ShareForWrite(false),
+ StdInMode(false),
+ DirItems(0),
+ ArcItems(0),
+ UpdatePairs(0),
+ NewNames(0)
+ {}
+
+
+STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
+{
+ COM_TRY_BEGIN
+ return Callback->SetTotal(size);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
+{
+ COM_TRY_BEGIN
+ return Callback->SetCompleted(completeValue);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ COM_TRY_BEGIN
+ return Callback->SetRatioInfo(inSize, outSize);
+ COM_TRY_END
+}
+
+
+/*
+STATPROPSTG kProperties[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidIsAnti, VT_BOOL}
+};
+
+STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
+{
+ return CStatPropEnumerator::CreateEnumerator(kProperties, sizeof(kProperties) / sizeof(kProperties[0]), enumerator);
+}
+*/
+
+STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
+ Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)
+{
+ COM_TRY_BEGIN
+ RINOK(Callback->CheckBreak());
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (newData != NULL) *newData = BoolToInt(up.NewData);
+ if (newProps != NULL) *newProps = BoolToInt(up.NewProps);
+ if (indexInArchive != NULL)
+ {
+ *indexInArchive = (UInt32)-1;
+ if (up.ExistInArchive())
+ *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ NWindows::NCOM::CPropVariant prop;
+
+ if (propID == kpidIsAnti)
+ {
+ prop = up.IsAnti;
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ if (up.IsAnti)
+ {
+ switch(propID)
+ {
+ case kpidIsDir:
+ case kpidPath:
+ break;
+ case kpidSize:
+ prop = (UInt64)0;
+ prop.Detach(value);
+ return S_OK;
+ default:
+ prop.Detach(value);
+ return S_OK;
+ }
+ }
+
+ if (up.ExistOnDisk())
+ {
+ const CDirItem &di = DirItems->Items[up.DirIndex];
+ switch(propID)
+ {
+ case kpidPath: prop = DirItems->GetLogPath(up.DirIndex); break;
+ case kpidIsDir: prop = di.IsDir(); break;
+ case kpidSize: prop = di.Size; break;
+ case kpidAttrib: prop = di.Attrib; break;
+ case kpidCTime: prop = di.CTime; break;
+ case kpidATime: prop = di.ATime; break;
+ case kpidMTime: prop = di.MTime; break;
+ }
+ }
+ else
+ {
+ if (propID == kpidPath)
+ {
+ if (up.NewNameIndex >= 0)
+ {
+ prop = (*NewNames)[up.NewNameIndex];
+ prop.Detach(value);
+ return S_OK;
+ }
+ }
+ if (up.ExistInArchive() && Archive)
+ {
+ UInt32 indexInArchive;
+ if (ArcItems == 0)
+ indexInArchive = up.ArcIndex;
+ else
+ indexInArchive = (*ArcItems)[up.ArcIndex].IndexInServer;
+ return Archive->GetProperty(indexInArchive, propID, value);
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
+{
+ COM_TRY_BEGIN
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (!up.NewData)
+ return E_FAIL;
+
+ RINOK(Callback->CheckBreak());
+ RINOK(Callback->Finilize());
+
+ if (up.IsAnti)
+ {
+ return Callback->GetStream((*ArcItems)[up.ArcIndex].Name, true);
+ }
+ const CDirItem &di = DirItems->Items[up.DirIndex];
+ RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), false));
+
+ if (di.IsDir())
+ return S_OK;
+
+ if (StdInMode)
+ {
+ CStdInFileStream *inStreamSpec = new CStdInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ *inStream = inStreamLoc.Detach();
+ }
+ else
+ {
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ const UString path = DirItems->GetPhyPath(up.DirIndex);
+ if (!inStreamSpec->OpenShared(path, ShareForWrite))
+ {
+ return Callback->OpenFileError(path, ::GetLastError());
+ }
+ *inStream = inStreamLoc.Detach();
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult)
+{
+ COM_TRY_BEGIN
+ return Callback->SetOperationResult(operationResult);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
+{
+ if (VolumesSizes.Size() == 0)
+ return S_FALSE;
+ if (index >= (UInt32)VolumesSizes.Size())
+ index = VolumesSizes.Size() - 1;
+ *size = VolumesSizes[index];
+ return S_OK;
+}
+
+STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
+{
+ COM_TRY_BEGIN
+ wchar_t temp[16];
+ ConvertUInt32ToString(index + 1, temp);
+ UString res = temp;
+ while (res.Length() < 2)
+ res = UString(L'0') + res;
+ UString fileName = VolName;
+ fileName += L'.';
+ fileName += res;
+ fileName += VolExt;
+ COutFileStream *streamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
+ if (!streamSpec->Create(fileName, false))
+ return ::GetLastError();
+ *volumeStream = streamLoc.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ COM_TRY_BEGIN
+ return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
+ COM_TRY_END
+}
+
+STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+ return Callback->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h
new file mode 100644
index 000000000..9a20c3159
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateCallback.h
@@ -0,0 +1,74 @@
+// UpdateCallback.h
+
+#ifndef __UPDATECALLBACK_H
+#define __UPDATECALLBACK_H
+
+#include "Common/MyCom.h"
+#include "Common/MyString.h"
+
+#include "../../IPassword.h"
+#include "../../ICoder.h"
+
+#include "../Common/UpdatePair.h"
+#include "../Common/UpdateProduce.h"
+
+#define INTERFACE_IUpdateCallbackUI(x) \
+ virtual HRESULT SetTotal(UInt64 size) x; \
+ virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \
+ virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \
+ virtual HRESULT CheckBreak() x; \
+ virtual HRESULT Finilize() x; \
+ virtual HRESULT SetNumFiles(UInt64 numFiles) x; \
+ virtual HRESULT GetStream(const wchar_t *name, bool isAnti) x; \
+ virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \
+ virtual HRESULT SetOperationResult(Int32 operationResult) x; \
+ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \
+ virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \
+ /* virtual HRESULT ShowDeleteFile(const wchar_t *name) x; */ \
+ /* virtual HRESULT CloseProgress() { return S_OK; }; */
+
+struct IUpdateCallbackUI
+{
+ INTERFACE_IUpdateCallbackUI(=0)
+};
+
+class CArchiveUpdateCallback:
+ public IArchiveUpdateCallback2,
+ public ICryptoGetTextPassword2,
+ public ICryptoGetTextPassword,
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP4(
+ IArchiveUpdateCallback2,
+ ICryptoGetTextPassword2,
+ ICryptoGetTextPassword,
+ ICompressProgressInfo)
+
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+
+ INTERFACE_IArchiveUpdateCallback2(;)
+
+ STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+public:
+ CRecordVector<UInt64> VolumesSizes;
+ UString VolName;
+ UString VolExt;
+
+ IUpdateCallbackUI *Callback;
+
+ bool ShareForWrite;
+ bool StdInMode;
+ const CDirItems *DirItems;
+ const CObjectVector<CArcItem> *ArcItems;
+ const CRecordVector<CUpdatePair2> *UpdatePairs;
+ const UStringVector *NewNames;
+ CMyComPtr<IInArchive> Archive;
+
+ CArchiveUpdateCallback();
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp
new file mode 100644
index 000000000..a43a9e770
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.cpp
@@ -0,0 +1,158 @@
+// UpdatePair.cpp
+
+#include "StdAfx.h"
+
+#include <time.h>
+
+#include "Common/Defs.h"
+#include "Common/Wildcard.h"
+
+#include "Windows/Time.h"
+
+#include "SortUtils.h"
+#include "UpdatePair.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2)
+{
+ switch(fileTimeType)
+ {
+ case NFileTimeType::kWindows:
+ return ::CompareFileTime(&time1, &time2);
+ case NFileTimeType::kUnix:
+ {
+ UInt32 unixTime1, unixTime2;
+ FileTimeToUnixTime(time1, unixTime1);
+ FileTimeToUnixTime(time2, unixTime2);
+ return MyCompare(unixTime1, unixTime2);
+ }
+ case NFileTimeType::kDOS:
+ {
+ UInt32 dosTime1, dosTime2;
+ FileTimeToDosTime(time1, dosTime1);
+ FileTimeToDosTime(time2, dosTime2);
+ return MyCompare(dosTime1, dosTime2);
+ }
+ }
+ throw 4191618;
+}
+
+static const wchar_t *kDuplicateFileNameMessage = L"Duplicate filename:";
+static const wchar_t *kNotCensoredCollisionMessaged = L"Internal file name collision (file on disk, file in archive):";
+
+static void ThrowError(const UString &message, const UString &s1, const UString &s2)
+{
+ UString m = message;
+ m += L'\n';
+ m += s1;
+ m += L'\n';
+ m += s2;
+ throw m;
+}
+
+static void TestDuplicateString(const UStringVector &strings, const CIntVector &indices)
+{
+ for(int i = 0; i + 1 < indices.Size(); i++)
+ if (CompareFileNames(strings[indices[i]], strings[indices[i + 1]]) == 0)
+ ThrowError(kDuplicateFileNameMessage, strings[indices[i]], strings[indices[i + 1]]);
+}
+
+void GetUpdatePairInfoList(
+ const CDirItems &dirItems,
+ const CObjectVector<CArcItem> &arcItems,
+ NFileTimeType::EEnum fileTimeType,
+ CRecordVector<CUpdatePair> &updatePairs)
+{
+ CIntVector dirIndices, arcIndices;
+
+ int numDirItems = dirItems.Items.Size();
+ int numArcItems = arcItems.Size();
+
+
+ {
+ UStringVector arcNames;
+ arcNames.Reserve(numArcItems);
+ for (int i = 0; i < numArcItems; i++)
+ arcNames.Add(arcItems[i].Name);
+ SortFileNames(arcNames, arcIndices);
+ TestDuplicateString(arcNames, arcIndices);
+ }
+
+ UStringVector dirNames;
+ {
+ dirNames.Reserve(numDirItems);
+ for (int i = 0; i < numDirItems; i++)
+ dirNames.Add(dirItems.GetLogPath(i));
+ SortFileNames(dirNames, dirIndices);
+ TestDuplicateString(dirNames, dirIndices);
+ }
+
+ int dirIndex = 0, arcIndex = 0;
+ while (dirIndex < numDirItems && arcIndex < numArcItems)
+ {
+ CUpdatePair pair;
+ int dirIndex2 = dirIndices[dirIndex];
+ int arcIndex2 = arcIndices[arcIndex];
+ const CDirItem &di = dirItems.Items[dirIndex2];
+ const CArcItem &ai = arcItems[arcIndex2];
+ int compareResult = CompareFileNames(dirNames[dirIndex2], ai.Name);
+ if (compareResult < 0)
+ {
+ pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+ pair.DirIndex = dirIndex2;
+ dirIndex++;
+ }
+ else if (compareResult > 0)
+ {
+ pair.State = ai.Censored ?
+ NUpdateArchive::NPairState::kOnlyInArchive:
+ NUpdateArchive::NPairState::kNotMasked;
+ pair.ArcIndex = arcIndex2;
+ arcIndex++;
+ }
+ else
+ {
+ if (!ai.Censored)
+ ThrowError(kNotCensoredCollisionMessaged, dirNames[dirIndex2], ai.Name);
+ pair.DirIndex = dirIndex2;
+ pair.ArcIndex = arcIndex2;
+ switch (ai.MTimeDefined ? MyCompareTime(
+ ai.TimeType != - 1 ? (NFileTimeType::EEnum)ai.TimeType : fileTimeType,
+ di.MTime, ai.MTime): 0)
+ {
+ case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
+ case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
+ default:
+ pair.State = (ai.SizeDefined && di.Size == ai.Size) ?
+ NUpdateArchive::NPairState::kSameFiles :
+ NUpdateArchive::NPairState::kUnknowNewerFiles;
+ }
+ dirIndex++;
+ arcIndex++;
+ }
+ updatePairs.Add(pair);
+ }
+
+ for (; dirIndex < numDirItems; dirIndex++)
+ {
+ CUpdatePair pair;
+ pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+ pair.DirIndex = dirIndices[dirIndex];
+ updatePairs.Add(pair);
+ }
+
+ for (; arcIndex < numArcItems; arcIndex++)
+ {
+ CUpdatePair pair;
+ int arcIndex2 = arcIndices[arcIndex];
+ pair.State = arcItems[arcIndex2].Censored ?
+ NUpdateArchive::NPairState::kOnlyInArchive:
+ NUpdateArchive::NPairState::kNotMasked;
+ pair.ArcIndex = arcIndex2;
+ updatePairs.Add(pair);
+ }
+
+ updatePairs.ReserveDown();
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h
new file mode 100644
index 000000000..3a332649c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdatePair.h
@@ -0,0 +1,25 @@
+// UpdatePair.h
+
+#ifndef __UPDATE_PAIR_H
+#define __UPDATE_PAIR_H
+
+#include "DirItem.h"
+#include "UpdateAction.h"
+
+#include "../../Archive/IArchive.h"
+
+struct CUpdatePair
+{
+ NUpdateArchive::NPairState::EEnum State;
+ int ArcIndex;
+ int DirIndex;
+ CUpdatePair(): ArcIndex(-1), DirIndex(-1) {}
+};
+
+void GetUpdatePairInfoList(
+ const CDirItems &dirItems,
+ const CObjectVector<CArcItem> &arcItems,
+ NFileTimeType::EEnum fileTimeType,
+ CRecordVector<CUpdatePair> &updatePairs);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp
new file mode 100644
index 000000000..c21db3b2a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.cpp
@@ -0,0 +1,58 @@
+// UpdateProduce.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateProduce.h"
+
+using namespace NUpdateArchive;
+
+static const char *kUpdateActionSetCollision = "Internal collision in update action set";
+
+void UpdateProduce(
+ const CRecordVector<CUpdatePair> &updatePairs,
+ const CActionSet &actionSet,
+ CRecordVector<CUpdatePair2> &operationChain,
+ IUpdateProduceCallback *callback)
+{
+ for (int i = 0; i < updatePairs.Size(); i++)
+ {
+ const CUpdatePair &pair = updatePairs[i];
+
+ CUpdatePair2 up2;
+ up2.IsAnti = false;
+ up2.DirIndex = pair.DirIndex;
+ up2.ArcIndex = pair.ArcIndex;
+ up2.NewData = up2.NewProps = true;
+
+ switch(actionSet.StateActions[pair.State])
+ {
+ case NPairAction::kIgnore:
+ /*
+ if (pair.State != NPairState::kOnlyOnDisk)
+ IgnoreArchiveItem(m_ArchiveItems[pair.ArcIndex]);
+ // cout << "deleting";
+ */
+ if (callback)
+ callback->ShowDeleteFile(pair.ArcIndex);
+ continue;
+
+ case NPairAction::kCopy:
+ if (pair.State == NPairState::kOnlyOnDisk)
+ throw kUpdateActionSetCollision;
+ up2.NewData = up2.NewProps = false;
+ break;
+
+ case NPairAction::kCompress:
+ if (pair.State == NPairState::kOnlyInArchive ||
+ pair.State == NPairState::kNotMasked)
+ throw kUpdateActionSetCollision;
+ break;
+
+ case NPairAction::kCompressAsAnti:
+ up2.IsAnti = true;
+ break;
+ }
+ operationChain.Add(up2);
+ }
+ operationChain.ReserveDown();
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h
new file mode 100644
index 000000000..e18648cd9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/UpdateProduce.h
@@ -0,0 +1,35 @@
+// UpdateProduce.h
+
+#ifndef __UPDATE_PRODUCE_H
+#define __UPDATE_PRODUCE_H
+
+#include "UpdatePair.h"
+
+struct CUpdatePair2
+{
+ bool NewData;
+ bool NewProps;
+ bool IsAnti;
+
+ int DirIndex;
+ int ArcIndex;
+ int NewNameIndex;
+
+ bool ExistOnDisk() const { return DirIndex != -1; }
+ bool ExistInArchive() const { return ArcIndex != -1; }
+
+ CUpdatePair2(): IsAnti(false), DirIndex(-1), ArcIndex(-1), NewNameIndex(-1) {}
+};
+
+struct IUpdateProduceCallback
+{
+ virtual HRESULT ShowDeleteFile(int arcIndex) = 0;
+};
+
+void UpdateProduce(
+ const CRecordVector<CUpdatePair> &updatePairs,
+ const NUpdateArchive::CActionSet &actionSet,
+ CRecordVector<CUpdatePair2> &operationChain,
+ IUpdateProduceCallback *callback);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp
new file mode 100644
index 000000000..164118e2c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.cpp
@@ -0,0 +1,59 @@
+// WorkDir.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StringConvert.h"
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileName.h"
+
+#include "WorkDir.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path)
+{
+ NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
+ #ifndef UNDER_CE
+ if (workDirInfo.ForRemovableOnly)
+ {
+ mode = NWorkDir::NMode::kCurrent;
+ UString prefix = path.Left(3);
+ if (prefix[1] == L':' && prefix[2] == L'\\')
+ {
+ UINT driveType = GetDriveType(GetSystemString(prefix, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP));
+ if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
+ mode = workDirInfo.Mode;
+ }
+ /*
+ CParsedPath parsedPath;
+ parsedPath.ParsePath(archiveName);
+ UINT driveType = GetDriveType(parsedPath.Prefix);
+ if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
+ mode = NZipSettings::NWorkDir::NMode::kCurrent;
+ */
+ }
+ #endif
+ switch(mode)
+ {
+ case NWorkDir::NMode::kCurrent:
+ {
+ return ExtractDirPrefixFromPath(path);
+ }
+ case NWorkDir::NMode::kSpecified:
+ {
+ UString tempDir = workDirInfo.Path;
+ NName::NormalizeDirPathPrefix(tempDir);
+ return tempDir;
+ }
+ default:
+ {
+ UString tempDir;
+ if (!NDirectory::MyGetTempPath(tempDir))
+ throw 141717;
+ return tempDir;
+ }
+ }
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.h b/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.h
new file mode 100644
index 000000000..0643d67a4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/WorkDir.h
@@ -0,0 +1,10 @@
+// WorkDir.h
+
+#ifndef __WORKDIR_H
+#define __WORKDIR_H
+
+#include "ZipRegistry.h"
+
+UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp
new file mode 100644
index 000000000..ac178078a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.cpp
@@ -0,0 +1,293 @@
+// ZipRegistry.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/Registry.h"
+#include "Windows/Synchronization.h"
+
+#include "ZipRegistry.h"
+
+using namespace NWindows;
+using namespace NRegistry;
+
+static NSynchronization::CCriticalSection g_CS;
+#define CS_LOCK NSynchronization::CCriticalSectionLock lock(g_CS);
+
+static const TCHAR *kCuPrefix = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR);
+
+static CSysString GetKeyPath(const CSysString &path) { return kCuPrefix + path; }
+
+static LONG OpenMainKey(CKey &key, LPCTSTR keyName)
+{
+ return key.Open(HKEY_CURRENT_USER, GetKeyPath(keyName), KEY_READ);
+}
+
+static LONG CreateMainKey(CKey &key, LPCTSTR keyName)
+{
+ return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName));
+}
+
+namespace NExtract
+{
+
+static const TCHAR *kKeyName = TEXT("Extraction");
+
+static const TCHAR *kExtractMode = TEXT("ExtractMode");
+static const TCHAR *kOverwriteMode = TEXT("OverwriteMode");
+static const TCHAR *kShowPassword = TEXT("ShowPassword");
+static const TCHAR *kPathHistory = TEXT("PathHistory");
+
+void CInfo::Save() const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kKeyName);
+ key.SetValue(kExtractMode, (UInt32)PathMode);
+ key.SetValue(kOverwriteMode, (UInt32)OverwriteMode);
+ key.SetValue(kShowPassword, ShowPassword);
+ key.RecurseDeleteKey(kPathHistory);
+ key.SetValue_Strings(kPathHistory, Paths);
+}
+
+
+void CInfo::Load()
+{
+ PathMode = NPathMode::kCurrentPathnames;
+ OverwriteMode = NOverwriteMode::kAskBefore;
+ ShowPassword = false;
+ Paths.Clear();
+
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
+ return;
+
+ key.GetValue_Strings(kPathHistory, Paths);
+ UInt32 v;
+ if (key.QueryValue(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kNoPathnames)
+ PathMode = (NPathMode::EEnum)v;
+ if (key.QueryValue(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kAutoRenameExisting)
+ OverwriteMode = (NOverwriteMode::EEnum)v;
+ key.GetValue_IfOk(kShowPassword, ShowPassword);
+}
+
+}
+
+namespace NCompression
+{
+
+static const TCHAR *kKeyName = TEXT("Compression");
+
+static const TCHAR *kArcHistory = TEXT("ArcHistory");
+static const WCHAR *kArchiver = L"Archiver";
+static const TCHAR *kShowPassword = TEXT("ShowPassword");
+static const TCHAR *kEncryptHeaders = TEXT("EncryptHeaders");
+
+static const TCHAR *kOptionsKeyName = TEXT("Options");
+
+static const TCHAR *kLevel = TEXT("Level");
+static const TCHAR *kDictionary = TEXT("Dictionary");
+static const TCHAR *kOrder = TEXT("Order");
+static const TCHAR *kBlockSize = TEXT("BlockSize");
+static const TCHAR *kNumThreads = TEXT("NumThreads");
+static const WCHAR *kMethod = L"Method";
+static const WCHAR *kOptions = L"Options";
+static const WCHAR *kEncryptionMethod = L"EncryptionMethod";
+
+static void SetRegString(CKey &key, const WCHAR *name, const UString &value)
+{
+ if (value.IsEmpty())
+ key.DeleteValue(name);
+ else
+ key.SetValue(name, value);
+}
+
+static void SetRegUInt32(CKey &key, const TCHAR *name, UInt32 value)
+{
+ if (value == (UInt32)-1)
+ key.DeleteValue(name);
+ else
+ key.SetValue(name, value);
+}
+
+static void GetRegString(CKey &key, const WCHAR *name, UString &value)
+{
+ if (key.QueryValue(name, value) != ERROR_SUCCESS)
+ value.Empty();
+}
+
+static void GetRegUInt32(CKey &key, const TCHAR *name, UInt32 &value)
+{
+ if (key.QueryValue(name, value) != ERROR_SUCCESS)
+ value = (UInt32)-1;
+}
+
+void CInfo::Save() const
+{
+ CS_LOCK
+
+ CKey key;
+ CreateMainKey(key, kKeyName);
+ key.SetValue(kLevel, (UInt32)Level);
+ key.SetValue(kArchiver, ArcType);
+ key.SetValue(kShowPassword, ShowPassword);
+ key.SetValue(kEncryptHeaders, EncryptHeaders);
+ key.RecurseDeleteKey(kArcHistory);
+ key.SetValue_Strings(kArcHistory, ArcPaths);
+
+ key.RecurseDeleteKey(kOptionsKeyName);
+ {
+ CKey optionsKey;
+ optionsKey.Create(key, kOptionsKeyName);
+ for (int i = 0; i < Formats.Size(); i++)
+ {
+ const CFormatOptions &fo = Formats[i];
+ CKey fk;
+ fk.Create(optionsKey, fo.FormatID);
+
+ SetRegUInt32(fk, kLevel, fo.Level);
+ SetRegUInt32(fk, kDictionary, fo.Dictionary);
+ SetRegUInt32(fk, kOrder, fo.Order);
+ SetRegUInt32(fk, kBlockSize, fo.BlockLogSize);
+ SetRegUInt32(fk, kNumThreads, fo.NumThreads);
+
+ SetRegString(fk, kMethod, fo.Method);
+ SetRegString(fk, kOptions, fo.Options);
+ SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
+ }
+ }
+}
+
+void CInfo::Load()
+{
+ ArcPaths.Clear();
+ Formats.Clear();
+
+ Level = 5;
+ ArcType = L"7z";
+ ShowPassword = false;
+ EncryptHeaders = false;
+
+ CS_LOCK
+ CKey key;
+
+ if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
+ return;
+
+ key.GetValue_Strings(kArcHistory, ArcPaths);
+
+ {
+ CKey optionsKey;
+ if (optionsKey.Open(key, kOptionsKeyName, KEY_READ) == ERROR_SUCCESS)
+ {
+ CSysStringVector formatIDs;
+ optionsKey.EnumKeys(formatIDs);
+ for (int i = 0; i < formatIDs.Size(); i++)
+ {
+ CKey fk;
+ CFormatOptions fo;
+ fo.FormatID = formatIDs[i];
+ if (fk.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS)
+ {
+ GetRegString(fk, kOptions, fo.Options);
+ GetRegString(fk, kMethod, fo.Method);
+ GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
+
+ GetRegUInt32(fk, kLevel, fo.Level);
+ GetRegUInt32(fk, kDictionary, fo.Dictionary);
+ GetRegUInt32(fk, kOrder, fo.Order);
+ GetRegUInt32(fk, kBlockSize, fo.BlockLogSize);
+ GetRegUInt32(fk, kNumThreads, fo.NumThreads);
+
+ Formats.Add(fo);
+ }
+ }
+ }
+ }
+
+ UString a;
+ if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS)
+ ArcType = a;
+ key.GetValue_IfOk(kLevel, Level);
+ key.GetValue_IfOk(kShowPassword, ShowPassword);
+ key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders);
+}
+
+}
+
+static const TCHAR *kOptionsInfoKeyName = TEXT("Options");
+
+namespace NWorkDir
+{
+static const TCHAR *kWorkDirType = TEXT("WorkDirType");
+static const WCHAR *kWorkDirPath = L"WorkDirPath";
+static const TCHAR *kTempRemovableOnly = TEXT("TempRemovableOnly");
+
+
+void CInfo::Save()const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kOptionsInfoKeyName);
+ key.SetValue(kWorkDirType, (UInt32)Mode);
+ key.SetValue(kWorkDirPath, Path);
+ key.SetValue(kTempRemovableOnly, ForRemovableOnly);
+}
+
+void CInfo::Load()
+{
+ SetDefault();
+
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
+ return;
+
+ UInt32 dirType;
+ if (key.QueryValue(kWorkDirType, dirType) != ERROR_SUCCESS)
+ return;
+ switch (dirType)
+ {
+ case NMode::kSystem:
+ case NMode::kCurrent:
+ case NMode::kSpecified:
+ Mode = (NMode::EEnum)dirType;
+ }
+ if (key.QueryValue(kWorkDirPath, Path) != ERROR_SUCCESS)
+ {
+ Path.Empty();
+ if (Mode == NMode::kSpecified)
+ Mode = NMode::kSystem;
+ }
+ key.GetValue_IfOk(kTempRemovableOnly, ForRemovableOnly);
+}
+
+}
+
+static const TCHAR *kCascadedMenu = TEXT("CascadedMenu");
+static const TCHAR *kContextMenu = TEXT("ContextMenu");
+
+void CContextMenuInfo::Save() const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kOptionsInfoKeyName);
+ key.SetValue(kCascadedMenu, Cascaded);
+ key.SetValue(kContextMenu, Flags);
+}
+
+void CContextMenuInfo::Load()
+{
+ Cascaded = true;
+ Flags = (UInt32)-1;
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
+ return;
+ key.GetValue_IfOk(kCascadedMenu, Cascaded);
+ key.GetValue_IfOk(kContextMenu, Flags);
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h b/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h
new file mode 100644
index 000000000..378353868
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Common/ZipRegistry.h
@@ -0,0 +1,105 @@
+// ZipRegistry.h
+
+#ifndef __ZIP_REGISTRY_H
+#define __ZIP_REGISTRY_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+#include "ExtractMode.h"
+
+namespace NExtract
+{
+ struct CInfo
+ {
+ NPathMode::EEnum PathMode;
+ NOverwriteMode::EEnum OverwriteMode;
+ bool ShowPassword;
+ UStringVector Paths;
+
+ void Save() const;
+ void Load();
+ };
+}
+
+namespace NCompression
+{
+ struct CFormatOptions
+ {
+ UInt32 Level;
+ UInt32 Dictionary;
+ UInt32 Order;
+ UInt32 BlockLogSize;
+ UInt32 NumThreads;
+
+ CSysString FormatID;
+ UString Method;
+ UString Options;
+ UString EncryptionMethod;
+
+ void ResetForLevelChange()
+ {
+ BlockLogSize = NumThreads = Level = Dictionary = Order = UInt32(-1);
+ Method.Empty();
+ // Options.Empty();
+ // EncryptionMethod.Empty();
+ }
+ CFormatOptions() { ResetForLevelChange(); }
+ };
+
+ struct CInfo
+ {
+ UInt32 Level;
+ bool ShowPassword;
+ bool EncryptHeaders;
+ UString ArcType;
+ UStringVector ArcPaths;
+
+ CObjectVector<CFormatOptions> Formats;
+
+ void Save() const;
+ void Load();
+ };
+}
+
+namespace NWorkDir
+{
+ namespace NMode
+ {
+ enum EEnum
+ {
+ kSystem,
+ kCurrent,
+ kSpecified
+ };
+ }
+ struct CInfo
+ {
+ NMode::EEnum Mode;
+ UString Path;
+ bool ForRemovableOnly;
+
+ void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
+ void SetDefault()
+ {
+ Mode = NMode::kSystem;
+ Path.Empty();
+ SetForRemovableOnlyDefault();
+ }
+
+ void Save() const;
+ void Load();
+ };
+}
+
+
+struct CContextMenuInfo
+{
+ bool Cascaded;
+ UInt32 Flags;
+
+ void Save() const;
+ void Load();
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/BenchCon.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/BenchCon.cpp
new file mode 100644
index 000000000..35e868c9b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/BenchCon.cpp
@@ -0,0 +1,297 @@
+// BenchCon.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyCom.h"
+
+#if !defined(_7ZIP_ST) || defined(_WIN32)
+#include "../../../Windows/System.h"
+#endif
+
+#include "../Common/Bench.h"
+
+#include "BenchCon.h"
+#include "ConsoleClose.h"
+
+struct CTotalBenchRes
+{
+ UInt64 NumIterations;
+ UInt64 Rating;
+ UInt64 Usage;
+ UInt64 RPU;
+ void Init() { NumIterations = 0; Rating = 0; Usage = 0; RPU = 0; }
+ void Normalize()
+ {
+ if (NumIterations == 0)
+ return;
+ Rating /= NumIterations;
+ Usage /= NumIterations;
+ RPU /= NumIterations;
+ NumIterations = 1;
+ }
+ void SetMid(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
+ {
+ Rating = (r1.Rating + r2.Rating) / 2;
+ Usage = (r1.Usage + r2.Usage) / 2;
+ RPU = (r1.RPU + r2.RPU) / 2;
+ NumIterations = (r1.NumIterations + r2.NumIterations) / 2;
+ }
+};
+
+struct CBenchCallback: public IBenchCallback
+{
+ CTotalBenchRes EncodeRes;
+ CTotalBenchRes DecodeRes;
+ FILE *f;
+ void Init() { EncodeRes.Init(); DecodeRes.Init(); }
+ void Normalize() { EncodeRes.Normalize(); DecodeRes.Normalize(); }
+ UInt32 dictionarySize;
+ HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
+ HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
+};
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ while (v1 > 1000000)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
+{
+ UInt64 elTime = elapsedTime;
+ NormalizeVals(freq, elTime);
+ if (elTime == 0)
+ elTime = 1;
+ return value * freq / elTime;
+}
+
+static void PrintNumber(FILE *f, UInt64 value, int size)
+{
+ char s[32];
+ ConvertUInt64ToString(value, s);
+ fprintf(f, " ");
+ for (int len = (int)strlen(s); len < size; len++)
+ fprintf(f, " ");
+ fputs(s, f);
+}
+
+static void PrintRating(FILE *f, UInt64 rating)
+{
+ PrintNumber(f, rating / 1000000, 6);
+}
+
+static void PrintResults(FILE *f, UInt64 usage, UInt64 rpu, UInt64 rating)
+{
+ PrintNumber(f, (usage + 5000) / 10000, 5);
+ PrintRating(f, rpu);
+ PrintRating(f, rating);
+}
+
+
+static void PrintResults(FILE *f, const CBenchInfo &info, UInt64 rating, CTotalBenchRes &res)
+{
+ UInt64 speed = MyMultDiv64(info.UnpackSize, info.GlobalTime, info.GlobalFreq);
+ PrintNumber(f, speed / 1024, 7);
+ UInt64 usage = GetUsage(info);
+ UInt64 rpu = GetRatingPerUsage(info, rating);
+ PrintResults(f, usage, rpu, rating);
+ res.NumIterations++;
+ res.RPU += rpu;
+ res.Rating += rating;
+ res.Usage += usage;
+}
+
+static void PrintTotals(FILE *f, const CTotalBenchRes &res)
+{
+ fprintf(f, " ");
+ PrintResults(f, res.Usage, res.RPU, res.Rating);
+}
+
+
+HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ if (final)
+ {
+ UInt64 rating = GetCompressRating(dictionarySize, info.GlobalTime, info.GlobalFreq, info.UnpackSize);
+ PrintResults(f, info, rating, EncodeRes);
+ }
+ return S_OK;
+}
+
+static const char *kSep = " | ";
+
+
+HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ if (final)
+ {
+ UInt64 rating = GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
+ fputs(kSep, f);
+ CBenchInfo info2 = info;
+ info2.UnpackSize *= info2.NumIterations;
+ info2.PackSize *= info2.NumIterations;
+ info2.NumIterations = 1;
+ PrintResults(f, info2, rating, DecodeRes);
+ }
+ return S_OK;
+}
+
+static void PrintRequirements(FILE *f, const char *sizeString, UInt64 size, const char *threadsString, UInt32 numThreads)
+{
+ fprintf(f, "\nRAM %s ", sizeString);
+ PrintNumber(f, (size >> 20), 5);
+ fprintf(f, " MB, # %s %3d", threadsString, (unsigned int)numThreads);
+}
+
+HRESULT LzmaBenchCon(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
+{
+ if (!CrcInternalTest())
+ return S_FALSE;
+ #ifndef _7ZIP_ST
+ UInt64 ramSize = NWindows::NSystem::GetRamSize(); //
+ UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+ PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+ if (numThreads == (UInt32)-1)
+ numThreads = numCPUs;
+ if (numThreads > 1)
+ numThreads &= ~1;
+ if (dictionary == (UInt32)-1)
+ {
+ int dicSizeLog;
+ for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
+ if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
+ break;
+ dictionary = (1 << dicSizeLog);
+ }
+ #else
+ if (dictionary == (UInt32)-1)
+ dictionary = (1 << 22);
+ numThreads = 1;
+ #endif
+
+ PrintRequirements(f, "usage:", GetBenchMemoryUsage(numThreads, dictionary), "Benchmark threads: ", numThreads);
+
+ CBenchCallback callback;
+ callback.Init();
+ callback.f = f;
+
+ fprintf(f, "\n\nDict Compressing | Decompressing\n ");
+ int j;
+ for (j = 0; j < 2; j++)
+ {
+ fprintf(f, " Speed Usage R/U Rating");
+ if (j == 0)
+ fputs(kSep, f);
+ }
+ fprintf(f, "\n ");
+ for (j = 0; j < 2; j++)
+ {
+ fprintf(f, " KB/s %% MIPS MIPS");
+ if (j == 0)
+ fputs(kSep, f);
+ }
+ fprintf(f, "\n\n");
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ const int kStartDicLog = 22;
+ int pow = (dictionary < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
+ while (((UInt32)1 << pow) > dictionary)
+ pow--;
+ for (; ((UInt32)1 << pow) <= dictionary; pow++)
+ {
+ fprintf(f, "%2d:", pow);
+ callback.dictionarySize = (UInt32)1 << pow;
+ HRESULT res = LzmaBench(
+ EXTERNAL_CODECS_LOC_VARS
+ numThreads, callback.dictionarySize, &callback);
+ fprintf(f, "\n");
+ RINOK(res);
+ }
+ }
+ callback.Normalize();
+ fprintf(f, "----------------------------------------------------------------\nAvr:");
+ PrintTotals(f, callback.EncodeRes);
+ fprintf(f, " ");
+ PrintTotals(f, callback.DecodeRes);
+ fprintf(f, "\nTot:");
+ CTotalBenchRes midRes;
+ midRes.SetMid(callback.EncodeRes, callback.DecodeRes);
+ PrintTotals(f, midRes);
+ fprintf(f, "\n");
+ return S_OK;
+}
+
+struct CTempValues
+{
+ UInt64 *Values;
+ CTempValues(UInt32 num) { Values = new UInt64[num]; }
+ ~CTempValues() { delete []Values; }
+};
+
+HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
+{
+ if (!CrcInternalTest())
+ return S_FALSE;
+
+ #ifndef _7ZIP_ST
+ UInt64 ramSize = NWindows::NSystem::GetRamSize();
+ UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
+ PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
+ if (numThreads == (UInt32)-1)
+ numThreads = numCPUs;
+ #else
+ numThreads = 1;
+ #endif
+ if (dictionary == (UInt32)-1)
+ dictionary = (1 << 24);
+
+ CTempValues speedTotals(numThreads);
+ fprintf(f, "\n\nSize");
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ {
+ fprintf(f, " %5d", ti + 1);
+ speedTotals.Values[ti] = 0;
+ }
+ fprintf(f, "\n\n");
+
+ UInt64 numSteps = 0;
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ for (int pow = 10; pow < 32; pow++)
+ {
+ UInt32 bufSize = (UInt32)1 << pow;
+ if (bufSize > dictionary)
+ break;
+ fprintf(f, "%2d: ", pow);
+ UInt64 speed;
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ {
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ RINOK(CrcBench(ti + 1, bufSize, speed));
+ PrintNumber(f, (speed >> 20), 5);
+ speedTotals.Values[ti] += speed;
+ }
+ fprintf(f, "\n");
+ numSteps++;
+ }
+ }
+ if (numSteps != 0)
+ {
+ fprintf(f, "\nAvg:");
+ for (UInt32 ti = 0; ti < numThreads; ti++)
+ PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), 5);
+ fprintf(f, "\n");
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/BenchCon.h b/src/libs/7zip/win/CPP/7zip/UI/Console/BenchCon.h
new file mode 100644
index 000000000..966a83a6a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/BenchCon.h
@@ -0,0 +1,16 @@
+// BenchCon.h
+
+#ifndef __BENCH_CON_H
+#define __BENCH_CON_H
+
+#include <stdio.h>
+
+#include "../../Common/CreateCoder.h"
+
+HRESULT LzmaBenchCon(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary);
+
+HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/ConsoleClose.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/ConsoleClose.cpp
new file mode 100644
index 000000000..5acae942d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/ConsoleClose.cpp
@@ -0,0 +1,73 @@
+// ConsoleClose.cpp
+
+#include "StdAfx.h"
+
+#include "ConsoleClose.h"
+
+static int g_BreakCounter = 0;
+static const int kBreakAbortThreshold = 2;
+
+namespace NConsoleClose {
+
+#if !defined(UNDER_CE) && defined(_WIN32)
+static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
+{
+ if (ctrlType == CTRL_LOGOFF_EVENT)
+ {
+ // printf("\nCTRL_LOGOFF_EVENT\n");
+ return TRUE;
+ }
+
+ g_BreakCounter++;
+ if (g_BreakCounter < kBreakAbortThreshold)
+ return TRUE;
+ return FALSE;
+ /*
+ switch(ctrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ if (g_BreakCounter < kBreakAbortThreshold)
+ return TRUE;
+ }
+ return FALSE;
+ */
+}
+#endif
+
+bool TestBreakSignal()
+{
+ #ifdef UNDER_CE
+ return false;
+ #else
+ /*
+ if (g_BreakCounter > 0)
+ return true;
+ */
+ return (g_BreakCounter > 0);
+ #endif
+}
+
+void CheckCtrlBreak()
+{
+ if (TestBreakSignal())
+ throw CCtrlBreakException();
+}
+
+CCtrlHandlerSetter::CCtrlHandlerSetter()
+{
+ #if !defined(UNDER_CE) && defined(_WIN32)
+ if(!SetConsoleCtrlHandler(HandlerRoutine, TRUE))
+ throw "SetConsoleCtrlHandler fails";
+ #endif
+}
+
+CCtrlHandlerSetter::~CCtrlHandlerSetter()
+{
+ #if !defined(UNDER_CE) && defined(_WIN32)
+ if(!SetConsoleCtrlHandler(HandlerRoutine, FALSE))
+ throw "SetConsoleCtrlHandler fails";
+ #endif
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/ConsoleClose.h b/src/libs/7zip/win/CPP/7zip/UI/Console/ConsoleClose.h
new file mode 100644
index 000000000..9019c4ce2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/ConsoleClose.h
@@ -0,0 +1,24 @@
+// ConsoleCloseUtils.h
+
+#ifndef __CONSOLECLOSEUTILS_H
+#define __CONSOLECLOSEUTILS_H
+
+namespace NConsoleClose {
+
+bool TestBreakSignal();
+
+class CCtrlHandlerSetter
+{
+public:
+ CCtrlHandlerSetter();
+ virtual ~CCtrlHandlerSetter();
+};
+
+class CCtrlBreakException
+{};
+
+void CheckCtrlBreak();
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
new file mode 100644
index 000000000..af65739c3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
@@ -0,0 +1,228 @@
+// ExtractCallbackConsole.h
+
+#include "StdAfx.h"
+
+#include "ExtractCallbackConsole.h"
+#include "UserInputUtils.h"
+#include "ConsoleClose.h"
+
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/Time.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+#include "Windows/Error.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDirectory;
+
+static const char *kTestString = "Testing ";
+static const char *kExtractString = "Extracting ";
+static const char *kSkipString = "Skipping ";
+
+// static const char *kCantAutoRename = "can not create file with auto name\n";
+// static const char *kCantRenameFile = "can not rename existing file\n";
+// static const char *kCantDeleteOutputFile = "can not delete output file ";
+static const char *kError = "ERROR: ";
+static const char *kMemoryExceptionMessage = "Can't allocate required memory!";
+
+static const char *kProcessing = "Processing archive: ";
+static const char *kEverythingIsOk = "Everything is Ok";
+static const char *kNoFiles = "No files to process";
+
+static const char *kUnsupportedMethod = "Unsupported Method";
+static const char *kCrcFailed = "CRC Failed";
+static const char *kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
+static const char *kDataError = "Data Error";
+static const char *kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
+static const char *kUnknownError = "Unknown Error";
+
+STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::AskOverwrite(
+ const wchar_t *existName, const FILETIME *, const UInt64 *,
+ const wchar_t *newName, const FILETIME *, const UInt64 *,
+ Int32 *answer)
+{
+ (*OutStream) << "file " << existName <<
+ "\nalready exists. Overwrite with " << endl;
+ (*OutStream) << newName;
+
+ NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(OutStream);
+
+ switch(overwriteAnswer)
+ {
+ case NUserAnswerMode::kQuit: return E_ABORT;
+ case NUserAnswerMode::kNo: *answer = NOverwriteAnswer::kNo; break;
+ case NUserAnswerMode::kNoAll: *answer = NOverwriteAnswer::kNoToAll; break;
+ case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break;
+ case NUserAnswerMode::kYes: *answer = NOverwriteAnswer::kYes; break;
+ case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break;
+ default: return E_FAIL;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, bool /* isFolder */, Int32 askExtractMode, const UInt64 *position)
+{
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract: (*OutStream) << kExtractString; break;
+ case NArchive::NExtract::NAskMode::kTest: (*OutStream) << kTestString; break;
+ case NArchive::NExtract::NAskMode::kSkip: (*OutStream) << kSkipString; break;
+ };
+ (*OutStream) << name;
+ if (position != 0)
+ (*OutStream) << " <" << *position << ">";
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::MessageError(const wchar_t *message)
+{
+ (*OutStream) << message << endl;
+ NumFileErrorsInCurrentArchive++;
+ NumFileErrors++;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetOperationResult(Int32 operationResult, bool encrypted)
+{
+ switch(operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+ default:
+ {
+ NumFileErrorsInCurrentArchive++;
+ NumFileErrors++;
+ (*OutStream) << " ";
+ switch(operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+ (*OutStream) << kUnsupportedMethod;
+ break;
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ (*OutStream) << (encrypted ? kCrcFailedEncrypted: kCrcFailed);
+ break;
+ case NArchive::NExtract::NOperationResult::kDataError:
+ (*OutStream) << (encrypted ? kDataErrorEncrypted : kDataError);
+ break;
+ default:
+ (*OutStream) << kUnknownError;
+ }
+ }
+ }
+ (*OutStream) << endl;
+ return S_OK;
+}
+
+#ifndef _NO_CRYPTO
+
+HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
+{
+ PasswordIsDefined = true;
+ Password = password;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+ if (!PasswordIsDefined)
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+#endif
+
+HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name)
+{
+ NumArchives++;
+ NumFileErrorsInCurrentArchive = 0;
+ (*OutStream) << endl << kProcessing << name << endl;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::OpenResult(const wchar_t * /* name */, HRESULT result, bool encrypted)
+{
+ (*OutStream) << endl;
+ if (result != S_OK)
+ {
+ (*OutStream) << "Error: ";
+ if (result == S_FALSE)
+ {
+ (*OutStream) << (encrypted ?
+ "Can not open encrypted archive. Wrong password?" :
+ "Can not open file as archive");
+ }
+ else
+ {
+ if (result == E_OUTOFMEMORY)
+ (*OutStream) << "Can't allocate required memory";
+ else
+ (*OutStream) << NError::MyFormatMessage(result);
+ }
+ (*OutStream) << endl;
+ NumArchiveErrors++;
+ }
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ThereAreNoFiles()
+{
+ (*OutStream) << endl << kNoFiles << endl;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
+{
+ if (result == S_OK)
+ {
+ (*OutStream) << endl;
+ if (NumFileErrorsInCurrentArchive == 0)
+ (*OutStream) << kEverythingIsOk << endl;
+ else
+ {
+ NumArchiveErrors++;
+ (*OutStream) << "Sub items Errors: " << NumFileErrorsInCurrentArchive << endl;
+ }
+ }
+ if (result == S_OK)
+ return result;
+ NumArchiveErrors++;
+ if (result == E_ABORT || result == ERROR_DISK_FULL)
+ return result;
+ (*OutStream) << endl << kError;
+ if (result == E_OUTOFMEMORY)
+ (*OutStream) << kMemoryExceptionMessage;
+ else
+ {
+ UString message;
+ NError::MyFormatMessage(result, message);
+ (*OutStream) << message;
+ }
+ (*OutStream) << endl;
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/ExtractCallbackConsole.h b/src/libs/7zip/win/CPP/7zip/UI/Console/ExtractCallbackConsole.h
new file mode 100644
index 000000000..e42ca6f40
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/ExtractCallbackConsole.h
@@ -0,0 +1,73 @@
+// ExtractCallbackConsole.h
+
+#ifndef __EXTRACTCALLBACKCONSOLE_H
+#define __EXTRACTCALLBACKCONSOLE_H
+
+#include "Common/MyString.h"
+#include "Common/StdOutStream.h"
+#include "../../Common/FileStreams.h"
+#include "../../IPassword.h"
+#include "../../Archive/IArchive.h"
+#include "../Common/ArchiveExtractCallback.h"
+
+class CExtractCallbackConsole:
+ public IExtractCallbackUI,
+ #ifndef _NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+public:
+ MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)
+ #ifndef _NO_CRYPTO
+ MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
+ #endif
+ MY_QUERYINTERFACE_END
+ MY_ADDREF_RELEASE
+
+ STDMETHOD(SetTotal)(UInt64 total);
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue);
+
+ // IFolderArchiveExtractCallback
+ STDMETHOD(AskOverwrite)(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer);
+ STDMETHOD (PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position);
+
+ STDMETHOD(MessageError)(const wchar_t *message);
+ STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted);
+
+ HRESULT BeforeOpen(const wchar_t *name);
+ HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted);
+ HRESULT ThereAreNoFiles();
+ HRESULT ExtractResult(HRESULT result);
+
+
+ #ifndef _NO_CRYPTO
+ HRESULT SetPassword(const UString &password);
+ STDMETHOD(CryptoGetTextPassword)(BSTR *password);
+
+ bool PasswordIsDefined;
+ UString Password;
+
+ #endif
+
+ UInt64 NumArchives;
+ UInt64 NumArchiveErrors;
+ UInt64 NumFileErrors;
+ UInt64 NumFileErrorsInCurrentArchive;
+
+ CStdOutStream *OutStream;
+
+ void Init()
+ {
+ NumArchives = 0;
+ NumArchiveErrors = 0;
+ NumFileErrors = 0;
+ NumFileErrorsInCurrentArchive = 0;
+ }
+
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/List.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/List.cpp
new file mode 100644
index 000000000..f747cfda8
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/List.cpp
@@ -0,0 +1,654 @@
+// List.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/MyCom.h"
+#include "Common/StdOutStream.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Error.h"
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../Common/OpenArchive.h"
+#include "../Common/PropIDUtils.h"
+
+#include "ConsoleClose.h"
+#include "List.h"
+#include "OpenCallbackConsole.h"
+
+using namespace NWindows;
+
+struct CPropIdToName
+{
+ PROPID PropID;
+ const wchar_t *Name;
+};
+
+static const CPropIdToName kPropIdToName[] =
+{
+ { kpidPath, L"Path" },
+ { kpidName, L"Name" },
+ { kpidIsDir, L"Folder" },
+ { kpidSize, L"Size" },
+ { kpidPackSize, L"Packed Size" },
+ { kpidAttrib, L"Attributes" },
+ { kpidCTime, L"Created" },
+ { kpidATime, L"Accessed" },
+ { kpidMTime, L"Modified" },
+ { kpidSolid, L"Solid" },
+ { kpidCommented, L"Commented" },
+ { kpidEncrypted, L"Encrypted" },
+ { kpidSplitBefore, L"Split Before" },
+ { kpidSplitAfter, L"Split After" },
+ { kpidDictionarySize, L"Dictionary Size" },
+ { kpidCRC, L"CRC" },
+ { kpidType, L"Type" },
+ { kpidIsAnti, L"Anti" },
+ { kpidMethod, L"Method" },
+ { kpidHostOS, L"Host OS" },
+ { kpidFileSystem, L"File System" },
+ { kpidUser, L"User" },
+ { kpidGroup, L"Group" },
+ { kpidBlock, L"Block" },
+ { kpidComment, L"Comment" },
+ { kpidPosition, L"Position" },
+ { kpidPrefix, L"Prefix" },
+ { kpidNumSubDirs, L"Folders" },
+ { kpidNumSubFiles, L"Files" },
+ { kpidUnpackVer, L"Version" },
+ { kpidVolume, L"Volume" },
+ { kpidIsVolume, L"Multivolume" },
+ { kpidOffset, L"Offset" },
+ { kpidLinks, L"Links" },
+ { kpidNumBlocks, L"Blocks" },
+ { kpidNumVolumes, L"Volumes" },
+
+ { kpidBit64, L"64-bit" },
+ { kpidBigEndian, L"Big-endian" },
+ { kpidCpu, L"CPU" },
+ { kpidPhySize, L"Physical Size" },
+ { kpidHeadersSize, L"Headers Size" },
+ { kpidChecksum, L"Checksum" },
+ { kpidCharacts, L"Characteristics" },
+ { kpidVa, L"Virtual Address" },
+ { kpidId, L"ID" },
+ { kpidShortName, L"Short Name" },
+ { kpidCreatorApp, L"Creator Application"},
+ { kpidSectorSize, L"Sector Size" },
+ { kpidPosixAttrib, L"Mode" },
+ { kpidLink, L"Link" },
+ { kpidError, L"Error" },
+
+ { kpidTotalSize, L"Total Size" },
+ { kpidFreeSpace, L"Free Space" },
+ { kpidClusterSize, L"Cluster Size" },
+ { kpidVolumeName, L"Label" }
+};
+
+static const char kEmptyAttribChar = '.';
+
+static const char *kListing = "Listing archive: ";
+static const wchar_t *kFilesMessage = L"files";
+static const wchar_t *kDirsMessage = L"folders";
+
+static void GetAttribString(DWORD wa, bool isDir, char *s)
+{
+ s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : kEmptyAttribChar;
+ s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar;
+ s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar;
+ s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar;
+ s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar;
+ s[5] = '\0';
+}
+
+enum EAdjustment
+{
+ kLeft,
+ kCenter,
+ kRight
+};
+
+struct CFieldInfo
+{
+ PROPID PropID;
+ UString Name;
+ EAdjustment TitleAdjustment;
+ EAdjustment TextAdjustment;
+ int PrefixSpacesWidth;
+ int Width;
+};
+
+struct CFieldInfoInit
+{
+ PROPID PropID;
+ const wchar_t *Name;
+ EAdjustment TitleAdjustment;
+ EAdjustment TextAdjustment;
+ int PrefixSpacesWidth;
+ int Width;
+};
+
+static CFieldInfoInit kStandardFieldTable[] =
+{
+ { kpidMTime, L" Date Time", kLeft, kLeft, 0, 19 },
+ { kpidAttrib, L"Attr", kRight, kCenter, 1, 5 },
+ { kpidSize, L"Size", kRight, kRight, 1, 12 },
+ { kpidPackSize, L"Compressed", kRight, kRight, 1, 12 },
+ { kpidPath, L"Name", kLeft, kLeft, 2, 24 }
+};
+
+static void PrintSpaces(int numSpaces)
+{
+ for (int i = 0; i < numSpaces; i++)
+ g_StdOut << ' ';
+}
+
+static void PrintString(EAdjustment adjustment, int width, const UString &textString)
+{
+ const int numSpaces = width - textString.Length();
+ int numLeftSpaces = 0;
+ switch (adjustment)
+ {
+ case kLeft:
+ numLeftSpaces = 0;
+ break;
+ case kCenter:
+ numLeftSpaces = numSpaces / 2;
+ break;
+ case kRight:
+ numLeftSpaces = numSpaces;
+ break;
+ }
+ PrintSpaces(numLeftSpaces);
+ g_StdOut << textString;
+ PrintSpaces(numSpaces - numLeftSpaces);
+}
+
+class CFieldPrinter
+{
+ CObjectVector<CFieldInfo> _fields;
+public:
+ void Clear() { _fields.Clear(); }
+ void Init(const CFieldInfoInit *standardFieldTable, int numItems);
+ HRESULT Init(IInArchive *archive);
+ void PrintTitle();
+ void PrintTitleLines();
+ HRESULT PrintItemInfo(const CArc &arc, UInt32 index, bool techMode);
+ HRESULT PrintSummaryInfo(UInt64 numFiles, UInt64 numDirs,
+ const UInt64 *size, const UInt64 *compressedSize);
+};
+
+void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, int numItems)
+{
+ Clear();
+ for (int i = 0; i < numItems; i++)
+ {
+ CFieldInfo fieldInfo;
+ const CFieldInfoInit &fieldInfoInit = standardFieldTable[i];
+ fieldInfo.PropID = fieldInfoInit.PropID;
+ fieldInfo.Name = fieldInfoInit.Name;
+ fieldInfo.TitleAdjustment = fieldInfoInit.TitleAdjustment;
+ fieldInfo.TextAdjustment = fieldInfoInit.TextAdjustment;
+ fieldInfo.PrefixSpacesWidth = fieldInfoInit.PrefixSpacesWidth;
+ fieldInfo.Width = fieldInfoInit.Width;
+ _fields.Add(fieldInfo);
+ }
+}
+
+static UString GetPropName(PROPID propID, BSTR name)
+{
+ for (int i = 0; i < sizeof(kPropIdToName) / sizeof(kPropIdToName[0]); i++)
+ {
+ const CPropIdToName &propIdToName = kPropIdToName[i];
+ if (propIdToName.PropID == propID)
+ return propIdToName.Name;
+ }
+ if (name)
+ return name;
+ wchar_t s[16];
+ ConvertUInt32ToString(propID, s);
+ return s;
+}
+
+HRESULT CFieldPrinter::Init(IInArchive *archive)
+{
+ Clear();
+ UInt32 numProps;
+ RINOK(archive->GetNumberOfProperties(&numProps));
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt));
+ CFieldInfo fieldInfo;
+ fieldInfo.PropID = propID;
+ fieldInfo.Name = GetPropName(propID, name);
+ _fields.Add(fieldInfo);
+ }
+ return S_OK;
+}
+
+void CFieldPrinter::PrintTitle()
+{
+ for (int i = 0; i < _fields.Size(); i++)
+ {
+ const CFieldInfo &fieldInfo = _fields[i];
+ PrintSpaces(fieldInfo.PrefixSpacesWidth);
+ PrintString(fieldInfo.TitleAdjustment,
+ ((fieldInfo.PropID == kpidPath) ? 0: fieldInfo.Width), fieldInfo.Name);
+ }
+}
+
+void CFieldPrinter::PrintTitleLines()
+{
+ for (int i = 0; i < _fields.Size(); i++)
+ {
+ const CFieldInfo &fieldInfo = _fields[i];
+ PrintSpaces(fieldInfo.PrefixSpacesWidth);
+ for (int i = 0; i < fieldInfo.Width; i++)
+ g_StdOut << '-';
+ }
+}
+
+
+static BOOL IsFileTimeZero(CONST FILETIME *lpFileTime)
+{
+ return (lpFileTime->dwLowDateTime == 0) && (lpFileTime->dwHighDateTime == 0);
+}
+
+static const char *kEmptyTimeString = " ";
+static void PrintTime(const NCOM::CPropVariant &prop)
+{
+ if (prop.vt != VT_FILETIME)
+ throw "incorrect item";
+ if (IsFileTimeZero(&prop.filetime))
+ g_StdOut << kEmptyTimeString;
+ else
+ {
+ FILETIME localFileTime;
+ if (!FileTimeToLocalFileTime(&prop.filetime, &localFileTime))
+ throw "FileTimeToLocalFileTime error";
+ char s[32];
+ if (ConvertFileTimeToString(localFileTime, s, true, true))
+ g_StdOut << s;
+ else
+ g_StdOut << kEmptyTimeString;
+ }
+}
+
+HRESULT CFieldPrinter::PrintItemInfo(const CArc &arc, UInt32 index, bool techMode)
+{
+ /*
+ if (techMode)
+ {
+ g_StdOut << "Index = ";
+ g_StdOut << (UInt64)index;
+ g_StdOut << endl;
+ }
+ */
+ for (int i = 0; i < _fields.Size(); i++)
+ {
+ const CFieldInfo &fieldInfo = _fields[i];
+ if (!techMode)
+ PrintSpaces(fieldInfo.PrefixSpacesWidth);
+
+ NCOM::CPropVariant prop;
+ if (fieldInfo.PropID == kpidPath)
+ {
+ UString s;
+ RINOK(arc.GetItemPath(index, s));
+ prop = s;
+ }
+ else
+ {
+ RINOK(arc.Archive->GetProperty(index, fieldInfo.PropID, &prop));
+ }
+ if (techMode)
+ {
+ g_StdOut << fieldInfo.Name << " = ";
+ }
+ int width = (fieldInfo.PropID == kpidPath) ? 0: fieldInfo.Width;
+ if (fieldInfo.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4))
+ {
+ UInt32 attrib = (prop.vt == VT_EMPTY) ? 0 : prop.ulVal;
+ bool isFolder;
+ RINOK(IsArchiveItemFolder(arc.Archive, index, isFolder));
+ char s[8];
+ GetAttribString(attrib, isFolder, s);
+ g_StdOut << s;
+ }
+ else if (prop.vt == VT_EMPTY)
+ {
+ if (!techMode)
+ PrintSpaces(width);
+ }
+ else if (fieldInfo.PropID == kpidMTime)
+ {
+ PrintTime(prop);
+ }
+ else if (prop.vt == VT_BSTR)
+ {
+ if (techMode)
+ g_StdOut << prop.bstrVal;
+ else
+ PrintString(fieldInfo.TextAdjustment, width, prop.bstrVal);
+ }
+ else
+ {
+ UString s = ConvertPropertyToString(prop, fieldInfo.PropID);
+ s.Replace(wchar_t(0xA), L' ');
+ s.Replace(wchar_t(0xD), L' ');
+
+ if (techMode)
+ g_StdOut << s;
+ else
+ PrintString(fieldInfo.TextAdjustment, width, s);
+ }
+ if (techMode)
+ g_StdOut << endl;
+ }
+ return S_OK;
+}
+
+static void PrintNumberString(EAdjustment adjustment, int width, const UInt64 *value)
+{
+ wchar_t textString[32] = { 0 };
+ if (value != NULL)
+ ConvertUInt64ToString(*value, textString);
+ PrintString(adjustment, width, textString);
+}
+
+
+HRESULT CFieldPrinter::PrintSummaryInfo(UInt64 numFiles, UInt64 numDirs,
+ const UInt64 *size, const UInt64 *compressedSize)
+{
+ for (int i = 0; i < _fields.Size(); i++)
+ {
+ const CFieldInfo &fieldInfo = _fields[i];
+ PrintSpaces(fieldInfo.PrefixSpacesWidth);
+ NCOM::CPropVariant prop;
+ if (fieldInfo.PropID == kpidSize)
+ PrintNumberString(fieldInfo.TextAdjustment, fieldInfo.Width, size);
+ else if (fieldInfo.PropID == kpidPackSize)
+ PrintNumberString(fieldInfo.TextAdjustment, fieldInfo.Width, compressedSize);
+ else if (fieldInfo.PropID == kpidPath)
+ {
+ wchar_t textString[32];
+ ConvertUInt64ToString(numFiles, textString);
+ UString temp = textString;
+ temp += L" ";
+ temp += kFilesMessage;
+ temp += L", ";
+ ConvertUInt64ToString(numDirs, textString);
+ temp += textString;
+ temp += L" ";
+ temp += kDirsMessage;
+ PrintString(fieldInfo.TextAdjustment, 0, temp);
+ }
+ else
+ PrintString(fieldInfo.TextAdjustment, fieldInfo.Width, L"");
+ }
+ return S_OK;
+}
+
+bool GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &value)
+{
+ NCOM::CPropVariant prop;
+ if (archive->GetProperty(index, propID, &prop) != S_OK)
+ throw "GetPropertyValue error";
+ if (prop.vt == VT_EMPTY)
+ return false;
+ value = ConvertPropVariantToUInt64(prop);
+ return true;
+}
+
+static void PrintPropPair(const wchar_t *name, const wchar_t *value)
+{
+ g_StdOut << name << " = " << value << endl;
+}
+
+HRESULT ListArchives(CCodecs *codecs, const CIntVector &formatIndices,
+ bool stdInMode,
+ UStringVector &arcPaths, UStringVector &arcPathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ bool enableHeaders, bool techMode,
+ #ifndef _NO_CRYPTO
+ bool &passwordEnabled, UString &password,
+ #endif
+ UInt64 &numErrors)
+{
+ numErrors = 0;
+ CFieldPrinter fieldPrinter;
+ if (!techMode)
+ fieldPrinter.Init(kStandardFieldTable, sizeof(kStandardFieldTable) / sizeof(kStandardFieldTable[0]));
+
+ UInt64 numFiles2 = 0, numDirs2 = 0, totalPackSize2 = 0, totalUnPackSize2 = 0;
+ UInt64 *totalPackSizePointer2 = 0, *totalUnPackSizePointer2 = 0;
+ int numArcs = /* stdInMode ? 1 : */ arcPaths.Size();
+ for (int i = 0; i < numArcs; i++)
+ {
+ const UString &archiveName = arcPaths[i];
+ UInt64 arcPackSize = 0;
+ if (!stdInMode)
+ {
+ NFile::NFind::CFileInfoW fi;
+ if (!fi.Find(archiveName) || fi.IsDir())
+ {
+ g_StdOut << endl << "Error: " << archiveName << " is not file" << endl;
+ numErrors++;
+ continue;
+ }
+ arcPackSize = fi.Size;
+ }
+
+ CArchiveLink archiveLink;
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = &g_StdOut;
+
+ #ifndef _NO_CRYPTO
+
+ openCallback.PasswordIsDefined = passwordEnabled;
+ openCallback.Password = password;
+
+ #endif
+
+ HRESULT result = archiveLink.Open2(codecs, formatIndices, stdInMode, NULL, archiveName, &openCallback);
+ if (result != S_OK)
+ {
+ if (result == E_ABORT)
+ return result;
+ g_StdOut << endl << "Error: " << archiveName << ": ";
+ if (result == S_FALSE)
+ {
+ #ifndef _NO_CRYPTO
+ if (openCallback.Open_WasPasswordAsked())
+ g_StdOut << "Can not open encrypted archive. Wrong password?";
+ else
+ #endif
+ g_StdOut << "Can not open file as archive";
+ }
+ else if (result == E_OUTOFMEMORY)
+ g_StdOut << "Can't allocate required memory";
+ else
+ g_StdOut << NError::MyFormatMessage(result);
+ g_StdOut << endl;
+ numErrors++;
+ continue;
+ }
+
+ if (!stdInMode)
+ for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
+ {
+ int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]);
+ if (index >= 0 && index > i)
+ {
+ arcPaths.Delete(index);
+ arcPathsFull.Delete(index);
+ numArcs = arcPaths.Size();
+ }
+ }
+
+ if (enableHeaders)
+ {
+ g_StdOut << endl << kListing << archiveName << endl << endl;
+
+ for (int i = 0; i < archiveLink.Arcs.Size(); i++)
+ {
+ const CArc &arc = archiveLink.Arcs[i];
+
+ g_StdOut << "--\n";
+ PrintPropPair(L"Path", arc.Path);
+ PrintPropPair(L"Type", codecs->Formats[arc.FormatIndex].Name);
+ if (!arc.ErrorMessage.IsEmpty())
+ PrintPropPair(L"Error", arc.ErrorMessage);
+ UInt32 numProps;
+ IInArchive *archive = arc.Archive;
+ if (archive->GetNumberOfArchiveProperties(&numProps) == S_OK)
+ {
+ for (UInt32 j = 0; j < numProps; j++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt));
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(propID, &prop));
+ UString s = ConvertPropertyToString(prop, propID);
+ if (!s.IsEmpty())
+ PrintPropPair(GetPropName(propID, name), s);
+ }
+ }
+ if (i != archiveLink.Arcs.Size() - 1)
+ {
+ UInt32 numProps;
+ g_StdOut << "----\n";
+ if (archive->GetNumberOfProperties(&numProps) == S_OK)
+ {
+ UInt32 mainIndex = archiveLink.Arcs[i + 1].SubfileIndex;
+ for (UInt32 j = 0; j < numProps; j++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt));
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(mainIndex, propID, &prop));
+ UString s = ConvertPropertyToString(prop, propID);
+ if (!s.IsEmpty())
+ PrintPropPair(GetPropName(propID, name), s);
+ }
+ }
+ }
+
+ }
+ g_StdOut << endl;
+ if (techMode)
+ g_StdOut << "----------\n";
+ }
+
+ if (enableHeaders && !techMode)
+ {
+ fieldPrinter.PrintTitle();
+ g_StdOut << endl;
+ fieldPrinter.PrintTitleLines();
+ g_StdOut << endl;
+ }
+
+ const CArc &arc = archiveLink.Arcs.Back();
+ IInArchive *archive = arc.Archive;
+ if (techMode)
+ {
+ RINOK(fieldPrinter.Init(archive));
+ }
+ UInt64 numFiles = 0, numDirs = 0, totalPackSize = 0, totalUnPackSize = 0;
+ UInt64 *totalPackSizePointer = 0, *totalUnPackSizePointer = 0;
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems));
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+
+ UString filePath;
+ HRESULT res = arc.GetItemPath(i, filePath);
+ if (stdInMode && res == E_INVALIDARG)
+ break;
+ RINOK(res);
+
+ bool isFolder;
+ RINOK(IsArchiveItemFolder(archive, i, isFolder));
+ if (!wildcardCensor.CheckPath(filePath, !isFolder))
+ continue;
+
+ fieldPrinter.PrintItemInfo(arc, i, techMode);
+
+ UInt64 packSize, unpackSize;
+ if (!GetUInt64Value(archive, i, kpidSize, unpackSize))
+ unpackSize = 0;
+ else
+ totalUnPackSizePointer = &totalUnPackSize;
+ if (!GetUInt64Value(archive, i, kpidPackSize, packSize))
+ packSize = 0;
+ else
+ totalPackSizePointer = &totalPackSize;
+
+ g_StdOut << endl;
+
+ if (isFolder)
+ numDirs++;
+ else
+ numFiles++;
+ totalPackSize += packSize;
+ totalUnPackSize += unpackSize;
+ }
+
+ if (!stdInMode && totalPackSizePointer == 0)
+ {
+ if (archiveLink.VolumePaths.Size() != 0)
+ arcPackSize += archiveLink.VolumesSize;
+ totalPackSize = (numFiles == 0) ? 0 : arcPackSize;
+ totalPackSizePointer = &totalPackSize;
+ }
+ if (totalUnPackSizePointer == 0 && numFiles == 0)
+ {
+ totalUnPackSize = 0;
+ totalUnPackSizePointer = &totalUnPackSize;
+ }
+ if (enableHeaders && !techMode)
+ {
+ fieldPrinter.PrintTitleLines();
+ g_StdOut << endl;
+ fieldPrinter.PrintSummaryInfo(numFiles, numDirs, totalUnPackSizePointer, totalPackSizePointer);
+ g_StdOut << endl;
+ }
+ if (totalPackSizePointer != 0)
+ {
+ totalPackSizePointer2 = &totalPackSize2;
+ totalPackSize2 += totalPackSize;
+ }
+ if (totalUnPackSizePointer != 0)
+ {
+ totalUnPackSizePointer2 = &totalUnPackSize2;
+ totalUnPackSize2 += totalUnPackSize;
+ }
+ numFiles2 += numFiles;
+ numDirs2 += numDirs;
+ }
+ if (enableHeaders && !techMode && numArcs > 1)
+ {
+ g_StdOut << endl;
+ fieldPrinter.PrintTitleLines();
+ g_StdOut << endl;
+ fieldPrinter.PrintSummaryInfo(numFiles2, numDirs2, totalUnPackSizePointer2, totalPackSizePointer2);
+ g_StdOut << endl;
+ g_StdOut << "Archives: " << numArcs << endl;
+ }
+ return S_OK;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/List.h b/src/libs/7zip/win/CPP/7zip/UI/Console/List.h
new file mode 100644
index 000000000..97d9fb15a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/List.h
@@ -0,0 +1,20 @@
+// List.h
+
+#ifndef __LIST_H
+#define __LIST_H
+
+#include "Common/Wildcard.h"
+#include "../Common/LoadCodecs.h"
+
+HRESULT ListArchives(CCodecs *codecs, const CIntVector &formatIndices,
+ bool stdInMode,
+ UStringVector &archivePaths, UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ bool enableHeaders, bool techMode,
+ #ifndef _NO_CRYPTO
+ bool &passwordEnabled, UString &password,
+ #endif
+ UInt64 &errors);
+
+#endif
+
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/Main.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/Main.cpp
new file mode 100644
index 000000000..9bd451f83
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/Main.cpp
@@ -0,0 +1,598 @@
+// Main.cpp
+
+#include "StdAfx.h"
+
+#if defined( _WIN32) && defined( _7ZIP_LARGE_PAGES)
+#include "../../../../C/Alloc.h"
+#endif
+
+#include "Common/MyInitGuid.h"
+
+#include "Common/CommandLineParser.h"
+#include "Common/IntToString.h"
+#include "Common/MyException.h"
+#include "Common/StdOutStream.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/Error.h"
+#ifdef _WIN32
+#include "Windows/MemoryLock.h"
+#endif
+
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/ExitCode.h"
+#include "../Common/Extract.h"
+#ifdef EXTERNAL_CODECS
+#include "../Common/LoadCodecs.h"
+#endif
+
+#include "BenchCon.h"
+#include "ExtractCallbackConsole.h"
+#include "List.h"
+#include "OpenCallbackConsole.h"
+#include "UpdateCallbackConsole.h"
+
+#include "../../MyVersion.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NCommandLineParser;
+
+HINSTANCE g_hInstance = 0;
+extern CStdOutStream *g_StdStream;
+
+static const char *kCopyrightString = "\n7-Zip"
+#ifndef EXTERNAL_CODECS
+" (A)"
+#endif
+
+#ifdef _WIN64
+" [64]"
+#endif
+
+" " MY_VERSION_COPYRIGHT_DATE "\n";
+
+static const char *kHelpString =
+ "\nUsage: 7z"
+#ifdef _NO_CRYPTO
+ "r"
+#else
+#ifndef EXTERNAL_CODECS
+ "a"
+#endif
+#endif
+ " <command> [<switches>...] <archive_name> [<file_names>...]\n"
+ " [<@listfiles...>]\n"
+ "\n"
+ "<Commands>\n"
+ " a: Add files to archive\n"
+ " b: Benchmark\n"
+ " d: Delete files from archive\n"
+ " e: Extract files from archive (without using directory names)\n"
+ " l: List contents of archive\n"
+// " l[a|t][f]: List contents of archive\n"
+// " a - with Additional fields\n"
+// " t - with all fields\n"
+// " f - with Full pathnames\n"
+ " t: Test integrity of archive\n"
+ " u: Update files to archive\n"
+ " x: eXtract files with full paths\n"
+ "<Switches>\n"
+ " -ai[r[-|0]]{@listfile|!wildcard}: Include archives\n"
+ " -ax[r[-|0]]{@listfile|!wildcard}: eXclude archives\n"
+ " -bd: Disable percentage indicator\n"
+ " -i[r[-|0]]{@listfile|!wildcard}: Include filenames\n"
+ " -m{Parameters}: set compression Method\n"
+ " -o{Directory}: set Output directory\n"
+ #ifndef _NO_CRYPTO
+ " -p{Password}: set Password\n"
+ #endif
+ " -r[-|0]: Recurse subdirectories\n"
+ " -scs{UTF-8 | WIN | DOS}: set charset for list files\n"
+ " -sfx[{name}]: Create SFX archive\n"
+ " -si[{name}]: read data from stdin\n"
+ " -slt: show technical information for l (List) command\n"
+ " -so: write data to stdout\n"
+ " -ssc[-]: set sensitive case mode\n"
+ " -ssw: compress shared files\n"
+ " -t{Type}: Set type of archive\n"
+ " -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName]: Update options\n"
+ " -v{Size}[b|k|m|g]: Create volumes\n"
+ " -w[{path}]: assign Work directory. Empty path means a temporary directory\n"
+ " -x[r[-|0]]]{@listfile|!wildcard}: eXclude filenames\n"
+ " -y: assume Yes on all queries\n";
+
+// ---------------------------
+// exception messages
+
+static const char *kEverythingIsOk = "Everything is Ok";
+static const char *kUserErrorMessage = "Incorrect command line";
+static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
+static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
+
+static const wchar_t *kDefaultSfxModule = L"7zCon.sfx";
+
+static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
+{
+ s << message << endl;
+ throw code;
+}
+
+static void PrintHelpAndExit(CStdOutStream &s)
+{
+ s << kHelpString;
+ ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError);
+}
+
+#ifndef _WIN32
+static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
+{
+ parts.Clear();
+ for (int i = 0; i < numArgs; i++)
+ {
+ UString s = MultiByteToUnicodeString(args[i]);
+ parts.Add(s);
+ }
+}
+#endif
+
+static void ShowCopyrightAndHelp(CStdOutStream &s, bool needHelp)
+{
+ s << kCopyrightString;
+ // s << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << "\n";
+ if (needHelp)
+ s << kHelpString;
+}
+
+#ifdef EXTERNAL_CODECS
+static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
+{
+ int len = s.Length();
+ stdStream << s;
+ for (int i = len; i < size; i++)
+ stdStream << ' ';
+}
+#endif
+
+static void PrintString(CStdOutStream &stdStream, const UString &s, int size)
+{
+ int len = s.Length();
+ stdStream << s;
+ for (int i = len; i < size; i++)
+ stdStream << ' ';
+}
+
+static inline char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+int Main2(
+ #ifndef _WIN32
+ int numArgs, const char *args[]
+ #endif
+)
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ SetFileApisToOEM();
+ #endif
+
+ UStringVector commandStrings;
+ #ifdef _WIN32
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
+ #else
+ GetArguments(numArgs, args, commandStrings);
+ #endif
+
+ if (commandStrings.Size() == 1)
+ {
+ ShowCopyrightAndHelp(g_StdOut, true);
+ return 0;
+ }
+ commandStrings.Delete(0);
+
+ CArchiveCommandLineOptions options;
+
+ CArchiveCommandLineParser parser;
+
+ parser.Parse1(commandStrings, options);
+
+ if (options.HelpMode)
+ {
+ ShowCopyrightAndHelp(g_StdOut, true);
+ return 0;
+ }
+
+ #if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
+ if (options.LargePages)
+ {
+ SetLargePageSize();
+ NSecurity::EnableLockMemoryPrivilege();
+ }
+ #endif
+
+ CStdOutStream &stdStream = options.StdOutMode ? g_StdErr : g_StdOut;
+ g_StdStream = &stdStream;
+
+ if (options.EnableHeaders)
+ ShowCopyrightAndHelp(stdStream, false);
+
+ parser.Parse2(options);
+
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr<
+ #ifdef EXTERNAL_CODECS
+ ICompressCodecsInfo
+ #else
+ IUnknown
+ #endif
+ > compressCodecsInfo = codecs;
+ HRESULT result = codecs->Load();
+ if (result != S_OK)
+ throw CSystemException(result);
+
+ bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+
+ if (codecs->Formats.Size() == 0 &&
+ (isExtractGroupCommand ||
+ options.Command.CommandType == NCommandType::kList ||
+ options.Command.IsFromUpdateGroup()))
+ throw kNoFormats;
+
+ CIntVector formatIndices;
+ if (!codecs->FindFormatForArchiveType(options.ArcType, formatIndices))
+ throw kUnsupportedArcTypeMessage;
+
+ if (options.Command.CommandType == NCommandType::kInfo)
+ {
+ stdStream << endl << "Formats:" << endl;
+ int i;
+ for (i = 0; i < codecs->Formats.Size(); i++)
+ {
+ const CArcInfoEx &arc = codecs->Formats[i];
+ #ifdef EXTERNAL_CODECS
+ if (arc.LibIndex >= 0)
+ {
+ char s[16];
+ ConvertUInt32ToString(arc.LibIndex, s);
+ PrintString(stdStream, s, 2);
+ }
+ else
+ #endif
+ stdStream << " ";
+ stdStream << ' ';
+ stdStream << (char)(arc.UpdateEnabled ? 'C' : ' ');
+ stdStream << (char)(arc.KeepName ? 'K' : ' ');
+ stdStream << " ";
+ PrintString(stdStream, arc.Name, 6);
+ stdStream << " ";
+ UString s;
+ for (int t = 0; t < arc.Exts.Size(); t++)
+ {
+ const CArcExtInfo &ext = arc.Exts[t];
+ s += ext.Ext;
+ if (!ext.AddExt.IsEmpty())
+ {
+ s += L" (";
+ s += ext.AddExt;
+ s += L')';
+ }
+ s += L' ';
+ }
+ PrintString(stdStream, s, 14);
+ stdStream << " ";
+ const CByteBuffer &sig = arc.StartSignature;
+ for (size_t j = 0; j < sig.GetCapacity(); j++)
+ {
+ Byte b = sig[j];
+ if (b > 0x20 && b < 0x80)
+ {
+ stdStream << (char)b;
+ }
+ else
+ {
+ stdStream << GetHex((Byte)((b >> 4) & 0xF));
+ stdStream << GetHex((Byte)(b & 0xF));
+ }
+ stdStream << ' ';
+ }
+ stdStream << endl;
+ }
+ stdStream << endl << "Codecs:" << endl;
+
+ #ifdef EXTERNAL_CODECS
+ UInt32 numMethods;
+ if (codecs->GetNumberOfMethods(&numMethods) == S_OK)
+ for (UInt32 j = 0; j < numMethods; j++)
+ {
+ int libIndex = codecs->GetCodecLibIndex(j);
+ if (libIndex >= 0)
+ {
+ char s[16];
+ ConvertUInt32ToString(libIndex, s);
+ PrintString(stdStream, s, 2);
+ }
+ else
+ stdStream << " ";
+ stdStream << ' ';
+ stdStream << (char)(codecs->GetCodecEncoderIsAssigned(j) ? 'C' : ' ');
+ UInt64 id;
+ stdStream << " ";
+ HRESULT res = codecs->GetCodecId(j, id);
+ if (res != S_OK)
+ id = (UInt64)(Int64)-1;
+ char s[32];
+ ConvertUInt64ToString(id, s, 16);
+ PrintString(stdStream, s, 8);
+ stdStream << " ";
+ PrintString(stdStream, codecs->GetCodecName(j), 11);
+ stdStream << endl;
+ /*
+ if (res != S_OK)
+ throw "incorrect Codec ID";
+ */
+ }
+ #endif
+ return S_OK;
+ }
+ else if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ if (options.Method.CompareNoCase(L"CRC") == 0)
+ {
+ HRESULT res = CrcBenchCon((FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
+ if (res != S_OK)
+ {
+ if (res == S_FALSE)
+ {
+ stdStream << "\nCRC Error\n";
+ return NExitCode::kFatalError;
+ }
+ throw CSystemException(res);
+ }
+ }
+ else
+ {
+ HRESULT res;
+ #ifdef EXTERNAL_CODECS
+ CObjectVector<CCodecInfoEx> externalCodecs;
+ res = LoadExternalCodecs(compressCodecsInfo, externalCodecs);
+ if (res != S_OK)
+ throw CSystemException(res);
+ #endif
+ res = LzmaBenchCon(
+ #ifdef EXTERNAL_CODECS
+ compressCodecsInfo, &externalCodecs,
+ #endif
+ (FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
+ if (res != S_OK)
+ {
+ if (res == S_FALSE)
+ {
+ stdStream << "\nDecoding Error\n";
+ return NExitCode::kFatalError;
+ }
+ throw CSystemException(res);
+ }
+ }
+ }
+ else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
+ {
+ if (isExtractGroupCommand)
+ {
+ CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+ ecs->OutStream = &stdStream;
+
+ #ifndef _NO_CRYPTO
+ ecs->PasswordIsDefined = options.PasswordEnabled;
+ ecs->Password = options.Password;
+ #endif
+
+ ecs->Init();
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = &stdStream;
+
+ #ifndef _NO_CRYPTO
+ openCallback.PasswordIsDefined = options.PasswordEnabled;
+ openCallback.Password = options.Password;
+ #endif
+
+ CExtractOptions eo;
+ eo.StdInMode = options.StdInMode;
+ eo.StdOutMode = options.StdOutMode;
+ eo.PathMode = options.Command.GetPathMode();
+ eo.TestMode = options.Command.IsTestMode();
+ eo.OverwriteMode = options.OverwriteMode;
+ eo.OutputDir = options.OutputDir;
+ eo.YesToAll = options.YesToAll;
+ eo.CalcCrc = options.CalcCrc;
+ #if !defined(_7ZIP_ST) && !defined(_SFX)
+ eo.Properties = options.ExtractProperties;
+ #endif
+ UString errorMessage;
+ CDecompressStat stat;
+ HRESULT result = DecompressArchives(
+ codecs,
+ formatIndices,
+ options.ArchivePathsSorted,
+ options.ArchivePathsFullSorted,
+ options.WildcardCensor.Pairs.Front().Head,
+ eo, &openCallback, ecs, errorMessage, stat);
+ if (!errorMessage.IsEmpty())
+ {
+ stdStream << endl << "Error: " << errorMessage;
+ if (result == S_OK)
+ result = E_FAIL;
+ }
+
+ stdStream << endl;
+ if (ecs->NumArchives > 1)
+ stdStream << "Archives: " << ecs->NumArchives << endl;
+ if (ecs->NumArchiveErrors != 0 || ecs->NumFileErrors != 0)
+ {
+ if (ecs->NumArchives > 1)
+ {
+ stdStream << endl;
+ if (ecs->NumArchiveErrors != 0)
+ stdStream << "Archive Errors: " << ecs->NumArchiveErrors << endl;
+ if (ecs->NumFileErrors != 0)
+ stdStream << "Sub items Errors: " << ecs->NumFileErrors << endl;
+ }
+ if (result != S_OK)
+ throw CSystemException(result);
+ return NExitCode::kFatalError;
+ }
+ if (result != S_OK)
+ throw CSystemException(result);
+ if (stat.NumFolders != 0)
+ stdStream << "Folders: " << stat.NumFolders << endl;
+ if (stat.NumFiles != 1 || stat.NumFolders != 0)
+ stdStream << "Files: " << stat.NumFiles << endl;
+ stdStream
+ << "Size: " << stat.UnpackSize << endl
+ << "Compressed: " << stat.PackSize << endl;
+ if (options.CalcCrc)
+ {
+ char s[16];
+ ConvertUInt32ToHexWithZeros(stat.CrcSum, s);
+ stdStream << "CRC: " << s << endl;
+ }
+ }
+ else
+ {
+ UInt64 numErrors = 0;
+ HRESULT result = ListArchives(
+ codecs,
+ formatIndices,
+ options.StdInMode,
+ options.ArchivePathsSorted,
+ options.ArchivePathsFullSorted,
+ options.WildcardCensor.Pairs.Front().Head,
+ options.EnableHeaders,
+ options.TechMode,
+ #ifndef _NO_CRYPTO
+ options.PasswordEnabled,
+ options.Password,
+ #endif
+ numErrors);
+ if (numErrors > 0)
+ {
+ g_StdOut << endl << "Errors: " << numErrors;
+ return NExitCode::kFatalError;
+ }
+ if (result != S_OK)
+ throw CSystemException(result);
+ }
+ }
+ else if (options.Command.IsFromUpdateGroup())
+ {
+ CUpdateOptions &uo = options.UpdateOptions;
+ if (uo.SfxMode && uo.SfxModule.IsEmpty())
+ uo.SfxModule = kDefaultSfxModule;
+
+ COpenCallbackConsole openCallback;
+ openCallback.OutStream = &stdStream;
+
+ #ifndef _NO_CRYPTO
+ bool passwordIsDefined =
+ options.PasswordEnabled && !options.Password.IsEmpty();
+ openCallback.PasswordIsDefined = passwordIsDefined;
+ openCallback.Password = options.Password;
+ #endif
+
+ CUpdateCallbackConsole callback;
+ callback.EnablePercents = options.EnablePercents;
+
+ #ifndef _NO_CRYPTO
+ callback.PasswordIsDefined = passwordIsDefined;
+ callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty();
+ callback.Password = options.Password;
+ #endif
+ callback.StdOutMode = uo.StdOutMode;
+ callback.Init(&stdStream);
+
+ CUpdateErrorInfo errorInfo;
+
+ if (!uo.Init(codecs, formatIndices, options.ArchiveName))
+ throw kUnsupportedArcTypeMessage;
+ HRESULT result = UpdateArchive(codecs,
+ options.WildcardCensor, uo,
+ errorInfo, &openCallback, &callback);
+
+ int exitCode = NExitCode::kSuccess;
+ if (callback.CantFindFiles.Size() > 0)
+ {
+ stdStream << endl;
+ stdStream << "WARNINGS for files:" << endl << endl;
+ int numErrors = callback.CantFindFiles.Size();
+ for (int i = 0; i < numErrors; i++)
+ {
+ stdStream << callback.CantFindFiles[i] << " : ";
+ stdStream << NError::MyFormatMessageW(callback.CantFindCodes[i]) << endl;
+ }
+ stdStream << "----------------" << endl;
+ stdStream << "WARNING: Cannot find " << numErrors << " file";
+ if (numErrors > 1)
+ stdStream << "s";
+ stdStream << endl;
+ exitCode = NExitCode::kWarning;
+ }
+
+ if (result != S_OK)
+ {
+ UString message;
+ if (!errorInfo.Message.IsEmpty())
+ {
+ message += errorInfo.Message;
+ message += L"\n";
+ }
+ if (!errorInfo.FileName.IsEmpty())
+ {
+ message += errorInfo.FileName;
+ message += L"\n";
+ }
+ if (!errorInfo.FileName2.IsEmpty())
+ {
+ message += errorInfo.FileName2;
+ message += L"\n";
+ }
+ if (errorInfo.SystemError != 0)
+ {
+ message += NError::MyFormatMessageW(errorInfo.SystemError);
+ message += L"\n";
+ }
+ if (!message.IsEmpty())
+ stdStream << L"\nError:\n" << message;
+ throw CSystemException(result);
+ }
+ int numErrors = callback.FailedFiles.Size();
+ if (numErrors == 0)
+ {
+ if (callback.CantFindFiles.Size() == 0)
+ stdStream << kEverythingIsOk << endl;
+ }
+ else
+ {
+ stdStream << endl;
+ stdStream << "WARNINGS for files:" << endl << endl;
+ for (int i = 0; i < numErrors; i++)
+ {
+ stdStream << callback.FailedFiles[i] << " : ";
+ stdStream << NError::MyFormatMessageW(callback.FailedCodes[i]) << endl;
+ }
+ stdStream << "----------------" << endl;
+ stdStream << "WARNING: Cannot open " << numErrors << " file";
+ if (numErrors > 1)
+ stdStream << "s";
+ stdStream << endl;
+ exitCode = NExitCode::kWarning;
+ }
+ return exitCode;
+ }
+ else
+ PrintHelpAndExit(stdStream);
+ return 0;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/MainAr.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/MainAr.cpp
new file mode 100644
index 000000000..c54a3d098
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/MainAr.cpp
@@ -0,0 +1,125 @@
+// MainAr.cpp
+
+#include "StdAfx.h"
+
+#include "Common/MyException.h"
+#include "Common/StdOutStream.h"
+
+#include "Windows/Error.h"
+#include "Windows/NtCheck.h"
+
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/ExitCode.h"
+
+#include "ConsoleClose.h"
+
+using namespace NWindows;
+
+CStdOutStream *g_StdStream = 0;
+
+extern int Main2(
+ #ifndef _WIN32
+ int numArgs, const char *args[]
+ #endif
+);
+
+static const char *kExceptionErrorMessage = "\n\nError:\n";
+static const char *kUserBreak = "\nBreak signaled\n";
+static const char *kMemoryExceptionMessage = "\n\nERROR: Can't allocate required memory!\n";
+static const char *kUnknownExceptionMessage = "\n\nUnknown Error\n";
+static const char *kInternalExceptionMessage = "\n\nInternal Error #";
+
+#define NT_CHECK_FAIL_ACTION (*g_StdStream) << "Unsupported Windows version"; return NExitCode::kFatalError;
+
+int MY_CDECL main
+(
+ #ifndef _WIN32
+ int numArgs, const char *args[]
+ #endif
+)
+{
+ g_StdStream = &g_StdOut;
+
+ NT_CHECK
+
+ NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
+ int res = 0;
+ try
+ {
+ res = Main2(
+ #ifndef _WIN32
+ numArgs, args
+ #endif
+ );
+ }
+ catch(const CNewException &)
+ {
+ (*g_StdStream) << kMemoryExceptionMessage;
+ return (NExitCode::kMemoryError);
+ }
+ catch(const NConsoleClose::CCtrlBreakException &)
+ {
+ (*g_StdStream) << endl << kUserBreak;
+ return (NExitCode::kUserBreak);
+ }
+ catch(const CArchiveCommandLineException &e)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << e << endl;
+ return (NExitCode::kUserError);
+ }
+ catch(const CSystemException &systemError)
+ {
+ if (systemError.ErrorCode == E_OUTOFMEMORY)
+ {
+ (*g_StdStream) << kMemoryExceptionMessage;
+ return (NExitCode::kMemoryError);
+ }
+ if (systemError.ErrorCode == E_ABORT)
+ {
+ (*g_StdStream) << endl << kUserBreak;
+ return (NExitCode::kUserBreak);
+ }
+ UString message;
+ NError::MyFormatMessage(systemError.ErrorCode, message);
+ (*g_StdStream) << endl << endl << "System error:" << endl << message << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(NExitCode::EEnum &exitCode)
+ {
+ (*g_StdStream) << kInternalExceptionMessage << exitCode << endl;
+ return (exitCode);
+ }
+ /*
+ catch(const NExitCode::CMultipleErrors &multipleErrors)
+ {
+ (*g_StdStream) << endl << multipleErrors.NumErrors << " errors" << endl;
+ return (NExitCode::kFatalError);
+ }
+ */
+ catch(const UString &s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(const AString &s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(const char *s)
+ {
+ (*g_StdStream) << kExceptionErrorMessage << s << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(int t)
+ {
+ (*g_StdStream) << kInternalExceptionMessage << t << endl;
+ return (NExitCode::kFatalError);
+ }
+ catch(...)
+ {
+ (*g_StdStream) << kUnknownExceptionMessage;
+ return (NExitCode::kFatalError);
+ }
+ return res;
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
new file mode 100644
index 000000000..7dba2ad5d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
@@ -0,0 +1,58 @@
+// OpenCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "OpenCallbackConsole.h"
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+
+HRESULT COpenCallbackConsole::Open_CheckBreak()
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *, const UInt64 *)
+{
+ return Open_CheckBreak();
+}
+
+HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *, const UInt64 *)
+{
+ return Open_CheckBreak();
+}
+
+#ifndef _NO_CRYPTO
+
+HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password)
+{
+ PasswordWasAsked = true;
+ RINOK(Open_CheckBreak());
+ if (!PasswordIsDefined)
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+HRESULT COpenCallbackConsole::Open_GetPasswordIfAny(UString &password)
+{
+ if (PasswordIsDefined)
+ password = Password;
+ return S_OK;
+}
+
+bool COpenCallbackConsole::Open_WasPasswordAsked()
+{
+ return PasswordWasAsked;
+}
+
+void COpenCallbackConsole::Open_ClearPasswordWasAskedFlag()
+{
+ PasswordWasAsked = false;
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/OpenCallbackConsole.h b/src/libs/7zip/win/CPP/7zip/UI/Console/OpenCallbackConsole.h
new file mode 100644
index 000000000..c002e6a72
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/OpenCallbackConsole.h
@@ -0,0 +1,24 @@
+// OpenCallbackConsole.h
+
+#ifndef __OPENCALLBACKCONSOLE_H
+#define __OPENCALLBACKCONSOLE_H
+
+#include "Common/StdOutStream.h"
+#include "../Common/ArchiveOpenCallback.h"
+
+class COpenCallbackConsole: public IOpenCallbackUI
+{
+public:
+ INTERFACE_IOpenCallbackUI(;)
+
+ CStdOutStream *OutStream;
+
+ #ifndef _NO_CRYPTO
+ bool PasswordIsDefined;
+ bool PasswordWasAsked;
+ UString Password;
+ COpenCallbackConsole(): PasswordIsDefined(false), PasswordWasAsked(false) {}
+ #endif
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.cpp
new file mode 100644
index 000000000..28452b177
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.cpp
@@ -0,0 +1,90 @@
+// PercentPrinter.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/MyString.h"
+
+#include "PercentPrinter.h"
+
+const int kPaddingSize = 2;
+const int kPercentsSize = 4;
+const int kMaxExtraSize = kPaddingSize + 32 + kPercentsSize;
+
+static void ClearPrev(char *p, int num)
+{
+ int i;
+ for (i = 0; i < num; i++) *p++ = '\b';
+ for (i = 0; i < num; i++) *p++ = ' ';
+ for (i = 0; i < num; i++) *p++ = '\b';
+ *p = '\0';
+}
+
+void CPercentPrinter::ClosePrint()
+{
+ if (m_NumExtraChars == 0)
+ return;
+ char s[kMaxExtraSize * 3 + 1];
+ ClearPrev(s, m_NumExtraChars);
+ (*OutStream) << s;
+ m_NumExtraChars = 0;
+}
+
+void CPercentPrinter::PrintString(const char *s)
+{
+ ClosePrint();
+ (*OutStream) << s;
+}
+
+void CPercentPrinter::PrintString(const wchar_t *s)
+{
+ ClosePrint();
+ (*OutStream) << s;
+}
+
+void CPercentPrinter::PrintNewLine()
+{
+ ClosePrint();
+ (*OutStream) << "\n";
+}
+
+void CPercentPrinter::RePrintRatio()
+{
+ char s[32];
+ ConvertUInt64ToString(((m_Total == 0) ? 0 : (m_CurValue * 100 / m_Total)), s);
+ int size = (int)strlen(s);
+ s[size++] = '%';
+ s[size] = '\0';
+
+ int extraSize = kPaddingSize + MyMax(size, kPercentsSize);
+ if (extraSize < m_NumExtraChars)
+ extraSize = m_NumExtraChars;
+
+ char fullString[kMaxExtraSize * 3];
+ char *p = fullString;
+ int i;
+ if (m_NumExtraChars == 0)
+ {
+ for (i = 0; i < extraSize; i++)
+ *p++ = ' ';
+ m_NumExtraChars = extraSize;
+ }
+
+ for (i = 0; i < m_NumExtraChars; i++)
+ *p++ = '\b';
+ m_NumExtraChars = extraSize;
+ for (; size < m_NumExtraChars; size++)
+ *p++ = ' ';
+ MyStringCopy(p, s);
+ (*OutStream) << fullString;
+ OutStream->Flush();
+ m_PrevValue = m_CurValue;
+}
+
+void CPercentPrinter::PrintRatio()
+{
+ if (m_CurValue < m_PrevValue + m_MinStepSize &&
+ m_CurValue + m_MinStepSize > m_PrevValue && m_NumExtraChars != 0)
+ return;
+ RePrintRatio();
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.h b/src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.h
new file mode 100644
index 000000000..97f2e6adb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/PercentPrinter.h
@@ -0,0 +1,31 @@
+// PercentPrinter.h
+
+#ifndef __PERCENTPRINTER_H
+#define __PERCENTPRINTER_H
+
+#include "Common/Types.h"
+#include "Common/StdOutStream.h"
+
+class CPercentPrinter
+{
+ UInt64 m_MinStepSize;
+ UInt64 m_PrevValue;
+ UInt64 m_CurValue;
+ UInt64 m_Total;
+ int m_NumExtraChars;
+public:
+ CStdOutStream *OutStream;
+
+ CPercentPrinter(UInt64 minStepSize = 1): m_MinStepSize(minStepSize),
+ m_PrevValue(0), m_CurValue(0), m_Total(1), m_NumExtraChars(0) {}
+ void SetTotal(UInt64 total) { m_Total = total; m_PrevValue = 0; }
+ void SetRatio(UInt64 doneValue) { m_CurValue = doneValue; }
+ void PrintString(const char *s);
+ void PrintString(const wchar_t *s);
+ void PrintNewLine();
+ void ClosePrint();
+ void RePrintRatio();
+ void PrintRatio();
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.cpp
new file mode 100644
index 000000000..d0feea85c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.h b/src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.h
new file mode 100644
index 000000000..2e4be10b2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
new file mode 100644
index 000000000..7f3373197
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
@@ -0,0 +1,261 @@
+// UpdateCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateCallbackConsole.h"
+
+#include "Windows/Error.h"
+#ifndef _7ZIP_ST
+#include "Windows/Synchronization.h"
+#endif
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+
+using namespace NWindows;
+
+#ifndef _7ZIP_ST
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+static const wchar_t *kEmptyFileAlias = L"[Content]";
+
+static const char *kCreatingArchiveMessage = "Creating archive ";
+static const char *kUpdatingArchiveMessage = "Updating archive ";
+static const char *kScanningMessage = "Scanning";
+
+
+HRESULT CUpdateCallbackConsole::OpenResult(const wchar_t *name, HRESULT result)
+{
+ (*OutStream) << endl;
+ if (result != S_OK)
+ (*OutStream) << "Error: " << name << " is not supported archive" << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartScanning()
+{
+ (*OutStream) << kScanningMessage;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::ScanProgress(UInt64 /* numFolders */, UInt64 /* numFiles */, const wchar_t * /* path */)
+{
+ return CheckBreak();
+}
+
+HRESULT CUpdateCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError)
+{
+ CantFindFiles.Add(name);
+ CantFindCodes.Add(systemError);
+ // m_PercentPrinter.ClosePrint();
+ if (!m_WarningsMode)
+ {
+ (*OutStream) << endl << endl;
+ m_PercentPrinter.PrintNewLine();
+ m_WarningsMode = true;
+ }
+ m_PercentPrinter.PrintString(name);
+ m_PercentPrinter.PrintString(": WARNING: ");
+ m_PercentPrinter.PrintString(NError::MyFormatMessageW(systemError));
+ m_PercentPrinter.PrintNewLine();
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::FinishScanning()
+{
+ (*OutStream) << endl << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
+{
+ if(updating)
+ (*OutStream) << kUpdatingArchiveMessage;
+ else
+ (*OutStream) << kCreatingArchiveMessage;
+ if (name != 0)
+ (*OutStream) << name;
+ else
+ (*OutStream) << "StdOut";
+ (*OutStream) << endl << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::FinishArchive()
+{
+ (*OutStream) << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CheckBreak()
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::Finilize()
+{
+ MT_LOCK
+ if (m_NeedBeClosed)
+ {
+ if (EnablePercents)
+ {
+ m_PercentPrinter.ClosePrint();
+ }
+ if (!StdOutMode && m_NeedNewLine)
+ {
+ m_PercentPrinter.PrintNewLine();
+ m_NeedNewLine = false;
+ }
+ m_NeedBeClosed = false;
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
+{
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
+{
+ MT_LOCK
+ if (EnablePercents)
+ m_PercentPrinter.SetTotal(size);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
+{
+ MT_LOCK
+ if (completeValue != NULL)
+ {
+ if (EnablePercents)
+ {
+ m_PercentPrinter.SetRatio(*completeValue);
+ m_PercentPrinter.PrintRatio();
+ m_NeedBeClosed = true;
+ }
+ }
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isAnti)
+{
+ MT_LOCK
+ if (StdOutMode)
+ return S_OK;
+ if(isAnti)
+ m_PercentPrinter.PrintString("Anti item ");
+ else
+ m_PercentPrinter.PrintString("Compressing ");
+ if (name[0] == 0)
+ name = kEmptyFileAlias;
+ m_PercentPrinter.PrintString(name);
+ if (EnablePercents)
+ m_PercentPrinter.RePrintRatio();
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::OpenFileError(const wchar_t *name, DWORD systemError)
+{
+ MT_LOCK
+ FailedCodes.Add(systemError);
+ FailedFiles.Add(name);
+ // if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ m_PercentPrinter.ClosePrint();
+ m_PercentPrinter.PrintNewLine();
+ m_PercentPrinter.PrintString("WARNING: ");
+ m_PercentPrinter.PrintString(NError::MyFormatMessageW(systemError));
+ return S_FALSE;
+ }
+ // return systemError;
+}
+
+HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 )
+{
+ m_NeedBeClosed = true;
+ m_NeedNewLine = true;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ *password = NULL;
+
+ #ifdef _NO_CRYPTO
+
+ *passwordIsDefined = false;
+ return S_OK;
+
+ #else
+
+ if (!PasswordIsDefined)
+ {
+ if (AskPassword)
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ }
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ return StringToBstr(Password, password);
+
+ #endif
+}
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+ *password = NULL;
+
+ #ifdef _NO_CRYPTO
+
+ return E_NOTIMPL;
+
+ #else
+
+ if (!PasswordIsDefined)
+ {
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ }
+ return StringToBstr(Password, password);
+
+ #endif
+}
+
+/*
+HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name)
+{
+ // MT_LOCK
+ if (StdOutMode)
+ return S_OK;
+ RINOK(Finilize());
+ m_PercentPrinter.PrintString("Deleting ");
+ if (name[0] == 0)
+ name = kEmptyFileAlias;
+ m_PercentPrinter.PrintString(name);
+ if (EnablePercents)
+ m_PercentPrinter.RePrintRatio();
+ m_NeedBeClosed = true;
+ m_NeedNewLine = true;
+ return S_OK;
+}
+*/
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/src/libs/7zip/win/CPP/7zip/UI/Console/UpdateCallbackConsole.h
new file mode 100644
index 000000000..5ffe3eb7a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/UpdateCallbackConsole.h
@@ -0,0 +1,62 @@
+// UpdateCallbackConsole.h
+
+#ifndef __UPDATE_CALLBACK_CONSOLE_H
+#define __UPDATE_CALLBACK_CONSOLE_H
+
+#include "Common/StdOutStream.h"
+
+#include "../Common/Update.h"
+
+#include "PercentPrinter.h"
+
+class CUpdateCallbackConsole: public IUpdateCallbackUI2
+{
+ CPercentPrinter m_PercentPrinter;
+ bool m_NeedBeClosed;
+ bool m_NeedNewLine;
+
+ bool m_WarningsMode;
+
+ CStdOutStream *OutStream;
+public:
+ bool EnablePercents;
+ bool StdOutMode;
+
+ #ifndef _NO_CRYPTO
+ bool PasswordIsDefined;
+ UString Password;
+ bool AskPassword;
+ #endif
+
+ CUpdateCallbackConsole():
+ m_PercentPrinter(1 << 16),
+ #ifndef _NO_CRYPTO
+ PasswordIsDefined(false),
+ AskPassword(false),
+ #endif
+ StdOutMode(false),
+ EnablePercents(true),
+ m_WarningsMode(false)
+ {}
+
+ ~CUpdateCallbackConsole() { Finilize(); }
+ void Init(CStdOutStream *outStream)
+ {
+ m_NeedBeClosed = false;
+ m_NeedNewLine = false;
+ FailedFiles.Clear();
+ FailedCodes.Clear();
+ OutStream = outStream;
+ m_PercentPrinter.OutStream = outStream;
+ }
+
+ INTERFACE_IUpdateCallbackUI2(;)
+
+ UStringVector FailedFiles;
+ CRecordVector<HRESULT> FailedCodes;
+
+ UStringVector CantFindFiles;
+ CRecordVector<HRESULT> CantFindCodes;
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/UserInputUtils.cpp b/src/libs/7zip/win/CPP/7zip/UI/Console/UserInputUtils.cpp
new file mode 100644
index 000000000..754680090
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/UserInputUtils.cpp
@@ -0,0 +1,87 @@
+// UserInputUtils.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StdInStream.h"
+#include "Common/StringConvert.h"
+
+#include "UserInputUtils.h"
+
+static const char kYes = 'Y';
+static const char kNo = 'N';
+static const char kYesAll = 'A';
+static const char kNoAll = 'S';
+static const char kAutoRenameAll = 'U';
+static const char kQuit = 'Q';
+
+static const char *kFirstQuestionMessage = "?\n";
+static const char *kHelpQuestionMessage =
+ "(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename all / (Q)uit? ";
+
+// return true if pressed Quite;
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream)
+{
+ (*outStream) << kFirstQuestionMessage;
+ for (;;)
+ {
+ (*outStream) << kHelpQuestionMessage;
+ outStream->Flush();
+ AString scannedString = g_StdIn.ScanStringUntilNewLine();
+ scannedString.Trim();
+ if (!scannedString.IsEmpty())
+ switch(
+ ::MyCharUpper(
+ #ifdef UNDER_CE
+ (wchar_t)
+ #endif
+ scannedString[0]))
+ {
+ case kYes:
+ return NUserAnswerMode::kYes;
+ case kNo:
+ return NUserAnswerMode::kNo;
+ case kYesAll:
+ return NUserAnswerMode::kYesAll;
+ case kNoAll:
+ return NUserAnswerMode::kNoAll;
+ case kAutoRenameAll:
+ return NUserAnswerMode::kAutoRenameAll;
+ case kQuit:
+ return NUserAnswerMode::kQuit;
+ }
+ }
+}
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+#define MY_DISABLE_ECHO
+#endif
+#endif
+
+UString GetPassword(CStdOutStream *outStream)
+{
+ (*outStream) << "\nEnter password"
+ #ifdef MY_DISABLE_ECHO
+ " (will not be echoed)"
+ #endif
+ ":";
+ outStream->Flush();
+
+ #ifdef MY_DISABLE_ECHO
+ HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
+ bool wasChanged = false;
+ DWORD mode = 0;
+ if (console != INVALID_HANDLE_VALUE && console != 0)
+ if (GetConsoleMode(console, &mode))
+ wasChanged = (SetConsoleMode(console, mode & ~ENABLE_ECHO_INPUT) != 0);
+ UString res = g_StdIn.ScanUStringUntilNewLine();
+ if (wasChanged)
+ SetConsoleMode(console, mode);
+ (*outStream) << "\n";
+ outStream->Flush();
+ return res;
+ #else
+ return g_StdIn.ScanUStringUntilNewLine();
+ #endif
+}
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Console/UserInputUtils.h b/src/libs/7zip/win/CPP/7zip/UI/Console/UserInputUtils.h
new file mode 100644
index 000000000..8b5232b3f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/7zip/UI/Console/UserInputUtils.h
@@ -0,0 +1,24 @@
+// UserInputUtils.h
+
+#ifndef __USERINPUTUTILS_H
+#define __USERINPUTUTILS_H
+
+#include "Common/StdOutStream.h"
+
+namespace NUserAnswerMode {
+
+enum EEnum
+{
+ kYes,
+ kNo,
+ kYesAll,
+ kNoAll,
+ kAutoRenameAll,
+ kQuit
+};
+}
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream);
+UString GetPassword(CStdOutStream *outStream);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/AutoPtr.h b/src/libs/7zip/win/CPP/Common/AutoPtr.h
new file mode 100644
index 000000000..006d31551
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/AutoPtr.h
@@ -0,0 +1,35 @@
+// Common/AutoPtr.h
+
+#ifndef __COMMON_AUTOPTR_H
+#define __COMMON_AUTOPTR_H
+
+template<class T> class CMyAutoPtr
+{
+ T *_p;
+public:
+ CMyAutoPtr(T *p = 0) : _p(p) {}
+ CMyAutoPtr(CMyAutoPtr<T>& p): _p(p.release()) {}
+ CMyAutoPtr<T>& operator=(CMyAutoPtr<T>& p)
+ {
+ reset(p.release());
+ return (*this);
+ }
+ ~CMyAutoPtr() { delete _p; }
+ T& operator*() const { return *_p; }
+ // T* operator->() const { return (&**this); }
+ T* get() const { return _p; }
+ T* release()
+ {
+ T *tmp = _p;
+ _p = 0;
+ return tmp;
+ }
+ void reset(T* p = 0)
+ {
+ if (p != _p)
+ delete _p;
+ _p = p;
+ }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/Buffer.h b/src/libs/7zip/win/CPP/Common/Buffer.h
new file mode 100644
index 000000000..118fe11fc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Buffer.h
@@ -0,0 +1,77 @@
+// Common/Buffer.h
+
+#ifndef __COMMON_BUFFER_H
+#define __COMMON_BUFFER_H
+
+#include "Defs.h"
+
+template <class T> class CBuffer
+{
+protected:
+ size_t _capacity;
+ T *_items;
+public:
+ void Free()
+ {
+ delete []_items;
+ _items = 0;
+ _capacity = 0;
+ }
+ CBuffer(): _capacity(0), _items(0) {};
+ CBuffer(const CBuffer &buffer): _capacity(0), _items(0) { *this = buffer; }
+ CBuffer(size_t size): _items(0), _capacity(0) { SetCapacity(size); }
+ virtual ~CBuffer() { delete []_items; }
+ operator T *() { return _items; };
+ operator const T *() const { return _items; };
+ size_t GetCapacity() const { return _capacity; }
+ void SetCapacity(size_t newCapacity)
+ {
+ if (newCapacity == _capacity)
+ return;
+ T *newBuffer;
+ if (newCapacity > 0)
+ {
+ newBuffer = new T[newCapacity];
+ if (_capacity > 0)
+ memmove(newBuffer, _items, MyMin(_capacity, newCapacity) * sizeof(T));
+ }
+ else
+ newBuffer = 0;
+ delete []_items;
+ _items = newBuffer;
+ _capacity = newCapacity;
+ }
+ CBuffer& operator=(const CBuffer &buffer)
+ {
+ Free();
+ if (buffer._capacity > 0)
+ {
+ SetCapacity(buffer._capacity);
+ memmove(_items, buffer._items, buffer._capacity * sizeof(T));
+ }
+ return *this;
+ }
+};
+
+template <class T>
+bool operator==(const CBuffer<T>& b1, const CBuffer<T>& b2)
+{
+ if (b1.GetCapacity() != b2.GetCapacity())
+ return false;
+ for (size_t i = 0; i < b1.GetCapacity(); i++)
+ if (b1[i] != b2[i])
+ return false;
+ return true;
+}
+
+template <class T>
+bool operator!=(const CBuffer<T>& b1, const CBuffer<T>& b2)
+{
+ return !(b1 == b2);
+}
+
+typedef CBuffer<char> CCharBuffer;
+typedef CBuffer<wchar_t> CWCharBuffer;
+typedef CBuffer<unsigned char> CByteBuffer;
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/CRC.cpp b/src/libs/7zip/win/CPP/Common/CRC.cpp
new file mode 100644
index 000000000..9a9f81fb7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/CRC.cpp
@@ -0,0 +1,7 @@
+// Common/CRC.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/7zCrc.h"
+
+struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit;
diff --git a/src/libs/7zip/win/CPP/Common/C_FileIO.cpp b/src/libs/7zip/win/CPP/Common/C_FileIO.cpp
new file mode 100644
index 000000000..b4893d658
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/C_FileIO.cpp
@@ -0,0 +1,88 @@
+// Common/C_FileIO.h
+
+#include "C_FileIO.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace NC {
+namespace NFile {
+namespace NIO {
+
+bool CFileBase::OpenBinary(const char *name, int flags)
+{
+ #ifdef O_BINARY
+ flags |= O_BINARY;
+ #endif
+ Close();
+ _handle = ::open(name, flags, 0666);
+ return _handle != -1;
+}
+
+bool CFileBase::Close()
+{
+ if (_handle == -1)
+ return true;
+ if (close(_handle) != 0)
+ return false;
+ _handle = -1;
+ return true;
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+ off_t curPos = Seek(0, SEEK_CUR);
+ off_t lengthTemp = Seek(0, SEEK_END);
+ Seek(curPos, SEEK_SET);
+ length = (UInt64)lengthTemp;
+ return true;
+}
+
+off_t CFileBase::Seek(off_t distanceToMove, int moveMethod) const
+{
+ return ::lseek(_handle, distanceToMove, moveMethod);
+}
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(const char *name)
+{
+ return CFileBase::OpenBinary(name, O_RDONLY);
+}
+
+bool CInFile::OpenShared(const char *name, bool)
+{
+ return Open(name);
+}
+
+ssize_t CInFile::Read(void *data, size_t size)
+{
+ return read(_handle, data, size);
+}
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Create(const char *name, bool createAlways)
+{
+ if (createAlways)
+ {
+ Close();
+ _handle = ::creat(name, 0666);
+ return _handle != -1;
+ }
+ return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY);
+}
+
+bool COutFile::Open(const char *name, DWORD creationDisposition)
+{
+ return Create(name, false);
+}
+
+ssize_t COutFile::Write(const void *data, size_t size)
+{
+ return write(_handle, data, size);
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/Common/C_FileIO.h b/src/libs/7zip/win/CPP/Common/C_FileIO.h
new file mode 100644
index 000000000..27aa56869
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/C_FileIO.h
@@ -0,0 +1,47 @@
+// Common/C_FileIO.h
+
+#ifndef __COMMON_C_FILEIO_H
+#define __COMMON_C_FILEIO_H
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "Types.h"
+#include "MyWindows.h"
+
+namespace NC {
+namespace NFile {
+namespace NIO {
+
+class CFileBase
+{
+protected:
+ int _handle;
+ bool OpenBinary(const char *name, int flags);
+public:
+ CFileBase(): _handle(-1) {};
+ ~CFileBase() { Close(); }
+ bool Close();
+ bool GetLength(UInt64 &length) const;
+ off_t Seek(off_t distanceToMove, int moveMethod) const;
+};
+
+class CInFile: public CFileBase
+{
+public:
+ bool Open(const char *name);
+ bool OpenShared(const char *name, bool shareForWrite);
+ ssize_t Read(void *data, size_t size);
+};
+
+class COutFile: public CFileBase
+{
+public:
+ bool Create(const char *name, bool createAlways);
+ bool Open(const char *name, DWORD creationDisposition);
+ ssize_t Write(const void *data, size_t size);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/ComTry.h b/src/libs/7zip/win/CPP/Common/ComTry.h
new file mode 100644
index 000000000..fb4ef0459
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/ComTry.h
@@ -0,0 +1,17 @@
+// ComTry.h
+
+#ifndef __COM_TRY_H
+#define __COM_TRY_H
+
+#include "MyWindows.h"
+// #include "Exception.h"
+// #include "NewHandler.h"
+
+#define COM_TRY_BEGIN try {
+#define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; }
+
+ // catch(const CNewException &) { return E_OUTOFMEMORY; }
+ // catch(const CSystemException &e) { return e.ErrorCode; }
+ // catch(...) { return E_FAIL; }
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/CommandLineParser.cpp b/src/libs/7zip/win/CPP/Common/CommandLineParser.cpp
new file mode 100644
index 000000000..80b467fcb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/CommandLineParser.cpp
@@ -0,0 +1,229 @@
+// CommandLineParser.cpp
+
+#include "StdAfx.h"
+
+#include "CommandLineParser.h"
+
+namespace NCommandLineParser {
+
+bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
+{
+ dest1.Empty();
+ dest2.Empty();
+ bool quoteMode = false;
+ int i;
+ for (i = 0; i < src.Length(); i++)
+ {
+ wchar_t c = src[i];
+ if (c == L' ' && !quoteMode)
+ {
+ dest2 = src.Mid(i + 1);
+ return i != 0;
+ }
+ if (c == L'\"')
+ quoteMode = !quoteMode;
+ else
+ dest1 += c;
+ }
+ return i != 0;
+}
+
+void SplitCommandLine(const UString &s, UStringVector &parts)
+{
+ UString sTemp = s;
+ sTemp.Trim();
+ parts.Clear();
+ for (;;)
+ {
+ UString s1, s2;
+ if (SplitCommandLine(sTemp, s1, s2))
+ parts.Add(s1);
+ if (s2.IsEmpty())
+ break;
+ sTemp = s2;
+ }
+}
+
+
+static const wchar_t kSwitchID1 = '-';
+// static const wchar_t kSwitchID2 = '/';
+
+static const wchar_t kSwitchMinus = '-';
+static const wchar_t *kStopSwitchParsing = L"--";
+
+static bool IsItSwitchChar(wchar_t c)
+{
+ return (c == kSwitchID1 /*|| c == kSwitchID2 */);
+}
+
+CParser::CParser(int numSwitches):
+ _numSwitches(numSwitches)
+{
+ _switches = new CSwitchResult[_numSwitches];
+}
+
+CParser::~CParser()
+{
+ delete []_switches;
+}
+
+void CParser::ParseStrings(const CSwitchForm *switchForms,
+ const UStringVector &commandStrings)
+{
+ int numCommandStrings = commandStrings.Size();
+ bool stopSwitch = false;
+ for (int i = 0; i < numCommandStrings; i++)
+ {
+ const UString &s = commandStrings[i];
+ if (stopSwitch)
+ NonSwitchStrings.Add(s);
+ else
+ if (s == kStopSwitchParsing)
+ stopSwitch = true;
+ else
+ if (!ParseString(s, switchForms))
+ NonSwitchStrings.Add(s);
+ }
+}
+
+// if string contains switch then function updates switch structures
+// out: (string is a switch)
+bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms)
+{
+ int len = s.Length();
+ if (len == 0)
+ return false;
+ int pos = 0;
+ if (!IsItSwitchChar(s[pos]))
+ return false;
+ while (pos < len)
+ {
+ if (IsItSwitchChar(s[pos]))
+ pos++;
+ const int kNoLen = -1;
+ int matchedSwitchIndex = 0; // GCC Warning
+ int maxLen = kNoLen;
+ for (int switchIndex = 0; switchIndex < _numSwitches; switchIndex++)
+ {
+ int switchLen = MyStringLen(switchForms[switchIndex].IDString);
+ if (switchLen <= maxLen || pos + switchLen > len)
+ continue;
+
+ UString temp = s + pos;
+ temp = temp.Left(switchLen);
+ if (temp.CompareNoCase(switchForms[switchIndex].IDString) == 0)
+ // if (_strnicmp(switchForms[switchIndex].IDString, LPCSTR(s) + pos, switchLen) == 0)
+ {
+ matchedSwitchIndex = switchIndex;
+ maxLen = switchLen;
+ }
+ }
+ if (maxLen == kNoLen)
+ throw "maxLen == kNoLen";
+ CSwitchResult &matchedSwitch = _switches[matchedSwitchIndex];
+ const CSwitchForm &switchForm = switchForms[matchedSwitchIndex];
+ if ((!switchForm.Multi) && matchedSwitch.ThereIs)
+ throw "switch must be single";
+ matchedSwitch.ThereIs = true;
+ pos += maxLen;
+ int tailSize = len - pos;
+ NSwitchType::EEnum type = switchForm.Type;
+ switch(type)
+ {
+ case NSwitchType::kPostMinus:
+ {
+ if (tailSize == 0)
+ matchedSwitch.WithMinus = false;
+ else
+ {
+ matchedSwitch.WithMinus = (s[pos] == kSwitchMinus);
+ if (matchedSwitch.WithMinus)
+ pos++;
+ }
+ break;
+ }
+ case NSwitchType::kPostChar:
+ {
+ if (tailSize < switchForm.MinLen)
+ throw "switch is not full";
+ UString set = switchForm.PostCharSet;
+ const int kEmptyCharValue = -1;
+ if (tailSize == 0)
+ matchedSwitch.PostCharIndex = kEmptyCharValue;
+ else
+ {
+ int index = set.Find(s[pos]);
+ if (index < 0)
+ matchedSwitch.PostCharIndex = kEmptyCharValue;
+ else
+ {
+ matchedSwitch.PostCharIndex = index;
+ pos++;
+ }
+ }
+ break;
+ }
+ case NSwitchType::kLimitedPostString:
+ case NSwitchType::kUnLimitedPostString:
+ {
+ int minLen = switchForm.MinLen;
+ if (tailSize < minLen)
+ throw "switch is not full";
+ if (type == NSwitchType::kUnLimitedPostString)
+ {
+ matchedSwitch.PostStrings.Add(s.Mid(pos));
+ return true;
+ }
+ int maxLen = switchForm.MaxLen;
+ UString stringSwitch = s.Mid(pos, minLen);
+ pos += minLen;
+ for (int i = minLen; i < maxLen && pos < len; i++, pos++)
+ {
+ wchar_t c = s[pos];
+ if (IsItSwitchChar(c))
+ break;
+ stringSwitch += c;
+ }
+ matchedSwitch.PostStrings.Add(stringSwitch);
+ break;
+ }
+ case NSwitchType::kSimple:
+ break;
+ }
+ }
+ return true;
+}
+
+const CSwitchResult& CParser::operator[](size_t index) const
+{
+ return _switches[index];
+}
+
+/////////////////////////////////
+// Command parsing procedures
+
+int ParseCommand(int numCommandForms, const CCommandForm *commandForms,
+ const UString &commandString, UString &postString)
+{
+ for (int i = 0; i < numCommandForms; i++)
+ {
+ const UString id = commandForms[i].IDString;
+ if (commandForms[i].PostStringMode)
+ {
+ if (commandString.Find(id) == 0)
+ {
+ postString = commandString.Mid(id.Length());
+ return i;
+ }
+ }
+ else
+ if (commandString == id)
+ {
+ postString.Empty();
+ return i;
+ }
+ }
+ return -1;
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/Common/CommandLineParser.h b/src/libs/7zip/win/CPP/Common/CommandLineParser.h
new file mode 100644
index 000000000..3d0b41dd4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/CommandLineParser.h
@@ -0,0 +1,72 @@
+// Common/CommandLineParser.h
+
+#ifndef __COMMON_COMMAND_LINE_PARSER_H
+#define __COMMON_COMMAND_LINE_PARSER_H
+
+#include "MyString.h"
+
+namespace NCommandLineParser {
+
+bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2);
+void SplitCommandLine(const UString &s, UStringVector &parts);
+
+namespace NSwitchType {
+ enum EEnum
+ {
+ kSimple,
+ kPostMinus,
+ kLimitedPostString,
+ kUnLimitedPostString,
+ kPostChar
+ };
+}
+
+struct CSwitchForm
+{
+ const wchar_t *IDString;
+ NSwitchType::EEnum Type;
+ bool Multi;
+ int MinLen;
+ int MaxLen;
+ const wchar_t *PostCharSet;
+};
+
+struct CSwitchResult
+{
+ bool ThereIs;
+ bool WithMinus;
+ UStringVector PostStrings;
+ int PostCharIndex;
+ CSwitchResult(): ThereIs(false) {};
+};
+
+class CParser
+{
+ int _numSwitches;
+ CSwitchResult *_switches;
+ bool ParseString(const UString &s, const CSwitchForm *switchForms);
+public:
+ UStringVector NonSwitchStrings;
+ CParser(int numSwitches);
+ ~CParser();
+ void ParseStrings(const CSwitchForm *switchForms,
+ const UStringVector &commandStrings);
+ const CSwitchResult& operator[](size_t index) const;
+};
+
+/////////////////////////////////
+// Command parsing procedures
+
+struct CCommandForm
+{
+ const wchar_t *IDString;
+ bool PostStringMode;
+};
+
+// Returns: Index of form and postString; -1, if there is no match
+int ParseCommand(int numCommandForms, const CCommandForm *commandForms,
+ const UString &commandString, UString &postString);
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/Defs.h b/src/libs/7zip/win/CPP/Common/Defs.h
new file mode 100644
index 000000000..dad3ae8f1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Defs.h
@@ -0,0 +1,20 @@
+// Common/Defs.h
+
+#ifndef __COMMON_DEFS_H
+#define __COMMON_DEFS_H
+
+template <class T> inline T MyMin(T a, T b)
+ { return a < b ? a : b; }
+template <class T> inline T MyMax(T a, T b)
+ { return a > b ? a : b; }
+
+template <class T> inline int MyCompare(T a, T b)
+ { return a < b ? -1 : (a == b ? 0 : 1); }
+
+inline int BoolToInt(bool value)
+ { return (value ? 1: 0); }
+
+inline bool IntToBool(int value)
+ { return (value != 0); }
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/DynamicBuffer.h b/src/libs/7zip/win/CPP/Common/DynamicBuffer.h
new file mode 100644
index 000000000..bf52a7425
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/DynamicBuffer.h
@@ -0,0 +1,50 @@
+// Common/DynamicBuffer.h
+
+#ifndef __COMMON_DYNAMIC_BUFFER_H
+#define __COMMON_DYNAMIC_BUFFER_H
+
+#include "Buffer.h"
+
+template <class T> class CDynamicBuffer: public CBuffer<T>
+{
+ void GrowLength(size_t size)
+ {
+ size_t delta;
+ if (this->_capacity > 64)
+ delta = this->_capacity / 4;
+ else if (this->_capacity > 8)
+ delta = 16;
+ else
+ delta = 4;
+ delta = MyMax(delta, size);
+ size_t newCap = this->_capacity + delta;
+ if (newCap < delta)
+ newCap = this->_capacity + size;
+ SetCapacity(newCap);
+ }
+public:
+ CDynamicBuffer(): CBuffer<T>() {};
+ CDynamicBuffer(const CDynamicBuffer &buffer): CBuffer<T>(buffer) {};
+ CDynamicBuffer(size_t size): CBuffer<T>(size) {};
+ CDynamicBuffer& operator=(const CDynamicBuffer &buffer)
+ {
+ this->Free();
+ if (buffer._capacity > 0)
+ {
+ SetCapacity(buffer._capacity);
+ memmove(this->_items, buffer._items, buffer._capacity * sizeof(T));
+ }
+ return *this;
+ }
+ void EnsureCapacity(size_t capacity)
+ {
+ if (this->_capacity < capacity)
+ GrowLength(capacity - this->_capacity);
+ }
+};
+
+typedef CDynamicBuffer<char> CCharDynamicBuffer;
+typedef CDynamicBuffer<wchar_t> CWCharDynamicBuffer;
+typedef CDynamicBuffer<unsigned char> CByteDynamicBuffer;
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/IntToString.cpp b/src/libs/7zip/win/CPP/Common/IntToString.cpp
new file mode 100644
index 000000000..013fee527
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/IntToString.cpp
@@ -0,0 +1,77 @@
+// Common/IntToString.cpp
+
+#include "StdAfx.h"
+
+#include "IntToString.h"
+
+void ConvertUInt64ToString(UInt64 value, char *s, UInt32 base)
+{
+ if (base < 2 || base > 36)
+ {
+ *s = '\0';
+ return;
+ }
+ char temp[72];
+ int pos = 0;
+ do
+ {
+ int delta = (int)(value % base);
+ temp[pos++] = (char)((delta < 10) ? ('0' + delta) : ('a' + (delta - 10)));
+ value /= base;
+ }
+ while (value != 0);
+ do
+ *s++ = temp[--pos];
+ while (pos > 0);
+ *s = '\0';
+}
+
+void ConvertUInt64ToString(UInt64 value, wchar_t *s)
+{
+ wchar_t temp[32];
+ int pos = 0;
+ do
+ {
+ temp[pos++] = (wchar_t)(L'0' + (int)(value % 10));
+ value /= 10;
+ }
+ while (value != 0);
+ do
+ *s++ = temp[--pos];
+ while (pos > 0);
+ *s = L'\0';
+}
+
+void ConvertUInt32ToString(UInt32 value, char *s) { ConvertUInt64ToString(value, s); }
+void ConvertUInt32ToString(UInt32 value, wchar_t *s) { ConvertUInt64ToString(value, s); }
+
+void ConvertInt64ToString(Int64 value, char *s)
+{
+ if (value < 0)
+ {
+ *s++ = '-';
+ value = -value;
+ }
+ ConvertUInt64ToString(value, s);
+}
+
+void ConvertInt64ToString(Int64 value, wchar_t *s)
+{
+ if (value < 0)
+ {
+ *s++ = L'-';
+ value = -value;
+ }
+ ConvertUInt64ToString(value, s);
+}
+
+void ConvertUInt32ToHexWithZeros(UInt32 value, char *s)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ int t = value & 0xF;
+ value >>= 4;
+ s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ s[8] = '\0';
+}
diff --git a/src/libs/7zip/win/CPP/Common/IntToString.h b/src/libs/7zip/win/CPP/Common/IntToString.h
new file mode 100644
index 000000000..782f930c5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/IntToString.h
@@ -0,0 +1,19 @@
+// Common/IntToString.h
+
+#ifndef __COMMON_INT_TO_STRING_H
+#define __COMMON_INT_TO_STRING_H
+
+#include <stddef.h>
+#include "Types.h"
+
+void ConvertUInt64ToString(UInt64 value, char *s, UInt32 base = 10);
+void ConvertUInt64ToString(UInt64 value, wchar_t *s);
+void ConvertInt64ToString(Int64 value, char *s);
+void ConvertInt64ToString(Int64 value, wchar_t *s);
+
+void ConvertUInt32ToString(UInt32 value, char *s);
+void ConvertUInt32ToString(UInt32 value, wchar_t *s);
+
+void ConvertUInt32ToHexWithZeros(UInt32 value, char *s);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/Lang.cpp b/src/libs/7zip/win/CPP/Common/Lang.cpp
new file mode 100644
index 000000000..75dfed426
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Lang.cpp
@@ -0,0 +1,130 @@
+// Common/Lang.cpp
+
+#include "StdAfx.h"
+
+#include "Lang.h"
+#include "TextConfig.h"
+
+#include "../Windows/FileIO.h"
+#include "UTFConvert.h"
+#include "Defs.h"
+
+static bool HexStringToNumber(const UString &s, UInt32 &value)
+{
+ value = 0;
+ if (s.IsEmpty())
+ return false;
+ for (int i = 0; i < s.Length(); i++)
+ {
+ wchar_t c = s[i];
+ int a;
+ if (c >= L'0' && c <= L'9')
+ a = c - L'0';
+ else if (c >= L'A' && c <= L'F')
+ a = 10 + c - L'A';
+ else if (c >= L'a' && c <= L'f')
+ a = 10 + c - L'a';
+ else
+ return false;
+ value *= 0x10;
+ value += a;
+ }
+ return true;
+}
+
+
+static bool WaitNextLine(const AString &s, int &pos)
+{
+ for (; pos < s.Length(); pos++)
+ if (s[pos] == 0x0A)
+ return true;
+ return false;
+}
+
+static int CompareLangItems(void *const *elem1, void *const *elem2, void *)
+{
+ const CLangPair &langPair1 = *(*((const CLangPair **)elem1));
+ const CLangPair &langPair2 = *(*((const CLangPair **)elem2));
+ return MyCompare(langPair1.Value, langPair2.Value);
+}
+
+bool CLang::Open(LPCWSTR fileName)
+{
+ _langPairs.Clear();
+ NWindows::NFile::NIO::CInFile file;
+ if (!file.Open(fileName))
+ return false;
+ UInt64 length;
+ if (!file.GetLength(length))
+ return false;
+ if (length > (1 << 20))
+ return false;
+ AString s;
+ char *p = s.GetBuffer((int)length + 1);
+ UInt32 processed;
+ if (!file.Read(p, (UInt32)length, processed))
+ return false;
+ p[(UInt32)length] = 0;
+ s.ReleaseBuffer();
+ file.Close();
+ int pos = 0;
+ if (s.Length() >= 3)
+ {
+ if (Byte(s[0]) == 0xEF && Byte(s[1]) == 0xBB && Byte(s[2]) == 0xBF)
+ pos += 3;
+ }
+
+ /////////////////////
+ // read header
+
+ AString stringID = ";!@Lang@!UTF-8!";
+ if (s.Mid(pos, stringID.Length()) != stringID)
+ return false;
+ pos += stringID.Length();
+
+ if (!WaitNextLine(s, pos))
+ return false;
+
+ CObjectVector<CTextConfigPair> pairs;
+ if (!GetTextConfig(s.Mid(pos), pairs))
+ return false;
+
+ _langPairs.Reserve(_langPairs.Size());
+ for (int i = 0; i < pairs.Size(); i++)
+ {
+ CTextConfigPair textConfigPair = pairs[i];
+ CLangPair langPair;
+ if (!HexStringToNumber(textConfigPair.ID, langPair.Value))
+ return false;
+ langPair.String = textConfigPair.String;
+ _langPairs.Add(langPair);
+ }
+ _langPairs.Sort(CompareLangItems, NULL);
+ return true;
+}
+
+int CLang::FindItem(UInt32 value) const
+{
+ int left = 0, right = _langPairs.Size();
+ while (left != right)
+ {
+ UInt32 mid = (left + right) / 2;
+ UInt32 midValue = _langPairs[mid].Value;
+ if (value == midValue)
+ return mid;
+ if (value < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+bool CLang::GetMessage(UInt32 value, UString &message) const
+{
+ int index = FindItem(value);
+ if (index < 0)
+ return false;
+ message = _langPairs[index].String;
+ return true;
+}
diff --git a/src/libs/7zip/win/CPP/Common/Lang.h b/src/libs/7zip/win/CPP/Common/Lang.h
new file mode 100644
index 000000000..cf978758e
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Lang.h
@@ -0,0 +1,28 @@
+// Common/Lang.h
+
+#ifndef __COMMON_LANG_H
+#define __COMMON_LANG_H
+
+#include "MyVector.h"
+#include "MyString.h"
+#include "Types.h"
+
+struct CLangPair
+{
+ UInt32 Value;
+ UString String;
+};
+
+class CLang
+{
+ CObjectVector<CLangPair> _langPairs;
+public:
+ bool Open(LPCWSTR fileName);
+ void Clear() { _langPairs.Clear(); }
+ int FindItem(UInt32 value) const;
+ bool GetMessage(UInt32 value, UString &message) const;
+};
+
+#endif
+
+
diff --git a/src/libs/7zip/win/CPP/Common/ListFileUtils.cpp b/src/libs/7zip/win/CPP/Common/ListFileUtils.cpp
new file mode 100644
index 000000000..c1c682a2c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/ListFileUtils.cpp
@@ -0,0 +1,75 @@
+// Common/ListFileUtils.cpp
+
+#include "StdAfx.h"
+
+#include "MyWindows.h"
+#include "../Windows/FileIO.h"
+
+#include "ListFileUtils.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+static const char kQuoteChar = '\"';
+static void RemoveQuote(UString &s)
+{
+ if (s.Length() >= 2)
+ if (s[0] == kQuoteChar && s[s.Length() - 1] == kQuoteChar)
+ s = s.Mid(1, s.Length() - 2);
+}
+
+bool ReadNamesFromListFile(LPCWSTR fileName, UStringVector &resultStrings, UINT codePage)
+{
+ NWindows::NFile::NIO::CInFile file;
+ if (!file.Open(fileName))
+ return false;
+ UInt64 length;
+ if (!file.GetLength(length))
+ return false;
+ if (length > ((UInt32)1 << 31))
+ return false;
+ AString s;
+ char *p = s.GetBuffer((int)length + 1);
+ UInt32 processed;
+ if (!file.Read(p, (UInt32)length, processed))
+ return false;
+ p[(UInt32)length] = 0;
+ s.ReleaseBuffer();
+ file.Close();
+
+ UString u;
+ #ifdef CP_UTF8
+ if (codePage == CP_UTF8)
+ {
+ if (!ConvertUTF8ToUnicode(s, u))
+ return false;
+ }
+ else
+ #endif
+ u = MultiByteToUnicodeString(s, codePage);
+ if (!u.IsEmpty())
+ {
+ if (u[0] == 0xFEFF)
+ u.Delete(0);
+ }
+
+ UString t;
+ for (int i = 0; i < u.Length(); i++)
+ {
+ wchar_t c = u[i];
+ if (c == L'\n' || c == 0xD)
+ {
+ t.Trim();
+ RemoveQuote(t);
+ if (!t.IsEmpty())
+ resultStrings.Add(t);
+ t.Empty();
+ }
+ else
+ t += c;
+ }
+ t.Trim();
+ RemoveQuote(t);
+ if (!t.IsEmpty())
+ resultStrings.Add(t);
+ return true;
+}
diff --git a/src/libs/7zip/win/CPP/Common/ListFileUtils.h b/src/libs/7zip/win/CPP/Common/ListFileUtils.h
new file mode 100644
index 000000000..c58a8bd42
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/ListFileUtils.h
@@ -0,0 +1,11 @@
+// Common/ListFileUtils.h
+
+#ifndef __COMMON_LISTFILEUTILS_H
+#define __COMMON_LISTFILEUTILS_H
+
+#include "MyString.h"
+#include "Types.h"
+
+bool ReadNamesFromListFile(LPCWSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyCom.h b/src/libs/7zip/win/CPP/Common/MyCom.h
new file mode 100644
index 000000000..2f00c258f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyCom.h
@@ -0,0 +1,225 @@
+// MyCom.h
+
+#ifndef __MYCOM_H
+#define __MYCOM_H
+
+#include "MyWindows.h"
+
+#ifndef RINOK
+#define RINOK(x) { HRESULT __result_ = (x); if (__result_ != S_OK) return __result_; }
+#endif
+
+template <class T>
+class CMyComPtr
+{
+ T* _p;
+public:
+ // typedef T _PtrClass;
+ CMyComPtr() { _p = NULL;}
+ CMyComPtr(T* p) {if ((_p = p) != NULL) p->AddRef(); }
+ CMyComPtr(const CMyComPtr<T>& lp)
+ {
+ if ((_p = lp._p) != NULL)
+ _p->AddRef();
+ }
+ ~CMyComPtr() { if (_p) _p->Release(); }
+ void Release() { if (_p) { _p->Release(); _p = NULL; } }
+ operator T*() const { return (T*)_p; }
+ // T& operator*() const { return *_p; }
+ T** operator&() { return &_p; }
+ T* operator->() const { return _p; }
+ T* operator=(T* p)
+ {
+ if (p != 0)
+ p->AddRef();
+ if (_p)
+ _p->Release();
+ _p = p;
+ return p;
+ }
+ T* operator=(const CMyComPtr<T>& lp) { return (*this = lp._p); }
+ bool operator!() const { return (_p == NULL); }
+ // bool operator==(T* pT) const { return _p == pT; }
+ // Compare two objects for equivalence
+ void Attach(T* p2)
+ {
+ Release();
+ _p = p2;
+ }
+ T* Detach()
+ {
+ T* pt = _p;
+ _p = NULL;
+ return pt;
+ }
+ #ifdef _WIN32
+ HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p);
+ }
+ #endif
+ /*
+ HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ CLSID clsid;
+ HRESULT hr = CLSIDFromProgID(szProgID, &clsid);
+ ATLASSERT(_p == NULL);
+ if (SUCCEEDED(hr))
+ hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p);
+ return hr;
+ }
+ */
+ template <class Q>
+ HRESULT QueryInterface(REFGUID iid, Q** pp) const
+ {
+ return _p->QueryInterface(iid, (void**)pp);
+ }
+};
+
+//////////////////////////////////////////////////////////
+
+inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr)
+{
+ *bstr = ::SysAllocString(src);
+ return (*bstr != 0) ? S_OK : E_OUTOFMEMORY;
+}
+
+class CMyComBSTR
+{
+public:
+ BSTR m_str;
+ CMyComBSTR(): m_str(NULL) {}
+ CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); }
+ // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); }
+ // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); }
+ CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); }
+ /*
+ CMyComBSTR(REFGUID src)
+ {
+ LPOLESTR szGuid;
+ StringFromCLSID(src, &szGuid);
+ m_str = ::SysAllocString(szGuid);
+ CoTaskMemFree(szGuid);
+ }
+ */
+ ~CMyComBSTR() { ::SysFreeString(m_str); }
+ CMyComBSTR& operator=(const CMyComBSTR& src)
+ {
+ if (m_str != src.m_str)
+ {
+ if (m_str)
+ ::SysFreeString(m_str);
+ m_str = src.MyCopy();
+ }
+ return *this;
+ }
+ CMyComBSTR& operator=(LPCOLESTR src)
+ {
+ ::SysFreeString(m_str);
+ m_str = ::SysAllocString(src);
+ return *this;
+ }
+ unsigned int Length() const { return ::SysStringLen(m_str); }
+ operator BSTR() const { return m_str; }
+ BSTR* operator&() { return &m_str; }
+ BSTR MyCopy() const
+ {
+ int byteLen = ::SysStringByteLen(m_str);
+ BSTR res = ::SysAllocStringByteLen(NULL, byteLen);
+ memcpy(res, m_str, byteLen);
+ return res;
+ }
+ /*
+ void Attach(BSTR src) { m_str = src; }
+ BSTR Detach()
+ {
+ BSTR s = m_str;
+ m_str = NULL;
+ return s;
+ }
+ */
+ void Empty()
+ {
+ ::SysFreeString(m_str);
+ m_str = NULL;
+ }
+ bool operator!() const { return (m_str == NULL); }
+};
+
+//////////////////////////////////////////////////////////
+
+class CMyUnknownImp
+{
+public:
+ ULONG __m_RefCount;
+ CMyUnknownImp(): __m_RefCount(0) {}
+};
+
+#define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \
+ (REFGUID iid, void **outObject) {
+
+#define MY_QUERYINTERFACE_ENTRY(i) if (iid == IID_ ## i) \
+ { *outObject = (void *)(i *)this; AddRef(); return S_OK; }
+
+#define MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) if (iid == IID_IUnknown) \
+ { *outObject = (void *)(IUnknown *)(i *)this; AddRef(); return S_OK; }
+
+#define MY_QUERYINTERFACE_BEGIN2(i) MY_QUERYINTERFACE_BEGIN \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \
+ MY_QUERYINTERFACE_ENTRY(i)
+
+#define MY_QUERYINTERFACE_END return E_NOINTERFACE; }
+
+#define MY_ADDREF_RELEASE \
+STDMETHOD_(ULONG, AddRef)() { return ++__m_RefCount; } \
+STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0) \
+ return __m_RefCount; delete this; return 0; }
+
+#define MY_UNKNOWN_IMP_SPEC(i) \
+ MY_QUERYINTERFACE_BEGIN \
+ i \
+ MY_QUERYINTERFACE_END \
+ MY_ADDREF_RELEASE
+
+
+#define MY_UNKNOWN_IMP MY_QUERYINTERFACE_BEGIN \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(IUnknown) \
+ MY_QUERYINTERFACE_END \
+ MY_ADDREF_RELEASE
+
+#define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \
+ MY_QUERYINTERFACE_ENTRY(i) \
+ )
+
+#define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ )
+
+#define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ )
+
+#define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ MY_QUERYINTERFACE_ENTRY(i4) \
+ )
+
+#define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ MY_QUERYINTERFACE_ENTRY(i4) \
+ MY_QUERYINTERFACE_ENTRY(i5) \
+ )
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyException.h b/src/libs/7zip/win/CPP/Common/MyException.h
new file mode 100644
index 000000000..f0ad11158
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyException.h
@@ -0,0 +1,14 @@
+// Common/Exception.h
+
+#ifndef __COMMON_EXCEPTION_H
+#define __COMMON_EXCEPTION_H
+
+#include "MyWindows.h"
+
+struct CSystemException
+{
+ HRESULT ErrorCode;
+ CSystemException(HRESULT errorCode): ErrorCode(errorCode) {}
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyGuidDef.h b/src/libs/7zip/win/CPP/Common/MyGuidDef.h
new file mode 100644
index 000000000..3c52cc07d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyGuidDef.h
@@ -0,0 +1,54 @@
+// Common/MyGuidDef.h
+
+#ifndef GUID_DEFINED
+#define GUID_DEFINED
+
+#include "Types.h"
+
+typedef struct {
+ UInt32 Data1;
+ UInt16 Data2;
+ UInt16 Data3;
+ unsigned char Data4[8];
+} GUID;
+
+#ifdef __cplusplus
+#define REFGUID const GUID &
+#else
+#define REFGUID const GUID *
+#endif
+
+#define REFCLSID REFGUID
+#define REFIID REFGUID
+
+#ifdef __cplusplus
+inline int operator==(REFGUID g1, REFGUID g2)
+{
+ for (int i = 0; i < (int)sizeof(g1); i++)
+ if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i])
+ return 0;
+ return 1;
+}
+inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); }
+#endif
+
+#ifdef __cplusplus
+ #define MY_EXTERN_C extern "C"
+#else
+ #define MY_EXTERN_C extern
+#endif
+
+#endif
+
+
+#ifdef DEFINE_GUID
+#undef DEFINE_GUID
+#endif
+
+#ifdef INITGUID
+ #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ MY_EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#else
+ #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ MY_EXTERN_C const GUID name
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyInitGuid.h b/src/libs/7zip/win/CPP/Common/MyInitGuid.h
new file mode 100644
index 000000000..d6a486980
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyInitGuid.h
@@ -0,0 +1,22 @@
+// Common/MyInitGuid.h
+
+#ifndef __COMMON_MY_INITGUID_H
+#define __COMMON_MY_INITGUID_H
+
+#ifdef _WIN32
+#ifdef UNDER_CE
+#include <basetyps.h>
+#endif
+#include <initguid.h>
+#ifdef UNDER_CE
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+#endif
+#else
+#define INITGUID
+#include "MyGuidDef.h"
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyMap.cpp b/src/libs/7zip/win/CPP/Common/MyMap.cpp
new file mode 100644
index 000000000..0ee11e8cd
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyMap.cpp
@@ -0,0 +1,140 @@
+// MyMap.cpp
+
+#include "StdAfx.h"
+
+#include "MyMap.h"
+
+static const unsigned kNumBitsMax = sizeof(UInt32) * 8;
+
+static UInt32 GetSubBits(UInt32 value, unsigned startPos, unsigned numBits)
+{
+ if (startPos == sizeof(value) * 8)
+ return 0;
+ value >>= startPos;
+ if (numBits == sizeof(value) * 8)
+ return value;
+ return value & (((UInt32)1 << numBits) - 1);
+}
+
+static inline unsigned GetSubBit(UInt32 v, unsigned n) { return (unsigned)(v >> n) & 1; }
+
+bool CMap32::Find(UInt32 key, UInt32 &valueRes) const
+{
+ valueRes = (UInt32)(Int32)-1;
+ if (Nodes.Size() == 0)
+ return false;
+ if (Nodes.Size() == 1)
+ {
+ const CNode &n = Nodes[0];
+ if (n.Len == kNumBitsMax)
+ {
+ valueRes = n.Values[0];
+ return (key == n.Key);
+ }
+ }
+
+ int cur = 0;
+ unsigned bitPos = kNumBitsMax;
+ for (;;)
+ {
+ const CNode &n = Nodes[cur];
+ bitPos -= n.Len;
+ if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len))
+ return false;
+ unsigned bit = GetSubBit(key, --bitPos);
+ if (n.IsLeaf[bit])
+ {
+ valueRes = n.Values[bit];
+ return (key == n.Keys[bit]);
+ }
+ cur = (int)n.Keys[bit];
+ }
+}
+
+bool CMap32::Set(UInt32 key, UInt32 value)
+{
+ if (Nodes.Size() == 0)
+ {
+ CNode n;
+ n.Key = n.Keys[0] = n.Keys[1] = key;
+ n.Values[0] = n.Values[1] = value;
+ n.IsLeaf[0] = n.IsLeaf[1] = 1;
+ n.Len = kNumBitsMax;
+ Nodes.Add(n);
+ return false;
+ }
+ if (Nodes.Size() == 1)
+ {
+ CNode &n = Nodes[0];
+ if (n.Len == kNumBitsMax)
+ {
+ if (key == n.Key)
+ {
+ n.Values[0] = n.Values[1] = value;
+ return true;
+ }
+ unsigned i = kNumBitsMax - 1;
+ for (;GetSubBit(key, i) == GetSubBit(n.Key, i); i--);
+ n.Len = (UInt16)(kNumBitsMax - (1 + i));
+ unsigned newBit = GetSubBit(key, i);
+ n.Values[newBit] = value;
+ n.Keys[newBit] = key;
+ return false;
+ }
+ }
+
+ int cur = 0;
+ unsigned bitPos = kNumBitsMax;
+ for (;;)
+ {
+ CNode &n = Nodes[cur];
+ bitPos -= n.Len;
+ if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len))
+ {
+ unsigned i = n.Len - 1;
+ for (; GetSubBit(key, bitPos + i) == GetSubBit(n.Key, bitPos + i); i--);
+
+ CNode e2(n);
+ e2.Len = (UInt16)i;
+
+ n.Len = (UInt16)(n.Len - (1 + i));
+ unsigned newBit = GetSubBit(key, bitPos + i);
+ n.Values[newBit] = value;
+ n.IsLeaf[newBit] = 1;
+ n.IsLeaf[1 - newBit] = 0;
+ n.Keys[newBit] = key;
+ n.Keys[1 - newBit] = Nodes.Size();
+ Nodes.Add(e2);
+ return false;
+ }
+ unsigned bit = GetSubBit(key, --bitPos);
+
+ if (n.IsLeaf[bit])
+ {
+ if (key == n.Keys[bit])
+ {
+ n.Values[bit] = value;
+ return true;
+ }
+ unsigned i = bitPos - 1;
+ for (;GetSubBit(key, i) == GetSubBit(n.Keys[bit], i); i--);
+
+ CNode e2;
+
+ unsigned newBit = GetSubBit(key, i);
+ e2.Values[newBit] = value;
+ e2.Values[1 - newBit] = n.Values[bit];
+ e2.IsLeaf[newBit] = e2.IsLeaf[1 - newBit] = 1;
+ e2.Keys[newBit] = key;
+ e2.Keys[1 - newBit] = e2.Key = n.Keys[bit];
+ e2.Len = (UInt16)(bitPos - (1 + i));
+
+ n.IsLeaf[bit] = 0;
+ n.Keys[bit] = Nodes.Size();
+
+ Nodes.Add(e2);
+ return false;
+ }
+ cur = (int)n.Keys[bit];
+ }
+}
diff --git a/src/libs/7zip/win/CPP/Common/MyMap.h b/src/libs/7zip/win/CPP/Common/MyMap.h
new file mode 100644
index 000000000..d0dd43f53
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyMap.h
@@ -0,0 +1,28 @@
+// MyMap.h
+
+#ifndef __COMMON_MYMAP_H
+#define __COMMON_MYMAP_H
+
+#include "MyVector.h"
+#include "Types.h"
+
+class CMap32
+{
+ struct CNode
+ {
+ UInt32 Key;
+ UInt32 Keys[2];
+ UInt32 Values[2];
+ UInt16 Len;
+ Byte IsLeaf[2];
+ };
+ CRecordVector<CNode> Nodes;
+
+public:
+
+ void Clear() { Nodes.Clear(); }
+ bool Find(UInt32 key, UInt32 &valueRes) const;
+ bool Set(UInt32 key, UInt32 value); // returns true, if there is such key already
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyString.cpp b/src/libs/7zip/win/CPP/Common/MyString.cpp
new file mode 100644
index 000000000..3d1ce2b84
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyString.cpp
@@ -0,0 +1,200 @@
+// Common/MyString.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <ctype.h>
+#endif
+
+#ifndef _UNICODE
+#include "StringConvert.h"
+#endif
+
+#include "MyString.h"
+
+
+#ifdef _WIN32
+
+#ifndef _UNICODE
+
+wchar_t MyCharUpper(wchar_t c)
+{
+ if (c == 0)
+ return 0;
+ wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned int)c);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return (wchar_t)(unsigned int)(UINT_PTR)res;
+ const int kBufferSize = 4;
+ char s[kBufferSize + 1];
+ int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufferSize, 0, 0);
+ if (numChars == 0 || numChars > kBufferSize)
+ return c;
+ s[numChars] = 0;
+ ::CharUpperA(s);
+ ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
+ return c;
+}
+
+wchar_t MyCharLower(wchar_t c)
+{
+ if (c == 0)
+ return 0;
+ wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned int)c);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return (wchar_t)(unsigned int)(UINT_PTR)res;
+ const int kBufferSize = 4;
+ char s[kBufferSize + 1];
+ int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufferSize, 0, 0);
+ if (numChars == 0 || numChars > kBufferSize)
+ return c;
+ s[numChars] = 0;
+ ::CharLowerA(s);
+ ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
+ return c;
+}
+
+wchar_t * MyStringUpper(wchar_t *s)
+{
+ if (s == 0)
+ return 0;
+ wchar_t *res = CharUpperW(s);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return res;
+ AString a = UnicodeStringToMultiByte(s);
+ a.MakeUpper();
+ return MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
+}
+
+wchar_t * MyStringLower(wchar_t *s)
+{
+ if (s == 0)
+ return 0;
+ wchar_t *res = CharLowerW(s);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return res;
+ AString a = UnicodeStringToMultiByte(s);
+ a.MakeLower();
+ return MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
+}
+
+#endif
+
+/*
+inline int ConvertCompareResult(int r) { return r - 2; }
+
+int MyStringCollate(const wchar_t *s1, const wchar_t *s2)
+{
+ int res = CompareStringW(
+ LOCALE_USER_DEFAULT, SORT_STRINGSORT, s1, -1, s2, -1);
+ #ifdef _UNICODE
+ return ConvertCompareResult(res);
+ #else
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return ConvertCompareResult(res);
+ return MyStringCollate(UnicodeStringToMultiByte(s1),
+ UnicodeStringToMultiByte(s2));
+ #endif
+}
+
+#ifndef UNDER_CE
+int MyStringCollate(const char *s1, const char *s2)
+{
+ return ConvertCompareResult(CompareStringA(
+ LOCALE_USER_DEFAULT, SORT_STRINGSORT, s1, -1, s2, -1));
+}
+
+int MyStringCollateNoCase(const char *s1, const char *s2)
+{
+ return ConvertCompareResult(CompareStringA(
+ LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, s1, -1, s2, -1));
+}
+#endif
+
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ int res = CompareStringW(
+ LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, s1, -1, s2, -1);
+ #ifdef _UNICODE
+ return ConvertCompareResult(res);
+ #else
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return ConvertCompareResult(res);
+ return MyStringCollateNoCase(UnicodeStringToMultiByte(s1),
+ UnicodeStringToMultiByte(s2));
+ #endif
+}
+*/
+
+#else
+
+wchar_t MyCharUpper(wchar_t c)
+{
+ return toupper(c);
+}
+
+/*
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ for (;;)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ wchar_t u1 = MyCharUpper(c1);
+ wchar_t u2 = MyCharUpper(c2);
+
+ if (u1 < u2) return -1;
+ if (u1 > u2) return 1;
+ if (u1 == 0) return 0;
+ }
+}
+*/
+
+#endif
+
+int MyStringCompare(const char *s1, const char *s2)
+{
+ for (;;)
+ {
+ unsigned char c1 = (unsigned char)*s1++;
+ unsigned char c2 = (unsigned char)*s2++;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ }
+}
+
+int MyStringCompare(const wchar_t *s1, const wchar_t *s2)
+{
+ for (;;)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ }
+}
+
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ for (;;)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 != c2)
+ {
+ wchar_t u1 = MyCharUpper(c1);
+ wchar_t u2 = MyCharUpper(c2);
+ if (u1 < u2) return -1;
+ if (u1 > u2) return 1;
+ }
+ if (c1 == 0) return 0;
+ }
+}
+
+/*
+int MyStringCompareNoCase(const char *s1, const char *s2)
+{
+ return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
+}
+*/
diff --git a/src/libs/7zip/win/CPP/Common/MyString.h b/src/libs/7zip/win/CPP/Common/MyString.h
new file mode 100644
index 000000000..f483e39dc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyString.h
@@ -0,0 +1,627 @@
+// Common/String.h
+
+#ifndef __COMMON_STRING_H
+#define __COMMON_STRING_H
+
+#include <string.h>
+
+#include "MyVector.h"
+
+#include <windows.h>
+
+template <class T>
+inline int MyStringLen(const T *s)
+{
+ int i;
+ for (i = 0; s[i] != '\0'; i++);
+ return i;
+}
+
+template <class T>
+inline T * MyStringCopy(T *dest, const T *src)
+{
+ T *destStart = dest;
+ while ((*dest++ = *src++) != 0);
+ return destStart;
+}
+
+inline wchar_t* MyStringGetNextCharPointer(wchar_t *p)
+ { return (p + 1); }
+inline const wchar_t* MyStringGetNextCharPointer(const wchar_t *p)
+ { return (p + 1); }
+inline wchar_t* MyStringGetPrevCharPointer(const wchar_t *, wchar_t *p)
+ { return (p - 1); }
+inline const wchar_t* MyStringGetPrevCharPointer(const wchar_t *, const wchar_t *p)
+ { return (p - 1); }
+
+#ifdef _WIN32
+
+inline const char* MyStringGetNextCharPointer(const char *p)
+{
+ #ifdef UNDER_CE
+ return p + 1;
+ #else
+ return CharNextA(p);
+ #endif
+}
+
+inline const char* MyStringGetPrevCharPointer(const char *base, const char *p)
+ { return CharPrevA(base, p); }
+
+inline char MyCharUpper(char c)
+ { return (char)(unsigned int)(UINT_PTR)CharUpperA((LPSTR)(UINT_PTR)(unsigned int)(unsigned char)c); }
+#ifdef _UNICODE
+inline wchar_t MyCharUpper(wchar_t c)
+ { return (wchar_t)(unsigned int)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned int)c); }
+#else
+wchar_t MyCharUpper(wchar_t c);
+#endif
+
+#ifdef _UNICODE
+inline wchar_t MyCharLower(wchar_t c)
+ { return (wchar_t)(unsigned int)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned int)c); }
+#else
+wchar_t MyCharLower(wchar_t c);
+#endif
+
+inline char MyCharLower(char c)
+#ifdef UNDER_CE
+ { return (char)MyCharLower((wchar_t)c); }
+#else
+ { return (char)(unsigned int)(UINT_PTR)CharLowerA((LPSTR)(UINT_PTR)(unsigned int)(unsigned char)c); }
+#endif
+
+inline char * MyStringUpper(char *s) { return CharUpperA(s); }
+#ifdef _UNICODE
+inline wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
+#else
+wchar_t * MyStringUpper(wchar_t *s);
+#endif
+
+inline char * MyStringLower(char *s) { return CharLowerA(s); }
+#ifdef _UNICODE
+inline wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
+#else
+wchar_t * MyStringLower(wchar_t *s);
+#endif
+
+#else // Standard-C
+wchar_t MyCharUpper(wchar_t c);
+#endif
+
+//////////////////////////////////////
+// Compare
+
+/*
+#ifndef UNDER_CE
+int MyStringCollate(const char *s1, const char *s2);
+int MyStringCollateNoCase(const char *s1, const char *s2);
+#endif
+int MyStringCollate(const wchar_t *s1, const wchar_t *s2);
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2);
+*/
+
+int MyStringCompare(const char *s1, const char *s2);
+int MyStringCompare(const wchar_t *s1, const wchar_t *s2);
+
+// int MyStringCompareNoCase(const char *s1, const char *s2);
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2);
+
+template <class T>
+class CStringBase
+{
+ void TrimLeftWithCharSet(const CStringBase &charSet)
+ {
+ const T *p = _chars;
+ while (charSet.Find(*p) >= 0 && (*p != 0))
+ p = GetNextCharPointer(p);
+ Delete(0, (int)(p - _chars));
+ }
+ void TrimRightWithCharSet(const CStringBase &charSet)
+ {
+ const T *p = _chars;
+ const T *pLast = NULL;
+ while (*p != 0)
+ {
+ if (charSet.Find(*p) >= 0)
+ {
+ if (pLast == NULL)
+ pLast = p;
+ }
+ else
+ pLast = NULL;
+ p = GetNextCharPointer(p);
+ }
+ if (pLast != NULL)
+ {
+ int i = (int)(pLast - _chars);
+ Delete(i, _length - i);
+ }
+
+ }
+ void MoveItems(int destIndex, int srcIndex)
+ {
+ memmove(_chars + destIndex, _chars + srcIndex,
+ sizeof(T) * (_length - srcIndex + 1));
+ }
+
+ void InsertSpace(int &index, int size)
+ {
+ CorrectIndex(index);
+ GrowLength(size);
+ MoveItems(index + size, index);
+ }
+
+ static const T *GetNextCharPointer(const T *p)
+ { return MyStringGetNextCharPointer(p); }
+ static const T *GetPrevCharPointer(const T *base, const T *p)
+ { return MyStringGetPrevCharPointer(base, p); }
+protected:
+ T *_chars;
+ int _length;
+ int _capacity;
+
+ void SetCapacity(int newCapacity)
+ {
+ int realCapacity = newCapacity + 1;
+ if (realCapacity == _capacity)
+ return;
+ /*
+ const int kMaxStringSize = 0x20000000;
+ if (newCapacity > kMaxStringSize || newCapacity < _length)
+ throw 1052337;
+ */
+ T *newBuffer = new T[realCapacity];
+ if (_capacity > 0)
+ {
+ for (int i = 0; i < _length; i++)
+ newBuffer[i] = _chars[i];
+ delete []_chars;
+ }
+ _chars = newBuffer;
+ _chars[_length] = 0;
+ _capacity = realCapacity;
+ }
+
+ void GrowLength(int n)
+ {
+ int freeSize = _capacity - _length - 1;
+ if (n <= freeSize)
+ return;
+ int delta;
+ if (_capacity > 64)
+ delta = _capacity / 2;
+ else if (_capacity > 8)
+ delta = 16;
+ else
+ delta = 4;
+ if (freeSize + delta < n)
+ delta = n - freeSize;
+ SetCapacity(_capacity + delta);
+ }
+
+ void CorrectIndex(int &index) const
+ {
+ if (index > _length)
+ index = _length;
+ }
+
+public:
+ CStringBase(): _chars(0), _length(0), _capacity(0) { SetCapacity(3); }
+ CStringBase(T c): _chars(0), _length(0), _capacity(0)
+ {
+ SetCapacity(1);
+ _chars[0] = c;
+ _chars[1] = 0;
+ _length = 1;
+ }
+ CStringBase(const T *chars): _chars(0), _length(0), _capacity(0)
+ {
+ int length = MyStringLen(chars);
+ SetCapacity(length);
+ MyStringCopy(_chars, chars); // can be optimized by memove()
+ _length = length;
+ }
+ CStringBase(const CStringBase &s): _chars(0), _length(0), _capacity(0)
+ {
+ SetCapacity(s._length);
+ MyStringCopy(_chars, s._chars);
+ _length = s._length;
+ }
+ ~CStringBase() { delete []_chars; }
+
+ operator const T*() const { return _chars;}
+
+ T Back() const { return _chars[_length - 1]; }
+
+ // The minimum size of the character buffer in characters.
+ // This value does not include space for a null terminator.
+ T* GetBuffer(int minBufLength)
+ {
+ if (minBufLength >= _capacity)
+ SetCapacity(minBufLength);
+ return _chars;
+ }
+ void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); }
+ void ReleaseBuffer(int newLength)
+ {
+ /*
+ if (newLength >= _capacity)
+ throw 282217;
+ */
+ _chars[newLength] = 0;
+ _length = newLength;
+ }
+
+ CStringBase& operator=(T c)
+ {
+ Empty();
+ SetCapacity(1);
+ _chars[0] = c;
+ _chars[1] = 0;
+ _length = 1;
+ return *this;
+ }
+ CStringBase& operator=(const T *chars)
+ {
+ Empty();
+ int length = MyStringLen(chars);
+ SetCapacity(length);
+ MyStringCopy(_chars, chars);
+ _length = length;
+ return *this;
+ }
+ CStringBase& operator=(const CStringBase& s)
+ {
+ if (&s == this)
+ return *this;
+ Empty();
+ SetCapacity(s._length);
+ MyStringCopy(_chars, s._chars);
+ _length = s._length;
+ return *this;
+ }
+
+ CStringBase& operator+=(T c)
+ {
+ GrowLength(1);
+ _chars[_length] = c;
+ _chars[++_length] = 0;
+ return *this;
+ }
+ CStringBase& operator+=(const T *s)
+ {
+ int len = MyStringLen(s);
+ GrowLength(len);
+ MyStringCopy(_chars + _length, s);
+ _length += len;
+ return *this;
+ }
+ CStringBase& operator+=(const CStringBase &s)
+ {
+ GrowLength(s._length);
+ MyStringCopy(_chars + _length, s._chars);
+ _length += s._length;
+ return *this;
+ }
+ void Empty()
+ {
+ _length = 0;
+ _chars[0] = 0;
+ }
+ int Length() const { return _length; }
+ bool IsEmpty() const { return (_length == 0); }
+
+ CStringBase Mid(int startIndex) const
+ { return Mid(startIndex, _length - startIndex); }
+ CStringBase Mid(int startIndex, int count) const
+ {
+ if (startIndex + count > _length)
+ count = _length - startIndex;
+
+ if (startIndex == 0 && startIndex + count == _length)
+ return *this;
+
+ CStringBase<T> result;
+ result.SetCapacity(count);
+ // MyStringNCopy(result._chars, _chars + startIndex, count);
+ for (int i = 0; i < count; i++)
+ result._chars[i] = _chars[startIndex + i];
+ result._chars[count] = 0;
+ result._length = count;
+ return result;
+ }
+ CStringBase Left(int count) const
+ { return Mid(0, count); }
+ CStringBase Right(int count) const
+ {
+ if (count > _length)
+ count = _length;
+ return Mid(_length - count, count);
+ }
+
+ void MakeUpper()
+ { MyStringUpper(_chars); }
+ void MakeLower()
+ { MyStringLower(_chars); }
+
+ int Compare(const CStringBase& s) const
+ { return MyStringCompare(_chars, s._chars); }
+
+ int Compare(const T *s) const
+ { return MyStringCompare(_chars, s); }
+
+ int CompareNoCase(const CStringBase& s) const
+ { return MyStringCompareNoCase(_chars, s._chars); }
+
+ int CompareNoCase(const T *s) const
+ { return MyStringCompareNoCase(_chars, s); }
+
+ /*
+ int Collate(const CStringBase& s) const
+ { return MyStringCollate(_chars, s._chars); }
+ int CollateNoCase(const CStringBase& s) const
+ { return MyStringCollateNoCase(_chars, s._chars); }
+ */
+
+ int Find(T c) const { return Find(c, 0); }
+ int Find(T c, int startIndex) const
+ {
+ const T *p = _chars + startIndex;
+ for (;;)
+ {
+ if (*p == c)
+ return (int)(p - _chars);
+ if (*p == 0)
+ return -1;
+ p = GetNextCharPointer(p);
+ }
+ }
+ int Find(const CStringBase &s) const { return Find(s, 0); }
+ int Find(const CStringBase &s, int startIndex) const
+ {
+ if (s.IsEmpty())
+ return startIndex;
+ for (; startIndex < _length; startIndex++)
+ {
+ int j;
+ for (j = 0; j < s._length && startIndex + j < _length; j++)
+ if (_chars[startIndex+j] != s._chars[j])
+ break;
+ if (j == s._length)
+ return startIndex;
+ }
+ return -1;
+ }
+ int ReverseFind(T c) const
+ {
+ if (_length == 0)
+ return -1;
+ const T *p = _chars + _length - 1;
+ for (;;)
+ {
+ if (*p == c)
+ return (int)(p - _chars);
+ if (p == _chars)
+ return -1;
+ p = GetPrevCharPointer(_chars, p);
+ }
+ }
+ int FindOneOf(const CStringBase &s) const
+ {
+ for (int i = 0; i < _length; i++)
+ if (s.Find(_chars[i]) >= 0)
+ return i;
+ return -1;
+ }
+
+ void TrimLeft(T c)
+ {
+ const T *p = _chars;
+ while (c == *p)
+ p = GetNextCharPointer(p);
+ Delete(0, p - _chars);
+ }
+ private:
+ CStringBase GetTrimDefaultCharSet()
+ {
+ CStringBase<T> charSet;
+ charSet += (T)' ';
+ charSet += (T)'\n';
+ charSet += (T)'\t';
+ return charSet;
+ }
+ public:
+
+ void TrimLeft()
+ {
+ TrimLeftWithCharSet(GetTrimDefaultCharSet());
+ }
+ void TrimRight()
+ {
+ TrimRightWithCharSet(GetTrimDefaultCharSet());
+ }
+ void TrimRight(T c)
+ {
+ const T *p = _chars;
+ const T *pLast = NULL;
+ while (*p != 0)
+ {
+ if (*p == c)
+ {
+ if (pLast == NULL)
+ pLast = p;
+ }
+ else
+ pLast = NULL;
+ p = GetNextCharPointer(p);
+ }
+ if (pLast != NULL)
+ {
+ int i = pLast - _chars;
+ Delete(i, _length - i);
+ }
+ }
+ void Trim()
+ {
+ TrimRight();
+ TrimLeft();
+ }
+
+ int Insert(int index, T c)
+ {
+ InsertSpace(index, 1);
+ _chars[index] = c;
+ _length++;
+ return _length;
+ }
+ int Insert(int index, const CStringBase &s)
+ {
+ CorrectIndex(index);
+ if (s.IsEmpty())
+ return _length;
+ int numInsertChars = s.Length();
+ InsertSpace(index, numInsertChars);
+ for (int i = 0; i < numInsertChars; i++)
+ _chars[index + i] = s[i];
+ _length += numInsertChars;
+ return _length;
+ }
+
+ // !!!!!!!!!!!!!!! test it if newChar = '\0'
+ int Replace(T oldChar, T newChar)
+ {
+ if (oldChar == newChar)
+ return 0;
+ int number = 0;
+ int pos = 0;
+ while (pos < Length())
+ {
+ pos = Find(oldChar, pos);
+ if (pos < 0)
+ break;
+ _chars[pos] = newChar;
+ pos++;
+ number++;
+ }
+ return number;
+ }
+ int Replace(const CStringBase &oldString, const CStringBase &newString)
+ {
+ if (oldString.IsEmpty())
+ return 0;
+ if (oldString == newString)
+ return 0;
+ int oldStringLength = oldString.Length();
+ int newStringLength = newString.Length();
+ int number = 0;
+ int pos = 0;
+ while (pos < _length)
+ {
+ pos = Find(oldString, pos);
+ if (pos < 0)
+ break;
+ Delete(pos, oldStringLength);
+ Insert(pos, newString);
+ pos += newStringLength;
+ number++;
+ }
+ return number;
+ }
+ int Delete(int index, int count = 1)
+ {
+ if (index + count > _length)
+ count = _length - index;
+ if (count > 0)
+ {
+ MoveItems(index, index + count);
+ _length -= count;
+ }
+ return _length;
+ }
+ void DeleteBack() { Delete(_length - 1); }
+};
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s1, const CStringBase<T>& s2)
+{
+ CStringBase<T> result(s1);
+ result += s2;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s, T c)
+{
+ CStringBase<T> result(s);
+ result += c;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(T c, const CStringBase<T>& s)
+{
+ CStringBase<T> result(c);
+ result += s;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s, const T * chars)
+{
+ CStringBase<T> result(s);
+ result += chars;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const T * chars, const CStringBase<T>& s)
+{
+ CStringBase<T> result(chars);
+ result += s;
+ return result;
+}
+
+template <class T>
+bool operator==(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) == 0); }
+
+template <class T>
+bool operator<(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) < 0); }
+
+template <class T>
+bool operator==(const T *s1, const CStringBase<T>& s2)
+ { return (s2.Compare(s1) == 0); }
+
+template <class T>
+bool operator==(const CStringBase<T>& s1, const T *s2)
+ { return (s1.Compare(s2) == 0); }
+
+template <class T>
+bool operator!=(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) != 0); }
+
+template <class T>
+bool operator!=(const T *s1, const CStringBase<T>& s2)
+ { return (s2.Compare(s1) != 0); }
+
+template <class T>
+bool operator!=(const CStringBase<T>& s1, const T *s2)
+ { return (s1.Compare(s2) != 0); }
+
+typedef CStringBase<char> AString;
+typedef CStringBase<wchar_t> UString;
+
+typedef CObjectVector<AString> AStringVector;
+typedef CObjectVector<UString> UStringVector;
+
+#ifdef _UNICODE
+ typedef UString CSysString;
+#else
+ typedef AString CSysString;
+#endif
+
+typedef CObjectVector<CSysString> CSysStringVector;
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyUnknown.h b/src/libs/7zip/win/CPP/Common/MyUnknown.h
new file mode 100644
index 000000000..e9e8666b9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyUnknown.h
@@ -0,0 +1,13 @@
+// MyUnknown.h
+
+#ifndef __MY_UNKNOWN_H
+#define __MY_UNKNOWN_H
+
+#ifdef _WIN32
+#include <basetyps.h>
+#include <unknwn.h>
+#else
+#include "MyWindows.h"
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyVector.cpp b/src/libs/7zip/win/CPP/Common/MyVector.cpp
new file mode 100644
index 000000000..3b5317688
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyVector.cpp
@@ -0,0 +1,87 @@
+// Common/MyVector.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "MyVector.h"
+
+CBaseRecordVector::~CBaseRecordVector() { ClearAndFree(); }
+
+void CBaseRecordVector::ClearAndFree()
+{
+ Clear();
+ delete []((unsigned char *)_items);
+ _capacity = 0;
+ _size = 0;
+ _items = 0;
+}
+
+void CBaseRecordVector::Clear() { DeleteFrom(0); }
+void CBaseRecordVector::DeleteBack() { Delete(_size - 1); }
+void CBaseRecordVector::DeleteFrom(int index) { Delete(index, _size - index); }
+
+void CBaseRecordVector::ReserveOnePosition()
+{
+ if (_size != _capacity)
+ return;
+ unsigned delta = 1;
+ if (_capacity >= 64)
+ delta = (unsigned)_capacity / 4;
+ else if (_capacity >= 8)
+ delta = 8;
+ Reserve(_capacity + (int)delta);
+}
+
+void CBaseRecordVector::Reserve(int newCapacity)
+{
+ // if (newCapacity <= _capacity)
+ if (newCapacity == _capacity)
+ return;
+ if ((unsigned)newCapacity >= ((unsigned)1 << (sizeof(unsigned) * 8 - 1)))
+ throw 1052353;
+ size_t newSize = (size_t)(unsigned)newCapacity * _itemSize;
+ if (newSize / _itemSize != (size_t)(unsigned)newCapacity)
+ throw 1052354;
+ unsigned char *p = NULL;
+ if (newSize > 0)
+ {
+ p = new unsigned char[newSize];
+ if (p == 0)
+ throw 1052355;
+ int numRecordsToMove = (_size < newCapacity ? _size : newCapacity);
+ memcpy(p, _items, _itemSize * numRecordsToMove);
+ }
+ delete [](unsigned char *)_items;
+ _items = p;
+ _capacity = newCapacity;
+}
+
+void CBaseRecordVector::ReserveDown()
+{
+ Reserve(_size);
+}
+
+void CBaseRecordVector::MoveItems(int destIndex, int srcIndex)
+{
+ memmove(((unsigned char *)_items) + destIndex * _itemSize,
+ ((unsigned char *)_items) + srcIndex * _itemSize,
+ _itemSize * (_size - srcIndex));
+}
+
+void CBaseRecordVector::InsertOneItem(int index)
+{
+ ReserveOnePosition();
+ MoveItems(index + 1, index);
+ _size++;
+}
+
+void CBaseRecordVector::Delete(int index, int num)
+{
+ TestIndexAndCorrectNum(index, num);
+ if (num > 0)
+ {
+ MoveItems(index, index + num);
+ _size -= num;
+ }
+}
diff --git a/src/libs/7zip/win/CPP/Common/MyVector.h b/src/libs/7zip/win/CPP/Common/MyVector.h
new file mode 100644
index 000000000..781b648bc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyVector.h
@@ -0,0 +1,266 @@
+// Common/Vector.h
+
+#ifndef __COMMON_VECTOR_H
+#define __COMMON_VECTOR_H
+
+#include "Defs.h"
+
+class CBaseRecordVector
+{
+ void MoveItems(int destIndex, int srcIndex);
+protected:
+ int _capacity;
+ int _size;
+ void *_items;
+ size_t _itemSize;
+
+ void ReserveOnePosition();
+ void InsertOneItem(int index);
+ void TestIndexAndCorrectNum(int index, int &num) const
+ { if (index + num > _size) num = _size - index; }
+public:
+ CBaseRecordVector(size_t itemSize): _capacity(0), _size(0), _items(0), _itemSize(itemSize) {}
+ virtual ~CBaseRecordVector();
+ void ClearAndFree();
+ int Size() const { return _size; }
+ bool IsEmpty() const { return (_size == 0); }
+ void Reserve(int newCapacity);
+ void ReserveDown();
+ virtual void Delete(int index, int num = 1);
+ void Clear();
+ void DeleteFrom(int index);
+ void DeleteBack();
+};
+
+template <class T>
+class CRecordVector: public CBaseRecordVector
+{
+public:
+ CRecordVector(): CBaseRecordVector(sizeof(T)){};
+ CRecordVector(const CRecordVector &v): CBaseRecordVector(sizeof(T)) { *this = v; }
+ CRecordVector& operator=(const CRecordVector &v)
+ {
+ Clear();
+ return (*this += v);
+ }
+ CRecordVector& operator+=(const CRecordVector &v)
+ {
+ int size = v.Size();
+ Reserve(Size() + size);
+ for (int i = 0; i < size; i++)
+ Add(v[i]);
+ return *this;
+ }
+ int Add(T item)
+ {
+ ReserveOnePosition();
+ ((T *)_items)[_size] = item;
+ return _size++;
+ }
+ void Insert(int index, T item)
+ {
+ InsertOneItem(index);
+ ((T *)_items)[index] = item;
+ }
+ // T* GetPointer() const { return (T*)_items; }
+ // operator const T *() const { return _items; };
+ const T& operator[](int index) const { return ((T *)_items)[index]; }
+ T& operator[](int index) { return ((T *)_items)[index]; }
+ const T& Front() const { return operator[](0); }
+ T& Front() { return operator[](0); }
+ const T& Back() const { return operator[](_size - 1); }
+ T& Back() { return operator[](_size - 1); }
+
+ void Swap(int i, int j)
+ {
+ T temp = operator[](i);
+ operator[](i) = operator[](j);
+ operator[](j) = temp;
+ }
+
+ int FindInSorted(const T& item, int left, int right) const
+ {
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+ int FindInSorted(const T& item) const
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+ int AddToUniqueSorted(const T& item)
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+
+ static void SortRefDown(T* p, int k, int size, int (*compare)(const T*, const T*, void *), void *param)
+ {
+ T temp = p[k];
+ for (;;)
+ {
+ int s = (k << 1);
+ if (s > size)
+ break;
+ if (s < size && compare(p + s + 1, p + s, param) > 0)
+ s++;
+ if (compare(&temp, p + s, param) >= 0)
+ break;
+ p[k] = p[s];
+ k = s;
+ }
+ p[k] = temp;
+ }
+
+ void Sort(int (*compare)(const T*, const T*, void *), void *param)
+ {
+ int size = _size;
+ if (size <= 1)
+ return;
+ T* p = (&Front()) - 1;
+ {
+ int i = size / 2;
+ do
+ SortRefDown(p, i, size, compare, param);
+ while (--i != 0);
+ }
+ do
+ {
+ T temp = p[size];
+ p[size--] = p[1];
+ p[1] = temp;
+ SortRefDown(p, 1, size, compare, param);
+ }
+ while (size > 1);
+ }
+};
+
+typedef CRecordVector<int> CIntVector;
+typedef CRecordVector<unsigned int> CUIntVector;
+typedef CRecordVector<bool> CBoolVector;
+typedef CRecordVector<unsigned char> CByteVector;
+typedef CRecordVector<void *> CPointerVector;
+
+template <class T>
+class CObjectVector: public CPointerVector
+{
+public:
+ CObjectVector() {};
+ ~CObjectVector() { Clear(); };
+ CObjectVector(const CObjectVector &v): CPointerVector() { *this = v; }
+ CObjectVector& operator=(const CObjectVector &v)
+ {
+ Clear();
+ return (*this += v);
+ }
+ CObjectVector& operator+=(const CObjectVector &v)
+ {
+ int size = v.Size();
+ Reserve(Size() + size);
+ for (int i = 0; i < size; i++)
+ Add(v[i]);
+ return *this;
+ }
+ const T& operator[](int index) const { return *((T *)CPointerVector::operator[](index)); }
+ T& operator[](int index) { return *((T *)CPointerVector::operator[](index)); }
+ T& Front() { return operator[](0); }
+ const T& Front() const { return operator[](0); }
+ T& Back() { return operator[](_size - 1); }
+ const T& Back() const { return operator[](_size - 1); }
+ int Add(const T& item) { return CPointerVector::Add(new T(item)); }
+ void Insert(int index, const T& item) { CPointerVector::Insert(index, new T(item)); }
+ virtual void Delete(int index, int num = 1)
+ {
+ TestIndexAndCorrectNum(index, num);
+ for (int i = 0; i < num; i++)
+ delete (T *)(((void **)_items)[index + i]);
+ CPointerVector::Delete(index, num);
+ }
+ int Find(const T& item) const
+ {
+ for (int i = 0; i < Size(); i++)
+ if (item == (*this)[i])
+ return i;
+ return -1;
+ }
+ int FindInSorted(const T& item) const
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+ int AddToSorted(const T& item)
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ {
+ right = mid + 1;
+ break;
+ }
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+
+ void Sort(int (*compare)(void *const *, void *const *, void *), void *param)
+ { CPointerVector::Sort(compare, param); }
+
+ static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */)
+ { return MyCompare(*(*((const T **)a1)), *(*((const T **)a2))); }
+ void Sort() { CPointerVector::Sort(CompareObjectItems, 0); }
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyWindows.cpp b/src/libs/7zip/win/CPP/Common/MyWindows.cpp
new file mode 100644
index 000000000..1283946c2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyWindows.cpp
@@ -0,0 +1,109 @@
+// MyWindows.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+
+#include "MyWindows.h"
+#include "Types.h"
+#include <malloc.h>
+
+static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); }
+static inline void FreeForBSTR(void *pv) { ::free(pv);}
+
+static UINT MyStringLen(const wchar_t *s)
+{
+ UINT i;
+ for (i = 0; s[i] != '\0'; i++);
+ return i;
+}
+
+BSTR SysAllocStringByteLen(LPCSTR psz, UINT len)
+{
+ int realLen = len + sizeof(UINT) + sizeof(OLECHAR) + sizeof(OLECHAR);
+ void *p = AllocateForBSTR(realLen);
+ if (p == 0)
+ return 0;
+ *(UINT *)p = len;
+ BSTR bstr = (BSTR)((UINT *)p + 1);
+ memmove(bstr, psz, len);
+ Byte *pb = ((Byte *)bstr) + len;
+ for (int i = 0; i < sizeof(OLECHAR) * 2; i++)
+ pb[i] = 0;
+ return bstr;
+}
+
+BSTR SysAllocString(const OLECHAR *sz)
+{
+ if (sz == 0)
+ return 0;
+ UINT strLen = MyStringLen(sz);
+ UINT len = (strLen + 1) * sizeof(OLECHAR);
+ void *p = AllocateForBSTR(len + sizeof(UINT));
+ if (p == 0)
+ return 0;
+ *(UINT *)p = strLen;
+ BSTR bstr = (BSTR)((UINT *)p + 1);
+ memmove(bstr, sz, len);
+ return bstr;
+}
+
+void SysFreeString(BSTR bstr)
+{
+ if (bstr != 0)
+ FreeForBSTR((UINT *)bstr - 1);
+}
+
+UINT SysStringByteLen(BSTR bstr)
+{
+ if (bstr == 0)
+ return 0;
+ return *((UINT *)bstr - 1);
+}
+
+UINT SysStringLen(BSTR bstr)
+{
+ return SysStringByteLen(bstr) / sizeof(OLECHAR);
+}
+
+HRESULT VariantClear(VARIANTARG *prop)
+{
+ if (prop->vt == VT_BSTR)
+ SysFreeString(prop->bstrVal);
+ prop->vt = VT_EMPTY;
+ return S_OK;
+}
+
+HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src)
+{
+ HRESULT res = ::VariantClear(dest);
+ if (res != S_OK)
+ return res;
+ if (src->vt == VT_BSTR)
+ {
+ dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal,
+ SysStringByteLen(src->bstrVal));
+ if (dest->bstrVal == 0)
+ return E_OUTOFMEMORY;
+ dest->vt = VT_BSTR;
+ }
+ else
+ *dest = *src;
+ return S_OK;
+}
+
+LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2)
+{
+ if (ft1->dwHighDateTime < ft2->dwHighDateTime) return -1;
+ if (ft1->dwHighDateTime > ft2->dwHighDateTime) return 1;
+ if (ft1->dwLowDateTime < ft2->dwLowDateTime) return -1;
+ if (ft1->dwLowDateTime > ft2->dwLowDateTime) return 1;
+ return 0;
+}
+
+DWORD GetLastError()
+{
+ return 0;
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyWindows.h b/src/libs/7zip/win/CPP/Common/MyWindows.h
new file mode 100644
index 000000000..8b0e5c069
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyWindows.h
@@ -0,0 +1,204 @@
+// MyWindows.h
+
+#ifndef __MYWINDOWS_H
+#define __MYWINDOWS_H
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+#else
+
+#include <stddef.h> // for wchar_t
+#include <string.h>
+
+#include "MyGuidDef.h"
+
+typedef char CHAR;
+typedef unsigned char UCHAR;
+
+#undef BYTE
+typedef unsigned char BYTE;
+
+typedef short SHORT;
+typedef unsigned short USHORT;
+
+#undef WORD
+typedef unsigned short WORD;
+typedef short VARIANT_BOOL;
+
+typedef int INT;
+typedef Int32 INT32;
+typedef unsigned int UINT;
+typedef UInt32 UINT32;
+typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit
+typedef UINT32 ULONG;
+
+#undef DWORD
+typedef UINT32 DWORD;
+
+typedef Int64 LONGLONG;
+typedef UInt64 ULONGLONG;
+
+typedef struct LARGE_INTEGER { LONGLONG QuadPart; }LARGE_INTEGER;
+typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart;} ULARGE_INTEGER;
+
+typedef const CHAR *LPCSTR;
+typedef CHAR TCHAR;
+typedef const TCHAR *LPCTSTR;
+typedef wchar_t WCHAR;
+typedef WCHAR OLECHAR;
+typedef const WCHAR *LPCWSTR;
+typedef OLECHAR *BSTR;
+typedef const OLECHAR *LPCOLESTR;
+typedef OLECHAR *LPOLESTR;
+
+typedef struct _FILETIME
+{
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+}FILETIME;
+
+#define HRESULT LONG
+#define FAILED(Status) ((HRESULT)(Status)<0)
+typedef ULONG PROPID;
+typedef LONG SCODE;
+
+#define S_OK ((HRESULT)0x00000000L)
+#define S_FALSE ((HRESULT)0x00000001L)
+#define E_NOTIMPL ((HRESULT)0x80004001L)
+#define E_NOINTERFACE ((HRESULT)0x80004002L)
+#define E_ABORT ((HRESULT)0x80004004L)
+#define E_FAIL ((HRESULT)0x80004005L)
+#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L)
+#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
+#define E_INVALIDARG ((HRESULT)0x80070057L)
+
+#ifdef _MSC_VER
+#define STDMETHODCALLTYPE __stdcall
+#else
+#define STDMETHODCALLTYPE
+#endif
+
+#define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f
+#define STDMETHOD(f) STDMETHOD_(HRESULT, f)
+#define STDMETHODIMP_(type) type STDMETHODCALLTYPE
+#define STDMETHODIMP STDMETHODIMP_(HRESULT)
+
+#define PURE = 0
+
+#define MIDL_INTERFACE(x) struct
+
+#ifdef __cplusplus
+
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+struct IUnknown
+{
+ STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE;
+ STDMETHOD_(ULONG, AddRef)() PURE;
+ STDMETHOD_(ULONG, Release)() PURE;
+ #ifndef _WIN32
+ virtual ~IUnknown() {}
+ #endif
+};
+
+typedef IUnknown *LPUNKNOWN;
+
+#endif
+
+#define VARIANT_TRUE ((VARIANT_BOOL)-1)
+#define VARIANT_FALSE ((VARIANT_BOOL)0)
+
+enum VARENUM
+{
+ VT_EMPTY = 0,
+ VT_NULL = 1,
+ VT_I2 = 2,
+ VT_I4 = 3,
+ VT_R4 = 4,
+ VT_R8 = 5,
+ VT_CY = 6,
+ VT_DATE = 7,
+ VT_BSTR = 8,
+ VT_DISPATCH = 9,
+ VT_ERROR = 10,
+ VT_BOOL = 11,
+ VT_VARIANT = 12,
+ VT_UNKNOWN = 13,
+ VT_DECIMAL = 14,
+ VT_I1 = 16,
+ VT_UI1 = 17,
+ VT_UI2 = 18,
+ VT_UI4 = 19,
+ VT_I8 = 20,
+ VT_UI8 = 21,
+ VT_INT = 22,
+ VT_UINT = 23,
+ VT_VOID = 24,
+ VT_HRESULT = 25,
+ VT_FILETIME = 64
+};
+
+typedef unsigned short VARTYPE;
+typedef WORD PROPVAR_PAD1;
+typedef WORD PROPVAR_PAD2;
+typedef WORD PROPVAR_PAD3;
+
+#ifdef __cplusplus
+
+typedef struct tagPROPVARIANT
+{
+ VARTYPE vt;
+ PROPVAR_PAD1 wReserved1;
+ PROPVAR_PAD2 wReserved2;
+ PROPVAR_PAD3 wReserved3;
+ union
+ {
+ CHAR cVal;
+ UCHAR bVal;
+ SHORT iVal;
+ USHORT uiVal;
+ LONG lVal;
+ ULONG ulVal;
+ INT intVal;
+ UINT uintVal;
+ LARGE_INTEGER hVal;
+ ULARGE_INTEGER uhVal;
+ VARIANT_BOOL boolVal;
+ SCODE scode;
+ FILETIME filetime;
+ BSTR bstrVal;
+ };
+} PROPVARIANT;
+
+typedef PROPVARIANT tagVARIANT;
+typedef tagVARIANT VARIANT;
+typedef VARIANT VARIANTARG;
+
+MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop);
+MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src);
+
+#endif
+
+MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len);
+MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz);
+MY_EXTERN_C void SysFreeString(BSTR bstr);
+MY_EXTERN_C UINT SysStringByteLen(BSTR bstr);
+MY_EXTERN_C UINT SysStringLen(BSTR bstr);
+
+MY_EXTERN_C DWORD GetLastError();
+MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2);
+
+#define CP_ACP 0
+#define CP_OEMCP 1
+
+typedef enum tagSTREAM_SEEK
+{
+ STREAM_SEEK_SET = 0,
+ STREAM_SEEK_CUR = 1,
+ STREAM_SEEK_END = 2
+} STREAM_SEEK;
+
+#endif
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/MyXml.cpp b/src/libs/7zip/win/CPP/Common/MyXml.cpp
new file mode 100644
index 000000000..8aa9ce8cd
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyXml.cpp
@@ -0,0 +1,209 @@
+// MyXml.cpp
+
+#include "StdAfx.h"
+
+#include "MyXml.h"
+
+static bool IsValidChar(char c)
+{
+ return
+ c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == '-';
+}
+
+static bool IsSpaceChar(char c)
+{
+ return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A);
+}
+
+#define SKIP_SPACES(s, pos) while (IsSpaceChar(s[pos])) pos++;
+
+static bool ReadProperty(const AString &s, int &pos, CXmlProp &prop)
+{
+ prop.Name.Empty();
+ prop.Value.Empty();
+ for (; pos < s.Length(); pos++)
+ {
+ char c = s[pos];
+ if (!IsValidChar(c))
+ break;
+ prop.Name += c;
+ }
+
+ if (prop.Name.IsEmpty())
+ return false;
+
+ SKIP_SPACES(s, pos);
+ if (s[pos++] != '=')
+ return false;
+
+ SKIP_SPACES(s, pos);
+ if (s[pos++] != '\"')
+ return false;
+
+ while (pos < s.Length())
+ {
+ char c = s[pos++];
+ if (c == '\"')
+ return true;
+ prop.Value += c;
+ }
+ return false;
+}
+
+int CXmlItem::FindProperty(const AString &propName) const
+{
+ for (int i = 0; i < Props.Size(); i++)
+ if (Props[i].Name == propName)
+ return i;
+ return -1;
+}
+
+AString CXmlItem::GetPropertyValue(const AString &propName) const
+{
+ int index = FindProperty(propName);
+ if (index >= 0)
+ return Props[index].Value;
+ return AString();
+}
+
+bool CXmlItem::IsTagged(const AString &tag) const
+{
+ return (IsTag && Name == tag);
+}
+
+int CXmlItem::FindSubTag(const AString &tag) const
+{
+ for (int i = 0; i < SubItems.Size(); i++)
+ if (SubItems[i].IsTagged(tag))
+ return i;
+ return -1;
+}
+
+AString CXmlItem::GetSubString() const
+{
+ if (SubItems.Size() == 1)
+ {
+ const CXmlItem &item = SubItems[0];
+ if (!item.IsTag)
+ return item.Name;
+ }
+ return AString();
+}
+
+AString CXmlItem::GetSubStringForTag(const AString &tag) const
+{
+ int index = FindSubTag(tag);
+ if (index >= 0)
+ return SubItems[index].GetSubString();
+ return AString();
+}
+
+bool CXmlItem::ParseItems(const AString &s, int &pos, int numAllowedLevels)
+{
+ if (numAllowedLevels == 0)
+ return false;
+ SubItems.Clear();
+ AString finishString = "</";
+ for (;;)
+ {
+ SKIP_SPACES(s, pos);
+
+ if (s.Mid(pos, finishString.Length()) == finishString)
+ return true;
+
+ CXmlItem item;
+ if (!item.ParseItem(s, pos, numAllowedLevels - 1))
+ return false;
+ SubItems.Add(item);
+ }
+}
+
+bool CXmlItem::ParseItem(const AString &s, int &pos, int numAllowedLevels)
+{
+ SKIP_SPACES(s, pos);
+
+ int pos2 = s.Find('<', pos);
+ if (pos2 < 0)
+ return false;
+ if (pos2 != pos)
+ {
+ IsTag = false;
+ Name += s.Mid(pos, pos2 - pos);
+ pos = pos2;
+ return true;
+ }
+ IsTag = true;
+
+ pos++;
+ SKIP_SPACES(s, pos);
+
+ for (; pos < s.Length(); pos++)
+ {
+ char c = s[pos];
+ if (!IsValidChar(c))
+ break;
+ Name += c;
+ }
+ if (Name.IsEmpty() || pos == s.Length())
+ return false;
+
+ int posTemp = pos;
+ for (;;)
+ {
+ SKIP_SPACES(s, pos);
+ if (s[pos] == '/')
+ {
+ pos++;
+ // SKIP_SPACES(s, pos);
+ return (s[pos++] == '>');
+ }
+ if (s[pos] == '>')
+ {
+ if (!ParseItems(s, ++pos, numAllowedLevels))
+ return false;
+ AString finishString = AString("</") + Name + AString(">");
+ if (s.Mid(pos, finishString.Length()) != finishString)
+ return false;
+ pos += finishString.Length();
+ return true;
+ }
+ if (posTemp == pos)
+ return false;
+
+ CXmlProp prop;
+ if (!ReadProperty(s, pos, prop))
+ return false;
+ Props.Add(prop);
+ posTemp = pos;
+ }
+}
+
+static bool SkipHeader(const AString &s, int &pos, const AString &startString, const AString &endString)
+{
+ SKIP_SPACES(s, pos);
+ if (s.Mid(pos, startString.Length()) == startString)
+ {
+ pos = s.Find(endString, pos);
+ if (pos < 0)
+ return false;
+ pos += endString.Length();
+ SKIP_SPACES(s, pos);
+ }
+ return true;
+}
+
+bool CXml::Parse(const AString &s)
+{
+ int pos = 0;
+ if (!SkipHeader(s, pos, "<?xml", "?>"))
+ return false;
+ if (!SkipHeader(s, pos, "<!DOCTYPE", ">"))
+ return false;
+ if (!Root.ParseItem(s, pos, 1000))
+ return false;
+ SKIP_SPACES(s, pos);
+ return (pos == s.Length() && Root.IsTag);
+}
diff --git a/src/libs/7zip/win/CPP/Common/MyXml.h b/src/libs/7zip/win/CPP/Common/MyXml.h
new file mode 100644
index 000000000..c6e8829ad
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/MyXml.h
@@ -0,0 +1,40 @@
+// MyXml.h
+
+#ifndef __MYXML_H
+#define __MYXML_H
+
+#include "MyString.h"
+
+struct CXmlProp
+{
+ AString Name;
+ AString Value;
+};
+
+class CXmlItem
+{
+ bool ParseItems(const AString &s, int &pos, int numAllowedLevels);
+
+public:
+ AString Name;
+ bool IsTag;
+ CObjectVector<CXmlProp> Props;
+ CObjectVector<CXmlItem> SubItems;
+
+ bool ParseItem(const AString &s, int &pos, int numAllowedLevels);
+
+ bool IsTagged(const AString &tag) const;
+ int FindProperty(const AString &propName) const;
+ AString GetPropertyValue(const AString &propName) const;
+ AString GetSubString() const;
+ int FindSubTag(const AString &tag) const;
+ AString GetSubStringForTag(const AString &tag) const;
+};
+
+struct CXml
+{
+ CXmlItem Root;
+ bool Parse(const AString &s);
+};
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/NewHandler.cpp b/src/libs/7zip/win/CPP/Common/NewHandler.cpp
new file mode 100644
index 000000000..aad6e7d16
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/NewHandler.cpp
@@ -0,0 +1,116 @@
+// NewHandler.cpp
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#include "NewHandler.h"
+
+// #define DEBUG_MEMORY_LEAK
+
+#ifndef DEBUG_MEMORY_LEAK
+
+#ifdef _WIN32
+void *
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator new(size_t size)
+{
+ // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
+ void *p = ::malloc(size);
+ if (p == 0)
+ throw CNewException();
+ return p;
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw()
+{
+ /*
+ if (p == 0)
+ return;
+ ::HeapFree(::GetProcessHeap(), 0, p);
+ */
+ ::free(p);
+}
+#endif
+
+#else
+
+#pragma init_seg(lib)
+const int kDebugSize = 1000000;
+static void *a[kDebugSize];
+static int index = 0;
+
+static int numAllocs = 0;
+void * __cdecl operator new(size_t size)
+{
+ numAllocs++;
+ void *p = HeapAlloc(GetProcessHeap(), 0, size);
+ if (index == 40)
+ {
+ int t = 1;
+ }
+ if (index < kDebugSize)
+ {
+ a[index] = p;
+ index++;
+ }
+ if (p == 0)
+ throw CNewException();
+ printf("Alloc %6d, size = %8d\n", numAllocs, size);
+ return p;
+}
+
+class CC
+{
+public:
+ CC()
+ {
+ for (int i = 0; i < kDebugSize; i++)
+ a[i] = 0;
+ }
+ ~CC()
+ {
+ for (int i = 0; i < kDebugSize; i++)
+ if (a[i] != 0)
+ return;
+ }
+} g_CC;
+
+
+void __cdecl operator delete(void *p)
+{
+ if (p == 0)
+ return;
+ /*
+ for (int i = 0; i < index; i++)
+ if (a[i] == p)
+ a[i] = 0;
+ */
+ HeapFree(GetProcessHeap(), 0, p);
+ numAllocs--;
+ printf("Free %d\n", numAllocs);
+}
+
+#endif
+
+/*
+int MemErrorVC(size_t)
+{
+ throw CNewException();
+ // return 1;
+}
+CNewHandlerSetter::CNewHandlerSetter()
+{
+ // MemErrorOldVCFunction = _set_new_handler(MemErrorVC);
+}
+CNewHandlerSetter::~CNewHandlerSetter()
+{
+ // _set_new_handler(MemErrorOldVCFunction);
+}
+*/
diff --git a/src/libs/7zip/win/CPP/Common/NewHandler.h b/src/libs/7zip/win/CPP/Common/NewHandler.h
new file mode 100644
index 000000000..215ba05f1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/NewHandler.h
@@ -0,0 +1,16 @@
+// Common/NewHandler.h
+
+#ifndef __COMMON_NEWHANDLER_H
+#define __COMMON_NEWHANDLER_H
+
+class CNewException {};
+
+#ifdef _WIN32
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw();
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/Random.cpp b/src/libs/7zip/win/CPP/Common/Random.cpp
new file mode 100644
index 000000000..4bd3fcf93
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Random.cpp
@@ -0,0 +1,26 @@
+// Common/Random.cpp
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <time.h>
+#endif
+
+#include "Random.h"
+
+void CRandom::Init(unsigned int seed) { srand(seed); }
+
+void CRandom::Init()
+{
+ Init((unsigned int)
+ #ifdef _WIN32
+ GetTickCount()
+ #else
+ time(NULL)
+ #endif
+ );
+}
+
+int CRandom::Generate() const { return rand(); }
diff --git a/src/libs/7zip/win/CPP/Common/Random.h b/src/libs/7zip/win/CPP/Common/Random.h
new file mode 100644
index 000000000..ffef20d12
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Random.h
@@ -0,0 +1,16 @@
+// Common/Random.h
+
+#ifndef __COMMON_RANDOM_H
+#define __COMMON_RANDOM_H
+
+class CRandom
+{
+public:
+ void Init();
+ void Init(unsigned int seed);
+ int Generate() const;
+};
+
+#endif
+
+
diff --git a/src/libs/7zip/win/CPP/Common/StdAfx.h b/src/libs/7zip/win/CPP/Common/StdAfx.h
new file mode 100644
index 000000000..b8ba1d5c4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+// #include "MyWindows.h"
+#include "NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/StdInStream.cpp b/src/libs/7zip/win/CPP/Common/StdInStream.cpp
new file mode 100644
index 000000000..f3dcb85f5
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StdInStream.cpp
@@ -0,0 +1,107 @@
+// Common/StdInStream.cpp
+
+#include "StdAfx.h"
+
+#include <tchar.h>
+
+#include "StdInStream.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+#ifdef _MSC_VER
+// "was declared deprecated" disabling
+#pragma warning(disable : 4996 )
+#endif
+
+static const char kIllegalChar = '\0';
+static const char kNewLineChar = '\n';
+
+static const char *kEOFMessage = "Unexpected end of input stream";
+static const char *kReadErrorMessage ="Error reading input stream";
+static const char *kIllegalCharMessage = "Illegal character in input stream";
+
+static LPCTSTR kFileOpenMode = TEXT("r");
+
+extern int g_CodePage;
+
+CStdInStream g_StdIn(stdin);
+
+bool CStdInStream::Open(LPCTSTR fileName)
+{
+ Close();
+ _stream = _tfopen(fileName, kFileOpenMode);
+ _streamIsOpen = (_stream != 0);
+ return _streamIsOpen;
+}
+
+bool CStdInStream::Close()
+{
+ if (!_streamIsOpen)
+ return true;
+ _streamIsOpen = (fclose(_stream) != 0);
+ return !_streamIsOpen;
+}
+
+CStdInStream::~CStdInStream()
+{
+ Close();
+}
+
+AString CStdInStream::ScanStringUntilNewLine(bool allowEOF)
+{
+ AString s;
+ for (;;)
+ {
+ int intChar = GetChar();
+ if (intChar == EOF)
+ {
+ if (allowEOF)
+ break;
+ throw kEOFMessage;
+ }
+ char c = char(intChar);
+ if (c == kIllegalChar)
+ throw kIllegalCharMessage;
+ if (c == kNewLineChar)
+ break;
+ s += c;
+ }
+ return s;
+}
+
+UString CStdInStream::ScanUStringUntilNewLine()
+{
+ AString s = ScanStringUntilNewLine(true);
+ int codePage = g_CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ UString dest;
+ if (codePage == CP_UTF8)
+ ConvertUTF8ToUnicode(s, dest);
+ else
+ dest = MultiByteToUnicodeString(s, (UINT)codePage);
+ return dest;
+}
+
+void CStdInStream::ReadToString(AString &resultString)
+{
+ resultString.Empty();
+ int c;
+ while ((c = GetChar()) != EOF)
+ resultString += char(c);
+}
+
+bool CStdInStream::Eof()
+{
+ return (feof(_stream) != 0);
+}
+
+int CStdInStream::GetChar()
+{
+ int c = fgetc(_stream); // getc() doesn't work in BeOS?
+ if (c == EOF && !Eof())
+ throw kReadErrorMessage;
+ return c;
+}
+
+
diff --git a/src/libs/7zip/win/CPP/Common/StdInStream.h b/src/libs/7zip/win/CPP/Common/StdInStream.h
new file mode 100644
index 000000000..0d182cc3c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StdInStream.h
@@ -0,0 +1,32 @@
+// Common/StdInStream.h
+
+#ifndef __COMMON_STDINSTREAM_H
+#define __COMMON_STDINSTREAM_H
+
+#include <stdio.h>
+
+#include "MyString.h"
+#include "Types.h"
+
+class CStdInStream
+{
+ bool _streamIsOpen;
+ FILE *_stream;
+public:
+ CStdInStream(): _streamIsOpen(false) {};
+ CStdInStream(FILE *stream): _streamIsOpen(false), _stream(stream) {};
+ ~CStdInStream();
+ bool Open(LPCTSTR fileName);
+ bool Close();
+
+ AString ScanStringUntilNewLine(bool allowEOF = false);
+ void ReadToString(AString &resultString);
+ UString ScanUStringUntilNewLine();
+
+ bool Eof();
+ int GetChar();
+};
+
+extern CStdInStream g_StdIn;
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/StdOutStream.cpp b/src/libs/7zip/win/CPP/Common/StdOutStream.cpp
new file mode 100644
index 000000000..061a76063
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StdOutStream.cpp
@@ -0,0 +1,104 @@
+// Common/StdOutStream.cpp
+
+#include "StdAfx.h"
+
+#include <tchar.h>
+
+#include "IntToString.h"
+#include "StdOutStream.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+#ifdef _MSC_VER
+// "was declared deprecated" disabling
+#pragma warning(disable : 4996 )
+#endif
+
+static const char kNewLineChar = '\n';
+
+static const char *kFileOpenMode = "wt";
+
+extern int g_CodePage;
+
+CStdOutStream g_StdOut(stdout);
+CStdOutStream g_StdErr(stderr);
+
+bool CStdOutStream::Open(const char *fileName)
+{
+ Close();
+ _stream = fopen(fileName, kFileOpenMode);
+ _streamIsOpen = (_stream != 0);
+ return _streamIsOpen;
+}
+
+bool CStdOutStream::Close()
+{
+ if (!_streamIsOpen)
+ return true;
+ if (fclose(_stream) != 0)
+ return false;
+ _stream = 0;
+ _streamIsOpen = false;
+ return true;
+}
+
+bool CStdOutStream::Flush()
+{
+ return (fflush(_stream) == 0);
+}
+
+CStdOutStream::~CStdOutStream ()
+{
+ Close();
+}
+
+CStdOutStream & CStdOutStream::operator<<(CStdOutStream & (*aFunction)(CStdOutStream &))
+{
+ (*aFunction)(*this);
+ return *this;
+}
+
+CStdOutStream & endl(CStdOutStream & outStream)
+{
+ return outStream << kNewLineChar;
+}
+
+CStdOutStream & CStdOutStream::operator<<(const char *s)
+{
+ fputs(s, _stream);
+ return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(const wchar_t *s)
+{
+ int codePage = g_CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ AString dest;
+ if (codePage == CP_UTF8)
+ ConvertUnicodeToUTF8(s, dest);
+ else
+ dest = UnicodeStringToMultiByte(s, (UINT)codePage);
+ *this << (const char *)dest;
+ return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(char c)
+{
+ fputc(c, _stream);
+ return *this;
+}
+
+CStdOutStream & CStdOutStream::operator<<(int number)
+{
+ char textString[32];
+ ConvertInt64ToString(number, textString);
+ return operator<<(textString);
+}
+
+CStdOutStream & CStdOutStream::operator<<(UInt64 number)
+{
+ char textString[32];
+ ConvertUInt64ToString(number, textString);
+ return operator<<(textString);
+}
diff --git a/src/libs/7zip/win/CPP/Common/StdOutStream.h b/src/libs/7zip/win/CPP/Common/StdOutStream.h
new file mode 100644
index 000000000..b0b2c615c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StdOutStream.h
@@ -0,0 +1,35 @@
+// Common/StdOutStream.h
+
+#ifndef __COMMON_STDOUTSTREAM_H
+#define __COMMON_STDOUTSTREAM_H
+
+#include <stdio.h>
+
+#include "Types.h"
+
+class CStdOutStream
+{
+ bool _streamIsOpen;
+ FILE *_stream;
+public:
+ CStdOutStream (): _streamIsOpen(false), _stream(0) {};
+ CStdOutStream (FILE *stream): _streamIsOpen(false), _stream(stream) {};
+ ~CStdOutStream ();
+ operator FILE *() { return _stream; }
+ bool Open(const char *fileName);
+ bool Close();
+ bool Flush();
+ CStdOutStream & operator<<(CStdOutStream & (* aFunction)(CStdOutStream &));
+ CStdOutStream & operator<<(const char *string);
+ CStdOutStream & operator<<(const wchar_t *string);
+ CStdOutStream & operator<<(char c);
+ CStdOutStream & operator<<(int number);
+ CStdOutStream & operator<<(UInt64 number);
+};
+
+CStdOutStream & endl(CStdOutStream & outStream);
+
+extern CStdOutStream g_StdOut;
+extern CStdOutStream g_StdErr;
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/StringConvert.cpp b/src/libs/7zip/win/CPP/Common/StringConvert.cpp
new file mode 100644
index 000000000..681895b71
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StringConvert.cpp
@@ -0,0 +1,97 @@
+// Common/StringConvert.cpp
+
+#include "StdAfx.h"
+
+#include "StringConvert.h"
+
+#ifndef _WIN32
+#include <stdlib.h>
+#endif
+
+#ifdef _WIN32
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+ UString resultString;
+ if (!srcString.IsEmpty())
+ {
+ int numChars = MultiByteToWideChar(codePage, 0, srcString,
+ srcString.Length(), resultString.GetBuffer(srcString.Length()),
+ srcString.Length() + 1);
+ if (numChars == 0)
+ throw 282228;
+ resultString.ReleaseBuffer(numChars);
+ }
+ return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed)
+{
+ AString dest;
+ defaultCharWasUsed = false;
+ if (!s.IsEmpty())
+ {
+ int numRequiredBytes = s.Length() * 2;
+ BOOL defUsed;
+ int numChars = WideCharToMultiByte(codePage, 0, s, s.Length(),
+ dest.GetBuffer(numRequiredBytes), numRequiredBytes + 1,
+ &defaultChar, &defUsed);
+ defaultCharWasUsed = (defUsed != FALSE);
+ if (numChars == 0)
+ throw 282229;
+ dest.ReleaseBuffer(numChars);
+ }
+ return dest;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+ bool defaultCharWasUsed;
+ return UnicodeStringToMultiByte(srcString, codePage, '_', defaultCharWasUsed);
+}
+
+#ifndef UNDER_CE
+AString SystemStringToOemString(const CSysString &srcString)
+{
+ AString result;
+ CharToOem(srcString, result.GetBuffer(srcString.Length() * 2));
+ result.ReleaseBuffer();
+ return result;
+}
+#endif
+
+#else
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+ UString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ resultString += wchar_t(srcString[i]);
+ /*
+ if (!srcString.IsEmpty())
+ {
+ int numChars = mbstowcs(resultString.GetBuffer(srcString.Length()), srcString, srcString.Length() + 1);
+ if (numChars < 0) throw "Your environment does not support UNICODE";
+ resultString.ReleaseBuffer(numChars);
+ }
+ */
+ return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+ AString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ resultString += char(srcString[i]);
+ /*
+ if (!srcString.IsEmpty())
+ {
+ int numRequiredBytes = srcString.Length() * 6 + 1;
+ int numChars = wcstombs(resultString.GetBuffer(numRequiredBytes), srcString, numRequiredBytes);
+ if (numChars < 0) throw "Your environment does not support UNICODE";
+ resultString.ReleaseBuffer(numChars);
+ }
+ */
+ return resultString;
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/StringConvert.h b/src/libs/7zip/win/CPP/Common/StringConvert.h
new file mode 100644
index 000000000..cd737becb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StringConvert.h
@@ -0,0 +1,73 @@
+// Common/StringConvert.h
+
+#ifndef __COMMON_STRING_CONVERT_H
+#define __COMMON_STRING_CONVERT_H
+
+#include "MyWindows.h"
+#include "MyString.h"
+#include "Types.h"
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage = CP_ACP);
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage, char defaultChar, bool &defaultCharWasUsed);
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage = CP_ACP);
+
+
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString)
+ { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString)
+ { return unicodeString; }
+inline UString GetUnicodeString(const AString &ansiString)
+ { return MultiByteToUnicodeString(ansiString); }
+inline UString GetUnicodeString(const AString &multiByteString, UINT codePage)
+ { return MultiByteToUnicodeString(multiByteString, codePage); }
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString, UINT)
+ { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString, UINT)
+ { return unicodeString; }
+
+inline const char* GetAnsiString(const char* ansiString)
+ { return ansiString; }
+inline const AString& GetAnsiString(const AString &ansiString)
+ { return ansiString; }
+inline AString GetAnsiString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString); }
+
+inline const char* GetOemString(const char* oemString)
+ { return oemString; }
+inline const AString& GetOemString(const AString &oemString)
+ { return oemString; }
+inline AString GetOemString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString, CP_OEMCP); }
+
+
+#ifdef _UNICODE
+ inline const wchar_t* GetSystemString(const wchar_t* unicodeString)
+ { return unicodeString;}
+ inline const UString& GetSystemString(const UString &unicodeString)
+ { return unicodeString;}
+ inline const wchar_t* GetSystemString(const wchar_t* unicodeString, UINT /* codePage */)
+ { return unicodeString;}
+ inline const UString& GetSystemString(const UString &unicodeString, UINT /* codePage */)
+ { return unicodeString;}
+ inline UString GetSystemString(const AString &multiByteString, UINT codePage)
+ { return MultiByteToUnicodeString(multiByteString, codePage);}
+ inline UString GetSystemString(const AString &multiByteString)
+ { return MultiByteToUnicodeString(multiByteString);}
+#else
+ inline const char* GetSystemString(const char *ansiString)
+ { return ansiString; }
+ inline const AString& GetSystemString(const AString &multiByteString, UINT)
+ { return multiByteString; }
+ inline const char * GetSystemString(const char *multiByteString, UINT)
+ { return multiByteString; }
+ inline AString GetSystemString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString); }
+ inline AString GetSystemString(const UString &unicodeString, UINT codePage)
+ { return UnicodeStringToMultiByte(unicodeString, codePage); }
+#endif
+
+#ifndef UNDER_CE
+AString SystemStringToOemString(const CSysString &srcString);
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/StringToInt.cpp b/src/libs/7zip/win/CPP/Common/StringToInt.cpp
new file mode 100644
index 000000000..9473766bc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StringToInt.cpp
@@ -0,0 +1,90 @@
+// Common/StringToInt.cpp
+
+#include "StdAfx.h"
+
+#include "StringToInt.h"
+
+UInt64 ConvertStringToUInt64(const char *s, const char **end)
+{
+ UInt64 result = 0;
+ for (;;)
+ {
+ char c = *s;
+ if (c < '0' || c > '9')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result *= 10;
+ result += (c - '0');
+ s++;
+ }
+}
+
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end)
+{
+ UInt64 result = 0;
+ for (;;)
+ {
+ char c = *s;
+ if (c < '0' || c > '7')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result <<= 3;
+ result += (c - '0');
+ s++;
+ }
+}
+
+UInt64 ConvertHexStringToUInt64(const char *s, const char **end)
+{
+ UInt64 result = 0;
+ for (;;)
+ {
+ char c = *s;
+ UInt32 v;
+ if (c >= '0' && c <= '9') v = (c - '0');
+ else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
+ else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
+ else
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result <<= 4;
+ result |= v;
+ s++;
+ }
+}
+
+
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end)
+{
+ UInt64 result = 0;
+ for (;;)
+ {
+ wchar_t c = *s;
+ if (c < '0' || c > '9')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result *= 10;
+ result += (c - '0');
+ s++;
+ }
+}
+
+
+Int64 ConvertStringToInt64(const char *s, const char **end)
+{
+ if (*s == '-')
+ return -(Int64)ConvertStringToUInt64(s + 1, end);
+ return ConvertStringToUInt64(s, end);
+}
diff --git a/src/libs/7zip/win/CPP/Common/StringToInt.h b/src/libs/7zip/win/CPP/Common/StringToInt.h
new file mode 100644
index 000000000..c0d860eff
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/StringToInt.h
@@ -0,0 +1,18 @@
+// Common/StringToInt.h
+
+#ifndef __COMMON_STRINGTOINT_H
+#define __COMMON_STRINGTOINT_H
+
+#include <string.h>
+#include "Types.h"
+
+UInt64 ConvertStringToUInt64(const char *s, const char **end);
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end);
+UInt64 ConvertHexStringToUInt64(const char *s, const char **end);
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end);
+
+Int64 ConvertStringToInt64(const char *s, const char **end);
+
+#endif
+
+
diff --git a/src/libs/7zip/win/CPP/Common/TextConfig.cpp b/src/libs/7zip/win/CPP/Common/TextConfig.cpp
new file mode 100644
index 000000000..34fedeb85
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/TextConfig.cpp
@@ -0,0 +1,138 @@
+// Common/TextConfig.cpp
+
+#include "StdAfx.h"
+
+#include "TextConfig.h"
+
+#include "Defs.h"
+#include "UTFConvert.h"
+
+static bool IsDelimitChar(char c)
+{
+ return (c == ' ' || c == 0x0A || c == 0x0D ||
+ c == '\0' || c == '\t');
+}
+
+static AString GetIDString(const char *string, int &finishPos)
+{
+ AString result;
+ for (finishPos = 0; ; finishPos++)
+ {
+ char c = string[finishPos];
+ if (IsDelimitChar(c) || c == '=')
+ break;
+ result += c;
+ }
+ return result;
+}
+
+static bool WaitNextLine(const AString &string, int &pos)
+{
+ for (;pos < string.Length(); pos++)
+ if (string[pos] == 0x0A)
+ return true;
+ return false;
+}
+
+static bool SkipSpaces(const AString &string, int &pos)
+{
+ for (;pos < string.Length(); pos++)
+ {
+ char c = string[pos];
+ if (!IsDelimitChar(c))
+ {
+ if (c != ';')
+ return true;
+ if (!WaitNextLine(string, pos))
+ return false;
+ }
+ }
+ return false;
+}
+
+bool GetTextConfig(const AString &string, CObjectVector<CTextConfigPair> &pairs)
+{
+ pairs.Clear();
+ int pos = 0;
+
+ /////////////////////
+ // read strings
+
+ for (;;)
+ {
+ if (!SkipSpaces(string, pos))
+ break;
+ CTextConfigPair pair;
+ int finishPos;
+ AString temp = GetIDString(((const char *)string) + pos, finishPos);
+ if (!ConvertUTF8ToUnicode(temp, pair.ID))
+ return false;
+ if (finishPos == 0)
+ return false;
+ pos += finishPos;
+ if (!SkipSpaces(string, pos))
+ return false;
+ if (string[pos] != '=')
+ return false;
+ pos++;
+ if (!SkipSpaces(string, pos))
+ return false;
+ if (string[pos] != '\"')
+ return false;
+ pos++;
+ AString message;
+ for (;;)
+ {
+ if (pos >= string.Length())
+ return false;
+ char c = string[pos++];
+ if (c == '\"')
+ break;
+ if (c == '\\')
+ {
+ char c = string[pos++];
+ switch(c)
+ {
+ case 'n':
+ message += '\n';
+ break;
+ case 't':
+ message += '\t';
+ break;
+ case '\\':
+ message += '\\';
+ break;
+ case '\"':
+ message += '\"';
+ break;
+ default:
+ message += '\\';
+ message += c;
+ break;
+ }
+ }
+ else
+ message += c;
+ }
+ if (!ConvertUTF8ToUnicode(message, pair.String))
+ return false;
+ pairs.Add(pair);
+ }
+ return true;
+}
+
+int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const UString &id)
+{
+ for (int i = 0; i < pairs.Size(); i++)
+ if (pairs[i].ID.Compare(id) == 0)
+ return i;
+ return -1;
+}
+
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const UString &id)
+{
+ int index = FindTextConfigItem(pairs, id);
+ if (index < 0)
+ return UString();
+ return pairs[index].String;
+}
diff --git a/src/libs/7zip/win/CPP/Common/TextConfig.h b/src/libs/7zip/win/CPP/Common/TextConfig.h
new file mode 100644
index 000000000..a25142a70
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/TextConfig.h
@@ -0,0 +1,22 @@
+// Common/TextConfig.h
+
+#ifndef __COMMON_TEXTCONFIG_H
+#define __COMMON_TEXTCONFIG_H
+
+#include "MyVector.h"
+#include "MyString.h"
+
+struct CTextConfigPair
+{
+ UString ID;
+ UString String;
+};
+
+bool GetTextConfig(const AString &text, CObjectVector<CTextConfigPair> &pairs);
+
+int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const UString &id);
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const UString &id);
+
+#endif
+
+
diff --git a/src/libs/7zip/win/CPP/Common/Types.h b/src/libs/7zip/win/CPP/Common/Types.h
new file mode 100644
index 000000000..9365b327f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Types.h
@@ -0,0 +1,11 @@
+// Common/Types.h
+
+#ifndef __COMMON_TYPES_H
+#define __COMMON_TYPES_H
+
+#include "../../C/Types.h"
+
+typedef int HRes;
+
+#endif
+
diff --git a/src/libs/7zip/win/CPP/Common/UTFConvert.cpp b/src/libs/7zip/win/CPP/Common/UTFConvert.cpp
new file mode 100644
index 000000000..95362430a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/UTFConvert.cpp
@@ -0,0 +1,145 @@
+// UTFConvert.cpp
+
+#include "StdAfx.h"
+
+#include "UTFConvert.h"
+#include "Types.h"
+
+static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+static Bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, size_t srcLen)
+{
+ size_t destPos = 0, srcPos = 0;
+ for (;;)
+ {
+ Byte c;
+ int numAdds;
+ if (srcPos == srcLen)
+ {
+ *destLen = destPos;
+ return True;
+ }
+ c = (Byte)src[srcPos++];
+
+ if (c < 0x80)
+ {
+ if (dest)
+ dest[destPos] = (wchar_t)c;
+ destPos++;
+ continue;
+ }
+ if (c < 0xC0)
+ break;
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (c < kUtf8Limits[numAdds])
+ break;
+ UInt32 value = (c - kUtf8Limits[numAdds - 1]);
+
+ do
+ {
+ Byte c2;
+ if (srcPos == srcLen)
+ break;
+ c2 = (Byte)src[srcPos++];
+ if (c2 < 0x80 || c2 >= 0xC0)
+ break;
+ value <<= 6;
+ value |= (c2 - 0x80);
+ }
+ while (--numAdds != 0);
+
+ if (value < 0x10000)
+ {
+ if (dest)
+ dest[destPos] = (wchar_t)value;
+ destPos++;
+ }
+ else
+ {
+ value -= 0x10000;
+ if (value >= 0x100000)
+ break;
+ if (dest)
+ {
+ dest[destPos + 0] = (wchar_t)(0xD800 + (value >> 10));
+ dest[destPos + 1] = (wchar_t)(0xDC00 + (value & 0x3FF));
+ }
+ destPos += 2;
+ }
+ }
+ *destLen = destPos;
+ return False;
+}
+
+static Bool Utf16_To_Utf8(char *dest, size_t *destLen, const wchar_t *src, size_t srcLen)
+{
+ size_t destPos = 0, srcPos = 0;
+ for (;;)
+ {
+ unsigned numAdds;
+ UInt32 value;
+ if (srcPos == srcLen)
+ {
+ *destLen = destPos;
+ return True;
+ }
+ value = src[srcPos++];
+ if (value < 0x80)
+ {
+ if (dest)
+ dest[destPos] = (char)value;
+ destPos++;
+ continue;
+ }
+ if (value >= 0xD800 && value < 0xE000)
+ {
+ UInt32 c2;
+ if (value >= 0xDC00 || srcPos == srcLen)
+ break;
+ c2 = src[srcPos++];
+ if (c2 < 0xDC00 || c2 >= 0xE000)
+ break;
+ value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
+ }
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+ break;
+ if (dest)
+ dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+ destPos++;
+ do
+ {
+ numAdds--;
+ if (dest)
+ dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+ destPos++;
+ }
+ while (numAdds != 0);
+ }
+ *destLen = destPos;
+ return False;
+}
+
+bool ConvertUTF8ToUnicode(const AString &src, UString &dest)
+{
+ dest.Empty();
+ size_t destLen = 0;
+ Utf8_To_Utf16(NULL, &destLen, src, src.Length());
+ wchar_t *p = dest.GetBuffer((int)destLen);
+ Bool res = Utf8_To_Utf16(p, &destLen, src, src.Length());
+ p[destLen] = 0;
+ dest.ReleaseBuffer();
+ return res ? true : false;
+}
+
+bool ConvertUnicodeToUTF8(const UString &src, AString &dest)
+{
+ dest.Empty();
+ size_t destLen = 0;
+ Utf16_To_Utf8(NULL, &destLen, src, src.Length());
+ char *p = dest.GetBuffer((int)destLen);
+ Bool res = Utf16_To_Utf8(p, &destLen, src, src.Length());
+ p[destLen] = 0;
+ dest.ReleaseBuffer();
+ return res ? true : false;
+}
diff --git a/src/libs/7zip/win/CPP/Common/UTFConvert.h b/src/libs/7zip/win/CPP/Common/UTFConvert.h
new file mode 100644
index 000000000..2a14600d9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/UTFConvert.h
@@ -0,0 +1,11 @@
+// Common/UTFConvert.h
+
+#ifndef __COMMON_UTFCONVERT_H
+#define __COMMON_UTFCONVERT_H
+
+#include "MyString.h"
+
+bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString);
+bool ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Common/Wildcard.cpp b/src/libs/7zip/win/CPP/Common/Wildcard.cpp
new file mode 100644
index 000000000..476ddebde
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Wildcard.cpp
@@ -0,0 +1,462 @@
+// Common/Wildcard.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/Types.h"
+
+#include "Wildcard.h"
+
+bool g_CaseSensitive =
+ #ifdef _WIN32
+ false;
+ #else
+ true;
+ #endif
+
+static const wchar_t kAnyCharsChar = L'*';
+static const wchar_t kAnyCharChar = L'?';
+
+#ifdef _WIN32
+static const wchar_t kDirDelimiter1 = L'\\';
+#endif
+static const wchar_t kDirDelimiter2 = L'/';
+
+static const UString kWildCardCharSet = L"?*";
+
+static const UString kIllegalWildCardFileNameChars=
+ L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF"
+ L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
+ L"\"/:<>\\|";
+
+
+static inline bool IsCharDirLimiter(wchar_t c)
+{
+ return (
+ #ifdef _WIN32
+ c == kDirDelimiter1 ||
+ #endif
+ c == kDirDelimiter2);
+}
+
+int CompareFileNames(const UString &s1, const UString &s2)
+{
+ if (g_CaseSensitive)
+ return s1.Compare(s2);
+ return s1.CompareNoCase(s2);
+}
+
+// -----------------------------------------
+// this function compares name with mask
+// ? - any char
+// * - any char or empty
+
+static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
+{
+ for (;;)
+ {
+ wchar_t m = *mask;
+ wchar_t c = *name;
+ if (m == 0)
+ return (c == 0);
+ if (m == kAnyCharsChar)
+ {
+ if (EnhancedMaskTest(mask + 1, name))
+ return true;
+ if (c == 0)
+ return false;
+ }
+ else
+ {
+ if (m == kAnyCharChar)
+ {
+ if (c == 0)
+ return false;
+ }
+ else if (m != c)
+ if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c))
+ return false;
+ mask++;
+ }
+ name++;
+ }
+}
+
+// --------------------------------------------------
+// Splits path to strings
+
+void SplitPathToParts(const UString &path, UStringVector &pathParts)
+{
+ pathParts.Clear();
+ UString name;
+ int len = path.Length();
+ if (len == 0)
+ return;
+ for (int i = 0; i < len; i++)
+ {
+ wchar_t c = path[i];
+ if (IsCharDirLimiter(c))
+ {
+ pathParts.Add(name);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ pathParts.Add(name);
+}
+
+void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name)
+{
+ int i;
+ for (i = path.Length() - 1; i >= 0; i--)
+ if (IsCharDirLimiter(path[i]))
+ break;
+ dirPrefix = path.Left(i + 1);
+ name = path.Mid(i + 1);
+}
+
+UString ExtractDirPrefixFromPath(const UString &path)
+{
+ int i;
+ for (i = path.Length() - 1; i >= 0; i--)
+ if (IsCharDirLimiter(path[i]))
+ break;
+ return path.Left(i + 1);
+}
+
+UString ExtractFileNameFromPath(const UString &path)
+{
+ int i;
+ for (i = path.Length() - 1; i >= 0; i--)
+ if (IsCharDirLimiter(path[i]))
+ break;
+ return path.Mid(i + 1);
+}
+
+
+bool CompareWildCardWithName(const UString &mask, const UString &name)
+{
+ return EnhancedMaskTest(mask, name);
+}
+
+bool DoesNameContainWildCard(const UString &path)
+{
+ return (path.FindOneOf(kWildCardCharSet) >= 0);
+}
+
+
+// ----------------------------------------------------------'
+// NWildcard
+
+namespace NWildcard {
+
+
+/*
+M = MaskParts.Size();
+N = TestNameParts.Size();
+
+ File Dir
+ForFile req M<=N [N-M, N) -
+ nonreq M=N [0, M) -
+
+ForDir req M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File
+ nonreq [0, M) same as ForBoth-File
+
+ForBoth req m<=N [0, M) ... [N-M, N) same as ForBoth-File
+ nonreq [0, M) same as ForBoth-File
+
+*/
+
+bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
+{
+ if (!isFile && !ForDir)
+ return false;
+ int delta = (int)pathParts.Size() - (int)PathParts.Size();
+ if (delta < 0)
+ return false;
+ int start = 0;
+ int finish = 0;
+ if (isFile)
+ {
+ if (!ForDir && !Recursive && delta !=0)
+ return false;
+ if (!ForFile && delta == 0)
+ return false;
+ if (!ForDir && Recursive)
+ start = delta;
+ }
+ if (Recursive)
+ {
+ finish = delta;
+ if (isFile && !ForFile)
+ finish = delta - 1;
+ }
+ for (int d = start; d <= finish; d++)
+ {
+ int i;
+ for (i = 0; i < PathParts.Size(); i++)
+ if (!CompareWildCardWithName(PathParts[i], pathParts[i + d]))
+ break;
+ if (i == PathParts.Size())
+ return true;
+ }
+ return false;
+}
+
+int CCensorNode::FindSubNode(const UString &name) const
+{
+ for (int i = 0; i < SubNodes.Size(); i++)
+ if (CompareFileNames(SubNodes[i].Name, name) == 0)
+ return i;
+ return -1;
+}
+
+void CCensorNode::AddItemSimple(bool include, CItem &item)
+{
+ if (include)
+ IncludeItems.Add(item);
+ else
+ ExcludeItems.Add(item);
+}
+
+void CCensorNode::AddItem(bool include, CItem &item)
+{
+ if (item.PathParts.Size() <= 1)
+ {
+ AddItemSimple(include, item);
+ return;
+ }
+ const UString &front = item.PathParts.Front();
+ if (DoesNameContainWildCard(front))
+ {
+ AddItemSimple(include, item);
+ return;
+ }
+ int index = FindSubNode(front);
+ if (index < 0)
+ index = SubNodes.Add(CCensorNode(front, this));
+ item.PathParts.Delete(0);
+ SubNodes[index].AddItem(include, item);
+}
+
+void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir)
+{
+ CItem item;
+ SplitPathToParts(path, item.PathParts);
+ item.Recursive = recursive;
+ item.ForFile = forFile;
+ item.ForDir = forDir;
+ AddItem(include, item);
+}
+
+bool CCensorNode::NeedCheckSubDirs() const
+{
+ for (int i = 0; i < IncludeItems.Size(); i++)
+ {
+ const CItem &item = IncludeItems[i];
+ if (item.Recursive || item.PathParts.Size() > 1)
+ return true;
+ }
+ return false;
+}
+
+bool CCensorNode::AreThereIncludeItems() const
+{
+ if (IncludeItems.Size() > 0)
+ return true;
+ for (int i = 0; i < SubNodes.Size(); i++)
+ if (SubNodes[i].AreThereIncludeItems())
+ return true;
+ return false;
+}
+
+bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
+{
+ const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
+ for (int i = 0; i < items.Size(); i++)
+ if (items[i].CheckPath(pathParts, isFile))
+ return true;
+ return false;
+}
+
+bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include) const
+{
+ if (CheckPathCurrent(false, pathParts, isFile))
+ {
+ include = false;
+ return true;
+ }
+ include = true;
+ bool finded = CheckPathCurrent(true, pathParts, isFile);
+ if (pathParts.Size() == 1)
+ return finded;
+ int index = FindSubNode(pathParts.Front());
+ if (index >= 0)
+ {
+ UStringVector pathParts2 = pathParts;
+ pathParts2.Delete(0);
+ if (SubNodes[index].CheckPath(pathParts2, isFile, include))
+ return true;
+ }
+ return finded;
+}
+
+bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const
+{
+ UStringVector pathParts;
+ SplitPathToParts(path, pathParts);
+ return CheckPath(pathParts, isFile, include);
+}
+
+bool CCensorNode::CheckPath(const UString &path, bool isFile) const
+{
+ bool include;
+ if (CheckPath(path, isFile, include))
+ return include;
+ return false;
+}
+
+bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const
+{
+ if (CheckPathCurrent(include, pathParts, isFile))
+ return true;
+ if (Parent == 0)
+ return false;
+ pathParts.Insert(0, Name);
+ return Parent->CheckPathToRoot(include, pathParts, isFile);
+}
+
+/*
+bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const
+{
+ UStringVector pathParts;
+ SplitPathToParts(path, pathParts);
+ return CheckPathToRoot(include, pathParts, isFile);
+}
+*/
+
+void CCensorNode::AddItem2(bool include, const UString &path, bool recursive)
+{
+ if (path.IsEmpty())
+ return;
+ bool forFile = true;
+ bool forFolder = true;
+ UString path2 = path;
+ if (IsCharDirLimiter(path[path.Length() - 1]))
+ {
+ path2.Delete(path.Length() - 1);
+ forFile = false;
+ }
+ AddItem(include, path2, recursive, forFile, forFolder);
+}
+
+void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
+{
+ ExcludeItems += fromNodes.ExcludeItems;
+ for (int i = 0; i < fromNodes.SubNodes.Size(); i++)
+ {
+ const CCensorNode &node = fromNodes.SubNodes[i];
+ int subNodeIndex = FindSubNode(node.Name);
+ if (subNodeIndex < 0)
+ subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this));
+ SubNodes[subNodeIndex].ExtendExclude(node);
+ }
+}
+
+int CCensor::FindPrefix(const UString &prefix) const
+{
+ for (int i = 0; i < Pairs.Size(); i++)
+ if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)
+ return i;
+ return -1;
+}
+
+void CCensor::AddItem(bool include, const UString &path, bool recursive)
+{
+ UStringVector pathParts;
+ if (path.IsEmpty())
+ throw "Empty file path";
+ SplitPathToParts(path, pathParts);
+ bool forFile = true;
+ if (pathParts.Back().IsEmpty())
+ {
+ forFile = false;
+ pathParts.DeleteBack();
+ }
+ const UString &front = pathParts.Front();
+ bool isAbs = false;
+ if (front.IsEmpty())
+ isAbs = true;
+ else if (front.Length() == 2 && front[1] == L':')
+ isAbs = true;
+ else
+ {
+ for (int i = 0; i < pathParts.Size(); i++)
+ {
+ const UString &part = pathParts[i];
+ if (part == L".." || part == L".")
+ {
+ isAbs = true;
+ break;
+ }
+ }
+ }
+ int numAbsParts = 0;
+ if (isAbs)
+ if (pathParts.Size() > 1)
+ numAbsParts = pathParts.Size() - 1;
+ else
+ numAbsParts = 1;
+ UString prefix;
+ for (int i = 0; i < numAbsParts; i++)
+ {
+ const UString &front = pathParts.Front();
+ if (DoesNameContainWildCard(front))
+ break;
+ prefix += front;
+ prefix += WCHAR_PATH_SEPARATOR;
+ pathParts.Delete(0);
+ }
+ int index = FindPrefix(prefix);
+ if (index < 0)
+ index = Pairs.Add(CPair(prefix));
+
+ CItem item;
+ item.PathParts = pathParts;
+ item.ForDir = true;
+ item.ForFile = forFile;
+ item.Recursive = recursive;
+ Pairs[index].Head.AddItem(include, item);
+}
+
+bool CCensor::CheckPath(const UString &path, bool isFile) const
+{
+ bool finded = false;
+ for (int i = 0; i < Pairs.Size(); i++)
+ {
+ bool include;
+ if (Pairs[i].Head.CheckPath(path, isFile, include))
+ {
+ if (!include)
+ return false;
+ finded = true;
+ }
+ }
+ return finded;
+}
+
+void CCensor::ExtendExclude()
+{
+ int i;
+ for (i = 0; i < Pairs.Size(); i++)
+ if (Pairs[i].Prefix.IsEmpty())
+ break;
+ if (i == Pairs.Size())
+ return;
+ int index = i;
+ for (i = 0; i < Pairs.Size(); i++)
+ if (index != i)
+ Pairs[i].Head.ExtendExclude(Pairs[index].Head);
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/Common/Wildcard.h b/src/libs/7zip/win/CPP/Common/Wildcard.h
new file mode 100644
index 000000000..6d4cbcece
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Common/Wildcard.h
@@ -0,0 +1,80 @@
+// Common/Wildcard.h
+
+#ifndef __COMMON_WILDCARD_H
+#define __COMMON_WILDCARD_H
+
+#include "MyString.h"
+
+int CompareFileNames(const UString &s1, const UString &s2);
+
+void SplitPathToParts(const UString &path, UStringVector &pathParts);
+void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name);
+UString ExtractDirPrefixFromPath(const UString &path);
+UString ExtractFileNameFromPath(const UString &path);
+bool DoesNameContainWildCard(const UString &path);
+bool CompareWildCardWithName(const UString &mask, const UString &name);
+
+namespace NWildcard {
+
+struct CItem
+{
+ UStringVector PathParts;
+ bool Recursive;
+ bool ForFile;
+ bool ForDir;
+ bool CheckPath(const UStringVector &pathParts, bool isFile) const;
+};
+
+class CCensorNode
+{
+ CCensorNode *Parent;
+ bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const;
+ void AddItemSimple(bool include, CItem &item);
+ bool CheckPath(UStringVector &pathParts, bool isFile, bool &include) const;
+public:
+ CCensorNode(): Parent(0) { };
+ CCensorNode(const UString &name, CCensorNode *parent): Name(name), Parent(parent) { };
+ UString Name;
+ CObjectVector<CCensorNode> SubNodes;
+ CObjectVector<CItem> IncludeItems;
+ CObjectVector<CItem> ExcludeItems;
+
+ int FindSubNode(const UString &path) const;
+
+ void AddItem(bool include, CItem &item);
+ void AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir);
+ void AddItem2(bool include, const UString &path, bool recursive);
+
+ bool NeedCheckSubDirs() const;
+ bool AreThereIncludeItems() const;
+
+ bool CheckPath(const UString &path, bool isFile, bool &include) const;
+ bool CheckPath(const UString &path, bool isFile) const;
+
+ bool CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const;
+ // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const;
+ void ExtendExclude(const CCensorNode &fromNodes);
+};
+
+struct CPair
+{
+ UString Prefix;
+ CCensorNode Head;
+ CPair(const UString &prefix): Prefix(prefix) { };
+};
+
+class CCensor
+{
+ int FindPrefix(const UString &prefix) const;
+public:
+ CObjectVector<CPair> Pairs;
+ bool AllAreRelative() const
+ { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); }
+ void AddItem(bool include, const UString &path, bool recursive);
+ bool CheckPath(const UString &path, bool isFile) const;
+ void ExtendExclude();
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/COM.cpp b/src/libs/7zip/win/CPP/Windows/COM.cpp
new file mode 100644
index 000000000..a746de12b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/COM.cpp
@@ -0,0 +1,37 @@
+// Windows/COM.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/COM.h"
+#include "Common/StringConvert.h"
+
+namespace NWindows {
+namespace NCOM {
+
+// CoInitialize (NULL); must be called!
+
+UString GUIDToStringW(REFGUID guid)
+{
+ UString string;
+ const int kStringSize = 48;
+ StringFromGUID2(guid, string.GetBuffer(kStringSize), kStringSize);
+ string.ReleaseBuffer();
+ return string;
+}
+
+AString GUIDToStringA(REFGUID guid)
+{
+ return UnicodeStringToMultiByte(GUIDToStringW(guid));
+}
+
+HRESULT StringToGUIDW(const wchar_t *string, GUID &classID)
+{
+ return CLSIDFromString((wchar_t *)string, &classID);
+}
+
+HRESULT StringToGUIDA(const char *string, GUID &classID)
+{
+ return StringToGUIDW(MultiByteToUnicodeString(string), classID);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/COM.h b/src/libs/7zip/win/CPP/Windows/COM.h
new file mode 100644
index 000000000..506bbbc64
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/COM.h
@@ -0,0 +1,69 @@
+// Windows/COM.h
+
+#ifndef __WINDOWS_COM_H
+#define __WINDOWS_COM_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+namespace NCOM {
+
+#ifdef _WIN32
+
+class CComInitializer
+{
+public:
+ CComInitializer()
+ {
+ #ifdef UNDER_CE
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ #else
+ // it's single thread. Do we need multithread?
+ CoInitialize(NULL);
+ #endif
+ };
+ ~CComInitializer() { CoUninitialize(); };
+};
+
+class CStgMedium
+{
+ STGMEDIUM _object;
+public:
+ bool _mustBeReleased;
+ CStgMedium(): _mustBeReleased(false) {}
+ ~CStgMedium() { Free(); }
+ void Free()
+ {
+ if (_mustBeReleased)
+ ReleaseStgMedium(&_object);
+ _mustBeReleased = false;
+ }
+ const STGMEDIUM* operator->() const { return &_object;}
+ STGMEDIUM* operator->() { return &_object;}
+ STGMEDIUM* operator&() { return &_object; }
+};
+
+#endif
+
+//////////////////////////////////
+// GUID <--> String Conversions
+UString GUIDToStringW(REFGUID guid);
+AString GUIDToStringA(REFGUID guid);
+#ifdef UNICODE
+ #define GUIDToString GUIDToStringW
+#else
+ #define GUIDToString GUIDToStringA
+#endif
+
+HRESULT StringToGUIDW(const wchar_t *string, GUID &classID);
+HRESULT StringToGUIDA(const char *string, GUID &classID);
+#ifdef UNICODE
+ #define StringToGUID StringToGUIDW
+#else
+ #define StringToGUID StringToGUIDA
+#endif
+
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Clipboard.cpp b/src/libs/7zip/win/CPP/Windows/Clipboard.cpp
new file mode 100644
index 000000000..e1ff62be2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Clipboard.cpp
@@ -0,0 +1,135 @@
+// Windows/Clipboard.cpp
+
+#include "StdAfx.h"
+
+#ifdef UNDER_CE
+#include <winuserm.h>
+#endif
+
+#include "Windows/Clipboard.h"
+#include "Windows/Defs.h"
+#include "Windows/Memory.h"
+#include "Windows/Shell.h"
+#include "Windows/Memory.h"
+
+#include "Common/StringConvert.h"
+
+namespace NWindows {
+
+bool CClipboard::Open(HWND wndNewOwner)
+{
+ m_Open = BOOLToBool(::OpenClipboard(wndNewOwner));
+ return m_Open;
+}
+
+CClipboard::~CClipboard()
+{
+ Close();
+}
+
+bool CClipboard::Close()
+{
+ if (!m_Open)
+ return true;
+ m_Open = !BOOLToBool(CloseClipboard());
+ return !m_Open;
+}
+
+bool ClipboardIsFormatAvailableHDROP()
+{
+ return BOOLToBool(IsClipboardFormatAvailable(CF_HDROP));
+}
+
+/*
+bool ClipboardGetTextString(AString &s)
+{
+ s.Empty();
+ if (!IsClipboardFormatAvailable(CF_TEXT))
+ return false;
+ CClipboard clipboard;
+
+ if (!clipboard.Open(NULL))
+ return false;
+
+ HGLOBAL h = ::GetClipboardData(CF_TEXT);
+ if (h != NULL)
+ {
+ NMemory::CGlobalLock globalLock(h);
+ const char *p = (const char *)globalLock.GetPointer();
+ if (p != NULL)
+ {
+ s = p;
+ return true;
+ }
+ }
+ return false;
+}
+*/
+
+/*
+bool ClipboardGetFileNames(UStringVector &names)
+{
+ names.Clear();
+ if (!IsClipboardFormatAvailable(CF_HDROP))
+ return false;
+ CClipboard clipboard;
+
+ if (!clipboard.Open(NULL))
+ return false;
+
+ HGLOBAL h = ::GetClipboardData(CF_HDROP);
+ if (h != NULL)
+ {
+ NMemory::CGlobalLock globalLock(h);
+ void *p = (void *)globalLock.GetPointer();
+ if (p != NULL)
+ {
+ NShell::CDrop drop(false);
+ drop.Attach((HDROP)p);
+ drop.QueryFileNames(names);
+ return true;
+ }
+ }
+ return false;
+}
+*/
+
+static bool ClipboardSetData(UINT uFormat, const void *data, size_t size)
+{
+ NMemory::CGlobal global;
+ if (!global.Alloc(GMEM_DDESHARE | GMEM_MOVEABLE, size))
+ return false;
+ {
+ NMemory::CGlobalLock globalLock(global);
+ LPVOID p = globalLock.GetPointer();
+ if (p == NULL)
+ return false;
+ memcpy(p, data, size);
+ }
+ if (::SetClipboardData(uFormat, global) == NULL)
+ return false;
+ global.Detach();
+ return true;
+}
+
+bool ClipboardSetText(HWND owner, const UString &s)
+{
+ CClipboard clipboard;
+ if (!clipboard.Open(owner))
+ return false;
+ if (!::EmptyClipboard())
+ return false;
+
+ bool res;
+ res = ClipboardSetData(CF_UNICODETEXT, (const wchar_t *)s, (s.Length() + 1) * sizeof(wchar_t));
+ #ifndef _UNICODE
+ AString a;
+ a = UnicodeStringToMultiByte(s, CP_ACP);
+ res |= ClipboardSetData(CF_TEXT, (const char *)a, (a.Length() + 1) * sizeof(char));
+ a = UnicodeStringToMultiByte(s, CP_OEMCP);
+ res |= ClipboardSetData(CF_OEMTEXT, (const char *)a, (a.Length() + 1) * sizeof(char));
+ #endif
+ return res;
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/Windows/Clipboard.h b/src/libs/7zip/win/CPP/Windows/Clipboard.h
new file mode 100644
index 000000000..c80ba5ea7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Clipboard.h
@@ -0,0 +1,28 @@
+// Windows/Clipboard.h
+
+#ifndef __CLIPBOARD_H
+#define __CLIPBOARD_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+
+class CClipboard
+{
+ bool m_Open;
+public:
+ CClipboard(): m_Open(false) {};
+ ~CClipboard();
+ bool Open(HWND wndNewOwner);
+ bool Close();
+};
+
+bool ClipboardIsFormatAvailableHDROP();
+
+// bool ClipboardGetFileNames(UStringVector &names);
+// bool ClipboardGetTextString(AString &s);
+bool ClipboardSetText(HWND owner, const UString &s);
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/CommonDialog.cpp b/src/libs/7zip/win/CPP/Windows/CommonDialog.cpp
new file mode 100644
index 000000000..4ee7412d0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/CommonDialog.cpp
@@ -0,0 +1,184 @@
+// Windows/CommonDialog.cpp
+
+#include "StdAfx.h"
+
+#ifdef UNDER_CE
+#include <commdlg.h>
+#endif
+
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+#include "Common/MyCom.h"
+
+#include "Windows/Defs.h"
+
+#include "CommonDialog.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows{
+
+#ifndef _UNICODE
+class CDoubleZeroStringListA
+{
+ CRecordVector<int> m_Indexes;
+ AString m_String;
+public:
+ void Add(LPCSTR s);
+ void SetForBuffer(LPSTR buffer);
+};
+
+void CDoubleZeroStringListA::Add(LPCSTR s)
+{
+ m_String += s;
+ m_Indexes.Add(m_String.Length());
+ m_String += ' ';
+}
+
+void CDoubleZeroStringListA::SetForBuffer(LPSTR buffer)
+{
+ MyStringCopy(buffer, (const char *)m_String);
+ for (int i = 0; i < m_Indexes.Size(); i++)
+ buffer[m_Indexes[i]] = '\0';
+}
+#endif
+
+class CDoubleZeroStringListW
+{
+ CRecordVector<int> m_Indexes;
+ UString m_String;
+public:
+ void Add(LPCWSTR s);
+ void SetForBuffer(LPWSTR buffer);
+};
+
+void CDoubleZeroStringListW::Add(LPCWSTR s)
+{
+ m_String += s;
+ m_Indexes.Add(m_String.Length());
+ m_String += L' ';
+}
+
+void CDoubleZeroStringListW::SetForBuffer(LPWSTR buffer)
+{
+ MyStringCopy(buffer, (const wchar_t *)m_String);
+ for (int i = 0; i < m_Indexes.Size(); i++)
+ buffer[m_Indexes[i]] = L'\0';
+}
+
+#define MY_OFN_PROJECT 0x00400000
+#define MY_OFN_SHOW_ALL 0x01000000
+
+bool MyGetOpenFileName(HWND hwnd, LPCWSTR title, LPCWSTR fullFileName,
+ LPCWSTR s, UString &resPath
+ #ifdef UNDER_CE
+ , bool openFolder
+ #endif
+ )
+{
+ const int kBufferSize = MAX_PATH * 2;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ CHAR buffer[kBufferSize];
+ MyStringCopy(buffer, (const char *)GetSystemString(fullFileName));
+ OPENFILENAME info;
+ info.lStructSize = sizeof(info);
+ info.hwndOwner = hwnd;
+ info.hInstance = 0;
+ const int kFilterBufferSize = MAX_PATH;
+ CHAR filterBuffer[kFilterBufferSize];
+ CDoubleZeroStringListA doubleZeroStringList;
+ doubleZeroStringList.Add(GetSystemString(s));
+ doubleZeroStringList.Add("*.*");
+ doubleZeroStringList.SetForBuffer(filterBuffer);
+ info.lpstrFilter = filterBuffer;
+
+ info.lpstrCustomFilter = NULL;
+ info.nMaxCustFilter = 0;
+ info.nFilterIndex = 0;
+
+ info.lpstrFile = buffer;
+ info.nMaxFile = kBufferSize;
+
+ info.lpstrFileTitle = NULL;
+ info.nMaxFileTitle = 0;
+
+ info.lpstrInitialDir= NULL;
+
+ info.lpstrTitle = 0;
+ AString titleA;
+ if (title != 0)
+ {
+ titleA = GetSystemString(title);
+ info.lpstrTitle = titleA;
+ }
+
+ info.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
+ info.nFileOffset = 0;
+ info.nFileExtension = 0;
+ info.lpstrDefExt = NULL;
+
+ info.lCustData = 0;
+ info.lpfnHook = NULL;
+ info.lpTemplateName = NULL;
+
+ bool res = BOOLToBool(::GetOpenFileNameA(&info));
+ resPath = GetUnicodeString(buffer);
+ return res;
+ }
+ else
+ #endif
+ {
+ WCHAR buffer[kBufferSize];
+ MyStringCopy(buffer, fullFileName);
+ OPENFILENAMEW info;
+ info.lStructSize = sizeof(info);
+ info.hwndOwner = hwnd;
+ info.hInstance = 0;
+ const int kFilterBufferSize = MAX_PATH;
+ WCHAR filterBuffer[kFilterBufferSize];
+ CDoubleZeroStringListW doubleZeroStringList;
+ doubleZeroStringList.Add(s);
+ doubleZeroStringList.Add(L"*.*");
+ doubleZeroStringList.SetForBuffer(filterBuffer);
+ info.lpstrFilter = filterBuffer;
+
+ info.lpstrCustomFilter = NULL;
+ info.nMaxCustFilter = 0;
+ info.nFilterIndex = 0;
+
+ info.lpstrFile = buffer;
+ info.nMaxFile = kBufferSize;
+
+ info.lpstrFileTitle = NULL;
+ info.nMaxFileTitle = 0;
+
+ info.lpstrInitialDir= NULL;
+
+ info.lpstrTitle = title;
+
+ info.Flags = OFN_EXPLORER | OFN_HIDEREADONLY
+ #ifdef UNDER_CE
+ | (openFolder ? (MY_OFN_PROJECT | MY_OFN_SHOW_ALL) : 0)
+ #endif
+ ;
+
+ info.nFileOffset = 0;
+ info.nFileExtension = 0;
+ info.lpstrDefExt = NULL;
+
+ info.lCustData = 0;
+ info.lpfnHook = NULL;
+ info.lpTemplateName = NULL;
+
+ bool res = BOOLToBool(::GetOpenFileNameW(&info));
+ resPath = buffer;
+ return res;
+ }
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/Windows/CommonDialog.h b/src/libs/7zip/win/CPP/Windows/CommonDialog.h
new file mode 100644
index 000000000..f24bb5b24
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/CommonDialog.h
@@ -0,0 +1,19 @@
+// Windows/CommonDialog.h
+
+#ifndef __WINDOWS_COMMON_DIALOG_H
+#define __WINDOWS_COMMON_DIALOG_H
+
+#include "Common/MyString.h"
+
+namespace NWindows{
+
+bool MyGetOpenFileName(HWND hwnd, LPCWSTR title, LPCWSTR fullFileName,
+ LPCWSTR s, UString &resPath
+ #ifdef UNDER_CE
+ , bool openFolder = false
+ #endif
+);
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Console.cpp b/src/libs/7zip/win/CPP/Windows/Console.cpp
new file mode 100644
index 000000000..7773fee22
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Console.cpp
@@ -0,0 +1,10 @@
+// Windows/Console.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/Console.h"
+
+namespace NWindows{
+namespace NConsole{
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/Console.h b/src/libs/7zip/win/CPP/Windows/Console.h
new file mode 100644
index 000000000..99ae90f1a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Console.h
@@ -0,0 +1,52 @@
+// Windows/Console.h
+
+#ifndef __WINDOWS_CONSOLE_H
+#define __WINDOWS_CONSOLE_H
+
+#include "Windows/Defs.h"
+
+namespace NWindows{
+namespace NConsole{
+
+class CBase
+{
+protected:
+ HANDLE m_Object;
+public:
+ void Attach(HANDLE aHandle) { m_Object = aHandle; };
+ bool GetMode(DWORD &aMode)
+ { return BOOLToBool(::GetConsoleMode(m_Object, &aMode)); }
+ bool SetMode(DWORD aMode)
+ { return BOOLToBool(::SetConsoleMode(m_Object, aMode)); }
+};
+
+class CIn: public CBase
+{
+public:
+ bool PeekEvents(PINPUT_RECORD anEvents, DWORD aNumEvents, DWORD &aNumEventsRead)
+ { return BOOLToBool(::PeekConsoleInput(m_Object, anEvents, aNumEvents, &aNumEventsRead)); }
+ bool PeekEvent(INPUT_RECORD &anEvent, DWORD &aNumEventsRead)
+ { return PeekEvents(&anEvent, 1, aNumEventsRead); }
+ bool ReadEvents(PINPUT_RECORD anEvents, DWORD aNumEvents, DWORD &aNumEventsRead)
+ { return BOOLToBool(::ReadConsoleInput(m_Object, anEvents, aNumEvents, &aNumEventsRead)); }
+ bool ReadEvent(INPUT_RECORD &anEvent, DWORD &aNumEventsRead)
+ { return ReadEvents(&anEvent, 1, aNumEventsRead); }
+ bool GetNumberOfEvents(DWORD &aNumberOfEvents)
+ { return BOOLToBool(::GetNumberOfConsoleInputEvents(m_Object, &aNumberOfEvents)); }
+
+ bool WriteEvents(const INPUT_RECORD *anEvents, DWORD aNumEvents, DWORD &aNumEventsWritten)
+ { return BOOLToBool(::WriteConsoleInput(m_Object, anEvents, aNumEvents, &aNumEventsWritten)); }
+ bool WriteEvent(const INPUT_RECORD &anEvent, DWORD &aNumEventsWritten)
+ { return WriteEvents(&anEvent, 1, aNumEventsWritten); }
+
+ bool Read(LPVOID aBuffer, DWORD aNumberOfCharsToRead, DWORD &aNumberOfCharsRead)
+ { return BOOLToBool(::ReadConsole(m_Object, aBuffer, aNumberOfCharsToRead, &aNumberOfCharsRead, NULL)); }
+
+ bool Flush()
+ { return BOOLToBool(::FlushConsoleInputBuffer(m_Object)); }
+
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/DLL.cpp b/src/libs/7zip/win/CPP/Windows/DLL.cpp
new file mode 100644
index 000000000..5afd72d9d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/DLL.cpp
@@ -0,0 +1,110 @@
+// Windows/DLL.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#include "DLL.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NDLL {
+
+bool CLibrary::Free()
+{
+ if (_module == 0)
+ return true;
+ // MessageBox(0, TEXT(""), TEXT("Free"), 0);
+ // Sleep(5000);
+ if (!::FreeLibrary(_module))
+ return false;
+ _module = 0;
+ return true;
+}
+
+bool CLibrary::LoadOperations(HMODULE newModule)
+{
+ if (newModule == NULL)
+ return false;
+ if (!Free())
+ return false;
+ _module = newModule;
+ return true;
+}
+
+bool CLibrary::LoadEx(LPCTSTR fileName, DWORD flags)
+{
+ // MessageBox(0, fileName, TEXT("LoadEx"), 0);
+ return LoadOperations(::LoadLibraryEx(fileName, NULL, flags));
+}
+
+bool CLibrary::Load(LPCTSTR fileName)
+{
+ // MessageBox(0, fileName, TEXT("Load"), 0);
+ // Sleep(5000);
+ // OutputDebugString(fileName);
+ // OutputDebugString(TEXT("\n"));
+ return LoadOperations(::LoadLibrary(fileName));
+}
+
+#ifndef _UNICODE
+static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
+CSysString GetSysPath(LPCWSTR sysPath)
+ { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); }
+
+bool CLibrary::LoadEx(LPCWSTR fileName, DWORD flags)
+{
+ if (g_IsNT)
+ return LoadOperations(::LoadLibraryExW(fileName, NULL, flags));
+ return LoadEx(GetSysPath(fileName), flags);
+}
+bool CLibrary::Load(LPCWSTR fileName)
+{
+ if (g_IsNT)
+ return LoadOperations(::LoadLibraryW(fileName));
+ return Load(GetSysPath(fileName));
+}
+#endif
+
+bool MyGetModuleFileName(HMODULE hModule, CSysString &result)
+{
+ result.Empty();
+ TCHAR fullPath[MAX_PATH + 2];
+ DWORD size = ::GetModuleFileName(hModule, fullPath, MAX_PATH + 1);
+ if (size <= MAX_PATH && size != 0)
+ {
+ result = fullPath;
+ return true;
+ }
+ return false;
+}
+
+#ifndef _UNICODE
+bool MyGetModuleFileName(HMODULE hModule, UString &result)
+{
+ result.Empty();
+ if (g_IsNT)
+ {
+ wchar_t fullPath[MAX_PATH + 2];
+ DWORD size = ::GetModuleFileNameW(hModule, fullPath, MAX_PATH + 1);
+ if (size <= MAX_PATH && size != 0)
+ {
+ result = fullPath;
+ return true;
+ }
+ return false;
+ }
+ CSysString resultSys;
+ if (!MyGetModuleFileName(hModule, resultSys))
+ return false;
+ result = MultiByteToUnicodeString(resultSys, GetCurrentCodePage());
+ return true;
+}
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/DLL.h b/src/libs/7zip/win/CPP/Windows/DLL.h
new file mode 100644
index 000000000..4a253b326
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/DLL.h
@@ -0,0 +1,59 @@
+// Windows/DLL.h
+
+#ifndef __WINDOWS_DLL_H
+#define __WINDOWS_DLL_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NDLL {
+
+#ifdef UNDER_CE
+#define My_GetProcAddress(module, proceName) GetProcAddressA(module, proceName)
+#else
+#define My_GetProcAddress(module, proceName) ::GetProcAddress(module, proceName)
+#endif
+
+class CLibrary
+{
+ bool LoadOperations(HMODULE newModule);
+protected:
+ HMODULE _module;
+public:
+ CLibrary(): _module(NULL) {};
+ ~CLibrary() { Free(); }
+
+ operator HMODULE() const { return _module; }
+ HMODULE* operator&() { return &_module; }
+ bool IsLoaded() const { return (_module != NULL); };
+
+ void Attach(HMODULE m)
+ {
+ Free();
+ _module = m;
+ }
+ HMODULE Detach()
+ {
+ HMODULE m = _module;
+ _module = NULL;
+ return m;
+ }
+
+ bool Free();
+ bool LoadEx(LPCTSTR fileName, DWORD flags = LOAD_LIBRARY_AS_DATAFILE);
+ bool Load(LPCTSTR fileName);
+ #ifndef _UNICODE
+ bool LoadEx(LPCWSTR fileName, DWORD flags = LOAD_LIBRARY_AS_DATAFILE);
+ bool Load(LPCWSTR fileName);
+ #endif
+ FARPROC GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); }
+};
+
+bool MyGetModuleFileName(HMODULE hModule, CSysString &result);
+#ifndef _UNICODE
+bool MyGetModuleFileName(HMODULE hModule, UString &result);
+#endif
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Defs.h b/src/libs/7zip/win/CPP/Windows/Defs.h
new file mode 100644
index 000000000..281c40c33
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Defs.h
@@ -0,0 +1,17 @@
+// Windows/Defs.h
+
+#ifndef __WINDOWS_DEFS_H
+#define __WINDOWS_DEFS_H
+
+#include "../Common/MyWindows.h"
+
+#ifdef _WIN32
+inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); }
+inline bool BOOLToBool(BOOL v) { return (v != FALSE); }
+inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); }
+#endif
+
+inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); }
+inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); }
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Error.cpp b/src/libs/7zip/win/CPP/Windows/Error.cpp
new file mode 100644
index 000000000..7b18c29cc
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Error.cpp
@@ -0,0 +1,50 @@
+// Windows/Error.h
+
+#include "StdAfx.h"
+
+#include "Windows/Error.h"
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NError {
+
+bool MyFormatMessage(DWORD messageID, CSysString &message)
+{
+ LPVOID msgBuf;
+ if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,messageID, 0, (LPTSTR) &msgBuf,0, NULL) == 0)
+ return false;
+ message = (LPCTSTR)msgBuf;
+ ::LocalFree(msgBuf);
+ return true;
+}
+
+#ifndef _UNICODE
+bool MyFormatMessage(DWORD messageID, UString &message)
+{
+ if (g_IsNT)
+ {
+ LPVOID msgBuf;
+ if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, messageID, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
+ return false;
+ message = (LPCWSTR)msgBuf;
+ ::LocalFree(msgBuf);
+ return true;
+ }
+ CSysString messageSys;
+ bool result = MyFormatMessage(messageID, messageSys);
+ message = GetUnicodeString(messageSys);
+ return result;
+}
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/Error.h b/src/libs/7zip/win/CPP/Windows/Error.h
new file mode 100644
index 000000000..05b5cd0ea
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Error.h
@@ -0,0 +1,33 @@
+// Windows/Error.h
+
+#ifndef __WINDOWS_ERROR_H
+#define __WINDOWS_ERROR_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+namespace NError {
+
+bool MyFormatMessage(DWORD messageID, CSysString &message);
+inline CSysString MyFormatMessage(DWORD messageID)
+{
+ CSysString message;
+ MyFormatMessage(messageID, message);
+ return message;
+}
+#ifdef _UNICODE
+inline UString MyFormatMessageW(DWORD messageID)
+ { return MyFormatMessage(messageID); }
+#else
+bool MyFormatMessage(DWORD messageID, UString &message);
+inline UString MyFormatMessageW(DWORD messageID)
+{
+ UString message;
+ MyFormatMessage(messageID, message);
+ return message;
+}
+#endif
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/FileDir.cpp b/src/libs/7zip/win/CPP/Windows/FileDir.cpp
new file mode 100644
index 000000000..857946031
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileDir.cpp
@@ -0,0 +1,909 @@
+// Windows/FileDir.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#include "FileDir.h"
+#include "FileFind.h"
+#include "FileName.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+
+#if defined(WIN_LONG_PATH) && defined(_UNICODE)
+#define WIN_LONG_PATH2
+#endif
+
+// SetCurrentDirectory doesn't support \\?\ prefix
+
+#ifdef WIN_LONG_PATH
+bool GetLongPathBase(LPCWSTR fileName, UString &res);
+bool GetLongPath(LPCWSTR fileName, UString &res);
+#endif
+
+namespace NDirectory {
+
+#ifndef _UNICODE
+static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
+static UString GetUnicodePath(const CSysString &sysPath)
+ { return MultiByteToUnicodeString(sysPath, GetCurrentCodePage()); }
+static CSysString GetSysPath(LPCWSTR sysPath)
+ { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); }
+#endif
+
+#ifndef UNDER_CE
+
+bool MyGetWindowsDirectory(CSysString &path)
+{
+ UINT needLength = ::GetWindowsDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+ path.ReleaseBuffer();
+ return (needLength > 0 && needLength <= MAX_PATH);
+}
+
+bool MyGetSystemDirectory(CSysString &path)
+{
+ UINT needLength = ::GetSystemDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+ path.ReleaseBuffer();
+ return (needLength > 0 && needLength <= MAX_PATH);
+}
+
+#endif
+
+#ifndef _UNICODE
+bool MyGetWindowsDirectory(UString &path)
+{
+ if (g_IsNT)
+ {
+ UINT needLength = ::GetWindowsDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+ path.ReleaseBuffer();
+ return (needLength > 0 && needLength <= MAX_PATH);
+ }
+ CSysString sysPath;
+ if (!MyGetWindowsDirectory(sysPath))
+ return false;
+ path = GetUnicodePath(sysPath);
+ return true;
+}
+
+bool MyGetSystemDirectory(UString &path)
+{
+ if (g_IsNT)
+ {
+ UINT needLength = ::GetSystemDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+ path.ReleaseBuffer();
+ return (needLength > 0 && needLength <= MAX_PATH);
+ }
+ CSysString sysPath;
+ if (!MyGetSystemDirectory(sysPath))
+ return false;
+ path = GetUnicodePath(sysPath);
+ return true;
+}
+#endif
+
+bool SetDirTime(LPCWSTR fileName, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return false;
+ }
+ #endif
+ HANDLE hDir = ::CreateFileW(fileName, GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ #ifdef WIN_LONG_PATH
+ if (hDir == INVALID_HANDLE_VALUE)
+ {
+ UString longPath;
+ if (GetLongPath(fileName, longPath))
+ hDir = ::CreateFileW(longPath, GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
+ #endif
+
+ bool res = false;
+ if (hDir != INVALID_HANDLE_VALUE)
+ {
+ res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime));
+ ::CloseHandle(hDir);
+ }
+ return res;
+}
+
+bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes)
+{
+ if (::SetFileAttributes(fileName, fileAttributes))
+ return true;
+ #ifdef WIN_LONG_PATH2
+ UString longPath;
+ if (GetLongPath(fileName, longPath))
+ return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
+ #endif
+ return false;
+}
+
+bool MyRemoveDirectory(LPCTSTR pathName)
+{
+ if (::RemoveDirectory(pathName))
+ return true;
+ #ifdef WIN_LONG_PATH2
+ UString longPath;
+ if (GetLongPath(pathName, longPath))
+ return BOOLToBool(::RemoveDirectoryW(longPath));
+ #endif
+ return false;
+}
+
+#ifdef WIN_LONG_PATH
+bool GetLongPaths(LPCWSTR s1, LPCWSTR s2, UString &d1, UString &d2)
+{
+ if (!GetLongPathBase(s1, d1) || !GetLongPathBase(s2, d2))
+ return false;
+ if (d1.IsEmpty() && d2.IsEmpty()) return false;
+ if (d1.IsEmpty()) d1 = s1;
+ if (d2.IsEmpty()) d2 = s2;
+ return true;
+}
+#endif
+
+bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName)
+{
+ if (::MoveFile(existFileName, newFileName))
+ return true;
+ #ifdef WIN_LONG_PATH2
+ UString d1, d2;
+ if (GetLongPaths(existFileName, newFileName, d1, d2))
+ return BOOLToBool(::MoveFileW(d1, d2));
+ #endif
+ return false;
+}
+
+#ifndef _UNICODE
+bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes)
+{
+ if (!g_IsNT)
+ return MySetFileAttributes(GetSysPath(fileName), fileAttributes);
+ if (::SetFileAttributesW(fileName, fileAttributes))
+ return true;
+ #ifdef WIN_LONG_PATH
+ UString longPath;
+ if (GetLongPath(fileName, longPath))
+ return BOOLToBool(::SetFileAttributesW(longPath, fileAttributes));
+ #endif
+ return false;
+}
+
+
+bool MyRemoveDirectory(LPCWSTR pathName)
+{
+ if (!g_IsNT)
+ return MyRemoveDirectory(GetSysPath(pathName));
+ if (::RemoveDirectoryW(pathName))
+ return true;
+ #ifdef WIN_LONG_PATH
+ UString longPath;
+ if (GetLongPath(pathName, longPath))
+ return BOOLToBool(::RemoveDirectoryW(longPath));
+ #endif
+ return false;
+}
+
+bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName)
+{
+ if (!g_IsNT)
+ return MyMoveFile(GetSysPath(existFileName), GetSysPath(newFileName));
+ if (::MoveFileW(existFileName, newFileName))
+ return true;
+ #ifdef WIN_LONG_PATH
+ UString d1, d2;
+ if (GetLongPaths(existFileName, newFileName, d1, d2))
+ return BOOLToBool(::MoveFileW(d1, d2));
+ #endif
+ return false;
+}
+#endif
+
+bool MyCreateDirectory(LPCTSTR pathName)
+{
+ if (::CreateDirectory(pathName, NULL))
+ return true;
+ #ifdef WIN_LONG_PATH2
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ {
+ UString longPath;
+ if (GetLongPath(pathName, longPath))
+ return BOOLToBool(::CreateDirectoryW(longPath, NULL));
+ }
+ #endif
+ return false;
+}
+
+#ifndef _UNICODE
+bool MyCreateDirectory(LPCWSTR pathName)
+{
+ if (!g_IsNT)
+ return MyCreateDirectory(GetSysPath(pathName));
+ if (::CreateDirectoryW(pathName, NULL))
+ return true;
+ #ifdef WIN_LONG_PATH
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ {
+ UString longPath;
+ if (GetLongPath(pathName, longPath))
+ return BOOLToBool(::CreateDirectoryW(longPath, NULL));
+ }
+ #endif
+ return false;
+}
+#endif
+
+/*
+bool CreateComplexDirectory(LPCTSTR pathName)
+{
+ NName::CParsedPath path;
+ path.ParsePath(pathName);
+ CSysString fullPath = path.Prefix;
+ DWORD errorCode = ERROR_SUCCESS;
+ for (int i = 0; i < path.PathParts.Size(); i++)
+ {
+ const CSysString &string = path.PathParts[i];
+ if (string.IsEmpty())
+ {
+ if (i != path.PathParts.Size() - 1)
+ return false;
+ return true;
+ }
+ fullPath += path.PathParts[i];
+ if (!MyCreateDirectory(fullPath))
+ {
+ DWORD errorCode = GetLastError();
+ if (errorCode != ERROR_ALREADY_EXISTS)
+ return false;
+ }
+ fullPath += NName::kDirDelimiter;
+ }
+ return true;
+}
+*/
+
+bool CreateComplexDirectory(LPCTSTR _aPathName)
+{
+ CSysString pathName = _aPathName;
+ int pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+ if (pos > 0 && pos == pathName.Length() - 1)
+ {
+ if (pathName.Length() == 3 && pathName[1] == ':')
+ return true; // Disk folder;
+ pathName.Delete(pos);
+ }
+ CSysString pathName2 = pathName;
+ pos = pathName.Length();
+ for (;;)
+ {
+ if (MyCreateDirectory(pathName))
+ break;
+ if (::GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ NFind::CFileInfo fileInfo;
+ if (!fileInfo.Find(pathName)) // For network folders
+ return true;
+ if (!fileInfo.IsDir())
+ return false;
+ break;
+ }
+ pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
+ if (pos < 0 || pos == 0)
+ return false;
+ if (pathName[pos - 1] == ':')
+ return false;
+ pathName = pathName.Left(pos);
+ }
+ pathName = pathName2;
+ while (pos < pathName.Length())
+ {
+ pos = pathName.Find(TEXT(CHAR_PATH_SEPARATOR), pos + 1);
+ if (pos < 0)
+ pos = pathName.Length();
+ if (!MyCreateDirectory(pathName.Left(pos)))
+ return false;
+ }
+ return true;
+}
+
+#ifndef _UNICODE
+
+bool CreateComplexDirectory(LPCWSTR _aPathName)
+{
+ UString pathName = _aPathName;
+ int pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
+ if (pos > 0 && pos == pathName.Length() - 1)
+ {
+ if (pathName.Length() == 3 && pathName[1] == L':')
+ return true; // Disk folder;
+ pathName.Delete(pos);
+ }
+ UString pathName2 = pathName;
+ pos = pathName.Length();
+ for (;;)
+ {
+ if (MyCreateDirectory(pathName))
+ break;
+ if (::GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ NFind::CFileInfoW fileInfo;
+ if (!fileInfo.Find(pathName)) // For network folders
+ return true;
+ if (!fileInfo.IsDir())
+ return false;
+ break;
+ }
+ pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR);
+ if (pos < 0 || pos == 0)
+ return false;
+ if (pathName[pos - 1] == L':')
+ return false;
+ pathName = pathName.Left(pos);
+ }
+ pathName = pathName2;
+ while (pos < pathName.Length())
+ {
+ pos = pathName.Find(WCHAR_PATH_SEPARATOR, pos + 1);
+ if (pos < 0)
+ pos = pathName.Length();
+ if (!MyCreateDirectory(pathName.Left(pos)))
+ return false;
+ }
+ return true;
+}
+
+#endif
+
+bool DeleteFileAlways(LPCTSTR name)
+{
+ if (!MySetFileAttributes(name, 0))
+ return false;
+ if (::DeleteFile(name))
+ return true;
+ #ifdef WIN_LONG_PATH2
+ UString longPath;
+ if (GetLongPath(name, longPath))
+ return BOOLToBool(::DeleteFileW(longPath));
+ #endif
+ return false;
+}
+
+#ifndef _UNICODE
+bool DeleteFileAlways(LPCWSTR name)
+{
+ if (!g_IsNT)
+ return DeleteFileAlways(GetSysPath(name));
+ if (!MySetFileAttributes(name, 0))
+ return false;
+ if (::DeleteFileW(name))
+ return true;
+ #ifdef WIN_LONG_PATH
+ UString longPath;
+ if (GetLongPath(name, longPath))
+ return BOOLToBool(::DeleteFileW(longPath));
+ #endif
+ return false;
+}
+#endif
+
+static bool RemoveDirectorySubItems2(const CSysString pathPrefix, const NFind::CFileInfo &fileInfo)
+{
+ if (fileInfo.IsDir())
+ return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
+ return DeleteFileAlways(pathPrefix + fileInfo.Name);
+}
+
+bool RemoveDirectoryWithSubItems(const CSysString &path)
+{
+ NFind::CFileInfo fileInfo;
+ CSysString pathPrefix = path + NName::kDirDelimiter;
+ {
+ NFind::CEnumerator enumerator(pathPrefix + TCHAR(NName::kAnyStringWildcard));
+ while (enumerator.Next(fileInfo))
+ if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
+ return false;
+ }
+ if (!MySetFileAttributes(path, 0))
+ return false;
+ return MyRemoveDirectory(path);
+}
+
+#ifndef _UNICODE
+static bool RemoveDirectorySubItems2(const UString pathPrefix, const NFind::CFileInfoW &fileInfo)
+{
+ if (fileInfo.IsDir())
+ return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name);
+ return DeleteFileAlways(pathPrefix + fileInfo.Name);
+}
+bool RemoveDirectoryWithSubItems(const UString &path)
+{
+ NFind::CFileInfoW fileInfo;
+ UString pathPrefix = path + UString(NName::kDirDelimiter);
+ {
+ NFind::CEnumeratorW enumerator(pathPrefix + UString(NName::kAnyStringWildcard));
+ while (enumerator.Next(fileInfo))
+ if (!RemoveDirectorySubItems2(pathPrefix, fileInfo))
+ return false;
+ }
+ if (!MySetFileAttributes(path, 0))
+ return false;
+ return MyRemoveDirectory(path);
+}
+#endif
+
+bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName)
+{
+ int index;
+ if (!MyGetFullPathName(fileName, resultName, index))
+ return false;
+ resultName = resultName.Left(index);
+ return true;
+}
+
+bool GetOnlyName(LPCTSTR fileName, CSysString &resultName)
+{
+ int index;
+ if (!MyGetFullPathName(fileName, resultName, index))
+ return false;
+ resultName = resultName.Mid(index);
+ return true;
+}
+
+#ifdef UNDER_CE
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath)
+{
+ resultPath = fileName;
+ return true;
+}
+
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex)
+{
+ resultPath = fileName;
+ // change it
+ fileNamePartStartIndex = resultPath.ReverseFind(WCHAR_PATH_SEPARATOR);
+ fileNamePartStartIndex++;
+ return true;
+}
+
+#else
+
+bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath)
+{
+ DWORD needLength = ::GetShortPathName(longPath, shortPath.GetBuffer(MAX_PATH + 1), MAX_PATH + 1);
+ shortPath.ReleaseBuffer();
+ return (needLength > 0 && needLength < MAX_PATH);
+}
+
+#ifdef WIN_LONG_PATH
+
+static UString GetLastPart(LPCWSTR path)
+{
+ int i = (int)wcslen(path);
+ for (; i > 0; i--)
+ {
+ WCHAR c = path[i - 1];
+ if (c == WCHAR_PATH_SEPARATOR || c == '/')
+ break;
+ }
+ return path + i;
+}
+
+static void AddTrailingDots(LPCWSTR oldPath, UString &newPath)
+{
+ int len = (int)wcslen(oldPath);
+ int i;
+ for (i = len; i > 0 && oldPath[i - 1] == '.'; i--);
+ if (i == 0 || i == len)
+ return;
+ UString oldName = GetLastPart(oldPath);
+ UString newName = GetLastPart(newPath);
+ int nonDotsLen = oldName.Length() - (len - i);
+ if (nonDotsLen == 0 || newName.CompareNoCase(oldName.Left(nonDotsLen)) != 0)
+ return;
+ for (; i != len; i++)
+ newPath += '.';
+}
+
+#endif
+
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, int &fileNamePartStartIndex)
+{
+ resultPath.Empty();
+ LPTSTR fileNamePointer = 0;
+ LPTSTR buffer = resultPath.GetBuffer(MAX_PATH);
+ DWORD needLength = ::GetFullPathName(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
+ resultPath.ReleaseBuffer();
+ if (needLength == 0)
+ return false;
+ if (needLength >= MAX_PATH)
+ {
+ #ifdef WIN_LONG_PATH2
+ needLength++;
+ buffer = resultPath.GetBuffer(needLength + 1);
+ DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
+ resultPath.ReleaseBuffer();
+ if (needLength2 == 0 || needLength2 > needLength)
+ #endif
+ return false;
+ }
+ if (fileNamePointer == 0)
+ fileNamePartStartIndex = lstrlen(fileName);
+ else
+ fileNamePartStartIndex = (int)(fileNamePointer - buffer);
+ #ifdef _UNICODE
+ #ifdef WIN_LONG_PATH
+ AddTrailingDots(fileName, resultPath);
+ #endif
+ #endif
+ return true;
+}
+
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex)
+{
+ resultPath.Empty();
+ if (g_IsNT)
+ {
+ LPWSTR fileNamePointer = 0;
+ LPWSTR buffer = resultPath.GetBuffer(MAX_PATH);
+ DWORD needLength = ::GetFullPathNameW(fileName, MAX_PATH + 1, buffer, &fileNamePointer);
+ resultPath.ReleaseBuffer();
+ if (needLength == 0)
+ return false;
+ if (needLength >= MAX_PATH)
+ {
+ #ifdef WIN_LONG_PATH
+ needLength++;
+ buffer = resultPath.GetBuffer(needLength + 1);
+ DWORD needLength2 = ::GetFullPathNameW(fileName, needLength, buffer, &fileNamePointer);
+ resultPath.ReleaseBuffer();
+ if (needLength2 == 0 || needLength2 > needLength)
+ #endif
+ return false;
+ }
+ if (fileNamePointer == 0)
+ fileNamePartStartIndex = MyStringLen(fileName);
+ else
+ fileNamePartStartIndex = (int)(fileNamePointer - buffer);
+ #ifdef WIN_LONG_PATH
+ AddTrailingDots(fileName, resultPath);
+ #endif
+ }
+ else
+ {
+ CSysString sysPath;
+ if (!MyGetFullPathName(GetSysPath(fileName), sysPath, fileNamePartStartIndex))
+ return false;
+ UString resultPath1 = GetUnicodePath(sysPath.Left(fileNamePartStartIndex));
+ UString resultPath2 = GetUnicodePath(sysPath.Mid(fileNamePartStartIndex));
+ fileNamePartStartIndex = resultPath1.Length();
+ resultPath = resultPath1 + resultPath2;
+ }
+ return true;
+}
+#endif
+
+
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &path)
+{
+ int index;
+ return MyGetFullPathName(fileName, path, index);
+}
+
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &path)
+{
+ int index;
+ return MyGetFullPathName(fileName, path, index);
+}
+#endif
+
+#ifndef _UNICODE
+bool GetOnlyName(LPCWSTR fileName, UString &resultName)
+{
+ int index;
+ if (!MyGetFullPathName(fileName, resultName, index))
+ return false;
+ resultName = resultName.Mid(index);
+ return true;
+}
+#endif
+
+#ifndef _UNICODE
+bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName)
+{
+ int index;
+ if (!MyGetFullPathName(fileName, resultName, index))
+ return false;
+ resultName = resultName.Left(index);
+ return true;
+}
+#endif
+
+bool MyGetCurrentDirectory(CSysString &path)
+{
+ DWORD needLength = ::GetCurrentDirectory(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
+ path.ReleaseBuffer();
+ return (needLength > 0 && needLength <= MAX_PATH);
+}
+
+#ifndef _UNICODE
+bool MySetCurrentDirectory(LPCWSTR path)
+{
+ if (g_IsNT)
+ return BOOLToBool(::SetCurrentDirectoryW(path));
+ return MySetCurrentDirectory(GetSysPath(path));
+}
+bool MyGetCurrentDirectory(UString &path)
+{
+ if (g_IsNT)
+ {
+ DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
+ path.ReleaseBuffer();
+ return (needLength > 0 && needLength <= MAX_PATH);
+ }
+ CSysString sysPath;
+ if (!MyGetCurrentDirectory(sysPath))
+ return false;
+ path = GetUnicodePath(sysPath);
+ return true;
+}
+#endif
+
+bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension,
+ CSysString &resultPath, UINT32 &filePart)
+{
+ LPTSTR filePartPointer;
+ DWORD value = ::SearchPath(path, fileName, extension,
+ MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
+ filePart = (UINT32)(filePartPointer - (LPCTSTR)resultPath);
+ resultPath.ReleaseBuffer();
+ return (value > 0 && value <= MAX_PATH);
+}
+#endif
+
+#ifndef _UNICODE
+bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension,
+ UString &resultPath, UINT32 &filePart)
+{
+ if (g_IsNT)
+ {
+ LPWSTR filePartPointer = 0;
+ DWORD value = ::SearchPathW(path, fileName, extension,
+ MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer);
+ filePart = (UINT32)(filePartPointer - (LPCWSTR)resultPath);
+ resultPath.ReleaseBuffer();
+ return (value > 0 && value <= MAX_PATH);
+ }
+
+ CSysString sysPath;
+ if (!MySearchPath(
+ path != 0 ? (LPCTSTR)GetSysPath(path): 0,
+ fileName != 0 ? (LPCTSTR)GetSysPath(fileName): 0,
+ extension != 0 ? (LPCTSTR)GetSysPath(extension): 0,
+ sysPath, filePart))
+ return false;
+ UString resultPath1 = GetUnicodePath(sysPath.Left(filePart));
+ UString resultPath2 = GetUnicodePath(sysPath.Mid(filePart));
+ filePart = resultPath1.Length();
+ resultPath = resultPath1 + resultPath2;
+ return true;
+}
+#endif
+
+bool MyGetTempPath(CSysString &path)
+{
+ DWORD needLength = ::GetTempPath(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
+ path.ReleaseBuffer();
+ return (needLength > 0 && needLength <= MAX_PATH);
+}
+
+#ifndef _UNICODE
+bool MyGetTempPath(UString &path)
+{
+ path.Empty();
+ if (g_IsNT)
+ {
+ DWORD needLength = ::GetTempPathW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1));
+ path.ReleaseBuffer();
+ return (needLength > 0 && needLength <= MAX_PATH);
+ }
+ CSysString sysPath;
+ if (!MyGetTempPath(sysPath))
+ return false;
+ path = GetUnicodePath(sysPath);
+ return true;
+}
+#endif
+
+UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &path)
+{
+ UINT number = ::GetTempFileName(dirPath, prefix, 0, path.GetBuffer(MAX_PATH + 1));
+ path.ReleaseBuffer();
+ return number;
+}
+
+#ifndef _UNICODE
+UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &path)
+{
+ if (g_IsNT)
+ {
+ UINT number = ::GetTempFileNameW(dirPath, prefix, 0, path.GetBuffer(MAX_PATH));
+ path.ReleaseBuffer();
+ return number;
+ }
+ CSysString sysPath;
+ UINT number = MyGetTempFileName(
+ dirPath ? (LPCTSTR)GetSysPath(dirPath): 0,
+ prefix ? (LPCTSTR)GetSysPath(prefix): 0,
+ sysPath);
+ path = GetUnicodePath(sysPath);
+ return number;
+}
+#endif
+
+UINT CTempFile::Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath)
+{
+ Remove();
+ UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
+ if (number != 0)
+ {
+ _fileName = resultPath;
+ _mustBeDeleted = true;
+ }
+ return number;
+}
+
+bool CTempFile::Create(LPCTSTR prefix, CSysString &resultPath)
+{
+ CSysString tempPath;
+ if (!MyGetTempPath(tempPath))
+ return false;
+ if (Create(tempPath, prefix, resultPath) != 0)
+ return true;
+ #ifdef UNDER_CE
+ return false;
+ #else
+ if (!MyGetWindowsDirectory(tempPath))
+ return false;
+ return (Create(tempPath, prefix, resultPath) != 0);
+ #endif
+}
+
+bool CTempFile::Remove()
+{
+ if (!_mustBeDeleted)
+ return true;
+ _mustBeDeleted = !DeleteFileAlways(_fileName);
+ return !_mustBeDeleted;
+}
+
+#ifndef _UNICODE
+
+UINT CTempFileW::Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath)
+{
+ Remove();
+ UINT number = MyGetTempFileName(dirPath, prefix, resultPath);
+ if (number != 0)
+ {
+ _fileName = resultPath;
+ _mustBeDeleted = true;
+ }
+ return number;
+}
+
+bool CTempFileW::Create(LPCWSTR prefix, UString &resultPath)
+{
+ UString tempPath;
+ if (!MyGetTempPath(tempPath))
+ return false;
+ if (Create(tempPath, prefix, resultPath) != 0)
+ return true;
+ if (!MyGetWindowsDirectory(tempPath))
+ return false;
+ return (Create(tempPath, prefix, resultPath) != 0);
+}
+
+bool CTempFileW::Remove()
+{
+ if (!_mustBeDeleted)
+ return true;
+ _mustBeDeleted = !DeleteFileAlways(_fileName);
+ return !_mustBeDeleted;
+}
+
+#endif
+
+bool CreateTempDirectory(LPCTSTR prefix, CSysString &dirName)
+{
+ /*
+ CSysString prefix = tempPath + prefixChars;
+ CRandom random;
+ random.Init();
+ */
+ for (;;)
+ {
+ {
+ CTempFile tempFile;
+ if (!tempFile.Create(prefix, dirName))
+ return false;
+ if (!tempFile.Remove())
+ return false;
+ }
+ /*
+ UINT32 randomNumber = random.Generate();
+ TCHAR randomNumberString[32];
+ _stprintf(randomNumberString, _T("%04X"), randomNumber);
+ dirName = prefix + randomNumberString;
+ */
+ if (NFind::DoesFileOrDirExist(dirName))
+ continue;
+ if (MyCreateDirectory(dirName))
+ return true;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ return false;
+ }
+}
+
+bool CTempDirectory::Create(LPCTSTR prefix)
+{
+ Remove();
+ return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));
+}
+
+#ifndef _UNICODE
+
+bool CreateTempDirectory(LPCWSTR prefix, UString &dirName)
+{
+ /*
+ CSysString prefix = tempPath + prefixChars;
+ CRandom random;
+ random.Init();
+ */
+ for (;;)
+ {
+ {
+ CTempFileW tempFile;
+ if (!tempFile.Create(prefix, dirName))
+ return false;
+ if (!tempFile.Remove())
+ return false;
+ }
+ /*
+ UINT32 randomNumber = random.Generate();
+ TCHAR randomNumberString[32];
+ _stprintf(randomNumberString, _T("%04X"), randomNumber);
+ dirName = prefix + randomNumberString;
+ */
+ if (NFind::DoesFileOrDirExist(dirName))
+ continue;
+ if (MyCreateDirectory(dirName))
+ return true;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ return false;
+ }
+}
+
+bool CTempDirectoryW::Create(LPCWSTR prefix)
+{
+ Remove();
+ return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir));
+}
+
+#endif
+
+}}}
diff --git a/src/libs/7zip/win/CPP/Windows/FileDir.h b/src/libs/7zip/win/CPP/Windows/FileDir.h
new file mode 100644
index 000000000..04542d872
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileDir.h
@@ -0,0 +1,177 @@
+// Windows/FileDir.h
+
+#ifndef __WINDOWS_FILEDIR_H
+#define __WINDOWS_FILEDIR_H
+
+#include "../Common/MyString.h"
+#include "Defs.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NDirectory {
+
+#ifdef WIN_LONG_PATH
+bool GetLongPaths(LPCWSTR s1, LPCWSTR s2, UString &d1, UString &d2);
+#endif
+
+bool MyGetWindowsDirectory(CSysString &path);
+bool MyGetSystemDirectory(CSysString &path);
+#ifndef _UNICODE
+bool MyGetWindowsDirectory(UString &path);
+bool MyGetSystemDirectory(UString &path);
+#endif
+
+bool SetDirTime(LPCWSTR fileName, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime);
+
+bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes);
+bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName);
+bool MyRemoveDirectory(LPCTSTR pathName);
+bool MyCreateDirectory(LPCTSTR pathName);
+bool CreateComplexDirectory(LPCTSTR pathName);
+bool DeleteFileAlways(LPCTSTR name);
+bool RemoveDirectoryWithSubItems(const CSysString &path);
+
+#ifndef _UNICODE
+bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes);
+bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName);
+bool MyRemoveDirectory(LPCWSTR pathName);
+bool MyCreateDirectory(LPCWSTR pathName);
+bool CreateComplexDirectory(LPCWSTR pathName);
+bool DeleteFileAlways(LPCWSTR name);
+bool RemoveDirectoryWithSubItems(const UString &path);
+#endif
+
+bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName);
+bool GetOnlyName(LPCTSTR fileName, CSysString &resultName);
+#ifdef UNDER_CE
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath);
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex);
+#else
+bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath);
+
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, int &fileNamePartStartIndex);
+bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath);
+#ifndef _UNICODE
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath,
+ int &fileNamePartStartIndex);
+bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath);
+bool GetOnlyName(LPCWSTR fileName, UString &resultName);
+bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName);
+#endif
+
+inline bool MySetCurrentDirectory(LPCTSTR path)
+ { return BOOLToBool(::SetCurrentDirectory(path)); }
+bool MyGetCurrentDirectory(CSysString &resultPath);
+#ifndef _UNICODE
+bool MySetCurrentDirectory(LPCWSTR path);
+bool MyGetCurrentDirectory(UString &resultPath);
+#endif
+
+bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, CSysString &resultPath, UINT32 &filePart);
+#ifndef _UNICODE
+bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, UString &resultPath, UINT32 &filePart);
+#endif
+
+inline bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, CSysString &resultPath)
+{
+ UINT32 value;
+ return MySearchPath(path, fileName, extension, resultPath, value);
+}
+
+#ifndef _UNICODE
+inline bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, UString &resultPath)
+{
+ UINT32 value;
+ return MySearchPath(path, fileName, extension, resultPath, value);
+}
+#endif
+
+#endif
+
+bool MyGetTempPath(CSysString &resultPath);
+#ifndef _UNICODE
+bool MyGetTempPath(UString &resultPath);
+#endif
+
+UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath);
+#ifndef _UNICODE
+UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath);
+#endif
+
+class CTempFile
+{
+ bool _mustBeDeleted;
+ CSysString _fileName;
+public:
+ CTempFile(): _mustBeDeleted(false) {}
+ ~CTempFile() { Remove(); }
+ void DisableDeleting() { _mustBeDeleted = false; }
+ UINT Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath);
+ bool Create(LPCTSTR prefix, CSysString &resultPath);
+ bool Remove();
+};
+
+#ifdef _UNICODE
+typedef CTempFile CTempFileW;
+#else
+class CTempFileW
+{
+ bool _mustBeDeleted;
+ UString _fileName;
+public:
+ CTempFileW(): _mustBeDeleted(false) {}
+ ~CTempFileW() { Remove(); }
+ void DisableDeleting() { _mustBeDeleted = false; }
+ UINT Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath);
+ bool Create(LPCWSTR prefix, UString &resultPath);
+ bool Remove();
+};
+#endif
+
+bool CreateTempDirectory(LPCTSTR prefixChars, CSysString &dirName);
+
+class CTempDirectory
+{
+ bool _mustBeDeleted;
+ CSysString _tempDir;
+public:
+ const CSysString &GetPath() const { return _tempDir; }
+ CTempDirectory(): _mustBeDeleted(false) {}
+ ~CTempDirectory() { Remove(); }
+ bool Create(LPCTSTR prefix) ;
+ bool Remove()
+ {
+ if (!_mustBeDeleted)
+ return true;
+ _mustBeDeleted = !RemoveDirectoryWithSubItems(_tempDir);
+ return (!_mustBeDeleted);
+ }
+ void DisableDeleting() { _mustBeDeleted = false; }
+};
+
+#ifdef _UNICODE
+typedef CTempDirectory CTempDirectoryW;
+#else
+class CTempDirectoryW
+{
+ bool _mustBeDeleted;
+ UString _tempDir;
+public:
+ const UString &GetPath() const { return _tempDir; }
+ CTempDirectoryW(): _mustBeDeleted(false) {}
+ ~CTempDirectoryW() { Remove(); }
+ bool Create(LPCWSTR prefix) ;
+ bool Remove()
+ {
+ if (!_mustBeDeleted)
+ return true;
+ _mustBeDeleted = !RemoveDirectoryWithSubItems(_tempDir);
+ return (!_mustBeDeleted);
+ }
+ void DisableDeleting() { _mustBeDeleted = false; }
+};
+#endif
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/FileFind.cpp b/src/libs/7zip/win/CPP/Windows/FileFind.cpp
new file mode 100644
index 000000000..e3358f905
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileFind.cpp
@@ -0,0 +1,462 @@
+// Windows/FileFind.cpp
+
+#include "StdAfx.h"
+
+#include "FileFind.h"
+#include "FileIO.h"
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+
+#ifdef SUPPORT_DEVICE_FILE
+bool IsDeviceName(LPCTSTR n);
+#ifndef _UNICODE
+bool IsDeviceName(LPCWSTR n);
+#endif
+#endif
+
+#if defined(WIN_LONG_PATH) && defined(_UNICODE)
+#define WIN_LONG_PATH2
+#endif
+
+bool GetLongPath(LPCWSTR fileName, UString &res);
+
+namespace NFind {
+
+static const TCHAR kDot = TEXT('.');
+
+bool CFileInfo::IsDots() const
+{
+ if (!IsDir() || Name.IsEmpty())
+ return false;
+ if (Name[0] != kDot)
+ return false;
+ return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2);
+}
+
+#ifndef _UNICODE
+bool CFileInfoW::IsDots() const
+{
+ if (!IsDir() || Name.IsEmpty())
+ return false;
+ if (Name[0] != kDot)
+ return false;
+ return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2);
+}
+#endif
+
+#define WIN_FD_TO_MY_FI(fi, fd) \
+ fi.Attrib = fd.dwFileAttributes; \
+ fi.CTime = fd.ftCreationTime; \
+ fi.ATime = fd.ftLastAccessTime; \
+ fi.MTime = fd.ftLastWriteTime; \
+ fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \
+ fi.IsDevice = false;
+
+ /*
+ #ifdef UNDER_CE
+ fi.ObjectID = fd.dwOID;
+ #else
+ fi.ReparseTag = fd.dwReserved0;
+ #endif
+ */
+
+static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi)
+{
+ WIN_FD_TO_MY_FI(fi, fd);
+ fi.Name = fd.cFileName;
+}
+
+#ifndef _UNICODE
+
+static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
+
+static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfoW &fi)
+{
+ WIN_FD_TO_MY_FI(fi, fd);
+ fi.Name = fd.cFileName;
+}
+
+static void ConvertWIN32_FIND_DATA_To_FileInfo(const WIN32_FIND_DATA &fd, CFileInfoW &fi)
+{
+ WIN_FD_TO_MY_FI(fi, fd);
+ fi.Name = GetUnicodeString(fd.cFileName, GetCurrentCodePage());
+}
+#endif
+
+////////////////////////////////
+// CFindFile
+
+bool CFindFile::Close()
+{
+ if (_handle == INVALID_HANDLE_VALUE)
+ return true;
+ if (!::FindClose(_handle))
+ return false;
+ _handle = INVALID_HANDLE_VALUE;
+ return true;
+}
+
+
+bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fi)
+{
+ if (!Close())
+ return false;
+ WIN32_FIND_DATA fd;
+ _handle = ::FindFirstFile(wildcard, &fd);
+ #ifdef WIN_LONG_PATH2
+ if (_handle == INVALID_HANDLE_VALUE)
+ {
+ UString longPath;
+ if (GetLongPath(wildcard, longPath))
+ _handle = ::FindFirstFileW(longPath, &fd);
+ }
+ #endif
+ if (_handle == INVALID_HANDLE_VALUE)
+ return false;
+ ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi);
+ return true;
+}
+
+#ifndef _UNICODE
+bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fi)
+{
+ if (!Close())
+ return false;
+ if (g_IsNT)
+ {
+ WIN32_FIND_DATAW fd;
+ _handle = ::FindFirstFileW(wildcard, &fd);
+ #ifdef WIN_LONG_PATH
+ if (_handle == INVALID_HANDLE_VALUE)
+ {
+ UString longPath;
+ if (GetLongPath(wildcard, longPath))
+ _handle = ::FindFirstFileW(longPath, &fd);
+ }
+ #endif
+ if (_handle != INVALID_HANDLE_VALUE)
+ ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi);
+ }
+ else
+ {
+ WIN32_FIND_DATAA fd;
+ _handle = ::FindFirstFileA(UnicodeStringToMultiByte(wildcard,
+ GetCurrentCodePage()), &fd);
+ if (_handle != INVALID_HANDLE_VALUE)
+ ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi);
+ }
+ return (_handle != INVALID_HANDLE_VALUE);
+}
+#endif
+
+bool CFindFile::FindNext(CFileInfo &fi)
+{
+ WIN32_FIND_DATA fd;
+ bool result = BOOLToBool(::FindNextFile(_handle, &fd));
+ if (result)
+ ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi);
+ return result;
+}
+
+#ifndef _UNICODE
+bool CFindFile::FindNext(CFileInfoW &fi)
+{
+ if (g_IsNT)
+ {
+ WIN32_FIND_DATAW fd;
+ if (!::FindNextFileW(_handle, &fd))
+ return false;
+ ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi);
+ }
+ else
+ {
+ WIN32_FIND_DATAA fd;
+ if (!::FindNextFileA(_handle, &fd))
+ return false;
+ ConvertWIN32_FIND_DATA_To_FileInfo(fd, fi);
+ }
+ return true;
+}
+#endif
+
+#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0;
+
+void CFileInfoBase::Clear()
+{
+ Size = 0;
+ MY_CLEAR_FILETIME(CTime);
+ MY_CLEAR_FILETIME(ATime);
+ MY_CLEAR_FILETIME(MTime);
+ Attrib = 0;
+}
+
+bool CFileInfo::Find(LPCTSTR wildcard)
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDeviceName(wildcard))
+ {
+ Clear();
+ IsDevice = true;
+ NIO::CInFile inFile;
+ if (!inFile.Open(wildcard))
+ return false;
+ Name = wildcard + 4;
+ if (inFile.LengthDefined)
+ Size = inFile.Length;
+ return true;
+ }
+ #endif
+ CFindFile finder;
+ return finder.FindFirst(wildcard, *this);
+}
+
+
+#ifndef _UNICODE
+bool CFileInfoW::Find(LPCWSTR wildcard)
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDeviceName(wildcard))
+ {
+ Clear();
+ IsDevice = true;
+ NIO::CInFile inFile;
+ if (!inFile.Open(wildcard))
+ return false;
+ Name = wildcard + 4;
+ if (inFile.LengthDefined)
+ Size = inFile.Length;
+ return true;
+ }
+ #endif
+ CFindFile finder;
+ return finder.FindFirst(wildcard, *this);
+}
+#endif
+
+bool DoesFileExist(LPCTSTR name)
+{
+ CFileInfo fi;
+ return fi.Find(name) && !fi.IsDir();
+}
+
+bool DoesDirExist(LPCTSTR name)
+{
+ CFileInfo fi;
+ return fi.Find(name) && fi.IsDir();
+}
+
+bool DoesFileOrDirExist(LPCTSTR name)
+{
+ CFileInfo fi;
+ return fi.Find(name);
+}
+
+#ifndef _UNICODE
+bool DoesFileExist(LPCWSTR name)
+{
+ CFileInfoW fi;
+ return fi.Find(name) && !fi.IsDir();
+}
+
+bool DoesDirExist(LPCWSTR name)
+{
+ CFileInfoW fi;
+ return fi.Find(name) && fi.IsDir();
+}
+bool DoesFileOrDirExist(LPCWSTR name)
+{
+ CFileInfoW fi;
+ return fi.Find(name);
+}
+#endif
+
+/////////////////////////////////////
+// CEnumerator
+
+bool CEnumerator::NextAny(CFileInfo &fi)
+{
+ if (_findFile.IsHandleAllocated())
+ return _findFile.FindNext(fi);
+ else
+ return _findFile.FindFirst(_wildcard, fi);
+}
+
+bool CEnumerator::Next(CFileInfo &fi)
+{
+ for (;;)
+ {
+ if (!NextAny(fi))
+ return false;
+ if (!fi.IsDots())
+ return true;
+ }
+}
+
+bool CEnumerator::Next(CFileInfo &fi, bool &found)
+{
+ if (Next(fi))
+ {
+ found = true;
+ return true;
+ }
+ found = false;
+ return (::GetLastError() == ERROR_NO_MORE_FILES);
+}
+
+#ifndef _UNICODE
+bool CEnumeratorW::NextAny(CFileInfoW &fi)
+{
+ if (_findFile.IsHandleAllocated())
+ return _findFile.FindNext(fi);
+ else
+ return _findFile.FindFirst(_wildcard, fi);
+}
+
+bool CEnumeratorW::Next(CFileInfoW &fi)
+{
+ for (;;)
+ {
+ if (!NextAny(fi))
+ return false;
+ if (!fi.IsDots())
+ return true;
+ }
+}
+
+bool CEnumeratorW::Next(CFileInfoW &fi, bool &found)
+{
+ if (Next(fi))
+ {
+ found = true;
+ return true;
+ }
+ found = false;
+ return (::GetLastError() == ERROR_NO_MORE_FILES);
+}
+
+#endif
+
+////////////////////////////////
+// CFindChangeNotification
+// FindFirstChangeNotification can return 0. MSDN doesn't tell about it.
+
+bool CFindChangeNotification::Close()
+{
+ if (!IsHandleAllocated())
+ return true;
+ if (!::FindCloseChangeNotification(_handle))
+ return false;
+ _handle = INVALID_HANDLE_VALUE;
+ return true;
+}
+
+HANDLE CFindChangeNotification::FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter)
+{
+ _handle = ::FindFirstChangeNotification(pathName, BoolToBOOL(watchSubtree), notifyFilter);
+ #ifdef WIN_LONG_PATH2
+ if (!IsHandleAllocated())
+ {
+ UString longPath;
+ if (GetLongPath(pathName, longPath))
+ _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter);
+ }
+ #endif
+ return _handle;
+}
+
+#ifndef _UNICODE
+HANDLE CFindChangeNotification::FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter)
+{
+ if (!g_IsNT)
+ return FindFirst(UnicodeStringToMultiByte(pathName, GetCurrentCodePage()), watchSubtree, notifyFilter);
+ _handle = ::FindFirstChangeNotificationW(pathName, BoolToBOOL(watchSubtree), notifyFilter);
+ #ifdef WIN_LONG_PATH
+ if (!IsHandleAllocated())
+ {
+ UString longPath;
+ if (GetLongPath(pathName, longPath))
+ _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter);
+ }
+ #endif
+ return _handle;
+}
+#endif
+
+#ifndef UNDER_CE
+bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings)
+{
+ driveStrings.Clear();
+ UINT32 size = GetLogicalDriveStrings(0, NULL);
+ if (size == 0)
+ return false;
+ CSysString buffer;
+ UINT32 newSize = GetLogicalDriveStrings(size, buffer.GetBuffer(size));
+ if (newSize == 0)
+ return false;
+ if (newSize > size)
+ return false;
+ CSysString string;
+ for (UINT32 i = 0; i < newSize; i++)
+ {
+ TCHAR c = buffer[i];
+ if (c == TEXT('\0'))
+ {
+ driveStrings.Add(string);
+ string.Empty();
+ }
+ else
+ string += c;
+ }
+ if (!string.IsEmpty())
+ return false;
+ return true;
+}
+
+#ifndef _UNICODE
+bool MyGetLogicalDriveStrings(UStringVector &driveStrings)
+{
+ driveStrings.Clear();
+ if (g_IsNT)
+ {
+ UINT32 size = GetLogicalDriveStringsW(0, NULL);
+ if (size == 0)
+ return false;
+ UString buffer;
+ UINT32 newSize = GetLogicalDriveStringsW(size, buffer.GetBuffer(size));
+ if (newSize == 0)
+ return false;
+ if (newSize > size)
+ return false;
+ UString string;
+ for (UINT32 i = 0; i < newSize; i++)
+ {
+ WCHAR c = buffer[i];
+ if (c == L'\0')
+ {
+ driveStrings.Add(string);
+ string.Empty();
+ }
+ else
+ string += c;
+ }
+ return string.IsEmpty();
+ }
+ CSysStringVector driveStringsA;
+ bool res = MyGetLogicalDriveStrings(driveStringsA);
+ for (int i = 0; i < driveStringsA.Size(); i++)
+ driveStrings.Add(GetUnicodeString(driveStringsA[i]));
+ return res;
+}
+#endif
+
+#endif
+
+}}}
diff --git a/src/libs/7zip/win/CPP/Windows/FileFind.h b/src/libs/7zip/win/CPP/Windows/FileFind.h
new file mode 100644
index 000000000..63631f66b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileFind.h
@@ -0,0 +1,161 @@
+// Windows/FileFind.h
+
+#ifndef __WINDOWS_FILEFIND_H
+#define __WINDOWS_FILEFIND_H
+
+#include "../Common/MyString.h"
+#include "../Common/Types.h"
+#include "Defs.h"
+#include "FileName.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NFind {
+
+namespace NAttributes
+{
+ inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; }
+ inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; }
+ inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; }
+ inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; }
+ inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; }
+ inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; }
+ inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; }
+}
+
+class CFileInfoBase
+{
+ bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); }
+protected:
+ void Clear();
+public:
+ UInt64 Size;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ DWORD Attrib;
+ bool IsDevice;
+
+ /*
+ #ifdef UNDER_CE
+ DWORD ObjectID;
+ #else
+ UINT32 ReparseTag;
+ #endif
+ */
+
+ bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); }
+ bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); }
+ bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); }
+ bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); }
+ bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); }
+ bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); }
+ bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); }
+ bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); }
+ bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); }
+ bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); }
+ bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); }
+ bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); }
+};
+
+struct CFileInfo: public CFileInfoBase
+{
+ CSysString Name;
+
+ bool IsDots() const;
+ bool Find(LPCTSTR wildcard);
+};
+
+#ifdef _UNICODE
+typedef CFileInfo CFileInfoW;
+#else
+struct CFileInfoW: public CFileInfoBase
+{
+ UString Name;
+
+ bool IsDots() const;
+ bool Find(LPCWSTR wildcard);
+};
+#endif
+
+class CFindFile
+{
+ friend class CEnumerator;
+ HANDLE _handle;
+public:
+ bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; }
+ CFindFile(): _handle(INVALID_HANDLE_VALUE) {}
+ ~CFindFile() { Close(); }
+ bool FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo);
+ bool FindNext(CFileInfo &fileInfo);
+ #ifndef _UNICODE
+ bool FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo);
+ bool FindNext(CFileInfoW &fileInfo);
+ #endif
+ bool Close();
+};
+
+bool DoesFileExist(LPCTSTR name);
+bool DoesDirExist(LPCTSTR name);
+bool DoesFileOrDirExist(LPCTSTR name);
+#ifndef _UNICODE
+bool DoesFileExist(LPCWSTR name);
+bool DoesDirExist(LPCWSTR name);
+bool DoesFileOrDirExist(LPCWSTR name);
+#endif
+
+class CEnumerator
+{
+ CFindFile _findFile;
+ CSysString _wildcard;
+ bool NextAny(CFileInfo &fileInfo);
+public:
+ CEnumerator(): _wildcard(NName::kAnyStringWildcard) {}
+ CEnumerator(const CSysString &wildcard): _wildcard(wildcard) {}
+ bool Next(CFileInfo &fileInfo);
+ bool Next(CFileInfo &fileInfo, bool &found);
+};
+
+#ifdef _UNICODE
+typedef CEnumerator CEnumeratorW;
+#else
+class CEnumeratorW
+{
+ CFindFile _findFile;
+ UString _wildcard;
+ bool NextAny(CFileInfoW &fileInfo);
+public:
+ CEnumeratorW(): _wildcard(NName::kAnyStringWildcard) {}
+ CEnumeratorW(const UString &wildcard): _wildcard(wildcard) {}
+ bool Next(CFileInfoW &fileInfo);
+ bool Next(CFileInfoW &fileInfo, bool &found);
+};
+#endif
+
+class CFindChangeNotification
+{
+ HANDLE _handle;
+public:
+ operator HANDLE () { return _handle; }
+ bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE && _handle != 0; }
+ CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {}
+ ~CFindChangeNotification() { Close(); }
+ bool Close();
+ HANDLE FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter);
+ #ifndef _UNICODE
+ HANDLE FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter);
+ #endif
+ bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); }
+};
+
+#ifndef UNDER_CE
+bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings);
+#ifndef _UNICODE
+bool MyGetLogicalDriveStrings(UStringVector &driveStrings);
+#endif
+#endif
+
+}}}
+
+#endif
+
diff --git a/src/libs/7zip/win/CPP/Windows/FileIO.cpp b/src/libs/7zip/win/CPP/Windows/FileIO.cpp
new file mode 100644
index 000000000..938e6c701
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileIO.cpp
@@ -0,0 +1,434 @@
+// Windows/FileIO.cpp
+
+#include "StdAfx.h"
+
+#include "FileIO.h"
+
+#if defined(WIN_LONG_PATH) || defined(SUPPORT_DEVICE_FILE)
+#include "../Common/MyString.h"
+#endif
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+
+#ifdef SUPPORT_DEVICE_FILE
+bool IsDeviceName(LPCTSTR n)
+{
+ #ifdef UNDER_CE
+ int len = (int)MyStringLen(n);
+ if (len < 5 || len > 5 || memcmp(n, TEXT("DSK"), 3 * sizeof(TCHAR)) != 0)
+ return false;
+ if (n[4] != ':')
+ return false;
+ // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ));
+ #else
+ if (n[0] != '\\' || n[1] != '\\' || n[2] != '.' || n[3] != '\\')
+ return false;
+ int len = (int)MyStringLen(n);
+ if (len == 6 && n[5] == ':')
+ return true;
+ if (len < 18 || len > 22 || memcmp(n + 4, TEXT("PhysicalDrive"), 13 * sizeof(TCHAR)) != 0)
+ return false;
+ for (int i = 17; i < len; i++)
+ if (n[i] < '0' || n[i] > '9')
+ return false;
+ #endif
+ return true;
+}
+
+#ifndef _UNICODE
+bool IsDeviceName(LPCWSTR n)
+{
+ if (n[0] != '\\' || n[1] != '\\' || n[2] != '.' || n[3] != '\\')
+ return false;
+ int len = (int)wcslen(n);
+ if (len == 6 && n[5] == ':')
+ return true;
+ if (len < 18 || len > 22 || wcsncmp(n + 4, L"PhysicalDrive", 13) != 0)
+ return false;
+ for (int i = 17; i < len; i++)
+ if (n[i] < '0' || n[i] > '9')
+ return false;
+ return true;
+}
+#endif
+#endif
+
+#if defined(WIN_LONG_PATH) && defined(_UNICODE)
+#define WIN_LONG_PATH2
+#endif
+
+#ifdef WIN_LONG_PATH
+bool GetLongPathBase(LPCWSTR s, UString &res)
+{
+ res.Empty();
+ int len = MyStringLen(s);
+ wchar_t c = s[0];
+ if (len < 1 || c == L'\\' || c == L'.' && (len == 1 || len == 2 && s[1] == L'.'))
+ return true;
+ UString curDir;
+ bool isAbs = false;
+ if (len > 3)
+ isAbs = (s[1] == L':' && s[2] == L'\\' && (c >= L'a' && c <= L'z' || c >= L'A' && c <= L'Z'));
+
+ if (!isAbs)
+ {
+ DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, curDir.GetBuffer(MAX_PATH + 1));
+ curDir.ReleaseBuffer();
+ if (needLength == 0 || needLength > MAX_PATH)
+ return false;
+ if (curDir[curDir.Length() - 1] != L'\\')
+ curDir += L'\\';
+ }
+ res = UString(L"\\\\?\\") + curDir + s;
+ return true;
+}
+
+bool GetLongPath(LPCWSTR path, UString &longPath)
+{
+ if (GetLongPathBase(path, longPath))
+ return !longPath.IsEmpty();
+ return false;
+}
+#endif
+
+namespace NIO {
+
+CFileBase::~CFileBase() { Close(); }
+
+bool CFileBase::Create(LPCTSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ if (!Close())
+ return false;
+ _handle = ::CreateFile(fileName, desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition,
+ flagsAndAttributes, (HANDLE)NULL);
+ #ifdef WIN_LONG_PATH2
+ if (_handle == INVALID_HANDLE_VALUE)
+ {
+ UString longPath;
+ if (GetLongPath(fileName, longPath))
+ _handle = ::CreateFileW(longPath, desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition,
+ flagsAndAttributes, (HANDLE)NULL);
+ }
+ #endif
+ #ifdef SUPPORT_DEVICE_FILE
+ IsDeviceFile = false;
+ #endif
+ return (_handle != INVALID_HANDLE_VALUE);
+}
+
+#ifndef _UNICODE
+bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ if (!g_IsNT)
+ return Create(UnicodeStringToMultiByte(fileName, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP),
+ desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
+ if (!Close())
+ return false;
+ _handle = ::CreateFileW(fileName, desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition,
+ flagsAndAttributes, (HANDLE)NULL);
+ #ifdef WIN_LONG_PATH
+ if (_handle == INVALID_HANDLE_VALUE)
+ {
+ UString longPath;
+ if (GetLongPath(fileName, longPath))
+ _handle = ::CreateFileW(longPath, desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition,
+ flagsAndAttributes, (HANDLE)NULL);
+ }
+ #endif
+ #ifdef SUPPORT_DEVICE_FILE
+ IsDeviceFile = false;
+ #endif
+ return (_handle != INVALID_HANDLE_VALUE);
+}
+#endif
+
+bool CFileBase::Close()
+{
+ if (_handle == INVALID_HANDLE_VALUE)
+ return true;
+ if (!::CloseHandle(_handle))
+ return false;
+ _handle = INVALID_HANDLE_VALUE;
+ return true;
+}
+
+bool CFileBase::GetPosition(UInt64 &position) const
+{
+ return Seek(0, FILE_CURRENT, position);
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDeviceFile && LengthDefined)
+ {
+ length = Length;
+ return true;
+ }
+ #endif
+
+ DWORD sizeHigh;
+ DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh);
+ if (sizeLow == 0xFFFFFFFF)
+ if (::GetLastError() != NO_ERROR)
+ return false;
+ length = (((UInt64)sizeHigh) << 32) + sizeLow;
+ return true;
+}
+
+bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ if (IsDeviceFile && LengthDefined && moveMethod == FILE_END)
+ {
+ distanceToMove += Length;
+ moveMethod = FILE_BEGIN;
+ }
+ #endif
+
+ LARGE_INTEGER value;
+ value.QuadPart = distanceToMove;
+ value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod);
+ if (value.LowPart == 0xFFFFFFFF)
+ if (::GetLastError() != NO_ERROR)
+ return false;
+ newPosition = value.QuadPart;
+ return true;
+}
+
+bool CFileBase::Seek(UInt64 position, UInt64 &newPosition)
+{
+ return Seek(position, FILE_BEGIN, newPosition);
+}
+
+bool CFileBase::SeekToBegin()
+{
+ UInt64 newPosition;
+ return Seek(0, newPosition);
+}
+
+bool CFileBase::SeekToEnd(UInt64 &newPosition)
+{
+ return Seek(0, FILE_END, newPosition);
+}
+
+bool CFileBase::GetFileInformation(CByHandleFileInfo &fileInfo) const
+{
+ BY_HANDLE_FILE_INFORMATION winFileInfo;
+ if (!::GetFileInformationByHandle(_handle, &winFileInfo))
+ return false;
+ fileInfo.Attrib = winFileInfo.dwFileAttributes;
+ fileInfo.CTime = winFileInfo.ftCreationTime;
+ fileInfo.ATime = winFileInfo.ftLastAccessTime;
+ fileInfo.MTime = winFileInfo.ftLastWriteTime;
+ fileInfo.VolumeSerialNumber = winFileInfo.dwFileAttributes;
+ fileInfo.Size = (((UInt64)winFileInfo.nFileSizeHigh) << 32) + winFileInfo.nFileSizeLow;
+ fileInfo.NumberOfLinks = winFileInfo.nNumberOfLinks;
+ fileInfo.FileIndex = (((UInt64)winFileInfo.nFileIndexHigh) << 32) + winFileInfo.nFileIndexLow;
+ return true;
+}
+
+/////////////////////////
+// CInFile
+
+#ifdef SUPPORT_DEVICE_FILE
+void CInFile::GetDeviceLength()
+{
+ if (_handle != INVALID_HANDLE_VALUE && IsDeviceFile)
+ {
+ #ifdef UNDER_CE
+ LengthDefined = true;
+ Length = 128 << 20;
+
+ #else
+ PARTITION_INFORMATION partInfo;
+ LengthDefined = true;
+ Length = 0;
+
+ if (GetPartitionInfo(&partInfo))
+ Length = partInfo.PartitionLength.QuadPart;
+ else
+ {
+ DISK_GEOMETRY geom;
+ if (!GetGeometry(&geom))
+ if (!GetCdRomGeometry(&geom))
+ LengthDefined = false;
+ if (LengthDefined)
+ Length = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
+ }
+ // SeekToBegin();
+ #endif
+ }
+}
+
+// ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 &&
+
+#define MY_DEVICE_EXTRA_CODE \
+ IsDeviceFile = IsDeviceName(fileName); \
+ GetDeviceLength();
+#else
+#define MY_DEVICE_EXTRA_CODE
+#endif
+
+bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ bool res = Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes);
+ MY_DEVICE_EXTRA_CODE
+ return res;
+}
+
+bool CInFile::OpenShared(LPCTSTR fileName, bool shareForWrite)
+{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
+
+bool CInFile::Open(LPCTSTR fileName)
+ { return OpenShared(fileName, false); }
+
+#ifndef _UNICODE
+bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ bool res = Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes);
+ MY_DEVICE_EXTRA_CODE
+ return res;
+}
+
+bool CInFile::OpenShared(LPCWSTR fileName, bool shareForWrite)
+{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
+
+bool CInFile::Open(LPCWSTR fileName)
+ { return OpenShared(fileName, false); }
+#endif
+
+// ReadFile and WriteFile functions in Windows have BUG:
+// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
+// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
+// (Insufficient system resources exist to complete the requested service).
+
+// Probably in some version of Windows there are problems with other sizes:
+// for 32 MB (maybe also for 16 MB).
+// And message can be "Network connection was lost"
+
+static UInt32 kChunkSizeMax = (1 << 22);
+
+bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize)
+{
+ DWORD processedLoc = 0;
+ bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
+ processedSize = (UInt32)processedLoc;
+ return res;
+}
+
+bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize)
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ return Read1(data, size, processedSize);
+}
+
+bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize)
+{
+ processedSize = 0;
+ do
+ {
+ UInt32 processedLoc = 0;
+ bool res = ReadPart(data, size, processedLoc);
+ processedSize += processedLoc;
+ if (!res)
+ return false;
+ if (processedLoc == 0)
+ return true;
+ data = (void *)((unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size > 0);
+ return true;
+}
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+ { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
+
+static inline DWORD GetCreationDisposition(bool createAlways)
+ { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
+
+bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition)
+ { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
+
+bool COutFile::Create(LPCTSTR fileName, bool createAlways)
+ { return Open(fileName, GetCreationDisposition(createAlways)); }
+
+#ifndef _UNICODE
+
+bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+ { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
+
+bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition)
+ { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
+
+bool COutFile::Create(LPCWSTR fileName, bool createAlways)
+ { return Open(fileName, GetCreationDisposition(createAlways)); }
+
+#endif
+
+bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
+ { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }
+
+bool COutFile::SetMTime(const FILETIME *mTime) { return SetTime(NULL, NULL, mTime); }
+
+bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize)
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ DWORD processedLoc = 0;
+ bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
+ processedSize = (UInt32)processedLoc;
+ return res;
+}
+
+bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize)
+{
+ processedSize = 0;
+ do
+ {
+ UInt32 processedLoc = 0;
+ bool res = WritePart(data, size, processedLoc);
+ processedSize += processedLoc;
+ if (!res)
+ return false;
+ if (processedLoc == 0)
+ return true;
+ data = (const void *)((const unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size > 0);
+ return true;
+}
+
+bool COutFile::SetEndOfFile() { return BOOLToBool(::SetEndOfFile(_handle)); }
+
+bool COutFile::SetLength(UInt64 length)
+{
+ UInt64 newPosition;
+ if (!Seek(length, newPosition))
+ return false;
+ if (newPosition != length)
+ return false;
+ return SetEndOfFile();
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/Windows/FileIO.h b/src/libs/7zip/win/CPP/Windows/FileIO.h
new file mode 100644
index 000000000..dce692fed
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileIO.h
@@ -0,0 +1,136 @@
+// Windows/FileIO.h
+
+#ifndef __WINDOWS_FILEIO_H
+#define __WINDOWS_FILEIO_H
+
+#include "../Common/Types.h"
+
+#include "Defs.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NIO {
+
+struct CByHandleFileInfo
+{
+ DWORD Attrib;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ DWORD VolumeSerialNumber;
+ UInt64 Size;
+ DWORD NumberOfLinks;
+ UInt64 FileIndex;
+};
+
+class CFileBase
+{
+protected:
+ HANDLE _handle;
+
+ bool Create(LPCTSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ #ifndef _UNICODE
+ bool Create(LPCWSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ #endif
+
+public:
+ #ifdef SUPPORT_DEVICE_FILE
+ bool IsDeviceFile;
+ bool LengthDefined;
+ UInt64 Length;
+ #endif
+
+ CFileBase(): _handle(INVALID_HANDLE_VALUE) {};
+ ~CFileBase();
+
+ bool Close();
+
+ bool GetPosition(UInt64 &position) const;
+ bool GetLength(UInt64 &length) const;
+
+ bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const;
+ bool Seek(UInt64 position, UInt64 &newPosition);
+ bool SeekToBegin();
+ bool SeekToEnd(UInt64 &newPosition);
+
+ bool GetFileInformation(CByHandleFileInfo &fileInfo) const;
+};
+
+#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
+#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+class CInFile: public CFileBase
+{
+ #ifdef SUPPORT_DEVICE_FILE
+ bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize,
+ LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped) const
+ {
+ return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize,
+ outBuffer, outSize, bytesReturned, overlapped));
+ }
+
+ bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer,
+ DWORD inSize, LPVOID outBuffer, DWORD outSize) const
+ {
+ DWORD ret;
+ return DeviceIoControl(controlCode, inBuffer, inSize, outBuffer, outSize, &ret, 0);
+ }
+
+ bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const
+ { return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize); }
+
+ #ifndef UNDER_CE
+ bool GetGeometry(DISK_GEOMETRY *res) const
+ { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
+
+ bool GetCdRomGeometry(DISK_GEOMETRY *res) const
+ { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
+
+ bool GetPartitionInfo(PARTITION_INFORMATION *res)
+ { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); }
+ #endif
+
+ void GetDeviceLength();
+ #endif
+
+public:
+ bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool OpenShared(LPCTSTR fileName, bool shareForWrite);
+ bool Open(LPCTSTR fileName);
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool OpenShared(LPCWSTR fileName, bool shareForWrite);
+ bool Open(LPCWSTR fileName);
+ #endif
+ bool Read1(void *data, UInt32 size, UInt32 &processedSize);
+ bool ReadPart(void *data, UInt32 size, UInt32 &processedSize);
+ bool Read(void *data, UInt32 size, UInt32 &processedSize);
+};
+
+class COutFile: public CFileBase
+{
+public:
+ bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(LPCTSTR fileName, DWORD creationDisposition);
+ bool Create(LPCTSTR fileName, bool createAlways);
+
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(LPCWSTR fileName, DWORD creationDisposition);
+ bool Create(LPCWSTR fileName, bool createAlways);
+ #endif
+
+ bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime);
+ bool SetMTime(const FILETIME *mTime);
+ bool WritePart(const void *data, UInt32 size, UInt32 &processedSize);
+ bool Write(const void *data, UInt32 size, UInt32 &processedSize);
+ bool SetEndOfFile();
+ bool SetLength(UInt64 length);
+};
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/FileMapping.cpp b/src/libs/7zip/win/CPP/Windows/FileMapping.cpp
new file mode 100644
index 000000000..55048fdb2
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileMapping.cpp
@@ -0,0 +1,12 @@
+// Windows/FileMapping.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileMapping.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NMapping {
+
+
+}}}
diff --git a/src/libs/7zip/win/CPP/Windows/FileMapping.h b/src/libs/7zip/win/CPP/Windows/FileMapping.h
new file mode 100644
index 000000000..3f0ebd74c
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileMapping.h
@@ -0,0 +1,62 @@
+// Windows/FileMapping.h
+
+#ifndef __WINDOWS_FILEMAPPING_H
+#define __WINDOWS_FILEMAPPING_H
+
+#include "Common/Types.h"
+
+#include "Handle.h"
+
+namespace NWindows {
+
+class CFileMapping: public CHandle
+{
+public:
+ WRes Create(DWORD protect, UInt64 maxSize, LPCTSTR name)
+ {
+ _handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect, (DWORD)(maxSize >> 32), (DWORD)maxSize, name);
+ return ::GetLastError();
+ }
+
+ WRes Open(DWORD desiredAccess, LPCTSTR name)
+ {
+ #ifdef UNDER_CE
+ WRes res = Create(PAGE_READONLY, 0, name);
+ if (res == ERROR_ALREADY_EXISTS)
+ return 0;
+ Close();
+ if (res == 0)
+ res = ERROR_FILE_NOT_FOUND;
+ return res;
+ #else
+ _handle = ::OpenFileMapping(desiredAccess, FALSE, name);
+ if (_handle != 0)
+ return 0;
+ return ::GetLastError();
+ #endif
+ }
+
+ LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap)
+ {
+ return ::MapViewOfFile(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap);
+ }
+
+ #ifndef UNDER_CE
+ LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap, LPVOID baseAddress)
+ {
+ return ::MapViewOfFileEx(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap, baseAddress);
+ }
+ #endif
+};
+
+class CFileUnmapper
+{
+ const void *_data;
+public:
+ CFileUnmapper(const void *data) : _data(data) {}
+ ~CFileUnmapper() { ::UnmapViewOfFile(_data); }
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/FileName.cpp b/src/libs/7zip/win/CPP/Windows/FileName.cpp
new file mode 100644
index 000000000..8443a4af9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileName.cpp
@@ -0,0 +1,50 @@
+// Windows/FileName.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/FileName.h"
+#include "Common/Wildcard.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+void NormalizeDirPathPrefix(CSysString &dirPath)
+{
+ if (dirPath.IsEmpty())
+ return;
+ if (dirPath.ReverseFind(kDirDelimiter) != dirPath.Length() - 1)
+ dirPath += kDirDelimiter;
+}
+
+#ifndef _UNICODE
+void NormalizeDirPathPrefix(UString &dirPath)
+{
+ if (dirPath.IsEmpty())
+ return;
+ if (dirPath.ReverseFind(wchar_t(kDirDelimiter)) != dirPath.Length() - 1)
+ dirPath += wchar_t(kDirDelimiter);
+}
+#endif
+
+const wchar_t kExtensionDelimiter = L'.';
+
+void SplitNameToPureNameAndExtension(const UString &fullName,
+ UString &pureName, UString &extensionDelimiter, UString &extension)
+{
+ int index = fullName.ReverseFind(kExtensionDelimiter);
+ if (index < 0)
+ {
+ pureName = fullName;
+ extensionDelimiter.Empty();
+ extension.Empty();
+ }
+ else
+ {
+ pureName = fullName.Left(index);
+ extensionDelimiter = kExtensionDelimiter;
+ extension = fullName.Mid(index + 1);
+ }
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/Windows/FileName.h b/src/libs/7zip/win/CPP/Windows/FileName.h
new file mode 100644
index 000000000..d98079026
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileName.h
@@ -0,0 +1,27 @@
+// Windows/FileName.h
+
+#ifndef __WINDOWS_FILENAME_H
+#define __WINDOWS_FILENAME_H
+
+#include "../../C/Types.h"
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+const TCHAR kDirDelimiter = CHAR_PATH_SEPARATOR;
+const TCHAR kAnyStringWildcard = '*';
+
+void NormalizeDirPathPrefix(CSysString &dirPath); // ensures that it ended with '\\'
+#ifndef _UNICODE
+void NormalizeDirPathPrefix(UString &dirPath); // ensures that it ended with '\\'
+#endif
+
+void SplitNameToPureNameAndExtension(const UString &fullName,
+ UString &pureName, UString &extensionDelimiter, UString &extension);
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/FileSystem.cpp b/src/libs/7zip/win/CPP/Windows/FileSystem.cpp
new file mode 100644
index 000000000..3ebfb7523
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileSystem.cpp
@@ -0,0 +1,126 @@
+// Windows/FileSystem.cpp
+
+#include "StdAfx.h"
+
+#include "FileSystem.h"
+#include "Defs.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+namespace NSystem {
+
+bool MyGetVolumeInformation(
+ LPCTSTR rootPathName,
+ CSysString &volumeName,
+ LPDWORD volumeSerialNumber,
+ LPDWORD maximumComponentLength,
+ LPDWORD fileSystemFlags,
+ CSysString &fileSystemName)
+{
+ bool result = BOOLToBool(GetVolumeInformation(
+ rootPathName,
+ volumeName.GetBuffer(MAX_PATH), MAX_PATH,
+ volumeSerialNumber,
+ maximumComponentLength,
+ fileSystemFlags,
+ fileSystemName.GetBuffer(MAX_PATH), MAX_PATH));
+ volumeName.ReleaseBuffer();
+ fileSystemName.ReleaseBuffer();
+ return result;
+}
+
+
+#ifndef _UNICODE
+bool MyGetVolumeInformation(
+ LPCWSTR rootPathName,
+ UString &volumeName,
+ LPDWORD volumeSerialNumber,
+ LPDWORD maximumComponentLength,
+ LPDWORD fileSystemFlags,
+ UString &fileSystemName)
+{
+ if (g_IsNT)
+ {
+ bool result = BOOLToBool(GetVolumeInformationW(
+ rootPathName,
+ volumeName.GetBuffer(MAX_PATH), MAX_PATH,
+ volumeSerialNumber,
+ maximumComponentLength,
+ fileSystemFlags,
+ fileSystemName.GetBuffer(MAX_PATH), MAX_PATH));
+ volumeName.ReleaseBuffer();
+ fileSystemName.ReleaseBuffer();
+ return result;
+ }
+ AString volumeNameA, fileSystemNameA;
+ bool result = MyGetVolumeInformation(GetSystemString(rootPathName), volumeNameA,
+ volumeSerialNumber, maximumComponentLength, fileSystemFlags,fileSystemNameA);
+ if (result)
+ {
+ volumeName = GetUnicodeString(volumeNameA);
+ fileSystemName = GetUnicodeString(fileSystemNameA);
+ }
+ return result;
+}
+#endif
+
+typedef BOOL (WINAPI * GetDiskFreeSpaceExPointer)(
+ LPCTSTR lpDirectoryName, // directory name
+ PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
+ PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
+ PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
+);
+
+bool MyGetDiskFreeSpace(LPCTSTR rootPathName,
+ UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize)
+{
+ GetDiskFreeSpaceExPointer pGetDiskFreeSpaceEx =
+ (GetDiskFreeSpaceExPointer)GetProcAddress(
+ GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExA");
+
+ bool sizeIsDetected = false;
+ if (pGetDiskFreeSpaceEx)
+ {
+ ULARGE_INTEGER i64FreeBytesToCaller, totalSize2, freeSize2;
+ sizeIsDetected = BOOLToBool(pGetDiskFreeSpaceEx(rootPathName,
+ &i64FreeBytesToCaller,
+ &totalSize2,
+ &freeSize2));
+ totalSize = totalSize2.QuadPart;
+ freeSize = freeSize2.QuadPart;
+ }
+
+ DWORD numSectorsPerCluster;
+ DWORD bytesPerSector;
+ DWORD numberOfFreeClusters;
+ DWORD totalNumberOfClusters;
+
+ if (!::GetDiskFreeSpace(rootPathName,
+ &numSectorsPerCluster,
+ &bytesPerSector,
+ &numberOfFreeClusters,
+ &totalNumberOfClusters))
+ return false;
+
+ clusterSize = (UInt64)bytesPerSector * (UInt64)numSectorsPerCluster;
+ if (!sizeIsDetected)
+ {
+ totalSize = clusterSize * (UInt64)totalNumberOfClusters;
+ freeSize = clusterSize * (UInt64)numberOfFreeClusters;
+ }
+ return true;
+}
+
+#ifndef _UNICODE
+bool MyGetDiskFreeSpace(LPCWSTR rootPathName,
+ UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize)
+{
+ return MyGetDiskFreeSpace(GetSystemString(rootPathName), clusterSize, totalSize, freeSize);
+}
+#endif
+
+}}}
diff --git a/src/libs/7zip/win/CPP/Windows/FileSystem.h b/src/libs/7zip/win/CPP/Windows/FileSystem.h
new file mode 100644
index 000000000..727497bbd
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/FileSystem.h
@@ -0,0 +1,51 @@
+// Windows/FileSystem.h
+
+#ifndef __WINDOWS_FILESYSTEM_H
+#define __WINDOWS_FILESYSTEM_H
+
+#include "../Common/MyString.h"
+#include "../Common/Types.h"
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+namespace NWindows {
+namespace NFile {
+namespace NSystem {
+
+bool MyGetVolumeInformation(
+ LPCTSTR rootPathName,
+ CSysString &volumeName,
+ LPDWORD volumeSerialNumber,
+ LPDWORD maximumComponentLength,
+ LPDWORD fileSystemFlags,
+ CSysString &fileSystemName);
+
+#ifndef _UNICODE
+bool MyGetVolumeInformation(
+ LPCWSTR rootPathName,
+ UString &volumeName,
+ LPDWORD volumeSerialNumber,
+ LPDWORD maximumComponentLength,
+ LPDWORD fileSystemFlags,
+ UString &fileSystemName);
+#endif
+
+inline UINT MyGetDriveType(LPCTSTR pathName) { return GetDriveType(pathName); }
+#ifndef _UNICODE
+inline UINT MyGetDriveType(LPCWSTR pathName) { return GetDriveType(GetSystemString(pathName)); }
+#endif
+
+bool MyGetDiskFreeSpace(LPCTSTR rootPathName,
+ UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
+
+#ifndef _UNICODE
+bool MyGetDiskFreeSpace(LPCWSTR rootPathName,
+ UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
+#endif
+
+}}}
+
+#endif
+
diff --git a/src/libs/7zip/win/CPP/Windows/Handle.h b/src/libs/7zip/win/CPP/Windows/Handle.h
new file mode 100644
index 000000000..bb7cb705d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Handle.h
@@ -0,0 +1,37 @@
+// Windows/Handle.h
+
+#ifndef __WINDOWS_HANDLE_H
+#define __WINDOWS_HANDLE_H
+
+namespace NWindows {
+
+class CHandle
+{
+protected:
+ HANDLE _handle;
+public:
+ operator HANDLE() { return _handle; }
+ CHandle(): _handle(NULL) {}
+ ~CHandle() { Close(); }
+ bool IsCreated() const { return (_handle != NULL); }
+ bool Close()
+ {
+ if (_handle == NULL)
+ return true;
+ if (!::CloseHandle(_handle))
+ return false;
+ _handle = NULL;
+ return true;
+ }
+ void Attach(HANDLE handle) { _handle = handle; }
+ HANDLE Detach()
+ {
+ HANDLE handle = _handle;
+ _handle = NULL;
+ return handle;
+ }
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Memory.cpp b/src/libs/7zip/win/CPP/Windows/Memory.cpp
new file mode 100644
index 000000000..4c23205e1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Memory.cpp
@@ -0,0 +1,36 @@
+// Windows/Memory.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/Memory.h"
+
+namespace NWindows {
+namespace NMemory {
+
+bool CGlobal::Alloc(UINT flags, SIZE_T size)
+{
+ HGLOBAL newBlock = ::GlobalAlloc(flags, size);
+ if (newBlock == NULL)
+ return false;
+ m_MemoryHandle = newBlock;
+ return true;
+}
+
+bool CGlobal::Free()
+{
+ if (m_MemoryHandle == NULL)
+ return true;
+ m_MemoryHandle = ::GlobalFree(m_MemoryHandle);
+ return (m_MemoryHandle == NULL);
+}
+
+bool CGlobal::ReAlloc(SIZE_T size)
+{
+ HGLOBAL newBlock = ::GlobalReAlloc(m_MemoryHandle, size, GMEM_MOVEABLE);
+ if (newBlock == NULL)
+ return false;
+ m_MemoryHandle = newBlock;
+ return true;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/Memory.h b/src/libs/7zip/win/CPP/Windows/Memory.h
new file mode 100644
index 000000000..1984baf6a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Memory.h
@@ -0,0 +1,53 @@
+// Windows/Memory.h
+
+#ifndef __WINDOWS_MEMORY_H
+#define __WINDOWS_MEMORY_H
+
+namespace NWindows {
+namespace NMemory {
+
+class CGlobal
+{
+ HGLOBAL m_MemoryHandle;
+public:
+ CGlobal(): m_MemoryHandle(NULL){};
+ ~CGlobal() { Free(); }
+ operator HGLOBAL() const { return m_MemoryHandle; };
+ void Attach(HGLOBAL hGlobal)
+ {
+ Free();
+ m_MemoryHandle = hGlobal;
+ }
+ HGLOBAL Detach()
+ {
+ HGLOBAL h = m_MemoryHandle;
+ m_MemoryHandle = NULL;
+ return h;
+ }
+ bool Alloc(UINT flags, SIZE_T size);
+ bool Free();
+ LPVOID Lock() const { return GlobalLock(m_MemoryHandle); }
+ void Unlock() const { GlobalUnlock(m_MemoryHandle); }
+ bool ReAlloc(SIZE_T size);
+};
+
+class CGlobalLock
+{
+ HGLOBAL m_Global;
+ LPVOID m_Pointer;
+public:
+ LPVOID GetPointer() const { return m_Pointer; }
+ CGlobalLock(HGLOBAL hGlobal): m_Global(hGlobal)
+ {
+ m_Pointer = GlobalLock(hGlobal);
+ };
+ ~CGlobalLock()
+ {
+ if (m_Pointer != NULL)
+ GlobalUnlock(m_Global);
+ }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/MemoryLock.cpp b/src/libs/7zip/win/CPP/Windows/MemoryLock.cpp
new file mode 100644
index 000000000..e0f430996
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/MemoryLock.cpp
@@ -0,0 +1,82 @@
+// Common/MemoryLock.cpp
+
+#include "StdAfx.h"
+
+namespace NWindows {
+namespace NSecurity {
+
+#ifndef UNDER_CE
+
+#ifndef _UNICODE
+typedef BOOL (WINAPI * OpenProcessTokenP)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
+typedef BOOL (WINAPI * LookupPrivilegeValueP)(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid);
+typedef BOOL (WINAPI * AdjustTokenPrivilegesP)(HANDLE TokenHandle, BOOL DisableAllPrivileges,
+ PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength);
+#endif
+
+#ifdef _UNICODE
+bool EnableLockMemoryPrivilege(
+#else
+static bool EnableLockMemoryPrivilege2(HMODULE hModule,
+#endif
+bool enable)
+{
+ #ifndef _UNICODE
+ if (hModule == NULL)
+ return false;
+ OpenProcessTokenP openProcessToken = (OpenProcessTokenP)GetProcAddress(hModule, "OpenProcessToken");
+ LookupPrivilegeValueP lookupPrivilegeValue = (LookupPrivilegeValueP)GetProcAddress(hModule, "LookupPrivilegeValueA" );
+ AdjustTokenPrivilegesP adjustTokenPrivileges = (AdjustTokenPrivilegesP)GetProcAddress(hModule, "AdjustTokenPrivileges");
+ if (openProcessToken == NULL || adjustTokenPrivileges == NULL || lookupPrivilegeValue == NULL)
+ return false;
+ #endif
+
+ HANDLE token;
+ if (!
+ #ifdef _UNICODE
+ ::OpenProcessToken
+ #else
+ openProcessToken
+ #endif
+ (::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
+ return false;
+ TOKEN_PRIVILEGES tp;
+ bool res = false;
+ if (
+ #ifdef _UNICODE
+ ::LookupPrivilegeValue
+ #else
+ lookupPrivilegeValue
+ #endif
+ (NULL, SE_LOCK_MEMORY_NAME, &(tp.Privileges[0].Luid)))
+ {
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED: 0;
+ if (
+ #ifdef _UNICODE
+ ::AdjustTokenPrivileges
+ #else
+ adjustTokenPrivileges
+ #endif
+ (token, FALSE, &tp, 0, NULL, NULL))
+ res = (GetLastError() == ERROR_SUCCESS);
+ }
+ ::CloseHandle(token);
+ return res;
+}
+
+#ifndef _UNICODE
+bool EnableLockMemoryPrivilege(bool enable)
+{
+ HMODULE hModule = LoadLibrary(TEXT("Advapi32.dll"));
+ if (hModule == NULL)
+ return false;
+ bool res = EnableLockMemoryPrivilege2(hModule, enable);
+ ::FreeLibrary(hModule);
+ return res;
+}
+#endif
+
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/MemoryLock.h b/src/libs/7zip/win/CPP/Windows/MemoryLock.h
new file mode 100644
index 000000000..5fe619de0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/MemoryLock.h
@@ -0,0 +1,15 @@
+// Windows/MemoryLock.h
+
+#ifndef __WINDOWS_MEMORYLOCK_H
+#define __WINDOWS_MEMORYLOCK_H
+
+namespace NWindows {
+namespace NSecurity {
+
+#ifndef UNDER_CE
+bool EnableLockMemoryPrivilege(bool enable = true);
+#endif
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Menu.cpp b/src/libs/7zip/win/CPP/Windows/Menu.cpp
new file mode 100644
index 000000000..675f86237
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Menu.cpp
@@ -0,0 +1,191 @@
+// Windows/Menu.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+#include "Windows/Menu.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si)
+{
+ ZeroMemory(&si, sizeof(si));
+ si.cbSize = sizeof(si);
+ si.fMask = item.fMask;
+ si.fType = item.fType;
+ si.fState = item.fState;
+ si.wID = item.wID;
+ si.hSubMenu = item.hSubMenu;
+ si.hbmpChecked = item.hbmpChecked;
+ si.hbmpUnchecked = item.hbmpUnchecked;
+ si.dwItemData = item.dwItemData;
+}
+
+#ifndef _UNICODE
+static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si)
+{
+ ZeroMemory(&si, sizeof(si));
+ si.cbSize = sizeof(si);
+ si.fMask = item.fMask;
+ si.fType = item.fType;
+ si.fState = item.fState;
+ si.wID = item.wID;
+ si.hSubMenu = item.hSubMenu;
+ si.hbmpChecked = item.hbmpChecked;
+ si.hbmpUnchecked = item.hbmpUnchecked;
+ si.dwItemData = item.dwItemData;
+}
+#endif
+
+static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item)
+{
+ item.fMask = si.fMask;
+ item.fType = si.fType;
+ item.fState = si.fState;
+ item.wID = si.wID;
+ item.hSubMenu = si.hSubMenu;
+ item.hbmpChecked = si.hbmpChecked;
+ item.hbmpUnchecked = si.hbmpUnchecked;
+ item.dwItemData = si.dwItemData;
+}
+
+#ifndef _UNICODE
+static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item)
+{
+ item.fMask = si.fMask;
+ item.fType = si.fType;
+ item.fState = si.fState;
+ item.wID = si.wID;
+ item.hSubMenu = si.hSubMenu;
+ item.hbmpChecked = si.hbmpChecked;
+ item.hbmpUnchecked = si.hbmpUnchecked;
+ item.dwItemData = si.dwItemData;
+}
+#endif
+
+bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item)
+{
+ const UINT kMaxSize = 512;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ CHAR s[kMaxSize + 1];
+ MENUITEMINFOA si;
+ ConvertItemToSysForm(item, si);
+ if (item.IsString())
+ {
+ si.cch = kMaxSize;
+ si.dwTypeData = s;
+ }
+ if (GetItemInfo(itemIndex, byPosition, &si))
+ {
+ ConvertItemToMyForm(si, item);
+ if (item.IsString())
+ item.StringValue = GetUnicodeString(s);
+ return true;
+ }
+ }
+ else
+ #endif
+ {
+ wchar_t s[kMaxSize + 1];
+ MENUITEMINFOW si;
+ ConvertItemToSysForm(item, si);
+ if (item.IsString())
+ {
+ si.cch = kMaxSize;
+ si.dwTypeData = s;
+ }
+ if (GetItemInfo(itemIndex, byPosition, &si))
+ {
+ ConvertItemToMyForm(si, item);
+ if (item.IsString())
+ item.StringValue = s;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ MENUITEMINFOA si;
+ ConvertItemToSysForm(item, si);
+ AString s;
+ if (item.IsString())
+ {
+ s = GetSystemString(item.StringValue);
+ si.dwTypeData = (LPTSTR)(LPCTSTR)s;
+ }
+ return SetItemInfo(itemIndex, byPosition, &si);
+ }
+ else
+ #endif
+ {
+ MENUITEMINFOW si;
+ ConvertItemToSysForm(item, si);
+ if (item.IsString())
+ si.dwTypeData = (LPWSTR)(LPCWSTR)item.StringValue;
+ return SetItemInfo(itemIndex, byPosition, &si);
+ }
+}
+
+bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ MENUITEMINFOA si;
+ ConvertItemToSysForm(item, si);
+ AString s;
+ if (item.IsString())
+ {
+ s = GetSystemString(item.StringValue);
+ si.dwTypeData = (LPTSTR)(LPCTSTR)s;
+ }
+ return InsertItem(itemIndex, byPosition, &si);
+ }
+ else
+ #endif
+ {
+ MENUITEMINFOW si;
+ ConvertItemToSysForm(item, si);
+ if (item.IsString())
+ si.dwTypeData = (LPWSTR)(LPCWSTR)item.StringValue;
+ #ifdef UNDER_CE
+ UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING;
+ UINT id = item.wID;
+ if ((item.fMask & MIIM_SUBMENU) != 0)
+ {
+ flags |= MF_POPUP;
+ id = (UINT)item.hSubMenu;
+ }
+ if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue))
+ return false;
+ return SetItemInfo(itemIndex, byPosition, &si);
+ #else
+ return InsertItem(itemIndex, byPosition, &si);
+ #endif
+ }
+}
+
+#ifndef _UNICODE
+bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem)
+{
+ if (g_IsNT)
+ return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem));
+ else
+ return AppendItem(flags, newItemID, GetSystemString(newItem));
+}
+#endif
+
+}
diff --git a/src/libs/7zip/win/CPP/Windows/Menu.h b/src/libs/7zip/win/CPP/Windows/Menu.h
new file mode 100644
index 000000000..2563b9117
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Menu.h
@@ -0,0 +1,153 @@
+// Windows/Menu.h
+
+#ifndef __WINDOWS_MENU_H
+#define __WINDOWS_MENU_H
+
+#include "Common/MyString.h"
+#include "Windows/Defs.h"
+
+namespace NWindows {
+
+struct CMenuItem
+{
+ UString StringValue;
+ UINT fMask;
+ UINT fType;
+ UINT fState;
+ UINT wID;
+ HMENU hSubMenu;
+ HBITMAP hbmpChecked;
+ HBITMAP hbmpUnchecked;
+ ULONG_PTR dwItemData;
+ // LPTSTR dwTypeData;
+ // UINT cch;
+ // HBITMAP hbmpItem;
+ bool IsString() const // change it MIIM_STRING
+ { return ((fMask & MIIM_TYPE) != 0 && (fType == MFT_STRING)); }
+ bool IsSeparator() const { return (fType == MFT_SEPARATOR); }
+ CMenuItem(): fMask(0), fType(0), fState(0), wID(0), hSubMenu(0), hbmpChecked(0),
+ hbmpUnchecked(0), dwItemData(0) {}
+};
+
+class CMenu
+{
+ HMENU _menu;
+public:
+ CMenu(): _menu(NULL) {};
+ operator HMENU() const { return _menu; }
+ void Attach(HMENU menu) { _menu = menu; }
+
+ HMENU Detach()
+ {
+ HMENU menu = _menu;
+ _menu = NULL;
+ return menu;
+ }
+
+ bool Create()
+ {
+ _menu = ::CreateMenu();
+ return (_menu != NULL);
+ }
+
+ bool CreatePopup()
+ {
+ _menu = ::CreatePopupMenu();
+ return (_menu != NULL);
+ }
+
+ bool Destroy()
+ {
+ if (_menu == NULL)
+ return false;
+ return BOOLToBool(::DestroyMenu(Detach()));
+ }
+
+ int GetItemCount()
+ {
+ #ifdef UNDER_CE
+ for (int i = 0;; i++)
+ {
+ CMenuItem item;
+ item.fMask = MIIM_STATE;
+ if (!GetItem(i, true, item))
+ return i;
+ }
+ #else
+ return GetMenuItemCount(_menu);
+ #endif
+ }
+
+ HMENU GetSubMenu(int pos) { return ::GetSubMenu(_menu, pos); }
+ #ifndef UNDER_CE
+ bool GetItemString(UINT idItem, UINT flag, CSysString &result)
+ {
+ result.Empty();
+ int len = ::GetMenuString(_menu, idItem, 0, 0, flag);
+ len = ::GetMenuString(_menu, idItem, result.GetBuffer(len + 2), len + 1, flag);
+ result.ReleaseBuffer();
+ return (len != 0);
+ }
+ UINT GetItemID(int pos) { return ::GetMenuItemID(_menu, pos); }
+ UINT GetItemState(UINT id, UINT flags) { return ::GetMenuState(_menu, id, flags); }
+ #endif
+
+ bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo)
+ { return BOOLToBool(::GetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo)
+ { return BOOLToBool(::SetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+
+ bool AppendItem(UINT flags, UINT_PTR newItemID, LPCTSTR newItem)
+ { return BOOLToBool(::AppendMenu(_menu, flags, newItemID, newItem)); }
+
+ bool Insert(UINT position, UINT flags, UINT_PTR idNewItem, LPCTSTR newItem)
+ { return BOOLToBool(::InsertMenu(_menu, position, flags, idNewItem, newItem)); }
+
+ #ifndef UNDER_CE
+ bool InsertItem(UINT itemIndex, bool byPosition, LPCMENUITEMINFO itemInfo)
+ { return BOOLToBool(::InsertMenuItem(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ #endif
+
+ bool RemoveItem(UINT item, UINT flags) { return BOOLToBool(::RemoveMenu(_menu, item, flags)); }
+ void RemoveAllItemsFrom(UINT index) { while (RemoveItem(index, MF_BYPOSITION)); }
+ void RemoveAllItems() { RemoveAllItemsFrom(0); }
+
+ #ifndef _UNICODE
+ bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo)
+ { return BOOLToBool(::GetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ bool InsertItem(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo)
+ { return BOOLToBool(::InsertMenuItemW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo)
+ { return BOOLToBool(::SetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ bool AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem);
+ #endif
+
+ bool GetItem(UINT itemIndex, bool byPosition, CMenuItem &item);
+ bool SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item);
+ bool InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item);
+
+ int Track(UINT flags, int x, int y, HWND hWnd) { return ::TrackPopupMenuEx(_menu, flags, x, y, hWnd, NULL); }
+
+ bool CheckRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT flags)
+ { return BOOLToBool(::CheckMenuRadioItem(_menu, idFirst, idLast, idCheck, flags)); }
+
+ DWORD CheckItem(UINT id, UINT uCheck) { return ::CheckMenuItem(_menu, id, uCheck); }
+ DWORD CheckItemByID(UINT id, bool check) { return CheckItem(id, MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED)); }
+
+ BOOL EnableItem(UINT uIDEnableItem, UINT uEnable) { return EnableMenuItem(_menu, uIDEnableItem, uEnable); }
+};
+
+class CMenuDestroyer
+{
+ CMenu *_menu;
+public:
+ CMenuDestroyer(CMenu &menu): _menu(&menu) {}
+ CMenuDestroyer(): _menu(0) {}
+ ~CMenuDestroyer() { if (_menu) _menu->Destroy(); }
+ void Attach(CMenu &menu) { _menu = &menu; }
+ void Disable() { _menu = 0; }
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/NationalTime.cpp b/src/libs/7zip/win/CPP/Windows/NationalTime.cpp
new file mode 100644
index 000000000..c231d3ced
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/NationalTime.cpp
@@ -0,0 +1,37 @@
+// Windows/NationalTime.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/NationalTime.h"
+
+namespace NWindows {
+namespace NNational {
+namespace NTime {
+
+bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
+ LPCTSTR format, CSysString &resultString)
+{
+ resultString.Empty();
+ int numChars = ::GetTimeFormat(locale, flags, time, format, NULL, 0);
+ if (numChars == 0)
+ return false;
+ numChars = ::GetTimeFormat(locale, flags, time, format,
+ resultString.GetBuffer(numChars), numChars + 1);
+ resultString.ReleaseBuffer();
+ return (numChars != 0);
+}
+
+bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
+ LPCTSTR format, CSysString &resultString)
+{
+ resultString.Empty();
+ int numChars = ::GetDateFormat(locale, flags, time, format, NULL, 0);
+ if (numChars == 0)
+ return false;
+ numChars = ::GetDateFormat(locale, flags, time, format,
+ resultString.GetBuffer(numChars), numChars + 1);
+ resultString.ReleaseBuffer();
+ return (numChars != 0);
+}
+
+}}}
diff --git a/src/libs/7zip/win/CPP/Windows/NationalTime.h b/src/libs/7zip/win/CPP/Windows/NationalTime.h
new file mode 100644
index 000000000..86e014bf9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/NationalTime.h
@@ -0,0 +1,20 @@
+// Windows/NationalTime.h
+
+#ifndef __WINDOWS_NATIONALTIME_H
+#define __WINDOWS_NATIONALTIME_H
+
+#include "Common/String.h"
+
+namespace NWindows {
+namespace NNational {
+namespace NTime {
+
+bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
+ LPCTSTR format, CSysString &resultString);
+
+bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
+ LPCTSTR format, CSysString &resultString);
+
+}}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Net.cpp b/src/libs/7zip/win/CPP/Windows/Net.cpp
new file mode 100644
index 000000000..b0a18732a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Net.cpp
@@ -0,0 +1,380 @@
+// Windows/Net.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+
+#include "Windows/Net.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NNet {
+
+DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource)
+{
+ Close();
+ DWORD result = ::WNetOpenEnum(scope, type, usage, netResource, &_handle);
+ _handleAllocated = (result == NO_ERROR);
+ return result;
+}
+
+#ifndef _UNICODE
+DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource)
+{
+ Close();
+ DWORD result = ::WNetOpenEnumW(scope, type, usage, netResource, &_handle);
+ _handleAllocated = (result == NO_ERROR);
+ return result;
+}
+#endif
+
+static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srsString)
+{
+ defined = (srsString != 0);
+ if (defined)
+ destString = srsString;
+ else
+ destString.Empty();
+}
+
+static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResource &resource)
+{
+ resource.Scope = netResource.dwScope;
+ resource.Type = netResource.dwType;
+ resource.DisplayType = netResource.dwDisplayType;
+ resource.Usage = netResource.dwUsage;
+ SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName);
+ SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName);
+ SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment);
+ SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider);
+}
+
+static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString)
+{
+ if (defined)
+ *destString = (TCHAR *)(const TCHAR *)srcString;
+ else
+ *destString = 0;
+}
+
+static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource)
+{
+ netResource.dwScope = resource.Scope;
+ netResource.dwType = resource.Type;
+ netResource.dwDisplayType = resource.DisplayType;
+ netResource.dwUsage = resource.Usage;
+ SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName);
+ SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName);
+ SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment);
+ SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider);
+}
+
+#ifndef _UNICODE
+
+static void SetComplexString(bool &defined, UString &destString, LPCWSTR srsString)
+{
+ defined = (srsString != 0);
+ if (defined)
+ destString = srsString;
+ else
+ destString.Empty();
+}
+
+static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CResourceW &resource)
+{
+ resource.Scope = netResource.dwScope;
+ resource.Type = netResource.dwType;
+ resource.DisplayType = netResource.dwDisplayType;
+ resource.Usage = netResource.dwUsage;
+ SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName);
+ SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName);
+ SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment);
+ SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider);
+}
+
+static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString)
+{
+ if (defined)
+ *destString = (WCHAR *)(const WCHAR *)srcString;
+ else
+ *destString = 0;
+}
+
+static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource)
+{
+ netResource.dwScope = resource.Scope;
+ netResource.dwType = resource.Type;
+ netResource.dwDisplayType = resource.DisplayType;
+ netResource.dwUsage = resource.Usage;
+ SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName);
+ SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName);
+ SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment);
+ SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider);
+}
+
+static void ConvertResourceWToResource(const CResourceW &resourceW, CResource &resource)
+{
+ *(CResourceBase *)&resource = *(CResourceBase *)&resourceW;
+ resource.LocalName = GetSystemString(resourceW.LocalName);
+ resource.RemoteName = GetSystemString(resourceW.RemoteName);
+ resource.Comment = GetSystemString(resourceW.Comment);
+ resource.Provider = GetSystemString(resourceW.Provider);
+}
+
+static void ConvertResourceToResourceW(const CResource &resource, CResourceW &resourceW)
+{
+ *(CResourceBase *)&resourceW = *(CResourceBase *)&resource;
+ resourceW.LocalName = GetUnicodeString(resource.LocalName);
+ resourceW.RemoteName = GetUnicodeString(resource.RemoteName);
+ resourceW.Comment = GetUnicodeString(resource.Comment);
+ resourceW.Provider = GetUnicodeString(resource.Provider);
+}
+#endif
+
+DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource)
+{
+ NETRESOURCE netResource;
+ LPNETRESOURCE pointer;
+ if (resource == 0)
+ pointer = 0;
+ else
+ {
+ ConvertCResourceToNETRESOURCE(*resource, netResource);
+ pointer = &netResource;
+ }
+ return Open(scope, type, usage, pointer);
+}
+
+#ifndef _UNICODE
+DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource)
+{
+ if (g_IsNT)
+ {
+ NETRESOURCEW netResource;
+ LPNETRESOURCEW pointer;
+ if (resource == 0)
+ pointer = 0;
+ else
+ {
+ ConvertCResourceToNETRESOURCE(*resource, netResource);
+ pointer = &netResource;
+ }
+ return Open(scope, type, usage, pointer);
+ }
+ CResource *pointer;
+ CResource resourceA;
+ if (resource == 0)
+ pointer = 0;
+ else
+ {
+ ConvertResourceWToResource(*resource, resourceA);
+ pointer = &resourceA;
+ }
+ return Open(scope, type, usage, pointer);
+}
+#endif
+
+DWORD CEnum::Close()
+{
+ if (!_handleAllocated)
+ return NO_ERROR;
+ DWORD result = ::WNetCloseEnum(_handle);
+ _handleAllocated = (result != NO_ERROR);
+ return result;
+}
+
+DWORD CEnum::Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
+{
+ return ::WNetEnumResource(_handle, lpcCount, lpBuffer, lpBufferSize);
+}
+
+#ifndef _UNICODE
+DWORD CEnum::NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
+{
+ return ::WNetEnumResourceW(_handle, lpcCount, lpBuffer, lpBufferSize);
+}
+#endif
+
+DWORD CEnum::Next(CResource &resource)
+{
+ CByteBuffer byteBuffer;
+ const DWORD kBufferSize = 16384;
+ byteBuffer.SetCapacity(kBufferSize);
+ LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ DWORD numEntries = 1;
+ DWORD result = Next(&numEntries, lpnrLocal, &bufferSize);
+ if (result != NO_ERROR)
+ return result;
+ if (numEntries != 1)
+ return (DWORD)E_FAIL;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], resource);
+ return result;
+}
+
+#ifndef _UNICODE
+DWORD CEnum::Next(CResourceW &resource)
+{
+ if (g_IsNT)
+ {
+ CByteBuffer byteBuffer;
+ const DWORD kBufferSize = 16384;
+ byteBuffer.SetCapacity(kBufferSize);
+ LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ DWORD numEntries = 1;
+ DWORD result = NextW(&numEntries, lpnrLocal, &bufferSize);
+ if (result != NO_ERROR)
+ return result;
+ if (numEntries != 1)
+ return (DWORD)E_FAIL;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], resource);
+ return result;
+ }
+ CResource resourceA;
+ DWORD result = Next(resourceA);
+ ConvertResourceToResourceW(resourceA, resource);
+ return result;
+}
+#endif
+
+
+DWORD GetResourceParent(const CResource &resource, CResource &parentResource)
+{
+ CByteBuffer byteBuffer;
+ const DWORD kBufferSize = 16384;
+ byteBuffer.SetCapacity(kBufferSize);
+ LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ NETRESOURCE netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ DWORD result = ::WNetGetResourceParent(&netResource, lpnrLocal, &bufferSize);
+ if (result != NO_ERROR)
+ return result;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource);
+ return result;
+}
+
+#ifndef _UNICODE
+DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource)
+{
+ if (g_IsNT)
+ {
+ CByteBuffer byteBuffer;
+ const DWORD kBufferSize = 16384;
+ byteBuffer.SetCapacity(kBufferSize);
+ LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ NETRESOURCEW netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ DWORD result = ::WNetGetResourceParentW(&netResource, lpnrLocal, &bufferSize);
+ if (result != NO_ERROR)
+ return result;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource);
+ return result;
+ }
+ CResource resourceA, parentResourceA;
+ ConvertResourceWToResource(resource, resourceA);
+ DWORD result = GetResourceParent(resourceA, parentResourceA);
+ ConvertResourceToResourceW(parentResourceA, parentResource);
+ return result;
+}
+#endif
+
+DWORD GetResourceInformation(const CResource &resource,
+ CResource &destResource, CSysString &systemPathPart)
+{
+ CByteBuffer byteBuffer;
+ const DWORD kBufferSize = 16384;
+ byteBuffer.SetCapacity(kBufferSize);
+ LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ NETRESOURCE netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ LPTSTR lplpSystem;
+ DWORD result = ::WNetGetResourceInformation(&netResource,
+ lpnrLocal, &bufferSize, &lplpSystem);
+ if (result != NO_ERROR)
+ return result;
+ if (lplpSystem != 0)
+ systemPathPart = lplpSystem;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource);
+ return result;
+}
+
+#ifndef _UNICODE
+DWORD GetResourceInformation(const CResourceW &resource,
+ CResourceW &destResource, UString &systemPathPart)
+{
+ if (g_IsNT)
+ {
+ CByteBuffer byteBuffer;
+ const DWORD kBufferSize = 16384;
+ byteBuffer.SetCapacity(kBufferSize);
+ LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ NETRESOURCEW netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ LPWSTR lplpSystem;
+ DWORD result = ::WNetGetResourceInformationW(&netResource,
+ lpnrLocal, &bufferSize, &lplpSystem);
+ if (result != NO_ERROR)
+ return result;
+ if (lplpSystem != 0)
+ systemPathPart = lplpSystem;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource);
+ return result;
+ }
+ CResource resourceA, destResourceA;
+ ConvertResourceWToResource(resource, resourceA);
+ AString systemPathPartA;
+ DWORD result = GetResourceInformation(resourceA, destResourceA, systemPathPartA);
+ ConvertResourceToResourceW(destResourceA, destResource);
+ systemPathPart = GetUnicodeString(systemPathPartA);
+ return result;
+}
+#endif
+
+DWORD AddConnection2(const CResource &resource,
+ LPCTSTR password, LPCTSTR userName, DWORD flags)
+{
+ NETRESOURCE netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ return ::WNetAddConnection2(&netResource,
+ password, userName, flags);
+}
+
+DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags);
+
+#ifndef _UNICODE
+DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags)
+{
+ if (g_IsNT)
+ {
+ NETRESOURCEW netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ return ::WNetAddConnection2W(&netResource,password, userName, flags);
+ }
+ CResource resourceA;
+ ConvertResourceWToResource(resource, resourceA);
+ CSysString passwordA = GetSystemString(password);
+ CSysString userNameA = GetSystemString(userName);
+ return AddConnection2(resourceA,
+ password ? (LPCTSTR)passwordA: 0,
+ userName ? (LPCTSTR)userNameA: 0,
+ flags);
+}
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/Net.h b/src/libs/7zip/win/CPP/Windows/Net.h
new file mode 100644
index 000000000..c88b61130
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Net.h
@@ -0,0 +1,87 @@
+// Windows/Net.h
+
+#ifndef __WINDOWS_NET_H
+#define __WINDOWS_NET_H
+
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+
+namespace NWindows {
+namespace NNet {
+
+struct CResourceBase
+{
+ DWORD Scope;
+ DWORD Type;
+ DWORD DisplayType;
+ DWORD Usage;
+ bool LocalNameIsDefined;
+ bool RemoteNameIsDefined;
+ bool CommentIsDefined;
+ bool ProviderIsDefined;
+};
+
+struct CResource: public CResourceBase
+{
+ CSysString LocalName;
+ CSysString RemoteName;
+ CSysString Comment;
+ CSysString Provider;
+};
+
+#ifdef _UNICODE
+typedef CResource CResourceW;
+#else
+struct CResourceW: public CResourceBase
+{
+ UString LocalName;
+ UString RemoteName;
+ UString Comment;
+ UString Provider;
+};
+#endif
+
+class CEnum
+{
+ HANDLE _handle;
+ bool _handleAllocated;
+ DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource);
+ DWORD Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize);
+ #ifndef _UNICODE
+ DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource);
+ DWORD NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize);
+ #endif
+protected:
+ bool IsHandleAllocated() const { return _handleAllocated; }
+public:
+ CEnum(): _handleAllocated(false) {}
+ ~CEnum() { Close(); }
+ DWORD Close();
+ DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource);
+ DWORD Next(CResource &resource);
+ #ifndef _UNICODE
+ DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource);
+ DWORD Next(CResourceW &resource);
+ #endif
+};
+
+DWORD GetResourceParent(const CResource &resource, CResource &parentResource);
+#ifndef _UNICODE
+DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource);
+#endif
+
+DWORD GetResourceInformation(const CResource &resource,
+ CResource &destResource, CSysString &systemPathPart);
+#ifndef _UNICODE
+DWORD GetResourceInformation(const CResourceW &resource,
+ CResourceW &destResource, UString &systemPathPart);
+#endif
+
+DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags);
+#ifndef _UNICODE
+DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags);
+#endif
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/NtCheck.h b/src/libs/7zip/win/CPP/Windows/NtCheck.h
new file mode 100644
index 000000000..e56318f00
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/NtCheck.h
@@ -0,0 +1,44 @@
+// Windows/NtCheck.h
+
+#ifndef __WINDOWS_NT_CHECK_H
+#define __WINDOWS_NT_CHECK_H
+
+#ifdef _WIN32
+
+#if !defined(_WIN64) && !defined(UNDER_CE)
+static inline bool IsItWindowsNT()
+{
+ OSVERSIONINFO vi;
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+
+#ifndef _UNICODE
+ #if defined(_WIN64) || defined(UNDER_CE)
+ bool g_IsNT = true;
+ #define SET_IS_NT
+ #else
+ bool g_IsNT = false;
+ #define SET_IS_NT g_IsNT = IsItWindowsNT();
+ #endif
+ #define NT_CHECK_ACTION
+ // #define NT_CHECK_ACTION { NT_CHECK_FAIL_ACTION }
+#else
+ #if !defined(_WIN64) && !defined(UNDER_CE)
+ #define NT_CHECK_ACTION if (!IsItWindowsNT()) { NT_CHECK_FAIL_ACTION }
+ #else
+ #define NT_CHECK_ACTION
+ #endif
+ #define SET_IS_NT
+#endif
+
+#define NT_CHECK NT_CHECK_ACTION SET_IS_NT
+
+#else
+
+#define NT_CHECK
+
+#endif
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Process.cpp b/src/libs/7zip/win/CPP/Windows/Process.cpp
new file mode 100644
index 000000000..9bcee7d5a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Process.cpp
@@ -0,0 +1,81 @@
+// Process.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/StringConvert.h"
+
+#include "Process.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+static UString GetQuotedString(const UString &s)
+{
+ return UString(L'\"') + s + UString(L'\"');
+}
+
+WRes CProcess::Create(LPCWSTR imageName, const UString &params, LPCWSTR curDir)
+{
+ Close();
+ const UString params2 =
+ #ifndef UNDER_CE
+ GetQuotedString(imageName) + L' ' +
+ #endif
+ params;
+ #ifdef UNDER_CE
+ curDir = 0;
+ #else
+ imageName = 0;
+ #endif
+ PROCESS_INFORMATION pi;
+ BOOL result;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ STARTUPINFOA si;
+ si.cb = sizeof(si);
+ si.lpReserved = 0;
+ si.lpDesktop = 0;
+ si.lpTitle = 0;
+ si.dwFlags = 0;
+ si.cbReserved2 = 0;
+ si.lpReserved2 = 0;
+
+ CSysString curDirA;
+ if (curDir != 0)
+ curDirA = GetSystemString(curDir);
+ result = ::CreateProcessA(NULL, (LPSTR)(LPCSTR)GetSystemString(params2),
+ NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi);
+ }
+ else
+ #endif
+ {
+ STARTUPINFOW si;
+ si.cb = sizeof(si);
+ si.lpReserved = 0;
+ si.lpDesktop = 0;
+ si.lpTitle = 0;
+ si.dwFlags = 0;
+ si.cbReserved2 = 0;
+ si.lpReserved2 = 0;
+
+ result = CreateProcessW(imageName, (LPWSTR)(LPCWSTR)params2,
+ NULL, NULL, FALSE, 0, NULL, (LPWSTR)curDir, &si, &pi);
+ }
+ if (result == 0)
+ return ::GetLastError();
+ ::CloseHandle(pi.hThread);
+ _handle = pi.hProcess;
+ return 0;
+}
+
+WRes MyCreateProcess(LPCWSTR imageName, const UString &params)
+{
+ CProcess process;
+ return process.Create(imageName, params, 0);
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/Windows/Process.h b/src/libs/7zip/win/CPP/Windows/Process.h
new file mode 100644
index 000000000..5b01c377a
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Process.h
@@ -0,0 +1,100 @@
+// Windows/Process.h
+
+#ifndef __WINDOWS_PROCESS_H
+#define __WINDOWS_PROCESS_H
+
+#include <psapi.h>
+
+#include "../Common/MyString.h"
+
+#include "Defs.h"
+#include "Handle.h"
+
+namespace NWindows {
+
+class CProcess: public CHandle
+{
+public:
+ bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId)
+ {
+ _handle = ::OpenProcess(desiredAccess, inheritHandle, processId);
+ return (_handle != 0);
+ }
+
+ #ifndef UNDER_CE
+
+ bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(_handle, lpExitCode)); }
+ bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(_handle, exitCode)); }
+ #if(WINVER >= 0x0500)
+ DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(_handle, uiFlags); }
+ #endif
+ bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(_handle, dwPriorityClass)); }
+ DWORD GetPriorityClass() { return ::GetPriorityClass(_handle); }
+ bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(_handle, lpIoCounters )); }
+
+ bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime)
+ { return BOOLToBool(::GetProcessTimes(_handle, creationTime, exitTime, kernelTime, userTime)); }
+
+ DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(_handle, milliseconds); }
+
+ // Debug
+
+ bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead)
+ { return BOOLToBool(::ReadProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesRead)); }
+
+ bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten)
+ { return BOOLToBool(::WriteProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesWritten)); }
+
+ bool FlushInstructionCache(LPCVOID baseAddress = 0, SIZE_T size = 0)
+ { return BOOLToBool(::FlushInstructionCache(_handle, baseAddress, size)); }
+
+ LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect)
+ { return VirtualAllocEx(_handle, address, size, allocationType, protect); }
+
+ bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType)
+ { return BOOLToBool(::VirtualFreeEx(_handle, address, size, freeType)); }
+
+ // Process Status API (PSAPI)
+
+ bool EmptyWorkingSet()
+ { return BOOLToBool(::EmptyWorkingSet(_handle)); }
+ bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes)
+ { return BOOLToBool(::EnumProcessModules(_handle, hModules, arraySizeInBytes, receivedBytes)); }
+
+ DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size)
+ { return ::GetModuleBaseName(_handle, hModule, baseName, size); }
+ bool MyGetModuleBaseName(HMODULE hModule, CSysString &name)
+ {
+ const int length = 1000;
+ DWORD resultLen = MyGetModuleBaseName(hModule, name.GetBuffer(length), length);
+ name.ReleaseBuffer();
+ return (resultLen != 0);
+ }
+
+ DWORD MyGetModuleFileNameEx(HMODULE hModule, LPTSTR baseName, DWORD size)
+ { return ::GetModuleFileNameEx(_handle, hModule, baseName, size); }
+ bool MyGetModuleFileNameEx(HMODULE hModule, CSysString &name)
+ {
+ const int length = MAX_PATH + 100;
+ DWORD resultLen = MyGetModuleFileNameEx(hModule, name.GetBuffer(length), length);
+ name.ReleaseBuffer();
+ return (resultLen != 0);
+ }
+
+ bool GetModuleInformation(HMODULE hModule, LPMODULEINFO moduleInfo)
+ { return BOOLToBool(::GetModuleInformation(_handle, hModule, moduleInfo, sizeof(MODULEINFO))); }
+ bool GetMemoryInfo(PPROCESS_MEMORY_COUNTERS memCounters)
+ { return BOOLToBool(::GetProcessMemoryInfo(_handle, memCounters, sizeof(PROCESS_MEMORY_COUNTERS))); }
+
+ #endif
+
+ WRes Create(LPCWSTR imageName, const UString &params, LPCWSTR curDir);
+
+ DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); }
+};
+
+WRes MyCreateProcess(LPCWSTR imageName, const UString &params);
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/ProcessMessages.cpp b/src/libs/7zip/win/CPP/Windows/ProcessMessages.cpp
new file mode 100644
index 000000000..0f48aee25
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/ProcessMessages.cpp
@@ -0,0 +1,22 @@
+// Windows/ProcessMessages.cpp
+
+#include "StdAfx.h"
+
+#include "ProcessMessages.h"
+
+namespace NWindows {
+
+void ProcessMessages(HWND window)
+{
+ MSG msg;
+ while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
+ {
+ if (window == (HWND) NULL || !IsDialogMessage(window, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+}
diff --git a/src/libs/7zip/win/CPP/Windows/ProcessMessages.h b/src/libs/7zip/win/CPP/Windows/ProcessMessages.h
new file mode 100644
index 000000000..63f8ec8a0
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/ProcessMessages.h
@@ -0,0 +1,14 @@
+// Windows/ProcessMessages.h
+
+#ifndef __WINDOWS_PROCESSMESSAGES_H
+#define __WINDOWS_PROCESSMESSAGES_H
+
+namespace NWindows {
+
+void ProcessMessages(HWND window);
+
+}
+
+#endif
+
+
diff --git a/src/libs/7zip/win/CPP/Windows/PropVariant.cpp b/src/libs/7zip/win/CPP/Windows/PropVariant.cpp
new file mode 100644
index 000000000..90212e08f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/PropVariant.cpp
@@ -0,0 +1,243 @@
+// Windows/PropVariant.cpp
+
+#include "StdAfx.h"
+
+#include "PropVariant.h"
+
+#include "../Common/Defs.h"
+
+namespace NWindows {
+namespace NCOM {
+
+CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
+{
+ vt = VT_EMPTY;
+ InternalCopy(&varSrc);
+}
+
+CPropVariant::CPropVariant(const CPropVariant &varSrc)
+{
+ vt = VT_EMPTY;
+ InternalCopy(&varSrc);
+}
+
+CPropVariant::CPropVariant(BSTR bstrSrc)
+{
+ vt = VT_EMPTY;
+ *this = bstrSrc;
+}
+
+CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
+{
+ vt = VT_EMPTY;
+ *this = lpszSrc;
+}
+
+CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
+{
+ InternalCopy(&varSrc);
+ return *this;
+}
+CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
+{
+ InternalCopy(&varSrc);
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
+{
+ *this = (LPCOLESTR)bstrSrc;
+ return *this;
+}
+
+static const char *kMemException = "out of memory";
+
+CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc)
+{
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ bstrVal = ::SysAllocString(lpszSrc);
+ if (bstrVal == NULL && lpszSrc != NULL)
+ {
+ throw kMemException;
+ // vt = VT_ERROR;
+ // scode = E_OUTOFMEMORY;
+ }
+ return *this;
+}
+
+
+CPropVariant& CPropVariant::operator=(const char *s)
+{
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ UINT len = (UINT)strlen(s);
+ bstrVal = ::SysAllocStringByteLen(0, (UINT)len * sizeof(OLECHAR));
+ if (bstrVal == NULL)
+ {
+ throw kMemException;
+ // vt = VT_ERROR;
+ // scode = E_OUTOFMEMORY;
+ }
+ else
+ {
+ for (UINT i = 0; i <= len; i++)
+ bstrVal[i] = s[i];
+ }
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(bool bSrc)
+{
+ if (vt != VT_BOOL)
+ {
+ InternalClear();
+ vt = VT_BOOL;
+ }
+ boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
+ return *this;
+}
+
+#define SET_PROP_FUNC(type, id, dest) \
+ CPropVariant& CPropVariant::operator=(type value) \
+ { if (vt != id) { InternalClear(); vt = id; } \
+ dest = value; return *this; }
+
+SET_PROP_FUNC(Byte, VT_UI1, bVal)
+SET_PROP_FUNC(Int16, VT_I2, iVal)
+SET_PROP_FUNC(Int32, VT_I4, lVal)
+SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
+SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
+SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime)
+
+static HRESULT MyPropVariantClear(PROPVARIANT *prop)
+{
+ switch(prop->vt)
+ {
+ case VT_UI1:
+ case VT_I1:
+ case VT_I2:
+ case VT_UI2:
+ case VT_BOOL:
+ case VT_I4:
+ case VT_UI4:
+ case VT_R4:
+ case VT_INT:
+ case VT_UINT:
+ case VT_ERROR:
+ case VT_FILETIME:
+ case VT_UI8:
+ case VT_R8:
+ case VT_CY:
+ case VT_DATE:
+ prop->vt = VT_EMPTY;
+ prop->wReserved1 = 0;
+ return S_OK;
+ }
+ return ::VariantClear((VARIANTARG *)prop);
+}
+
+HRESULT CPropVariant::Clear()
+{
+ return MyPropVariantClear(this);
+}
+
+HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc)
+{
+ ::VariantClear((tagVARIANT *)this);
+ switch(pSrc->vt)
+ {
+ case VT_UI1:
+ case VT_I1:
+ case VT_I2:
+ case VT_UI2:
+ case VT_BOOL:
+ case VT_I4:
+ case VT_UI4:
+ case VT_R4:
+ case VT_INT:
+ case VT_UINT:
+ case VT_ERROR:
+ case VT_FILETIME:
+ case VT_UI8:
+ case VT_R8:
+ case VT_CY:
+ case VT_DATE:
+ memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
+ return S_OK;
+ }
+ return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
+}
+
+
+HRESULT CPropVariant::Attach(PROPVARIANT *pSrc)
+{
+ HRESULT hr = Clear();
+ if (FAILED(hr))
+ return hr;
+ memcpy(this, pSrc, sizeof(PROPVARIANT));
+ pSrc->vt = VT_EMPTY;
+ return S_OK;
+}
+
+HRESULT CPropVariant::Detach(PROPVARIANT *pDest)
+{
+ HRESULT hr = MyPropVariantClear(pDest);
+ if (FAILED(hr))
+ return hr;
+ memcpy(pDest, this, sizeof(PROPVARIANT));
+ vt = VT_EMPTY;
+ return S_OK;
+}
+
+HRESULT CPropVariant::InternalClear()
+{
+ HRESULT hr = Clear();
+ if (FAILED(hr))
+ {
+ vt = VT_ERROR;
+ scode = hr;
+ }
+ return hr;
+}
+
+void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
+{
+ HRESULT hr = Copy(pSrc);
+ if (FAILED(hr))
+ {
+ if (hr == E_OUTOFMEMORY)
+ throw kMemException;
+ vt = VT_ERROR;
+ scode = hr;
+ }
+}
+
+int CPropVariant::Compare(const CPropVariant &a)
+{
+ if (vt != a.vt)
+ return MyCompare(vt, a.vt);
+ switch (vt)
+ {
+ case VT_EMPTY: return 0;
+ // case VT_I1: return MyCompare(cVal, a.cVal);
+ case VT_UI1: return MyCompare(bVal, a.bVal);
+ case VT_I2: return MyCompare(iVal, a.iVal);
+ case VT_UI2: return MyCompare(uiVal, a.uiVal);
+ case VT_I4: return MyCompare(lVal, a.lVal);
+ case VT_UI4: return MyCompare(ulVal, a.ulVal);
+ // case VT_UINT: return MyCompare(uintVal, a.uintVal);
+ case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
+ case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
+ case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
+ case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime);
+ case VT_BSTR:
+ return 0; // Not implemented
+ // return MyCompare(aPropVarint.cVal);
+ default: return 0;
+ }
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/PropVariant.h b/src/libs/7zip/win/CPP/Windows/PropVariant.h
new file mode 100644
index 000000000..d018034eb
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/PropVariant.h
@@ -0,0 +1,56 @@
+// Windows/PropVariant.h
+
+#ifndef __WINDOWS_PROPVARIANT_H
+#define __WINDOWS_PROPVARIANT_H
+
+#include "../Common/MyWindows.h"
+#include "../Common/Types.h"
+
+namespace NWindows {
+namespace NCOM {
+
+class CPropVariant : public tagPROPVARIANT
+{
+public:
+ CPropVariant() { vt = VT_EMPTY; wReserved1 = 0; }
+ ~CPropVariant() { Clear(); }
+ CPropVariant(const PROPVARIANT &varSrc);
+ CPropVariant(const CPropVariant &varSrc);
+ CPropVariant(BSTR bstrSrc);
+ CPropVariant(LPCOLESTR lpszSrc);
+ CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); };
+ CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; }
+ CPropVariant(Int16 value) { vt = VT_I2; wReserved1 = 0; iVal = value; }
+ CPropVariant(Int32 value) { vt = VT_I4; wReserved1 = 0; lVal = value; }
+ CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; }
+ CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; }
+ CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; }
+
+ CPropVariant& operator=(const CPropVariant &varSrc);
+ CPropVariant& operator=(const PROPVARIANT &varSrc);
+ CPropVariant& operator=(BSTR bstrSrc);
+ CPropVariant& operator=(LPCOLESTR lpszSrc);
+ CPropVariant& operator=(const char *s);
+ CPropVariant& operator=(bool bSrc);
+ CPropVariant& operator=(Byte value);
+ CPropVariant& operator=(Int16 value);
+ CPropVariant& operator=(Int32 value);
+ CPropVariant& operator=(UInt32 value);
+ CPropVariant& operator=(Int64 value);
+ CPropVariant& operator=(UInt64 value);
+ CPropVariant& operator=(const FILETIME &value);
+
+ HRESULT Clear();
+ HRESULT Copy(const PROPVARIANT *pSrc);
+ HRESULT Attach(PROPVARIANT *pSrc);
+ HRESULT Detach(PROPVARIANT *pDest);
+
+ HRESULT InternalClear();
+ void InternalCopy(const PROPVARIANT *pSrc);
+
+ int Compare(const CPropVariant &a1);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/PropVariantConversions.cpp b/src/libs/7zip/win/CPP/Windows/PropVariantConversions.cpp
new file mode 100644
index 000000000..2d8456cd6
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/PropVariantConversions.cpp
@@ -0,0 +1,105 @@
+// PropVariantConversions.cpp
+
+#include "StdAfx.h"
+
+#include "Common/IntToString.h"
+#include "Common/StringConvert.h"
+
+#include "Windows/Defs.h"
+
+#include "PropVariantConversions.h"
+
+static UString ConvertUInt64ToString(UInt64 value)
+{
+ wchar_t buffer[32];
+ ConvertUInt64ToString(value, buffer);
+ return buffer;
+}
+
+static UString ConvertInt64ToString(Int64 value)
+{
+ wchar_t buffer[32];
+ ConvertInt64ToString(value, buffer);
+ return buffer;
+}
+
+static char *UIntToStringSpec(char c, UInt32 value, char *s, int numPos)
+{
+ if (c != 0)
+ *s++ = c;
+ char temp[16];
+ int pos = 0;
+ do
+ {
+ temp[pos++] = (char)('0' + value % 10);
+ value /= 10;
+ }
+ while (value != 0);
+ int i;
+ for (i = 0; i < numPos - pos; i++)
+ *s++ = '0';
+ do
+ *s++ = temp[--pos];
+ while (pos > 0);
+ *s = '\0';
+ return s;
+}
+
+bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime, bool includeSeconds)
+{
+ s[0] = '\0';
+ SYSTEMTIME st;
+ if (!BOOLToBool(FileTimeToSystemTime(&ft, &st)))
+ return false;
+ s = UIntToStringSpec(0, st.wYear, s, 4);
+ s = UIntToStringSpec('-', st.wMonth, s, 2);
+ s = UIntToStringSpec('-', st.wDay, s, 2);
+ if (includeTime)
+ {
+ s = UIntToStringSpec(' ', st.wHour, s, 2);
+ s = UIntToStringSpec(':', st.wMinute, s, 2);
+ if (includeSeconds)
+ UIntToStringSpec(':', st.wSecond, s, 2);
+ }
+ return true;
+}
+
+UString ConvertFileTimeToString(const FILETIME &ft, bool includeTime, bool includeSeconds)
+{
+ char s[32];
+ ConvertFileTimeToString(ft, s, includeTime, includeSeconds);
+ return GetUnicodeString(s);
+}
+
+
+UString ConvertPropVariantToString(const PROPVARIANT &prop)
+{
+ switch (prop.vt)
+ {
+ case VT_EMPTY: return UString();
+ case VT_BSTR: return prop.bstrVal;
+ case VT_UI1: return ConvertUInt64ToString(prop.bVal);
+ case VT_UI2: return ConvertUInt64ToString(prop.uiVal);
+ case VT_UI4: return ConvertUInt64ToString(prop.ulVal);
+ case VT_UI8: return ConvertUInt64ToString(prop.uhVal.QuadPart);
+ case VT_FILETIME: return ConvertFileTimeToString(prop.filetime, true, true);
+ // case VT_I1: return ConvertInt64ToString(prop.cVal);
+ case VT_I2: return ConvertInt64ToString(prop.iVal);
+ case VT_I4: return ConvertInt64ToString(prop.lVal);
+ case VT_I8: return ConvertInt64ToString(prop.hVal.QuadPart);
+ case VT_BOOL: return VARIANT_BOOLToBool(prop.boolVal) ? L"+" : L"-";
+ default: throw 150245;
+ }
+}
+
+UInt64 ConvertPropVariantToUInt64(const PROPVARIANT &prop)
+{
+ switch (prop.vt)
+ {
+ case VT_UI1: return prop.bVal;
+ case VT_UI2: return prop.uiVal;
+ case VT_UI4: return prop.ulVal;
+ case VT_UI8: return (UInt64)prop.uhVal.QuadPart;
+ default: throw 151199;
+ }
+}
diff --git a/src/libs/7zip/win/CPP/Windows/PropVariantConversions.h b/src/libs/7zip/win/CPP/Windows/PropVariantConversions.h
new file mode 100644
index 000000000..3de4dedb3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/PropVariantConversions.h
@@ -0,0 +1,14 @@
+// Windows/PropVariantConversions.h
+
+#ifndef __PROP_VARIANT_CONVERSIONS_H
+#define __PROP_VARIANT_CONVERSIONS_H
+
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime = true, bool includeSeconds = true);
+UString ConvertFileTimeToString(const FILETIME &ft, bool includeTime = true, bool includeSeconds = true);
+UString ConvertPropVariantToString(const PROPVARIANT &prop);
+UInt64 ConvertPropVariantToUInt64(const PROPVARIANT &prop);
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/PropVariantUtils.cpp b/src/libs/7zip/win/CPP/Windows/PropVariantUtils.cpp
new file mode 100644
index 000000000..0a9cfab7f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/PropVariantUtils.cpp
@@ -0,0 +1,78 @@
+// PropVariantUtils.cpp
+
+#include "StdAfx.h"
+
+#include "PropVariantUtils.h"
+#include "Common/StringConvert.h"
+#include "Common/IntToString.h"
+
+using namespace NWindows;
+
+static AString GetHex(UInt32 v)
+{
+ char sz[32] = { '0', 'x' };
+ ConvertUInt64ToString(v, sz + 2, 16);
+ return sz;
+}
+
+void StringToProp(const AString &s, NCOM::CPropVariant &prop)
+{
+ prop = MultiByteToUnicodeString(s);
+}
+
+void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NCOM::CPropVariant &prop)
+{
+ AString s;
+ for (unsigned i = 0; i < num; i++)
+ {
+ const CUInt32PCharPair &p = pairs[i];
+ if (p.Value == value)
+ s = p.Name;
+ }
+ if (s.IsEmpty())
+ s = GetHex(value);
+ StringToProp(s, prop);
+}
+
+AString TypeToString(const char *table[], unsigned num, UInt32 value)
+{
+ if (value < num)
+ return table[value];
+ return GetHex(value);
+}
+
+void TypeToProp(const char *table[], unsigned num, UInt32 value, NCOM::CPropVariant &prop)
+{
+ StringToProp(TypeToString(table, num, value), prop);
+}
+
+
+AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags)
+{
+ AString s;
+ for (unsigned i = 0; i < num; i++)
+ {
+ const CUInt32PCharPair &p = pairs[i];
+ UInt32 flag = (UInt32)1 << (unsigned)p.Value;
+ if ((flags & flag) != 0)
+ {
+ if (!s.IsEmpty())
+ s += ' ';
+ s += p.Name;
+ }
+ flags &= ~flag;
+ }
+ if (flags != 0)
+ {
+ if (!s.IsEmpty())
+ s += ' ';
+ s += GetHex(flags);
+ }
+ return s;
+}
+
+void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM::CPropVariant &prop)
+{
+ StringToProp(FlagsToString(pairs, num, flags), prop);
+}
+
diff --git a/src/libs/7zip/win/CPP/Windows/PropVariantUtils.h b/src/libs/7zip/win/CPP/Windows/PropVariantUtils.h
new file mode 100644
index 000000000..5aaf65cb9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/PropVariantUtils.h
@@ -0,0 +1,28 @@
+// Windows/PropVariantUtils.h
+
+#ifndef __PROP_VARIANT_UTILS_H
+#define __PROP_VARIANT_UTILS_H
+
+#include "Common/MyString.h"
+#include "PropVariant.h"
+
+struct CUInt32PCharPair
+{
+ UInt32 Value;
+ const char *Name;
+};
+
+void StringToProp(const AString &s, NWindows::NCOM::CPropVariant &prop);
+void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop);
+
+AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags);
+void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop);
+
+AString TypeToString(const char *table[], unsigned num, UInt32 value);
+void TypeToProp(const char *table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop);
+
+#define PAIR_TO_PROP(pairs, value, prop) PairToProp(pairs, sizeof(pairs) / sizeof(pairs[0]), value, prop)
+#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, sizeof(pairs) / sizeof(pairs[0]), value, prop)
+#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, sizeof(table) / sizeof(table[0]), value, prop)
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Registry.cpp b/src/libs/7zip/win/CPP/Windows/Registry.cpp
new file mode 100644
index 000000000..8b25375d9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Registry.cpp
@@ -0,0 +1,369 @@
+// Windows/Registry.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+#include "Windows/Registry.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NRegistry {
+
+#define MYASSERT(expr) // _ASSERTE(expr)
+
+LONG CKey::Create(HKEY parentKey, LPCTSTR keyName,
+ LPTSTR keyClass, DWORD options, REGSAM accessMask,
+ LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition)
+{
+ MYASSERT(parentKey != NULL);
+ DWORD dispositionReal;
+ HKEY key = NULL;
+ LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass,
+ options, accessMask, securityAttributes, &key, &dispositionReal);
+ if (disposition != NULL)
+ *disposition = dispositionReal;
+ if (res == ERROR_SUCCESS)
+ {
+ res = Close();
+ _object = key;
+ }
+ return res;
+}
+
+LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask)
+{
+ MYASSERT(parentKey != NULL);
+ HKEY key = NULL;
+ LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key);
+ if (res == ERROR_SUCCESS)
+ {
+ res = Close();
+ MYASSERT(res == ERROR_SUCCESS);
+ _object = key;
+ }
+ return res;
+}
+
+LONG CKey::Close()
+{
+ LONG res = ERROR_SUCCESS;
+ if (_object != NULL)
+ {
+ res = RegCloseKey(_object);
+ _object = NULL;
+ }
+ return res;
+}
+
+// win95, win98: deletes sunkey and all its subkeys
+// winNT to be deleted must not have subkeys
+LONG CKey::DeleteSubKey(LPCTSTR subKeyName)
+{
+ MYASSERT(_object != NULL);
+ return RegDeleteKey(_object, subKeyName);
+}
+
+LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName)
+{
+ CKey key;
+ LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
+ if (res != ERROR_SUCCESS)
+ return res;
+ FILETIME fileTime;
+ const UInt32 kBufferSize = MAX_PATH + 1; // 256 in ATL
+ DWORD size = kBufferSize;
+ TCHAR buffer[kBufferSize];
+ while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS)
+ {
+ res = key.RecurseDeleteKey(buffer);
+ if (res != ERROR_SUCCESS)
+ return res;
+ size = kBufferSize;
+ }
+ key.Close();
+ return DeleteSubKey(subKeyName);
+}
+
+
+/////////////////////////
+// Value Functions
+
+static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); }
+static inline bool UINT32ToBool(UInt32 value) { return (value != 0); }
+
+
+LONG CKey::DeleteValue(LPCTSTR name)
+{
+ MYASSERT(_object != NULL);
+ return ::RegDeleteValue(_object, name);
+}
+
+#ifndef _UNICODE
+LONG CKey::DeleteValue(LPCWSTR name)
+{
+ MYASSERT(_object != NULL);
+ if (g_IsNT)
+ return ::RegDeleteValueW(_object, name);
+ return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name));
+}
+#endif
+
+LONG CKey::SetValue(LPCTSTR name, UInt32 value)
+{
+ MYASSERT(_object != NULL);
+ return RegSetValueEx(_object, name, NULL, REG_DWORD,
+ (BYTE * const)&value, sizeof(UInt32));
+}
+
+LONG CKey::SetValue(LPCTSTR name, bool value)
+{
+ return SetValue(name, BoolToUINT32(value));
+}
+
+LONG CKey::SetValue(LPCTSTR name, LPCTSTR value)
+{
+ MYASSERT(value != NULL);
+ MYASSERT(_object != NULL);
+ return RegSetValueEx(_object, name, NULL, REG_SZ,
+ (const BYTE * )value, (lstrlen(value) + 1) * sizeof(TCHAR));
+}
+
+/*
+LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
+{
+ MYASSERT(value != NULL);
+ MYASSERT(_object != NULL);
+ return RegSetValueEx(_object, name, NULL, REG_SZ,
+ (const BYTE *)(const TCHAR *)value, (value.Length() + 1) * sizeof(TCHAR));
+}
+*/
+
+#ifndef _UNICODE
+
+LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
+{
+ MYASSERT(value != NULL);
+ MYASSERT(_object != NULL);
+ if (g_IsNT)
+ return RegSetValueExW(_object, name, NULL, REG_SZ,
+ (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t)));
+ return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name),
+ value == 0 ? 0 : (LPCSTR)GetSystemString(value));
+}
+
+#endif
+
+
+LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size)
+{
+ MYASSERT(value != NULL);
+ MYASSERT(_object != NULL);
+ return RegSetValueEx(_object, name, NULL, REG_BINARY,
+ (const BYTE *)value, size);
+}
+
+LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
+{
+ MYASSERT(value != NULL);
+ CKey key;
+ LONG res = key.Create(parentKey, keyName);
+ if (res == ERROR_SUCCESS)
+ res = key.SetValue(valueName, value);
+ return res;
+}
+
+LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
+{
+ MYASSERT(value != NULL);
+ CKey key;
+ LONG res = key.Create(_object, keyName);
+ if (res == ERROR_SUCCESS)
+ res = key.SetValue(valueName, value);
+ return res;
+}
+
+LONG CKey::QueryValue(LPCTSTR name, UInt32 &value)
+{
+ DWORD type = NULL;
+ DWORD count = sizeof(DWORD);
+ LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type,
+ (LPBYTE)&value, &count);
+ MYASSERT((res!=ERROR_SUCCESS) || (type == REG_DWORD));
+ MYASSERT((res!=ERROR_SUCCESS) || (count == sizeof(UInt32)));
+ return res;
+}
+
+LONG CKey::QueryValue(LPCTSTR name, bool &value)
+{
+ UInt32 uintValue = BoolToUINT32(value);
+ LONG res = QueryValue(name, uintValue);
+ value = UINT32ToBool(uintValue);
+ return res;
+}
+
+LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value)
+{
+ UInt32 newVal;
+ LONG res = QueryValue(name, newVal);
+ if (res == ERROR_SUCCESS)
+ value = newVal;
+ return res;
+}
+
+LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value)
+{
+ bool newVal;
+ LONG res = QueryValue(name, newVal);
+ if (res == ERROR_SUCCESS)
+ value = newVal;
+ return res;
+}
+
+LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count)
+{
+ MYASSERT(count != NULL);
+ DWORD type = NULL;
+ LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
+ MYASSERT((res!=ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
+ return res;
+}
+
+LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
+{
+ value.Empty();
+ DWORD type = NULL;
+ UInt32 currentSize = 0;
+ LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&currentSize);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ return res;
+ res = QueryValue(name, value.GetBuffer(currentSize), currentSize);
+ value.ReleaseBuffer();
+ return res;
+}
+
+#ifndef _UNICODE
+LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count)
+{
+ MYASSERT(count != NULL);
+ DWORD type = NULL;
+ LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
+ MYASSERT((res!=ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
+ return res;
+}
+LONG CKey::QueryValue(LPCWSTR name, UString &value)
+{
+ value.Empty();
+ DWORD type = NULL;
+ UInt32 currentSize = 0;
+
+ LONG res;
+ if (g_IsNT)
+ {
+ res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)&currentSize);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ return res;
+ res = QueryValue(name, value.GetBuffer(currentSize), currentSize);
+ value.ReleaseBuffer();
+ }
+ else
+ {
+ AString vTemp;
+ res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp);
+ value = GetUnicodeString(vTemp);
+ }
+ return res;
+}
+#endif
+
+LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count)
+{
+ DWORD type = NULL;
+ LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
+ MYASSERT((res!=ERROR_SUCCESS) || (type == REG_BINARY));
+ return res;
+}
+
+
+LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize)
+{
+ DWORD type = NULL;
+ dataSize = 0;
+ LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&dataSize);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ return res;
+ value.SetCapacity(dataSize);
+ return QueryValue(name, (BYTE *)value, dataSize);
+}
+
+LONG CKey::EnumKeys(CSysStringVector &keyNames)
+{
+ keyNames.Clear();
+ CSysString keyName;
+ for (UInt32 index = 0; ; index++)
+ {
+ const UInt32 kBufferSize = MAX_PATH + 1; // 256 in ATL
+ FILETIME lastWriteTime;
+ UInt32 nameSize = kBufferSize;
+ LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuffer(kBufferSize),
+ (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime);
+ keyName.ReleaseBuffer();
+ if (result == ERROR_NO_MORE_ITEMS)
+ break;
+ if (result != ERROR_SUCCESS)
+ return result;
+ keyNames.Add(keyName);
+ }
+ return ERROR_SUCCESS;
+}
+
+LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
+{
+ UInt32 numChars = 0;
+ int i;
+ for (i = 0; i < strings.Size(); i++)
+ numChars += strings[i].Length() + 1;
+ CBuffer<wchar_t> buffer;
+ buffer.SetCapacity(numChars);
+ int pos = 0;
+ for (i = 0; i < strings.Size(); i++)
+ {
+ const UString &s = strings[i];
+ MyStringCopy((wchar_t *)buffer + pos, (const wchar_t *)s);
+ pos += s.Length() + 1;
+ }
+ return SetValue(valueName, buffer, numChars * sizeof(wchar_t));
+}
+
+LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
+{
+ strings.Clear();
+ CByteBuffer buffer;
+ UInt32 dataSize;
+ LONG res = QueryValue(valueName, buffer, dataSize);
+ if (res != ERROR_SUCCESS)
+ return res;
+ if (dataSize % sizeof(wchar_t) != 0)
+ return E_FAIL;
+ const wchar_t *data = (const wchar_t *)(const Byte *)buffer;
+ int numChars = dataSize / sizeof(wchar_t);
+ UString s;
+ for (int i = 0; i < numChars; i++)
+ {
+ wchar_t c = data[i];
+ if (c == 0)
+ {
+ strings.Add(s);
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ return res;
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/Registry.h b/src/libs/7zip/win/CPP/Windows/Registry.h
new file mode 100644
index 000000000..f0561e688
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Registry.h
@@ -0,0 +1,85 @@
+// Windows/Registry.h
+
+#ifndef __WINDOWS_REGISTRY_H
+#define __WINDOWS_REGISTRY_H
+
+#include "Common/Buffer.h"
+#include "Common/MyString.h"
+#include "Common/Types.h"
+
+namespace NWindows {
+namespace NRegistry {
+
+LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value);
+
+class CKey
+{
+ HKEY _object;
+public:
+ CKey(): _object(NULL) {}
+ ~CKey() { Close(); }
+
+ operator HKEY() const { return _object; }
+ void Attach(HKEY key) { _object = key; }
+ HKEY Detach()
+ {
+ HKEY key = _object;
+ _object = NULL;
+ return key;
+ }
+
+ LONG Create(HKEY parentKey, LPCTSTR keyName,
+ LPTSTR keyClass = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,
+ REGSAM accessMask = KEY_ALL_ACCESS,
+ LPSECURITY_ATTRIBUTES securityAttributes = NULL,
+ LPDWORD disposition = NULL);
+ LONG Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask = KEY_ALL_ACCESS);
+
+ LONG Close();
+
+ LONG DeleteSubKey(LPCTSTR subKeyName);
+ LONG RecurseDeleteKey(LPCTSTR subKeyName);
+
+ LONG DeleteValue(LPCTSTR name);
+ #ifndef _UNICODE
+ LONG DeleteValue(LPCWSTR name);
+ #endif
+
+ LONG SetValue(LPCTSTR valueName, UInt32 value);
+ LONG SetValue(LPCTSTR valueName, bool value);
+ LONG SetValue(LPCTSTR valueName, LPCTSTR value);
+ // LONG SetValue(LPCTSTR valueName, const CSysString &value);
+ #ifndef _UNICODE
+ LONG SetValue(LPCWSTR name, LPCWSTR value);
+ // LONG SetValue(LPCWSTR name, const UString &value);
+ #endif
+
+ LONG SetValue(LPCTSTR name, const void *value, UInt32 size);
+
+ LONG SetValue_Strings(LPCTSTR valueName, const UStringVector &strings);
+ LONG GetValue_Strings(LPCTSTR valueName, UStringVector &strings);
+
+ LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value);
+
+ LONG QueryValue(LPCTSTR name, UInt32 &value);
+ LONG QueryValue(LPCTSTR name, bool &value);
+ LONG QueryValue(LPCTSTR name, LPTSTR value, UInt32 &dataSize);
+ LONG QueryValue(LPCTSTR name, CSysString &value);
+
+ LONG GetValue_IfOk(LPCTSTR name, UInt32 &value);
+ LONG GetValue_IfOk(LPCTSTR name, bool &value);
+
+ #ifndef _UNICODE
+ LONG QueryValue(LPCWSTR name, LPWSTR value, UInt32 &dataSize);
+ LONG QueryValue(LPCWSTR name, UString &value);
+ #endif
+
+ LONG QueryValue(LPCTSTR name, void *value, UInt32 &dataSize);
+ LONG QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize);
+
+ LONG EnumKeys(CSysStringVector &keyNames);
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/ResourceString.cpp b/src/libs/7zip/win/CPP/Windows/ResourceString.cpp
new file mode 100644
index 000000000..781f03b33
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/ResourceString.cpp
@@ -0,0 +1,64 @@
+// Windows/ResourceString.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/ResourceString.h"
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+
+extern HINSTANCE g_hInstance;
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+CSysString MyLoadString(HINSTANCE hInstance, UINT resourceID)
+{
+ CSysString s;
+ int size = 256;
+ int len;
+ do
+ {
+ size += 256;
+ len = ::LoadString(hInstance, resourceID, s.GetBuffer(size - 1), size);
+ }
+ while (size - len <= 1);
+ s.ReleaseBuffer();
+ return s;
+}
+
+CSysString MyLoadString(UINT resourceID)
+{
+ return MyLoadString(g_hInstance, resourceID);
+}
+
+#ifndef _UNICODE
+UString MyLoadStringW(HINSTANCE hInstance, UINT resourceID)
+{
+ if (g_IsNT)
+ {
+ UString s;
+ int size = 256;
+ int len;
+ do
+ {
+ size += 256;
+ len = ::LoadStringW(hInstance, resourceID, s.GetBuffer(size - 1), size);
+ }
+ while (size - len <= 1);
+ s.ReleaseBuffer();
+ return s;
+ }
+ return GetUnicodeString(MyLoadString(hInstance, resourceID));
+}
+
+UString MyLoadStringW(UINT resourceID)
+{
+ return MyLoadStringW(g_hInstance, resourceID);
+}
+
+#endif
+
+}
diff --git a/src/libs/7zip/win/CPP/Windows/ResourceString.h b/src/libs/7zip/win/CPP/Windows/ResourceString.h
new file mode 100644
index 000000000..ac9c5cd5d
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/ResourceString.h
@@ -0,0 +1,22 @@
+// Windows/ResourceString.h
+
+#ifndef __WINDOWS_RESOURCESTRING_H
+#define __WINDOWS_RESOURCESTRING_H
+
+#include "Common/MyString.h"
+
+namespace NWindows {
+
+CSysString MyLoadString(HINSTANCE hInstance, UINT resourceID);
+CSysString MyLoadString(UINT resourceID);
+#ifdef _UNICODE
+inline UString MyLoadStringW(HINSTANCE hInstance, UINT resourceID) { return MyLoadString(hInstance, resourceID); }
+inline UString MyLoadStringW(UINT resourceID) { return MyLoadString(resourceID); }
+#else
+UString MyLoadStringW(HINSTANCE hInstance, UINT resourceID);
+UString MyLoadStringW(UINT resourceID);
+#endif
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Security.cpp b/src/libs/7zip/win/CPP/Windows/Security.cpp
new file mode 100644
index 000000000..6f5bcad35
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Security.cpp
@@ -0,0 +1,179 @@
+// Windows/Security.cpp
+
+#include "StdAfx.h"
+
+#include "Security.h"
+
+namespace NWindows {
+namespace NSecurity {
+
+/*
+bool MyLookupAccountSid(LPCTSTR systemName, PSID sid,
+ CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse)
+{
+ DWORD accountNameSize = 0, domainNameSize = 0;
+
+ if (!::LookupAccountSid(systemName, sid,
+ accountName.GetBuffer(0), &accountNameSize,
+ domainName.GetBuffer(0), &domainNameSize, sidNameUse))
+ {
+ if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return false;
+ }
+ bool result = BOOLToBool(::LookupAccountSid(systemName, sid,
+ accountName.GetBuffer(accountNameSize), &accountNameSize,
+ domainName.GetBuffer(domainNameSize), &domainNameSize, sidNameUse));
+ accountName.ReleaseBuffer();
+ domainName.ReleaseBuffer();
+ return result;
+}
+*/
+
+static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest)
+{
+ int len = (int)wcslen(src);
+ dest->Length = (USHORT)(len * sizeof(WCHAR));
+ dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR));
+ dest->Buffer = src;
+}
+
+/*
+static void MyLookupSids(CPolicy &policy, PSID ps)
+{
+ LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL;
+ LSA_TRANSLATED_NAME *names = NULL;
+ NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names);
+ int res = LsaNtStatusToWinError(nts);
+ LsaFreeMemory(referencedDomains);
+ LsaFreeMemory(names);
+}
+*/
+
+#ifndef _UNICODE
+typedef BOOL (WINAPI * LookupAccountNameWP)(
+ LPCWSTR lpSystemName,
+ LPCWSTR lpAccountName,
+ PSID Sid,
+ LPDWORD cbSid,
+ LPWSTR ReferencedDomainName,
+ LPDWORD cchReferencedDomainName,
+ PSID_NAME_USE peUse
+ );
+#endif
+
+static PSID GetSid(LPWSTR accountName)
+{
+ #ifndef _UNICODE
+ HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll"));
+ if (hModule == NULL)
+ return NULL;
+ LookupAccountNameWP lookupAccountNameW = (LookupAccountNameWP)GetProcAddress(hModule, "LookupAccountNameW");
+ if (lookupAccountNameW == NULL)
+ return NULL;
+ #endif
+
+ DWORD sidLen = 0, domainLen = 0;
+ SID_NAME_USE sidNameUse;
+ if (!
+ #ifdef _UNICODE
+ ::LookupAccountNameW
+ #else
+ lookupAccountNameW
+ #endif
+ (NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse))
+ {
+ if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen);
+ LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR));
+ BOOL res =
+ #ifdef _UNICODE
+ ::LookupAccountNameW
+ #else
+ lookupAccountNameW
+ #endif
+ (NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse);
+ ::HeapFree(GetProcessHeap(), 0, domainName);
+ if (res)
+ return pSid;
+ }
+ }
+ return NULL;
+}
+
+#define MY__SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege"
+
+bool AddLockMemoryPrivilege()
+{
+ CPolicy policy;
+ LSA_OBJECT_ATTRIBUTES attr;
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = NULL;
+ attr.ObjectName = NULL;
+ attr.Attributes = 0;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ if (policy.Open(NULL, &attr,
+ // GENERIC_WRITE)
+ POLICY_ALL_ACCESS)
+ // STANDARD_RIGHTS_REQUIRED,
+ // GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES)
+ != 0)
+ return false;
+ LSA_UNICODE_STRING userRights;
+ wchar_t s[128] = MY__SE_LOCK_MEMORY_NAME;
+ SetLsaString(s, &userRights);
+ WCHAR userName[256 + 2];
+ DWORD size = 256;
+ if (!GetUserNameW(userName, &size))
+ return false;
+ PSID psid = GetSid(userName);
+ if (psid == NULL)
+ return false;
+ bool res = false;
+
+ /*
+ PLSA_UNICODE_STRING userRightsArray;
+ ULONG countOfRights;
+ NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights);
+ if (status != 0)
+ return false;
+ bool finded = false;
+ for (ULONG i = 0; i < countOfRights; i++)
+ {
+ LSA_UNICODE_STRING &ur = userRightsArray[i];
+ if (ur.Length != s.Length() * sizeof(WCHAR))
+ continue;
+ if (wcsncmp(ur.Buffer, s, s.Length()) != 0)
+ continue;
+ finded = true;
+ res = true;
+ break;
+ }
+ if (!finded)
+ */
+ {
+ /*
+ LSA_ENUMERATION_INFORMATION *enums;
+ ULONG countReturned;
+ NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned);
+ if (status == 0)
+ {
+ for (ULONG i = 0; i < countReturned; i++)
+ MyLookupSids(policy, enums[i].Sid);
+ if (enums)
+ ::LsaFreeMemory(enums);
+ res = true;
+ }
+ */
+ NTSTATUS status = policy.AddAccountRights(psid, &userRights);
+ if (status == 0)
+ res = true;
+ // ULONG res = LsaNtStatusToWinError(status);
+ }
+ HeapFree(GetProcessHeap(), 0, psid);
+ return res;
+}
+
+}}
+
diff --git a/src/libs/7zip/win/CPP/Windows/Security.h b/src/libs/7zip/win/CPP/Windows/Security.h
new file mode 100644
index 000000000..ba66de445
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Security.h
@@ -0,0 +1,167 @@
+// Windows/Security.h
+
+#ifndef __WINDOWS_SECURITY_H
+#define __WINDOWS_SECURITY_H
+
+#include <NTSecAPI.h>
+
+#include "Defs.h"
+
+namespace NWindows {
+namespace NSecurity {
+
+class CAccessToken
+{
+ HANDLE _handle;
+public:
+ CAccessToken(): _handle(NULL) {};
+ ~CAccessToken() { Close(); }
+ bool Close()
+ {
+ if (_handle == NULL)
+ return true;
+ bool res = BOOLToBool(::CloseHandle(_handle));
+ if (res)
+ _handle = NULL;
+ return res;
+ }
+
+ bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess)
+ {
+ Close();
+ return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle));
+ }
+
+ /*
+ bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf)
+ {
+ Close();
+ return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle));
+ }
+ */
+
+ bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState,
+ DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength)
+ { return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges),
+ newState, bufferLength, previousState, returnLength)); }
+
+ bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState)
+ { return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); }
+
+ bool AdjustPrivileges(PTOKEN_PRIVILEGES newState)
+ { return AdjustPrivileges(false, newState); }
+
+};
+
+#ifndef _UNICODE
+typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName,
+ PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle);
+typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle);
+typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle,
+ PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights );
+#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
+#endif
+
+struct CPolicy
+{
+protected:
+ LSA_HANDLE _handle;
+ #ifndef _UNICODE
+ HMODULE hModule;
+ #endif
+public:
+ operator LSA_HANDLE() const { return _handle; }
+ CPolicy(): _handle(NULL)
+ {
+ #ifndef _UNICODE
+ hModule = GetModuleHandle(TEXT("Advapi32.dll"));
+ #endif
+ };
+ ~CPolicy() { Close(); }
+
+ NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes,
+ ACCESS_MASK desiredAccess)
+ {
+ #ifndef _UNICODE
+ if (hModule == NULL)
+ return MY_STATUS_NOT_IMPLEMENTED;
+ LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy");
+ if (lsaOpenPolicy == NULL)
+ return MY_STATUS_NOT_IMPLEMENTED;
+ #endif
+
+ Close();
+ return
+ #ifdef _UNICODE
+ ::LsaOpenPolicy
+ #else
+ lsaOpenPolicy
+ #endif
+ (systemName, objectAttributes, desiredAccess, &_handle);
+ }
+
+ NTSTATUS Close()
+ {
+ if (_handle == NULL)
+ return 0;
+
+ #ifndef _UNICODE
+ if (hModule == NULL)
+ return MY_STATUS_NOT_IMPLEMENTED;
+ LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose");
+ if (lsaClose == NULL)
+ return MY_STATUS_NOT_IMPLEMENTED;
+ #endif
+
+ NTSTATUS res =
+ #ifdef _UNICODE
+ ::LsaClose
+ #else
+ lsaClose
+ #endif
+ (_handle);
+ _handle = NULL;
+ return res;
+ }
+
+ NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights,
+ PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned)
+ { return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); }
+
+ NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights)
+ { return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); }
+
+ NTSTATUS LookupSids(ULONG count, PSID* sids,
+ PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names)
+ { return LsaLookupSids(_handle, count, sids, referencedDomains, names); }
+
+ NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
+ {
+ #ifndef _UNICODE
+ if (hModule == NULL)
+ return MY_STATUS_NOT_IMPLEMENTED;
+ LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights");
+ if (lsaAddAccountRights == NULL)
+ return MY_STATUS_NOT_IMPLEMENTED;
+ #endif
+
+ return
+ #ifdef _UNICODE
+ ::LsaAddAccountRights
+ #else
+ lsaAddAccountRights
+ #endif
+ (_handle, accountSid, userRights, countOfRights);
+ }
+ NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights)
+ { return AddAccountRights(accountSid, userRights, 1); }
+
+ NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
+ { return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); }
+};
+
+bool AddLockMemoryPrivilege();
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Shell.cpp b/src/libs/7zip/win/CPP/Windows/Shell.cpp
new file mode 100644
index 000000000..010449fb4
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Shell.cpp
@@ -0,0 +1,335 @@
+// Windows/Shell.cpp
+
+#include "StdAfx.h"
+
+#include "Common/MyCom.h"
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+
+#include "Windows/COM.h"
+#include "Windows/Shell.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NShell {
+
+#ifndef UNDER_CE
+
+// SHGetMalloc is unsupported in Windows Mobile?
+
+void CItemIDList::Free()
+{
+ if (m_Object == NULL)
+ return;
+ CMyComPtr<IMalloc> shellMalloc;
+ if (::SHGetMalloc(&shellMalloc) != NOERROR)
+ throw 41099;
+ shellMalloc->Free(m_Object);
+ m_Object = NULL;
+}
+
+/*
+CItemIDList::(LPCITEMIDLIST itemIDList): m_Object(NULL)
+ { *this = itemIDList; }
+CItemIDList::(const CItemIDList& itemIDList): m_Object(NULL)
+ { *this = itemIDList; }
+
+CItemIDList& CItemIDList::operator=(LPCITEMIDLIST object)
+{
+ Free();
+ if (object != 0)
+ {
+ UINT32 size = GetSize(object);
+ m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
+ if (m_Object != NULL)
+ MoveMemory(m_Object, object, size);
+ }
+ return *this;
+}
+
+CItemIDList& CItemIDList::operator=(const CItemIDList &object)
+{
+ Free();
+ if (object.m_Object != NULL)
+ {
+ UINT32 size = GetSize(object.m_Object);
+ m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
+ if (m_Object != NULL)
+ MoveMemory(m_Object, object.m_Object, size);
+ }
+ return *this;
+}
+*/
+
+/////////////////////////////
+// CDrop
+
+void CDrop::Attach(HDROP object)
+{
+ Free();
+ m_Object = object;
+ m_Assigned = true;
+}
+
+void CDrop::Free()
+{
+ if (m_MustBeFinished && m_Assigned)
+ Finish();
+ m_Assigned = false;
+}
+
+UINT CDrop::QueryCountOfFiles()
+{
+ return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0);
+}
+
+UString CDrop::QueryFileName(UINT fileIndex)
+{
+ UString fileName;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ AString fileNameA;
+ UINT bufferSize = QueryFile(fileIndex, (LPTSTR)NULL, 0);
+ QueryFile(fileIndex, fileNameA.GetBuffer(bufferSize + 2), bufferSize + 1);
+ fileNameA.ReleaseBuffer();
+ fileName = GetUnicodeString(fileNameA);
+ }
+ else
+ #endif
+ {
+ UINT bufferSize = QueryFile(fileIndex, (LPWSTR)NULL, 0);
+ QueryFile(fileIndex, fileName.GetBuffer(bufferSize + 2), bufferSize + 1);
+ fileName.ReleaseBuffer();
+ }
+ return fileName;
+}
+
+void CDrop::QueryFileNames(UStringVector &fileNames)
+{
+ fileNames.Clear();
+ UINT numFiles = QueryCountOfFiles();
+ fileNames.Reserve(numFiles);
+ for (UINT i = 0; i < numFiles; i++)
+ fileNames.Add(QueryFileName(i));
+}
+
+
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path)
+{
+ bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuffer(MAX_PATH * 2)));
+ path.ReleaseBuffer();
+ return result;
+}
+
+#endif
+
+#ifdef UNDER_CE
+
+bool BrowseForFolder(LPBROWSEINFO, CSysString)
+{
+ return false;
+}
+
+bool BrowseForFolder(HWND, LPCTSTR, UINT, LPCTSTR, CSysString &)
+{
+ return false;
+}
+
+bool BrowseForFolder(HWND owner, LPCTSTR title,
+ LPCTSTR initialFolder, CSysString &resultPath)
+{
+ /*
+ // SHBrowseForFolder doesn't work before CE 6.0 ?
+ if (GetProcAddress(LoadLibrary(L"ceshell.dll", L"SHBrowseForFolder") == 0)
+ MessageBoxW(0, L"no", L"", 0);
+ else
+ MessageBoxW(0, L"yes", L"", 0);
+ */
+ /*
+ UString s = L"all files";
+ s += L" (*.*)";
+ return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true);
+ */
+ return false;
+}
+
+#else
+
+bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath)
+{
+ NWindows::NCOM::CComInitializer comInitializer;
+ LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo);
+ if (itemIDList == NULL)
+ return false;
+ CItemIDList itemIDListHolder;
+ itemIDListHolder.Attach(itemIDList);
+ return GetPathFromIDList(itemIDList, resultPath);
+}
+
+
+int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
+{
+ #ifndef UNDER_CE
+ switch(uMsg)
+ {
+ case BFFM_INITIALIZED:
+ {
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, data);
+ break;
+ }
+ /*
+ case BFFM_SELCHANGED:
+ {
+ TCHAR dir[MAX_PATH];
+ if (::SHGetPathFromIDList((LPITEMIDLIST) lp , dir))
+ SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)dir);
+ else
+ SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)TEXT(""));
+ break;
+ }
+ */
+ default:
+ break;
+ }
+ #endif
+ return 0;
+}
+
+
+bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags,
+ LPCTSTR initialFolder, CSysString &resultPath)
+{
+ CSysString displayName;
+ BROWSEINFO browseInfo;
+ browseInfo.hwndOwner = owner;
+ browseInfo.pidlRoot = NULL;
+
+ // there are Unicode/astring problems in WinCE SDK!!!
+ #ifdef UNDER_CE
+ browseInfo.pszDisplayName = (LPSTR)displayName.GetBuffer(MAX_PATH);
+ browseInfo.lpszTitle = (LPCSTR)title;
+ #else
+ browseInfo.pszDisplayName = displayName.GetBuffer(MAX_PATH);
+ browseInfo.lpszTitle = title;
+ #endif
+ browseInfo.ulFlags = ulFlags;
+ browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL;
+ browseInfo.lParam = (LPARAM)initialFolder;
+ return BrowseForFolder(&browseInfo, resultPath);
+}
+
+bool BrowseForFolder(HWND owner, LPCTSTR title,
+ LPCTSTR initialFolder, CSysString &resultPath)
+{
+ return BrowseForFolder(owner, title,
+ #ifndef UNDER_CE
+ BIF_NEWDIALOGSTYLE |
+ #endif
+ BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT, initialFolder, resultPath);
+ // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0)
+}
+
+#ifndef _UNICODE
+
+typedef BOOL (WINAPI * SHGetPathFromIDListWP)(LPCITEMIDLIST pidl, LPWSTR pszPath);
+
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path)
+{
+ path.Empty();
+ SHGetPathFromIDListWP shGetPathFromIDListW = (SHGetPathFromIDListWP)
+ ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW");
+ if (shGetPathFromIDListW == 0)
+ return false;
+ bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuffer(MAX_PATH * 2)));
+ path.ReleaseBuffer();
+ return result;
+}
+
+typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi);
+
+bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath)
+{
+ NWindows::NCOM::CComInitializer comInitializer;
+ SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP)
+ ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW");
+ if (shBrowseForFolderW == 0)
+ return false;
+ LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo);
+ if (itemIDList == NULL)
+ return false;
+ CItemIDList itemIDListHolder;
+ itemIDListHolder.Attach(itemIDList);
+ return GetPathFromIDList(itemIDList, resultPath);
+}
+
+
+int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
+{
+ switch(uMsg)
+ {
+ case BFFM_INITIALIZED:
+ {
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, data);
+ break;
+ }
+ /*
+ case BFFM_SELCHANGED:
+ {
+ wchar_t dir[MAX_PATH * 2];
+
+ if (shGetPathFromIDListW((LPITEMIDLIST)lp , dir))
+ SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir);
+ else
+ SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)L"");
+ break;
+ }
+ */
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+static bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags,
+ LPCWSTR initialFolder, UString &resultPath)
+{
+ UString displayName;
+ BROWSEINFOW browseInfo;
+ browseInfo.hwndOwner = owner;
+ browseInfo.pidlRoot = NULL;
+ browseInfo.pszDisplayName = displayName.GetBuffer(MAX_PATH);
+ browseInfo.lpszTitle = title;
+ browseInfo.ulFlags = ulFlags;
+ browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc2 : NULL;
+ browseInfo.lParam = (LPARAM)initialFolder;
+ return BrowseForFolder(&browseInfo, resultPath);
+}
+
+bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath)
+{
+ if (g_IsNT)
+ return BrowseForFolder(owner, title,
+ BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
+ // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
+ , initialFolder, resultPath);
+ // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0)
+ CSysString s;
+ bool res = BrowseForFolder(owner, GetSystemString(title),
+ BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
+ // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
+ , GetSystemString(initialFolder), s);
+ resultPath = GetUnicodeString(s);
+ return res;
+}
+
+#endif
+
+#endif
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/Shell.h b/src/libs/7zip/win/CPP/Windows/Shell.h
new file mode 100644
index 000000000..d2b39acfe
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Shell.h
@@ -0,0 +1,93 @@
+// Windows/Shell.h
+
+#ifndef __WINDOWS_SHELL_H
+#define __WINDOWS_SHELL_H
+
+#include <windows.h>
+#include <shlobj.h>
+
+#include "Common/MyString.h"
+#include "Windows/Defs.h"
+
+namespace NWindows{
+namespace NShell{
+
+/////////////////////////
+// CItemIDList
+#ifndef UNDER_CE
+
+class CItemIDList
+{
+ LPITEMIDLIST m_Object;
+public:
+ CItemIDList(): m_Object(NULL) {}
+ // CItemIDList(LPCITEMIDLIST itemIDList);
+ // CItemIDList(const CItemIDList& itemIDList);
+ ~CItemIDList() { Free(); }
+ void Free();
+ void Attach(LPITEMIDLIST object)
+ {
+ Free();
+ m_Object = object;
+ }
+ LPITEMIDLIST Detach()
+ {
+ LPITEMIDLIST object = m_Object;
+ m_Object = NULL;
+ return object;
+ }
+ operator LPITEMIDLIST() { return m_Object;}
+ operator LPCITEMIDLIST() const { return m_Object;}
+ LPITEMIDLIST* operator&() { return &m_Object; }
+ LPITEMIDLIST operator->() { return m_Object; }
+
+ // CItemIDList& operator=(LPCITEMIDLIST object);
+ // CItemIDList& operator=(const CItemIDList &object);
+};
+
+/////////////////////////////
+// CDrop
+
+class CDrop
+{
+ HDROP m_Object;
+ bool m_MustBeFinished;
+ bool m_Assigned;
+ void Free();
+public:
+ CDrop(bool mustBeFinished) : m_MustBeFinished(mustBeFinished), m_Assigned(false) {}
+ ~CDrop() { Free(); }
+
+ void Attach(HDROP object);
+ operator HDROP() { return m_Object;}
+ bool QueryPoint(LPPOINT point)
+ { return BOOLToBool(::DragQueryPoint(m_Object, point)); }
+ void Finish() { ::DragFinish(m_Object); }
+ UINT QueryFile(UINT fileIndex, LPTSTR fileName, UINT fileNameSize)
+ { return ::DragQueryFile(m_Object, fileIndex, fileName, fileNameSize); }
+ #ifndef _UNICODE
+ UINT QueryFile(UINT fileIndex, LPWSTR fileName, UINT fileNameSize)
+ { return ::DragQueryFileW(m_Object, fileIndex, fileName, fileNameSize); }
+ #endif
+ UINT QueryCountOfFiles();
+ UString QueryFileName(UINT fileIndex);
+ void QueryFileNames(UStringVector &fileNames);
+};
+
+#endif
+
+/////////////////////////////
+// Functions
+
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path);
+bool BrowseForFolder(LPBROWSEINFO lpbi, CSysString &resultPath);
+bool BrowseForFolder(HWND owner, LPCTSTR title, LPCTSTR initialFolder, CSysString &resultPath);
+
+#ifndef _UNICODE
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path);
+bool BrowseForFolder(LPBROWSEINFO lpbi, UString &resultPath);
+bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath);
+#endif
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/StdAfx.h b/src/libs/7zip/win/CPP/Windows/StdAfx.h
new file mode 100644
index 000000000..8b383c5ba
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../Common/MyWindows.h"
+#include "../Common/NewHandler.h"
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Synchronization.cpp b/src/libs/7zip/win/CPP/Windows/Synchronization.cpp
new file mode 100644
index 000000000..5f86d1eb1
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Synchronization.cpp
@@ -0,0 +1,10 @@
+// Windows/Synchronization.cpp
+
+#include "StdAfx.h"
+
+#include "Synchronization.h"
+
+namespace NWindows {
+namespace NSynchronization {
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/Synchronization.h b/src/libs/7zip/win/CPP/Windows/Synchronization.h
new file mode 100644
index 000000000..dc695f6f3
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Synchronization.h
@@ -0,0 +1,164 @@
+// Windows/Synchronization.h
+
+#ifndef __WINDOWS_SYNCHRONIZATION_H
+#define __WINDOWS_SYNCHRONIZATION_H
+
+#include "../../C/Threads.h"
+
+#include "Defs.h"
+
+#ifdef _WIN32
+#include "Handle.h"
+#endif
+
+namespace NWindows {
+namespace NSynchronization {
+
+class CBaseEvent
+{
+protected:
+ ::CEvent _object;
+public:
+ bool IsCreated() { return Event_IsCreated(&_object) != 0; }
+ operator HANDLE() { return _object; }
+ CBaseEvent() { Event_Construct(&_object); }
+ ~CBaseEvent() { Close(); }
+ WRes Close() { return Event_Close(&_object); }
+ #ifdef _WIN32
+ WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
+ {
+ _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name);
+ if (name == NULL && _object != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+ {
+ _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);
+ if (_object != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ #endif
+
+ WRes Set() { return Event_Set(&_object); }
+ // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); }
+ WRes Reset() { return Event_Reset(&_object); }
+ WRes Lock() { return Event_Wait(&_object); }
+};
+
+class CManualResetEvent: public CBaseEvent
+{
+public:
+ WRes Create(bool initiallyOwn = false)
+ {
+ return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0);
+ }
+ WRes CreateIfNotCreated()
+ {
+ if (IsCreated())
+ return 0;
+ return ManualResetEvent_CreateNotSignaled(&_object);
+ }
+ #ifdef _WIN32
+ WRes CreateWithName(bool initiallyOwn, LPCTSTR name)
+ {
+ return CBaseEvent::Create(true, initiallyOwn, name);
+ }
+ #endif
+};
+
+class CAutoResetEvent: public CBaseEvent
+{
+public:
+ WRes Create()
+ {
+ return AutoResetEvent_CreateNotSignaled(&_object);
+ }
+ WRes CreateIfNotCreated()
+ {
+ if (IsCreated())
+ return 0;
+ return AutoResetEvent_CreateNotSignaled(&_object);
+ }
+};
+
+#ifdef _WIN32
+class CObject: public CHandle
+{
+public:
+ WRes Lock(DWORD timeoutInterval = INFINITE)
+ { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); }
+};
+class CMutex: public CObject
+{
+public:
+ WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
+ {
+ _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name);
+ if (name == NULL && _handle != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ #ifndef UNDER_CE
+ WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+ {
+ _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name);
+ if (_handle != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ #endif
+ WRes Release()
+ {
+ return ::ReleaseMutex(_handle) ? 0 : ::GetLastError();
+ }
+};
+class CMutexLock
+{
+ CMutex *_object;
+public:
+ CMutexLock(CMutex &object): _object(&object) { _object->Lock(); }
+ ~CMutexLock() { _object->Release(); }
+};
+#endif
+
+class CSemaphore
+{
+ ::CSemaphore _object;
+public:
+ CSemaphore() { Semaphore_Construct(&_object); }
+ ~CSemaphore() { Close(); }
+ WRes Close() { return Semaphore_Close(&_object); }
+ operator HANDLE() { return _object; }
+ WRes Create(UInt32 initiallyCount, UInt32 maxCount)
+ {
+ return Semaphore_Create(&_object, initiallyCount, maxCount);
+ }
+ WRes Release() { return Semaphore_Release1(&_object); }
+ WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }
+ WRes Lock() { return Semaphore_Wait(&_object); }
+};
+
+class CCriticalSection
+{
+ ::CCriticalSection _object;
+public:
+ CCriticalSection() { CriticalSection_Init(&_object); }
+ ~CCriticalSection() { CriticalSection_Delete(&_object); }
+ void Enter() { CriticalSection_Enter(&_object); }
+ void Leave() { CriticalSection_Leave(&_object); }
+};
+
+class CCriticalSectionLock
+{
+ CCriticalSection *_object;
+ void Unlock() { _object->Leave(); }
+public:
+ CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }
+ ~CCriticalSectionLock() { Unlock(); }
+};
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/System.cpp b/src/libs/7zip/win/CPP/Windows/System.cpp
new file mode 100644
index 000000000..4bc8d2a3f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/System.cpp
@@ -0,0 +1,72 @@
+// Windows/System.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/Defs.h"
+
+#include "System.h"
+
+namespace NWindows {
+namespace NSystem {
+
+UInt32 GetNumberOfProcessors()
+{
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ return (UInt32)systemInfo.dwNumberOfProcessors;
+}
+
+#ifndef UNDER_CE
+
+#if !defined(_WIN64) && defined(__GNUC__)
+
+typedef struct _MY_MEMORYSTATUSEX {
+ DWORD dwLength;
+ DWORD dwMemoryLoad;
+ DWORDLONG ullTotalPhys;
+ DWORDLONG ullAvailPhys;
+ DWORDLONG ullTotalPageFile;
+ DWORDLONG ullAvailPageFile;
+ DWORDLONG ullTotalVirtual;
+ DWORDLONG ullAvailVirtual;
+ DWORDLONG ullAvailExtendedVirtual;
+} MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX;
+
+#else
+
+#define MY_MEMORYSTATUSEX MEMORYSTATUSEX
+#define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX
+
+#endif
+
+typedef BOOL (WINAPI *GlobalMemoryStatusExP)(MY_LPMEMORYSTATUSEX lpBuffer);
+
+#endif
+
+UInt64 GetRamSize()
+{
+ #ifndef UNDER_CE
+ MY_MEMORYSTATUSEX stat;
+ stat.dwLength = sizeof(stat);
+ #endif
+ #ifdef _WIN64
+ if (!::GlobalMemoryStatusEx(&stat))
+ return 0;
+ return MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
+ #else
+ #ifndef UNDER_CE
+ GlobalMemoryStatusExP globalMemoryStatusEx = (GlobalMemoryStatusExP)
+ ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GlobalMemoryStatusEx");
+ if (globalMemoryStatusEx != 0 && globalMemoryStatusEx(&stat))
+ return MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
+ #endif
+ {
+ MEMORYSTATUS stat;
+ stat.dwLength = sizeof(stat);
+ ::GlobalMemoryStatus(&stat);
+ return MyMin(stat.dwTotalVirtual, stat.dwTotalPhys);
+ }
+ #endif
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/System.h b/src/libs/7zip/win/CPP/Windows/System.h
new file mode 100644
index 000000000..e0067158f
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/System.h
@@ -0,0 +1,16 @@
+// Windows/System.h
+
+#ifndef __WINDOWS_SYSTEM_H
+#define __WINDOWS_SYSTEM_H
+
+#include "../Common/Types.h"
+
+namespace NWindows {
+namespace NSystem {
+
+UInt32 GetNumberOfProcessors();
+UInt64 GetRamSize();
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Thread.h b/src/libs/7zip/win/CPP/Windows/Thread.h
new file mode 100644
index 000000000..16a509d47
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Thread.h
@@ -0,0 +1,38 @@
+// Windows/Thread.h
+
+#ifndef __WINDOWS_THREAD_H
+#define __WINDOWS_THREAD_H
+
+#include "../../C/Threads.h"
+
+#include "Defs.h"
+
+namespace NWindows {
+
+class CThread
+{
+ ::CThread thread;
+public:
+ CThread() { Thread_Construct(&thread); }
+ ~CThread() { Close(); }
+ bool IsCreated() { return Thread_WasCreated(&thread) != 0; }
+ WRes Close() { return Thread_Close(&thread); }
+ WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
+ { return Thread_Create(&thread, startAddress, parameter); }
+ WRes Wait() { return Thread_Wait(&thread); }
+
+ #ifdef _WIN32
+ operator HANDLE() { return thread; }
+ void Attach(HANDLE handle) { thread = handle; }
+ HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; }
+ DWORD Resume() { return ::ResumeThread(thread); }
+ DWORD Suspend() { return ::SuspendThread(thread); }
+ bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); }
+ int GetPriority() { return ::GetThreadPriority(thread); }
+ bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); }
+ #endif
+};
+
+}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Time.cpp b/src/libs/7zip/win/CPP/Windows/Time.cpp
new file mode 100644
index 000000000..ec9ca47d9
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Time.cpp
@@ -0,0 +1,170 @@
+// Windows/Time.cpp
+
+#include "StdAfx.h"
+
+#include "Windows/Defs.h"
+
+#include "Time.h"
+
+namespace NWindows {
+namespace NTime {
+
+static const UInt32 kNumTimeQuantumsInSecond = 10000000;
+static const UInt32 kFileTimeStartYear = 1601;
+static const UInt32 kDosTimeStartYear = 1980;
+static const UInt32 kUnixTimeStartYear = 1970;
+static const UInt64 kUnixTimeStartValue = ((UInt64)kNumTimeQuantumsInSecond) *
+ 60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
+
+bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft)
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft));
+ #else
+ ft.dwLowDateTime = 0;
+ ft.dwHighDateTime = 0;
+ UInt64 res;
+ if (!GetSecondsSince1601(kDosTimeStartYear + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F,
+ (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (dosTime & 0x1F) * 2, res))
+ return false;
+ res *= kNumTimeQuantumsInSecond;
+ ft.dwLowDateTime = (UInt32)res;
+ ft.dwHighDateTime = (UInt32)(res >> 32);
+ return true;
+ #endif
+}
+
+static const UInt32 kHighDosTime = 0xFF9FBF7D;
+static const UInt32 kLowDosTime = 0x210000;
+
+#define PERIOD_4 (4 * 365 + 1)
+#define PERIOD_100 (PERIOD_4 * 25 - 1)
+#define PERIOD_400 (PERIOD_100 * 4 + 1)
+
+bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime)
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+
+ WORD datePart, timePart;
+ if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart))
+ {
+ dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime;
+ return false;
+ }
+ dosTime = (((UInt32)datePart) << 16) + timePart;
+
+ #else
+
+ unsigned year, mon, day, hour, min, sec;
+ UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32);
+ Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ unsigned temp;
+ UInt32 v;
+ v64 += (kNumTimeQuantumsInSecond * 2 - 1);
+ v64 /= kNumTimeQuantumsInSecond;
+ sec = (unsigned)(v64 % 60);
+ v64 /= 60;
+ min = (unsigned)(v64 % 60);
+ v64 /= 60;
+ hour = (unsigned)(v64 % 24);
+ v64 /= 24;
+
+ v = (UInt32)v64;
+
+ year = (unsigned)(kFileTimeStartYear + v / PERIOD_400 * 400);
+ v %= PERIOD_400;
+
+ temp = (unsigned)(v / PERIOD_100);
+ if (temp == 4)
+ temp = 3;
+ year += temp * 100;
+ v -= temp * PERIOD_100;
+
+ temp = v / PERIOD_4;
+ if (temp == 25)
+ temp = 24;
+ year += temp * 4;
+ v -= temp * PERIOD_4;
+
+ temp = v / 365;
+ if (temp == 4)
+ temp = 3;
+ year += temp;
+ v -= temp * 365;
+
+ if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+ ms[1] = 29;
+ for (mon = 1; mon <= 12; mon++)
+ {
+ unsigned s = ms[mon - 1];
+ if (v < s)
+ break;
+ v -= s;
+ }
+ day = (unsigned)v + 1;
+
+ dosTime = kLowDosTime;
+ if (year < kDosTimeStartYear)
+ return false;
+ year -= kDosTimeStartYear;
+ dosTime = kHighDosTime;
+ if (year >= 128)
+ return false;
+ dosTime = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1);
+ #endif
+ return true;
+}
+
+void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft)
+{
+ UInt64 v = kUnixTimeStartValue + ((UInt64)unixTime) * kNumTimeQuantumsInSecond;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+bool FileTimeToUnixTime(const FILETIME &ft, UInt32 &unixTime)
+{
+ UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+ if (winTime < kUnixTimeStartValue)
+ {
+ unixTime = 0;
+ return false;
+ }
+ winTime = (winTime - kUnixTimeStartValue) / kNumTimeQuantumsInSecond;
+ if (winTime > 0xFFFFFFFF)
+ {
+ unixTime = 0xFFFFFFFF;
+ return false;
+ }
+ unixTime = (UInt32)winTime;
+ return true;
+}
+
+bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
+ unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds)
+{
+ resSeconds = 0;
+ if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 ||
+ day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59)
+ return false;
+ UInt32 numYears = year - kFileTimeStartYear;
+ UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400;
+ Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+ ms[1] = 29;
+ month--;
+ for (unsigned i = 0; i < month; i++)
+ numDays += ms[i];
+ numDays += day - 1;
+ resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec;
+ return true;
+}
+
+void GetCurUtcFileTime(FILETIME &ft)
+{
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+}
+
+}}
diff --git a/src/libs/7zip/win/CPP/Windows/Time.h b/src/libs/7zip/win/CPP/Windows/Time.h
new file mode 100644
index 000000000..6f510b22b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Time.h
@@ -0,0 +1,21 @@
+// Windows/Time.h
+
+#ifndef __WINDOWS_TIME_H
+#define __WINDOWS_TIME_H
+
+#include "Common/Types.h"
+
+namespace NWindows {
+namespace NTime {
+
+bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime);
+bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime);
+void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime);
+bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime);
+bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
+ unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds);
+void GetCurUtcFileTime(FILETIME &ft);
+
+}}
+
+#endif
diff --git a/src/libs/7zip/win/CPP/Windows/Window.cpp b/src/libs/7zip/win/CPP/Windows/Window.cpp
new file mode 100644
index 000000000..3ad29e6d7
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Window.cpp
@@ -0,0 +1,169 @@
+// Windows/Window.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "Common/StringConvert.h"
+#endif
+#include "Windows/Window.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+#ifndef _UNICODE
+ATOM MyRegisterClass(CONST WNDCLASSW *wndClass)
+{
+ if (g_IsNT)
+ return RegisterClassW(wndClass);
+ WNDCLASSA wndClassA;
+ wndClassA.style = wndClass->style;
+ wndClassA.lpfnWndProc = wndClass->lpfnWndProc;
+ wndClassA.cbClsExtra = wndClass->cbClsExtra;
+ wndClassA.cbWndExtra = wndClass->cbWndExtra;
+ wndClassA.hInstance = wndClass->hInstance;
+ wndClassA.hIcon = wndClass->hIcon;
+ wndClassA.hCursor = wndClass->hCursor;
+ wndClassA.hbrBackground = wndClass->hbrBackground;
+ AString menuName;
+ AString className;
+ if (IS_INTRESOURCE(wndClass->lpszMenuName))
+ wndClassA.lpszMenuName = (LPCSTR)wndClass->lpszMenuName;
+ else
+ {
+ menuName = GetSystemString(wndClass->lpszMenuName);
+ wndClassA.lpszMenuName = menuName;
+ }
+ if (IS_INTRESOURCE(wndClass->lpszClassName))
+ wndClassA.lpszClassName = (LPCSTR)wndClass->lpszClassName;
+ else
+ {
+ className = GetSystemString(wndClass->lpszClassName);
+ wndClassA.lpszClassName = className;
+ }
+ return RegisterClassA(&wndClassA);
+}
+
+bool CWindow::Create(LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+{
+ if (g_IsNT)
+ {
+ _window = ::CreateWindowW(className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+ return (_window != NULL);
+ }
+ return Create(GetSystemString(className), GetSystemString(windowName),
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+}
+
+bool CWindow::CreateEx(DWORD exStyle, LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+{
+ if (g_IsNT)
+ {
+ _window = ::CreateWindowExW(exStyle, className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+ return (_window != NULL);
+ }
+ AString classNameA;
+ LPCSTR classNameP;
+ if (IS_INTRESOURCE(className))
+ classNameP = (LPCSTR)className;
+ else
+ {
+ classNameA = GetSystemString(className);
+ classNameP = classNameA;
+ }
+ AString windowNameA;
+ LPCSTR windowNameP;
+ if (IS_INTRESOURCE(windowName))
+ windowNameP = (LPCSTR)windowName;
+ else
+ {
+ windowNameA = GetSystemString(windowName);
+ windowNameP = windowNameA;
+ }
+ return CreateEx(exStyle, classNameP, windowNameP,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+}
+
+#endif
+
+#ifndef _UNICODE
+bool MySetWindowText(HWND wnd, LPCWSTR s)
+{
+ if (g_IsNT)
+ return BOOLToBool(::SetWindowTextW(wnd, s));
+ return BOOLToBool(::SetWindowTextA(wnd, UnicodeStringToMultiByte(s)));
+}
+#endif
+
+bool CWindow::GetText(CSysString &s)
+{
+ s.Empty();
+ int length = GetTextLength();
+ if (length == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ length = GetText(s.GetBuffer(length), length + 1);
+ s.ReleaseBuffer();
+ if (length == 0)
+ return (::GetLastError() != ERROR_SUCCESS);
+ return true;
+}
+
+#ifndef _UNICODE
+bool CWindow::GetText(UString &s)
+{
+ if (g_IsNT)
+ {
+ s.Empty();
+ int length = GetWindowTextLengthW(_window);
+ if (length == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ length = GetWindowTextW(_window, s.GetBuffer(length), length + 1);
+ s.ReleaseBuffer();
+ if (length == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ return true;
+ }
+ CSysString sysString;
+ bool result = GetText(sysString);
+ s = GetUnicodeString(sysString);
+ return result;
+}
+#endif
+
+
+/*
+bool CWindow::ModifyStyleBase(int styleOffset,
+ DWORD remove, DWORD add, UINT flags)
+{
+ DWORD style = GetWindowLong(styleOffset);
+ DWORD newStyle = (style & ~remove) | add;
+ if (style == newStyle)
+ return false; // it is not good
+
+ SetWindowLong(styleOffset, newStyle);
+ if (flags != 0)
+ {
+ ::SetWindowPos(_window, NULL, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | flags);
+ }
+ return TRUE;
+}
+*/
+
+}
diff --git a/src/libs/7zip/win/CPP/Windows/Window.h b/src/libs/7zip/win/CPP/Windows/Window.h
new file mode 100644
index 000000000..729b0f24b
--- /dev/null
+++ b/src/libs/7zip/win/CPP/Windows/Window.h
@@ -0,0 +1,261 @@
+// Windows/Window.h
+
+#ifndef __WINDOWS_WINDOW_H
+#define __WINDOWS_WINDOW_H
+
+#include "Defs.h"
+#include "Common/MyString.h"
+
+namespace NWindows {
+
+inline ATOM MyRegisterClass(CONST WNDCLASS *wndClass)
+ { return ::RegisterClass(wndClass); }
+
+#ifndef _UNICODE
+ATOM MyRegisterClass(CONST WNDCLASSW *wndClass);
+#endif
+
+#ifdef _UNICODE
+inline bool MySetWindowText(HWND wnd, LPCWSTR s) { return BOOLToBool(::SetWindowText(wnd, s)); }
+#else
+bool MySetWindowText(HWND wnd, LPCWSTR s);
+#endif
+
+
+#ifdef UNDER_CE
+#define GWLP_USERDATA GWL_USERDATA
+#define GWLP_WNDPROC GWL_WNDPROC
+#define BTNS_BUTTON TBSTYLE_BUTTON
+#define WC_COMBOBOXW L"ComboBox"
+#define DWLP_MSGRESULT DWL_MSGRESULT
+#endif
+
+class CWindow
+{
+private:
+ // bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags);
+protected:
+ HWND _window;
+public:
+ CWindow(HWND newWindow = NULL): _window(newWindow){};
+ CWindow& operator=(HWND newWindow)
+ {
+ _window = newWindow;
+ return *this;
+ }
+ operator HWND() const { return _window; }
+ void Attach(HWND newWindow) { _window = newWindow; }
+ HWND Detach()
+ {
+ HWND window = _window;
+ _window = NULL;
+ return window;
+ }
+
+ bool Foreground() { return BOOLToBool(::SetForegroundWindow(_window)); }
+
+ HWND GetParent() const { return ::GetParent(_window); }
+ bool GetWindowRect(LPRECT rect) const { return BOOLToBool(::GetWindowRect(_window,rect)); }
+ #ifndef UNDER_CE
+ bool IsZoomed() const { return BOOLToBool(::IsZoomed(_window)); }
+ #endif
+ bool ClientToScreen(LPPOINT point) const { return BOOLToBool(::ClientToScreen(_window, point)); }
+ bool ScreenToClient(LPPOINT point) const { return BOOLToBool(::ScreenToClient(_window, point)); }
+
+ bool CreateEx(DWORD exStyle, LPCTSTR className,
+ LPCTSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+ {
+ _window = ::CreateWindowEx(exStyle, className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+ return (_window != NULL);
+ }
+
+ bool Create(LPCTSTR className,
+ LPCTSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+ {
+ _window = ::CreateWindow(className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+ return (_window != NULL);
+ }
+
+ #ifndef _UNICODE
+ bool Create(LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam);
+ bool CreateEx(DWORD exStyle, LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam);
+ #endif
+
+
+ bool Destroy()
+ {
+ if (_window == NULL)
+ return true;
+ bool result = BOOLToBool(::DestroyWindow(_window));
+ if (result)
+ _window = NULL;
+ return result;
+ }
+ bool IsWindow() { return BOOLToBool(::IsWindow(_window)); }
+ bool Move(int x, int y, int width, int height, bool repaint = true)
+ { return BOOLToBool(::MoveWindow(_window, x, y, width, height, BoolToBOOL(repaint))); }
+
+ bool ChangeSubWindowSizeX(HWND hwnd, int xSize)
+ {
+ RECT rect;
+ ::GetWindowRect(hwnd, &rect);
+ POINT p1;
+ p1.x = rect.left;
+ p1.y = rect.top;
+ ScreenToClient(&p1);
+ return BOOLToBool(::MoveWindow(hwnd, p1.x, p1.y, xSize, rect.bottom - rect.top, TRUE));
+ }
+
+ void ScreenToClient(RECT *rect)
+ {
+ POINT p1, p2;
+ p1.x = rect->left;
+ p1.y = rect->top;
+ p2.x = rect->right;
+ p2.y = rect->bottom;
+ ScreenToClient(&p1);
+ ScreenToClient(&p2);
+
+ rect->left = p1.x;
+ rect->top = p1.y;
+ rect->right = p2.x;
+ rect->bottom = p2.y;
+ }
+
+ bool GetClientRect(LPRECT rect) { return BOOLToBool(::GetClientRect(_window, rect)); }
+ bool Show(int cmdShow) { return BOOLToBool(::ShowWindow(_window, cmdShow)); }
+ #ifndef UNDER_CE
+ bool SetPlacement(CONST WINDOWPLACEMENT *placement) { return BOOLToBool(::SetWindowPlacement(_window, placement)); }
+ bool GetPlacement(WINDOWPLACEMENT *placement) { return BOOLToBool(::GetWindowPlacement(_window, placement)); }
+ #endif
+ bool Update() { return BOOLToBool(::UpdateWindow(_window)); }
+ bool InvalidateRect(LPCRECT rect, bool backgroundErase = true)
+ { return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); }
+ void SetRedraw(bool redraw = true) { SendMessage(WM_SETREDRAW, BoolToBOOL(redraw), 0); }
+
+ LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, style); }
+ LONG_PTR GetStyle() const { return GetLongPtr(GWL_STYLE); }
+ // bool MyIsMaximized() const { return ((GetStyle() & WS_MAXIMIZE) != 0); }
+
+ LONG_PTR SetLong(int index, LONG newLongPtr) { return ::SetWindowLong(_window, index, newLongPtr); }
+ LONG_PTR GetLong(int index) const { return ::GetWindowLong(_window, index); }
+ LONG_PTR SetUserDataLong(LONG newLongPtr) { return SetLong(GWLP_USERDATA, newLongPtr); }
+ LONG_PTR GetUserDataLong() const { return GetLong(GWLP_USERDATA); }
+
+
+ #ifdef UNDER_CE
+
+ LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) { return SetLong(index, newLongPtr); }
+ LONG_PTR GetLongPtr(int index) const { return GetLong(index); }
+
+ LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetUserDataLong(newLongPtr); }
+ LONG_PTR GetUserDataLongPtr() const { return GetUserDataLong(); }
+
+ #else
+
+ LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr)
+ { return ::SetWindowLongPtr(_window, index,
+ #ifndef _WIN64
+ (LONG)
+ #endif
+ newLongPtr); }
+ #ifndef _UNICODE
+ LONG_PTR SetLongPtrW(int index, LONG_PTR newLongPtr)
+ { return ::SetWindowLongPtrW(_window, index,
+ #ifndef _WIN64
+ (LONG)
+ #endif
+ newLongPtr); }
+ #endif
+
+ LONG_PTR GetLongPtr(int index) const { return ::GetWindowLongPtr(_window, index); }
+ LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetLongPtr(GWLP_USERDATA, newLongPtr); }
+ LONG_PTR GetUserDataLongPtr() const { return GetLongPtr(GWLP_USERDATA); }
+
+ #endif
+
+ /*
+ bool ModifyStyle(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0)
+ { return ModifyStyleBase(GWL_STYLE, remove, add, flags); }
+ bool ModifyStyleEx(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0)
+ { return ModifyStyleBase(GWL_EXSTYLE, remove, add, flags); }
+ */
+
+ HWND SetFocus() { return ::SetFocus(_window); }
+
+ LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return ::SendMessage(_window, message, wParam, lParam) ;}
+ #ifndef _UNICODE
+ LRESULT SendMessageW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return ::SendMessageW(_window, message, wParam, lParam) ;}
+ #endif
+
+ bool PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return BOOLToBool(::PostMessage(_window, message, wParam, lParam)) ;}
+ #ifndef _UNICODE
+ LRESULT PostMessageW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return ::PostMessageW(_window, message, wParam, lParam) ;}
+ #endif
+
+ bool SetText(LPCTSTR s) { return BOOLToBool(::SetWindowText(_window, s)); }
+ #ifndef _UNICODE
+ bool CWindow::SetText(LPCWSTR s) { return MySetWindowText(_window, s); }
+ #endif
+
+ int GetTextLength() const
+ { return GetWindowTextLength(_window); }
+ UINT GetText(LPTSTR string, int maxCount) const
+ { return GetWindowText(_window, string, maxCount); }
+ bool GetText(CSysString &s);
+ #ifndef _UNICODE
+ /*
+ UINT GetText(LPWSTR string, int maxCount) const
+ { return GetWindowTextW(_window, string, maxCount); }
+ */
+ bool GetText(UString &s);
+ #endif
+
+ bool Enable(bool enable)
+ { return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); }
+
+ bool IsEnabled()
+ { return BOOLToBool(::IsWindowEnabled(_window)); }
+
+ #ifndef UNDER_CE
+ HMENU GetSystemMenu(bool revert)
+ { return ::GetSystemMenu(_window, BoolToBOOL(revert)); }
+ #endif
+
+ UINT_PTR SetTimer(UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = 0)
+ { return ::SetTimer(_window, idEvent, elapse, timerFunc); }
+ bool KillTimer(UINT_PTR idEvent)
+ {return BOOLToBool(::KillTimer(_window, idEvent)); }
+
+ HICON SetIcon(WPARAM sizeType, HICON icon) { return (HICON)SendMessage(WM_SETICON, sizeType, (LPARAM)icon); }
+};
+
+#define RECT_SIZE_X(r) ((r).right - (r).left)
+#define RECT_SIZE_Y(r) ((r).bottom - (r).top)
+
+}
+
+#endif
+
diff --git a/src/libs/7zip/win/DOC/7zC.txt b/src/libs/7zip/win/DOC/7zC.txt
new file mode 100644
index 000000000..5d5d06d7b
--- /dev/null
+++ b/src/libs/7zip/win/DOC/7zC.txt
@@ -0,0 +1,194 @@
+7z ANSI-C Decoder 4.62
+----------------------
+
+7z ANSI-C provides 7z/LZMA decoding.
+7z ANSI-C version is simplified version ported from C++ code.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+
+LICENSE
+-------
+
+7z ANSI-C Decoder is part of the LZMA SDK.
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+Files
+---------------------
+
+7zDecode.* - Low level 7z decoding
+7zExtract.* - High level 7z decoding
+7zHeader.* - .7z format constants
+7zIn.* - .7z archive opening
+7zItem.* - .7z structures
+7zMain.c - Test application
+
+
+How To Use
+----------
+
+You must download 7-Zip program from www.7-zip.org.
+
+You can create .7z archive with 7z.exe or 7za.exe:
+
+ 7za.exe a archive.7z *.htm -r -mx -m0fb=255
+
+If you have big number of files in archive, and you need fast extracting,
+you can use partly-solid archives:
+
+ 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
+
+In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
+512KB for extracting one file from such archive.
+
+
+Limitations of current version of 7z ANSI-C Decoder
+---------------------------------------------------
+
+ - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
+ - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
+ - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
+
+These limitations will be fixed in future versions.
+
+
+Using 7z ANSI-C Decoder Test application:
+-----------------------------------------
+
+Usage: 7zDec <command> <archive_name>
+
+<Command>:
+ e: Extract files from archive
+ l: List contents of archive
+ t: Test integrity of archive
+
+Example:
+
+ 7zDec l archive.7z
+
+lists contents of archive.7z
+
+ 7zDec e archive.7z
+
+extracts files from archive.7z to current folder.
+
+
+How to use .7z Decoder
+----------------------
+
+Memory allocation
+~~~~~~~~~~~~~~~~~
+
+7z Decoder uses two memory pools:
+1) Temporary pool
+2) Main pool
+Such scheme can allow you to avoid fragmentation of allocated blocks.
+
+
+Steps for using 7z decoder
+--------------------------
+
+Use code at 7zMain.c as example.
+
+1) Declare variables:
+ inStream /* implements ILookInStream interface */
+ CSzArEx db; /* 7z archive database structure */
+ ISzAlloc allocImp; /* memory functions for main pool */
+ ISzAlloc allocTempImp; /* memory functions for temporary pool */
+
+2) call CrcGenerateTable(); function to initialize CRC structures.
+
+3) call SzArEx_Init(&db); function to initialize db structures.
+
+4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive
+
+This function opens archive "inStream" and reads headers to "db".
+All items in "db" will be allocated with "allocMain" functions.
+SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
+
+5) List items or Extract items
+
+ Listing code:
+ ~~~~~~~~~~~~~
+ {
+ UInt32 i;
+ for (i = 0; i < db.db.NumFiles; i++)
+ {
+ CFileItem *f = db.db.Files + i;
+ printf("%10d %s\n", (int)f->Size, f->Name);
+ }
+ }
+
+ Extracting code:
+ ~~~~~~~~~~~~~~~~
+
+ SZ_RESULT SzAr_Extract(
+ CArchiveDatabaseEx *db,
+ ILookInStream *inStream,
+ UInt32 fileIndex, /* index of file */
+ UInt32 *blockIndex, /* index of solid block */
+ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
+ size_t *outBufferSize, /* buffer size for output buffer */
+ size_t *offset, /* offset of stream for required file in *outBuffer */
+ size_t *outSizeProcessed, /* size of file in *outBuffer */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp);
+
+ If you need to decompress more than one file, you can send these values from previous call:
+ blockIndex,
+ outBuffer,
+ outBufferSize,
+ You can consider "outBuffer" as cache of solid block. If your archive is solid,
+ it will increase decompression speed.
+
+ After decompressing you must free "outBuffer":
+ allocImp.Free(outBuffer);
+
+6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
+
+
+
+
+Memory requirements for .7z decoding
+------------------------------------
+
+Memory usage for Archive opening:
+ - Temporary pool:
+ - Memory for uncompressed .7z headers
+ - some other temporary blocks
+ - Main pool:
+ - Memory for database:
+ Estimated size of one file structures in solid archive:
+ - Size (4 or 8 Bytes)
+ - CRC32 (4 bytes)
+ - LastWriteTime (8 bytes)
+ - Some file information (4 bytes)
+ - File Name (variable length) + pointer + allocation structures
+
+Memory usage for archive Decompressing:
+ - Temporary pool:
+ - Memory for LZMA decompressing structures
+ - Main pool:
+ - Memory for decompressed solid block
+ - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
+ temprorary buffers can be about 15% of solid block size.
+
+
+7z Decoder doesn't allocate memory for compressed blocks.
+Instead of this, you must allocate buffer with desired
+size before calling 7z Decoder. Use 7zMain.c as example.
+
+
+Defines
+-------
+
+_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/src/libs/7zip/win/DOC/7zFormat.txt b/src/libs/7zip/win/DOC/7zFormat.txt
new file mode 100644
index 000000000..55b52b1b9
--- /dev/null
+++ b/src/libs/7zip/win/DOC/7zFormat.txt
@@ -0,0 +1,469 @@
+7z Format description (4.59)
+----------------------------
+
+This file contains description of 7z archive format.
+7z archive can contain files compressed with any method.
+See "Methods.txt" for description for defined compressing methods.
+
+
+Format structure Overview
+-------------------------
+
+Some fields can be optional.
+
+Archive structure
+~~~~~~~~~~~~~~~~~
+SignatureHeader
+[PackedStreams]
+[PackedStreamsForHeaders]
+[
+ Header
+ or
+ {
+ Packed Header
+ HeaderInfo
+ }
+]
+
+
+
+Header structure
+~~~~~~~~~~~~~~~~
+{
+ ArchiveProperties
+ AdditionalStreams
+ {
+ PackInfo
+ {
+ PackPos
+ NumPackStreams
+ Sizes[NumPackStreams]
+ CRCs[NumPackStreams]
+ }
+ CodersInfo
+ {
+ NumFolders
+ Folders[NumFolders]
+ {
+ NumCoders
+ CodersInfo[NumCoders]
+ {
+ ID
+ NumInStreams;
+ NumOutStreams;
+ PropertiesSize
+ Properties[PropertiesSize]
+ }
+ NumBindPairs
+ BindPairsInfo[NumBindPairs]
+ {
+ InIndex;
+ OutIndex;
+ }
+ PackedIndices
+ }
+ UnPackSize[Folders][Folders.NumOutstreams]
+ CRCs[NumFolders]
+ }
+ SubStreamsInfo
+ {
+ NumUnPackStreamsInFolders[NumFolders];
+ UnPackSizes[]
+ CRCs[]
+ }
+ }
+ MainStreamsInfo
+ {
+ (Same as in AdditionalStreams)
+ }
+ FilesInfo
+ {
+ NumFiles
+ Properties[]
+ {
+ ID
+ Size
+ Data
+ }
+ }
+}
+
+HeaderInfo structure
+~~~~~~~~~~~~~~~~~~~~
+{
+ (Same as in AdditionalStreams)
+}
+
+
+
+Notes about Notation and encoding
+---------------------------------
+
+7z uses little endian encoding.
+
+7z archive format has optional headers that are marked as
+[]
+Header
+[]
+
+REAL_UINT64 means real UINT64.
+
+UINT64 means real UINT64 encoded with the following scheme:
+
+ Size of encoding sequence depends from first byte:
+ First_Byte Extra_Bytes Value
+ (binary)
+ 0xxxxxxx : ( xxxxxxx )
+ 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
+ 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
+ ...
+ 1111110x BYTE y[6] : ( x << (8 * 6)) + y
+ 11111110 BYTE y[7] : y
+ 11111111 BYTE y[8] : y
+
+
+
+Property IDs
+------------
+
+0x00 = kEnd
+
+0x01 = kHeader
+
+0x02 = kArchiveProperties
+
+0x03 = kAdditionalStreamsInfo
+0x04 = kMainStreamsInfo
+0x05 = kFilesInfo
+
+0x06 = kPackInfo
+0x07 = kUnPackInfo
+0x08 = kSubStreamsInfo
+
+0x09 = kSize
+0x0A = kCRC
+
+0x0B = kFolder
+
+0x0C = kCodersUnPackSize
+0x0D = kNumUnPackStream
+
+0x0E = kEmptyStream
+0x0F = kEmptyFile
+0x10 = kAnti
+
+0x11 = kName
+0x12 = kCTime
+0x13 = kATime
+0x14 = kMTime
+0x15 = kWinAttributes
+0x16 = kComment
+
+0x17 = kEncodedHeader
+
+0x18 = kStartPos
+0x19 = kDummy
+
+
+7z format headers
+-----------------
+
+SignatureHeader
+~~~~~~~~~~~~~~~
+ BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+ ArchiveVersion
+ {
+ BYTE Major; // now = 0
+ BYTE Minor; // now = 2
+ };
+
+ UINT32 StartHeaderCRC;
+
+ StartHeader
+ {
+ REAL_UINT64 NextHeaderOffset
+ REAL_UINT64 NextHeaderSize
+ UINT32 NextHeaderCRC
+ }
+
+
+...........................
+
+
+ArchiveProperties
+~~~~~~~~~~~~~~~~~
+BYTE NID::kArchiveProperties (0x02)
+for (;;)
+{
+ BYTE PropertyType;
+ if (aType == 0)
+ break;
+ UINT64 PropertySize;
+ BYTE PropertyData[PropertySize];
+}
+
+
+Digests (NumStreams)
+~~~~~~~~~~~~~~~~~~~~~
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumStreams)
+ BIT Defined
+ }
+ UINT32 CRCs[NumDefined]
+
+
+PackInfo
+~~~~~~~~~~~~
+ BYTE NID::kPackInfo (0x06)
+ UINT64 PackPos
+ UINT64 NumPackStreams
+
+ []
+ BYTE NID::kSize (0x09)
+ UINT64 PackSizes[NumPackStreams]
+ []
+
+ []
+ BYTE NID::kCRC (0x0A)
+ PackStreamDigests[NumPackStreams]
+ []
+
+ BYTE NID::kEnd
+
+
+Folder
+~~~~~~
+ UINT64 NumCoders;
+ for (NumCoders)
+ {
+ BYTE
+ {
+ 0:3 CodecIdSize
+ 4: Is Complex Coder
+ 5: There Are Attributes
+ 6: Reserved
+ 7: There are more alternative methods. (Not used anymore, must be 0).
+ }
+ BYTE CodecId[CodecIdSize]
+ if (Is Complex Coder)
+ {
+ UINT64 NumInStreams;
+ UINT64 NumOutStreams;
+ }
+ if (There Are Attributes)
+ {
+ UINT64 PropertiesSize
+ BYTE Properties[PropertiesSize]
+ }
+ }
+
+ NumBindPairs = NumOutStreamsTotal - 1;
+
+ for (NumBindPairs)
+ {
+ UINT64 InIndex;
+ UINT64 OutIndex;
+ }
+
+ NumPackedStreams = NumInStreamsTotal - NumBindPairs;
+ if (NumPackedStreams > 1)
+ for(NumPackedStreams)
+ {
+ UINT64 Index;
+ };
+
+
+
+
+Coders Info
+~~~~~~~~~~~
+
+ BYTE NID::kUnPackInfo (0x07)
+
+
+ BYTE NID::kFolder (0x0B)
+ UINT64 NumFolders
+ BYTE External
+ switch(External)
+ {
+ case 0:
+ Folders[NumFolders]
+ case 1:
+ UINT64 DataStreamIndex
+ }
+
+
+ BYTE ID::kCodersUnPackSize (0x0C)
+ for(Folders)
+ for(Folder.NumOutStreams)
+ UINT64 UnPackSize;
+
+
+ []
+ BYTE NID::kCRC (0x0A)
+ UnPackDigests[NumFolders]
+ []
+
+
+
+ BYTE NID::kEnd
+
+
+
+SubStreams Info
+~~~~~~~~~~~~~~
+ BYTE NID::kSubStreamsInfo; (0x08)
+
+ []
+ BYTE NID::kNumUnPackStream; (0x0D)
+ UINT64 NumUnPackStreamsInFolders[NumFolders];
+ []
+
+
+ []
+ BYTE NID::kSize (0x09)
+ UINT64 UnPackSizes[]
+ []
+
+
+ []
+ BYTE NID::kCRC (0x0A)
+ Digests[Number of streams with unknown CRC]
+ []
+
+
+ BYTE NID::kEnd
+
+
+Streams Info
+~~~~~~~~~~~~
+
+ []
+ PackInfo
+ []
+
+
+ []
+ CodersInfo
+ []
+
+
+ []
+ SubStreamsInfo
+ []
+
+ BYTE NID::kEnd
+
+
+FilesInfo
+~~~~~~~~~
+ BYTE NID::kFilesInfo; (0x05)
+ UINT64 NumFiles
+
+ for (;;)
+ {
+ BYTE PropertyType;
+ if (aType == 0)
+ break;
+
+ UINT64 Size;
+
+ switch(PropertyType)
+ {
+ kEmptyStream: (0x0E)
+ for(NumFiles)
+ BIT IsEmptyStream
+
+ kEmptyFile: (0x0F)
+ for(EmptyStreams)
+ BIT IsEmptyFile
+
+ kAnti: (0x10)
+ for(EmptyStreams)
+ BIT IsAntiFile
+
+ case kCTime: (0x12)
+ case kATime: (0x13)
+ case kMTime: (0x14)
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumFiles)
+ BIT TimeDefined
+ }
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Definded Items)
+ UINT64 Time
+ []
+
+ kNames: (0x11)
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Files)
+ {
+ wchar_t Names[NameSize];
+ wchar_t 0;
+ }
+ []
+
+ kAttributes: (0x15)
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumFiles)
+ BIT AttributesAreDefined
+ }
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Definded Attributes)
+ UINT32 Attributes
+ []
+ }
+ }
+
+
+Header
+~~~~~~
+ BYTE NID::kHeader (0x01)
+
+ []
+ ArchiveProperties
+ []
+
+ []
+ BYTE NID::kAdditionalStreamsInfo; (0x03)
+ StreamsInfo
+ []
+
+ []
+ BYTE NID::kMainStreamsInfo; (0x04)
+ StreamsInfo
+ []
+
+ []
+ FilesInfo
+ []
+
+ BYTE NID::kEnd
+
+
+HeaderInfo
+~~~~~~~~~~
+ []
+ BYTE NID::kEncodedHeader; (0x17)
+ StreamsInfo for Encoded Header
+ []
+
+
+---
+End of document
diff --git a/src/libs/7zip/win/DOC/License.txt b/src/libs/7zip/win/DOC/License.txt
new file mode 100644
index 000000000..a6a721853
--- /dev/null
+++ b/src/libs/7zip/win/DOC/License.txt
@@ -0,0 +1,52 @@
+ 7-Zip source code
+ ~~~~~~~~~~~~~~~~~
+ License for use and distribution
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ 7-Zip Copyright (C) 1999-2010 Igor Pavlov.
+
+ Licenses for files are:
+
+ 1) CPP/7zip/Compress/Rar* files: GNU LGPL + unRAR restriction
+ 2) All other files: GNU LGPL
+
+ The GNU LGPL + unRAR restriction means that you must follow both
+ GNU LGPL rules and unRAR restriction rules.
+
+
+ GNU LGPL information
+ --------------------
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ unRAR restriction
+ -----------------
+
+ The decompression engine for RAR archives was developed using source
+ code of unRAR program.
+ All copyrights to original unRAR code are owned by Alexander Roshal.
+
+ The license for original unRAR code has the following restriction:
+
+ The unRAR sources cannot be used to re-create the RAR compression algorithm,
+ which is proprietary. Distribution of modified unRAR sources in separate form
+ or as a part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+
+ --
+ Igor Pavlov
diff --git a/src/libs/7zip/win/DOC/Methods.txt b/src/libs/7zip/win/DOC/Methods.txt
new file mode 100644
index 000000000..f52e7c315
--- /dev/null
+++ b/src/libs/7zip/win/DOC/Methods.txt
@@ -0,0 +1,152 @@
+7-Zip method IDs (9.18)
+-----------------------
+
+Each compression or crypto method in 7z has unique binary value (ID).
+The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes).
+
+If you want to add some new ID, you have two ways:
+1) Write request for allocating IDs to 7-zip developers.
+2) Generate 8-bytes ID:
+
+ 3F ZZ ZZ ZZ ZZ ZZ MM MM
+
+ 3F - Prefix for random IDs (1 byte)
+ ZZ ZZ ZZ ZZ ZZ - Developer ID (5 bytes). Use real random bytes.
+
+ MM MM - Method ID (2 bytes)
+
+ You can notify 7-Zip developers about your Developer ID / Method ID.
+
+ Note: Use new ID only if old codec can not decode data encoded with new version.
+
+
+List of defined IDs
+-------------------
+
+00 - Copy
+
+03 - Delta
+04 - x86 (BCJ)
+05 - PPC (Big Endian)
+06 - IA64
+07 - ARM (little endian)
+08 - ARM Thumb (little endian)
+09 - SPARC
+21 - LZMA2
+
+02.. - Common
+ 03 Swap
+ - 2 Swap2
+ - 4 Swap4
+
+03.. - 7z
+ 01 - LZMA
+ 01 - Version
+
+ 03 - Branch
+ 01 - x86
+ 03 - BCJ
+ 1B - BCJ2
+ 02 - PPC
+ 05 - PPC (Big Endian)
+ 03 - Alpha
+ 01 - Alpha
+ 04 - IA64
+ 01 - IA64
+ 05 - ARM
+ 01 - ARM
+ 06 - M68
+ 05 - M68 (Big Endian)
+ 07 - ARM Thumb
+ 01 - ARMT
+ 08 - SPARC
+ 05 - SPARC
+
+ 04 - PPMD
+ 01 - Version
+
+ 7F -
+ 01 - experimental methods.
+
+
+04.. - Misc
+ 00 - Reserved
+ 01 - Zip
+ 00 - Copy (not used). Use {00} instead
+ 01 - Shrink
+ 06 - Implode
+ 08 - Deflate
+ 09 - Deflate64
+ 10 - Imploding
+ 12 - BZip2 (not used). Use {04 02 02} instead
+ 14 - LZMA
+ 60 - Jpeg
+ 61 - WavPack
+ 62 - PPMd
+ 63 - wzAES
+ 02 - BZip
+ 02 - BZip2
+ 03 - Rar
+ 01 - Rar15
+ 02 - Rar20
+ 03 - Rar29
+ 04 - Arj
+ 01 - Arj (1,2,3)
+ 02 - Arj 4
+ 05 - Z
+ 06 - Lzh
+ 07 - Reserved for 7z
+ 08 - Cab
+ 09 - NSIS
+ 01 - DeflateNSIS
+ 02 - BZip2NSIS
+
+
+06.. - Crypto
+ 00 -
+ 01 - AES
+ 0x - AES-128
+ 4x - AES-192
+ 8x - AES-256
+ Cx - AES
+
+ x0 - ECB
+ x1 - CBC
+ x2 - CFB
+ x3 - OFB
+
+ 07 - Reserved
+ 0F - Reserved
+
+ F0 - Misc Ciphers (Real Ciphers without hashing algo)
+
+ F1 - Misc Ciphers (Combine)
+ 01 - Zip
+ 01 - Main Zip crypto algo
+ 03 - RAR
+ 02 -
+ 03 - Rar29 AES-128 + (modified SHA-1)
+ 07 - 7z
+ 01 - AES-256 + SHA-256
+
+07.. - Hash (subject to change)
+ 00 -
+ 01 - CRC
+ 02 - SHA-1
+ 03 - SHA-256
+ 04 - SHA-384
+ 05 - SHA-512
+
+ F0 - Misc Hash
+
+ F1 - Misc
+ 03 - RAR
+ 03 - Rar29 Password Hashing (modified SHA1)
+ 07 - 7z
+ 01 - SHA-256 Password Hashing
+
+
+
+
+---
+End of document
diff --git a/src/libs/7zip/win/DOC/copying.txt b/src/libs/7zip/win/DOC/copying.txt
new file mode 100644
index 000000000..4c3890127
--- /dev/null
+++ b/src/libs/7zip/win/DOC/copying.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/libs/7zip/win/DOC/history.txt b/src/libs/7zip/win/DOC/history.txt
new file mode 100644
index 000000000..05a9a2165
--- /dev/null
+++ b/src/libs/7zip/win/DOC/history.txt
@@ -0,0 +1,456 @@
+Sources history of the 7-Zip
+----------------------------
+
+9.18 2010-11-02
+-------------------------
+- New small SFX module for installers (C/Util/SfxSetup).
+
+
+9.17 2010-10-04
+-------------------------
+- IStream.h::IOutStream::
+ STDMETHOD(SetSize)(Int64 newSize) PURE;
+ was changed to
+ STDMETHOD(SetSize)(UInt64 newSize) PURE;
+
+
+9.09 2009-12-12
+-------------------------
+- The bug was fixed:
+ Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c
+ incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
+
+
+9.05 2009-07-05
+-------------------------
+- FileMapping.h::CFileMapping now returns WRes
+
+
+9.04 2009-05-30
+-------------------------
+- ICoder.h: NCoderPropID::EEnum values were changed
+
+
+9.02 2009-04-23
+-------------------------
+- Bug was fixed: if swap2 filter was requests at compression,
+ 7-zip used swap4 filter instead (but id was swap2), so archives were incorrect.
+
+4.61 2008-11-23
+-------------------------
+- Bug in ver. 4.58+ was fixed:
+ 7-Zip didn't use any -m* switch after -mtc, -mcl or -mcu for .zip archives.
+- Bug in .CAB code was fixed. 7-Zip didn't show some empty files,
+ if .CAB archive contains more than one empty file.
+
+
+4.59 2008-07-27
+-------------------------
+- Bug was fixed:
+ LZMA Encoder in fast compression mode could access memory outside of
+ allocated range in some rare cases.
+
+
+4.59 alpha 2008-05-30
+-------------------------
+- BUGS was fixed:
+ 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases.
+ 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties.
+
+4.58 alpha 9 2008-04-29
+-------------------------
+- BUG was fixed: 7-Zip showed incorrect timestamps in ISO files.
+
+
+4.58 alpha 8 2008-04-15
+-------------------------
+- BUG in 4.58 alpha 5/6/7 was fixed:
+ LZMA encoder worked incorrectly, if lp != 0.
+- Unicode (UTF-8) support for filenames in .ZIP archives. Now there are 3 modes:
+ 1) Default mode: 7-Zip uses UTF-8, if the local code page doesn't contain required symbols.
+ 2) -mcu switch: 7-Zip uses UTF-8, if there are non-ASCII symbols.
+ 3) -mcl switch: 7-Zip uses local code page.
+- Now it's possible to use -mSW- and -mSW+ switches instead of -mSW=off and -mSW=on
+
+
+4.58 alpha 7 2008-04-08
+-------------------------
+- BUG was fixed: BZip2Encoder and BZip2Decoder used CEvent objects without
+ creating, when BZip2 code was called with one thread (with -mmt1 switch or with
+ default switches on single thread CPU).
+- .lzma support.
+- RPM and NSIS support was improved.
+- LZMA now stores only (2 << n) or (3 << n) dictionary size value to LZMA properties.
+
+
+4.58 alpha 6 2008-03-27
+-------------------------
+- NTFS time extra in ZIP.
+- New item property - kpidTimeType - VT_UI4 (0 - NTFS, 1 - Unix, 2 - DOS).
+- Static CRC table is not required now for Lzma Encoder (in Lz MatchFinder).
+
+
+4.58 alpha 5 2008-03-19
+-------------------------
+- Creation time (-mtc switch) for .7z archives
+- LZMA encoder was converted to ANSI-C
+
+
+4.58 alpha 3 2008-02-25
+-------------------------
+- Speed optimizations for LZMA decoding. Now it uses C code instead of C++.
+- 7-Zip now has 128 MB dictionary limit for 32-bit version:
+ It's for speed optimization: kNumLogBits = 9 + sizeof(size_t) / 2;
+- TAR: 'D' link flag support.
+- 7-Zip now can unpack multivolume RAR archives created with
+ "old style volume names" scheme (-vn switch) and names *.001, *.002, ...
+- Fixed bugs:
+ - 7-Zip FM could not copy / move files to root network folders like \\COMPNAME\FOLDERNAME\
+ In case of move it removed original files.
+ - SFX-WIN: if there are errors, it still could return 0.
+ - ZIP (.XPS file) isZip64 && thisDiskNumber16 == 0xFFFF.
+ - ZIP name updating:
+ If zip file contains extra field and you try to change properties of files,
+ 7-zip tries to delete all extra fileds (except for WzAES).
+ And that code could hang.
+ - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run.
+ - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp
+ as modification time stamp.
+
+4.58 alpha 2 2007-12-31
+-------------------------
+- Small changes in Deflate and LZMA compression.
+- Some speed optimizations.
+
+
+4.57
+----
+- Bug was fixed:
+ Anti item is created for wrong file:
+ http://sourceforge.net/forum/forum.php?thread_id=1880366&forum_id=45798
+
+
+4.52 beta 2007-07-32
+-------------------------
+- 7-Zip could not decompress some cab files
+- "." dir creating at FAT was fixed / long names
+
+
+4.50 beta 2007-07-24
+-------------------------
+- 7-Zip now replaces unsupported filenames (like "nul", "com1") during extracting.
+- New switch for command line version:
+ -ssc[-] enables/disables case-sensitive mode.
+- 7z.exe l shows archive comment for zip archives
+- Some bugs were fixed: long paths names shorter than 4.
+- Speed optimizations for AES encryption.
+
+
+
+4.56 beta 2007-09-13
+-------------------------
+- some fixes in LZ encoder (LZMA and Deflate) code.
+ size_t was replaces to ptrdiff_t.
+ size_t version worked incorrectly with some compilers.
+
+
+4.46 beta 2007-05-25
+-------------------------
+- CPP Synchronization objects now return HRes (error code) instead of bool.
+
+
+4.45 beta 2007-04-16
+-------------------------
+- 7-Zip now uses C version of CRC, so you must call CrcGenerateTable at
+ stratup code, or you must add CPP/Common/CRC.cpp to your project.
+- Method ID in .7z now is 63-bit integer (UInt64).
+- Open error messages
+- unRar 1.5 fixed
+- unShrink fixed
+- BUG of 4.43 beta and 4.44 beta was fixed.
+ 7-Zip compressing to .zip in multi-threading mode didn't work in some cases.
+
+
+4.44 beta 2007-01-20
+-------------------------
+
+- Bug was fixed: LZMAEncoder.cpp::CEncoder::GetOptimumFast
+ it was:
+ data++
+ fixed version:
+ data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
+ It could lead to very small cpmpression ratio decreasing when block needs move.
+
+
+4.30 beta 2005-11-18
+-------------------------
+- Security.h::AddLockMemoryPrivilege - installs "Large pages" feature
+- MemoryLock.h::EnableLockMemoryPrivilege - enables "Large pages" feature
+- Alloc.h::SetLargePageSize - sets optimal LargePageSize size
+
+
+4.27 2005-09-21
+-------------------------
+- Some GUIDs/interfaces were changed.
+ IStream.h:
+ ISequentialInStream::Read now works as old ReadPart
+ ISequentialOutStream::Write now works as old WritePart
+
+
+4.26 beta 2005-08-05
+-------------------------
+- MyAlloc(0)/BigAlloc(0) now return 0
+
+
+4.25 beta 2005-07-31
+-------------------------
+- More 64-bit compatibilty
+
+
+4.24 beta 2005-07-06
+-------------------------
+- Common\NewHandler.h: using throw() for code size optimization.
+
+
+4.23 2005-06-29
+-------------------------
+- Bug was fixed: memory leak in Cab decoder.
+
+
+4.19 beta 2005-05-21
+-------------------------
+- BZip2 code was rewritten. Now 7-Zip doesn't use original BZip2 code.
+ Old (original) version was moved to folder 7zip/Compress/BZip2Original/
+
+
+4.14 beta 2005-01-11
+-------------------------
+- STL using was reduced
+- 7za now supports Split(001) archves
+
+
+4.10 beta 2004-10-21
+-------------------------
+- Codecs now use new interface: ICompressSetDecoderProperties2
+
+
+4.07 beta 2004-10-03
+-------------------------
+- some interfaces were changed slightly to support
+ -stdin -stdout mode.
+- FilterCoder for simple filters
+- Wildcard censor class was changed.
+- Bug was fixed: when encrypted stream was multiple 16,
+ it used additional 16 empty bytes.
+
+
+3.11 2003-10-06
+-------------------------
+ File functions support unicode strings even
+ on Windows 95/98/ME.
+
+
+3.08.02 2003-09-20
+-------------------------
+ More compatible with GCC.
+
+
+3.08.02 beta 2003-08-20
+-------------------------
+ Extracting bug in 7zExtract.cpp was fixed.
+
+
+3.08 beta 2003-08-19
+-------------------------
+ Big source code reconstruction.
+
+
+2.30 Beta 32 2003-05-15
+-------------------------
+ Small changes in Deflate decoder.
+
+
+2.30 Beta 31 2003-04-29
+-------------------------
+ Common/NewHandler.cpp
+ HeapAlloc in (included to beta 30) was changed to malloc.
+ HeapAlloc worked slower in Win95/98/Me.
+
+
+2.30 Beta 30 2003-04-21
+-------------------------
+ new file: Common/String.cpp
+ Common/NewHandler.* were changed
+
+
+2.30 Beta 29 2003-04-07
+-------------------------
+ Small changes in LZMA code.
+
+
+2.30 Beta 28 2003-02-16
+-------------------------
+ Processing anti-files was corrected.
+
+
+2.30 Beta 27 2003-01-24
+-------------------------
+ Project/Archiver/Format/Common/ArchiveInterface.h:
+ new IArchiveOpenVolumeCallback interface.
+
+
+2.30 Beta 26 2003-01-12
+-------------------------
+ SDK/Interface/PropID.h:
+ kpidComment now is kpidCommented
+
+
+2.30 Beta 25 2003-01-02
+-------------------------
+ Main archive interfaces were changed.
+
+
+2.30 Beta 24 2002-11-01
+-------------------------
+ SDK/Windows/Synchronization.h
+ SDK/Windows/Synchronization.cpp
+ - some changes.
+
+
+2.30 Beta 23 2002-09-07
+-------------------------
+ Project/FileManager folder was added.
+ Notation of some source files was changed.
+
+
+2.30 Beta 22 2002-08-28
+-------------------------
+ Project/FileManager folder was added.
+ Notation of some source files was changed.
+
+
+
+2.30 Beta 21 2002-07-08
+-------------------------
+ Project/Compress/LZ/MatchFinder/BinTree/BinTree.h
+ Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h
+ Project/Compress/LZ/MatchFinder/BinTree/HC.h
+ Project/Compress/LZ/MatchFinder/BinTree/HCMain.h
+ - RAM requirements for LZMA (7z) compression were reduced.
+
+
+2.30 Beta 20 2002-07-01
+-------------------------
+- SDK/Stream/WindowOut.h
+ now it uses only required memory (dictionary size).
+- Project/Archiver/Resource
+ contains common resurces
+
+
+2.30 Beta 19 2002-04-11
+-------------------------
+- SDK/Archive/Rar/Handler.cpp
+ supporting RAR29
+
+2.30 Beta 18 2002-03-25
+-------------------------
+- SDK/Archive/Cab/MSZipDecoder.cpp
+ SDK/Archive/Cab/LZXDecoder.cpp:
+ bug with corrupted archives was fixed
+- Project/Compress/LZ/MatchFinder/BinTree/BinTree.h
+- Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h
+ some speed optimization (using prefetching)
+
+
+2.30 Beta 17 2002-03-03
+-------------------------
+- ARJ suppport.
+
+
+2.30 Beta 16 2002-02-24
+-------------------------
+- Project/Compress/LZ/LZMA/Decoder.cpp:
+ Bug was fixed: LZMA could not extract more than 4 GB.
+- RPM and CPIO formats.
+- Project/Compress/LZ/LZMA/Encoder.*
+ Project/Archiver/Format/7z/OutHandler.cpp
+ New fast compression mode for LZMA: -m0a=0.
+- New match finders for LZMA: bt4b, hc3, hc4.
+
+
+2.30 Beta 15 2002-02-17
+-------------------------
+- Compression ratio in LZMA was slightly improved:
+ Project/Compress/LZ/LZMA/Encoder.*
+ Project/Archiver/Format/7z/OutHandler.cpp
+
+
+2.30 Beta 14 2002-02-10
+-------------------------
+- Supporting multithreading for LZMA:
+ Project/Compress/LZ/MatchFinder/MT
+- Common/String.h:
+ CStringBase::Replace function was fixed.
+
+
+2.30 Beta 13 2002-01-27
+-------------------------
+- Compress/LZ/MatchFinder/BinTree3.h:
+ method
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ - one VirtualAlloc array was splitted to
+ the for 3 arrays.
+ - Hash-functions were changed.
+
+
+
+2.30 Beta 12 2002-01-16
+-------------------------
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ Compress/LZ/MatchFinder/Patricia.h:
+ Compress/PPM/PPMd/SubAlloc.h:
+ Beta 11 bugs were fixed:
+ - VirtualFree was used incorrectly
+ - checking WIN32 instead _WINDOWS.
+ Compress/LZ/MatchFinder/Patricia.h:
+ Beta 11 bug with deleting m_Hash2Descendants was fixed.
+
+
+2.30 Beta 11 2002-01-15
+-------------------------
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ Compress/LZ/MatchFinder/Patricia.h:
+ Compress/PPM/PPMd/SubAlloc.h:
+ using VirtualAlloc for memory allocating
+- Exlorer/ContextMenu.cpp:
+ Testing supporting.
+ CreateProcess instead WinExec
+- Format/Common/IArchiveHandler.h:
+ Exlorer/ProxyHandler.cpp:
+ FAR/Plugin.cpp:
+ New properties names: Method, HostOS.
+- Exlorer/OverwriteDialog.cpp:
+ FAR/OverwriteDialog.cpp:
+ Windows/PropVariantConversions.h
+ Using National time format was eliminated.
+
+
+
+2.30 Beta 10 2002-01-11
+-------------------------
+- Exlorer/ContextMenu.cpp: bug with context menu on
+ Windows NT4 in Unicode version was fixed.
+- Format/7z/UpdateArchiveEngine.cpp: bug was fixed -
+ Updating in Beta 8 and 9 didn't work.
+- Exlorer/CCompressDialog.cpp: history growing bug was fixed.
+
+
+2.30 Beta 9 2002-01-08
+-------------------------
+- SDK/Common/Vector.h: sopporting sorted object vectors .
+- Lang features.
+- Two new match finders: pat3h and pat4h.
+- SDK/Archive/Zip/InEngine.cpp: bug was fixed.
+- SDK/Windows/FileDir.cpp: function CreateComplexDirectory
+ was changed.
+
diff --git a/src/libs/7zip/win/DOC/lzma.txt b/src/libs/7zip/win/DOC/lzma.txt
new file mode 100644
index 000000000..659323237
--- /dev/null
+++ b/src/libs/7zip/win/DOC/lzma.txt
@@ -0,0 +1,598 @@
+LZMA SDK 9.20
+-------------
+
+LZMA SDK provides the documentation, samples, header files, libraries,
+and tools you need to develop applications that use LZMA compression.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+LZMA is an improved version of famous LZ77 compression algorithm.
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for
+decompressing.
+
+
+
+LICENSE
+-------
+
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+Some code in LZMA SDK is based on public domain code from another developers:
+ 1) PPMd var.H (2001): Dmitry Shkarin
+ 2) SHA-256: Wei Dai (Crypto++ library)
+
+
+LZMA SDK Contents
+-----------------
+
+LZMA SDK includes:
+
+ - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing
+ - Compiled file->file LZMA compressing/decompressing program for Windows system
+
+
+UNIX/Linux version
+------------------
+To compile C++ version of file->file LZMA encoding, go to directory
+CPP/7zip/Bundles/LzmaCon
+and call make to recompile it:
+ make -f makefile.gcc clean all
+
+In some UNIX/Linux versions you must compile LZMA with static libraries.
+To compile with static libraries, you can use
+LIB = -lm -static
+
+
+Files
+---------------------
+lzma.txt - LZMA SDK description (this file)
+7zFormat.txt - 7z Format description
+7zC.txt - 7z ANSI-C Decoder description
+methods.txt - Compression method IDs for .7z
+lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
+7zr.exe - 7-Zip with 7z/lzma/xz support.
+history.txt - history of the LZMA SDK
+
+
+Source code structure
+---------------------
+
+C/ - C files
+ 7zCrc*.* - CRC code
+ Alloc.* - Memory allocation functions
+ Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+ LzFind.* - Match finder for LZ (LZMA) encoders
+ LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding
+ LzHash.h - Additional file for LZ match finder
+ LzmaDec.* - LZMA decoding
+ LzmaEnc.* - LZMA encoding
+ LzmaLib.* - LZMA Library for DLL calling
+ Types.h - Basic types for another .c files
+ Threads.* - The code for multithreading.
+
+ LzmaLib - LZMA Library (.DLL for Windows)
+
+ LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder).
+
+ Archive - files related to archiving
+ 7z - 7z ANSI-C Decoder
+
+CPP/ -- CPP files
+
+ Common - common files for C++ projects
+ Windows - common files for Windows related code
+
+ 7zip - files related to 7-Zip Project
+
+ Common - common files for 7-Zip
+
+ Compress - files related to compression/decompression
+
+ Archive - files related to archiving
+
+ Common - common files for archive handling
+ 7z - 7z C++ Encoder/Decoder
+
+ Bundles - Modules that are bundles of other modules
+
+ Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2
+ LzmaCon - lzma.exe: LZMA compression/decompression
+ Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2
+ Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2.
+
+ UI - User Interface files
+
+ Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
+ Common - Common UI files
+ Console - Code for console archiver
+
+
+
+CS/ - C# files
+ 7zip
+ Common - some common files for 7-Zip
+ Compress - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ LzmaAlone - file->file LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+Java/ - Java files
+ SevenZip
+ Compression - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+
+C/C++ source code of LZMA SDK is part of 7-Zip project.
+7-Zip source code can be downloaded from 7-Zip's SourceForge page:
+
+ http://sourceforge.net/projects/sevenzip/
+
+
+
+LZMA features
+-------------
+ - Variable dictionary size (up to 1 GB)
+ - Estimated compressing speed: about 2 MB/s on 2 GHz CPU
+ - Estimated decompressing speed:
+ - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64
+ - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC
+ - Small memory requirements for decompressing (16 KB + DictionarySize)
+ - Small code size for decompressing: 5-8 KB
+
+LZMA decoder uses only integer operations and can be
+implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
+
+Some critical operations that affect the speed of LZMA decompression:
+ 1) 32*16 bit integer multiply
+ 2) Misspredicted branches (penalty mostly depends from pipeline length)
+ 3) 32-bit shift and arithmetic operations
+
+The speed of LZMA decompressing mostly depends from CPU speed.
+Memory speed has no big meaning. But if your CPU has small data cache,
+overall weight of memory speed will slightly increase.
+
+
+How To Use
+----------
+
+Using LZMA encoder/decoder executable
+--------------------------------------
+
+Usage: LZMA <e|d> inputFile outputFile [<switches>...]
+
+ e: encode file
+
+ d: decode file
+
+ b: Benchmark. There are two tests: compressing and decompressing
+ with LZMA method. Benchmark shows rating in MIPS (million
+ instructions per second). Rating value is calculated from
+ measured speed and it is normalized with Intel's Core 2 results.
+ Also Benchmark checks possible hardware errors (RAM
+ errors in most cases). Benchmark uses these settings:
+ (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter.
+ Also you can change the number of iterations. Example for 30 iterations:
+ LZMA b 30
+ Default number of iterations is 10.
+
+<Switches>
+
+
+ -a{N}: set compression mode 0 = fast, 1 = normal
+ default: 1 (normal)
+
+ d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB)
+ The maximum value for dictionary size is 1 GB = 2^30 bytes.
+ Dictionary size is calculated as DictionarySize = 2^N bytes.
+ For decompressing file compressed by LZMA method with dictionary
+ size D = 2^N you need about D bytes of memory (RAM).
+
+ -fb{N}: set number of fast bytes - [5, 273], default: 128
+ Usually big number gives a little bit better compression ratio
+ and slower compression process.
+
+ -lc{N}: set number of literal context bits - [0, 8], default: 3
+ Sometimes lc=4 gives gain for big files.
+
+ -lp{N}: set number of literal pos bits - [0, 4], default: 0
+ lp switch is intended for periodical data when period is
+ equal 2^N. For example, for 32-bit (4 bytes)
+ periodical data you can use lp=2. Often it's better to set lc0,
+ if you change lp switch.
+
+ -pb{N}: set number of pos bits - [0, 4], default: 2
+ pb switch is intended for periodical data
+ when period is equal 2^N.
+
+ -mf{MF_ID}: set Match Finder. Default: bt4.
+ Algorithms from hc* group doesn't provide good compression
+ ratio, but they often works pretty fast in combination with
+ fast mode (-a0).
+
+ Memory requirements depend from dictionary size
+ (parameter "d" in table below).
+
+ MF_ID Memory Description
+
+ bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing.
+ bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing.
+ bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing.
+ hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
+
+ -eos: write End Of Stream marker. By default LZMA doesn't write
+ eos marker, since LZMA decoder knows uncompressed size
+ stored in .lzma file header.
+
+ -si: Read data from stdin (it will write End Of Stream marker).
+ -so: Write data to stdout
+
+
+Examples:
+
+1) LZMA e file.bin file.lzma -d16 -lc0
+
+compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
+and 0 literal context bits. -lc0 allows to reduce memory requirements
+for decompression.
+
+
+2) LZMA e file.bin file.lzma -lc0 -lp2
+
+compresses file.bin to file.lzma with settings suitable
+for 32-bit periodical data (for example, ARM or MIPS code).
+
+3) LZMA d file.lzma file.bin
+
+decompresses file.lzma to file.bin.
+
+
+Compression ratio hints
+-----------------------
+
+Recommendations
+---------------
+
+To increase the compression ratio for LZMA compressing it's desirable
+to have aligned data (if it's possible) and also it's desirable to locate
+data in such order, where code is grouped in one place and data is
+grouped in other place (it's better than such mixing: code, data, code,
+data, ...).
+
+
+Filters
+-------
+You can increase the compression ratio for some data types, using
+special filters before compressing. For example, it's possible to
+increase the compression ratio on 5-10% for code for those CPU ISAs:
+x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
+
+You can find C source code of such filters in C/Bra*.* files
+
+You can check the compression ratio gain of these filters with such
+7-Zip commands (example for ARM code):
+No filter:
+ 7z a a1.7z a.bin -m0=lzma
+
+With filter for little-endian ARM code:
+ 7z a a2.7z a.bin -m0=arm -m1=lzma
+
+It works in such manner:
+Compressing = Filter_encoding + LZMA_encoding
+Decompressing = LZMA_decoding + Filter_decoding
+
+Compressing and decompressing speed of such filters is very high,
+so it will not increase decompressing time too much.
+Moreover, it reduces decompression time for LZMA_decoding,
+since compression ratio with filtering is higher.
+
+These filters convert CALL (calling procedure) instructions
+from relative offsets to absolute addresses, so such data becomes more
+compressible.
+
+For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+ 0 1 Special LZMA properties (lc,lp, pb in encoded form)
+ 1 4 Dictionary size (little endian)
+ 5 8 Uncompressed size (little endian). -1 means unknown size
+ 13 Compressed data
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
+If you want to use old interfaces you can download previous version of LZMA SDK
+from sourceforge.net site.
+
+To use ANSI-C LZMA Decoder you need the following files:
+1) LzmaDec.h + LzmaDec.c + Types.h
+LzmaUtil/LzmaUtil.c is example application that uses these files.
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+Stack usage of LZMA decoding function for local variables is not
+larger than 200-400 bytes.
+
+LZMA Decoder uses dictionary buffer and internal state structure.
+Internal state structure consumes
+ state_size = (4 + (1.5 << (lc + lp))) KB
+by default (lc=3, lp=0), state_size = 16 KB.
+
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 2 interfaces:
+1) Single-call Decompressing
+2) Multi-call State Decompressing (zlib-like interface)
+
+You must use external allocator:
+Example:
+void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
+void SzFree(void *p, void *address) { p = p; free(address); }
+ISzAlloc alloc = { SzAlloc, SzFree };
+
+You can use p = p; operator to disable compiler warnings.
+
+
+Single-call Decompressing
+-------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+Compile defines: no defines
+Memory Requirements:
+ - Input buffer: compressed size
+ - Output buffer: uncompressed size
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+
+Interface:
+ int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ propData - LZMA properties (5 bytes)
+ propSize - size of propData buffer (5 bytes)
+ finishMode - It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+ You can use LZMA_FINISH_END, when you know that
+ current output buffer covers last bytes of stream.
+ alloc - Memory allocator.
+
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+
+ Output:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+
+ If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
+ and output value of destLen will be less than output buffer size limit.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+
+Multi-call State Decompressing (zlib-like interface)
+----------------------------------------------------
+
+When to use: file->file decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in LZMA properties header)
+
+1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
+ unsigned char header[LZMA_PROPS_SIZE + 8];
+ ReadFile(inFile, header, sizeof(header)
+
+2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
+
+ CLzmaDec state;
+ LzmaDec_Constr(&state);
+ res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
+ if (res != SZ_OK)
+ return res;
+
+3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
+
+ LzmaDec_Init(&state);
+ for (;;)
+ {
+ ...
+ int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
+ ...
+ }
+
+
+4) Free all allocated structures
+ LzmaDec_Free(&state, &g_Alloc);
+
+For full code example, look at C/LzmaUtil/LzmaUtil.c code.
+
+
+How To compress data
+--------------------
+
+Compile files: LzmaEnc.h + LzmaEnc.c + Types.h +
+LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h
+
+Memory Requirements:
+ - (dictSize * 11.5 + 6 MB) + state_size
+
+Lzma Encoder can use two memory allocators:
+1) alloc - for small arrays.
+2) allocBig - for big arrays.
+
+For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
+better compression speed. Note that Windows has bad implementation for
+Large RAM Pages.
+It's OK to use same allocator for alloc and allocBig.
+
+
+Single-call Compression with callbacks
+--------------------------------------
+
+Check C/LzmaUtil/LzmaUtil.c as example,
+
+When to use: file->file decompressing
+
+1) you must implement callback structures for interfaces:
+ISeqInStream
+ISeqOutStream
+ICompressProgress
+ISzAlloc
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+ CFileSeqInStream inStream;
+ CFileSeqOutStream outStream;
+
+ inStream.funcTable.Read = MyRead;
+ inStream.file = inFile;
+ outStream.funcTable.Write = MyWrite;
+ outStream.file = outFile;
+
+
+2) Create CLzmaEncHandle object;
+
+ CLzmaEncHandle enc;
+
+ enc = LzmaEnc_Create(&g_Alloc);
+ if (enc == 0)
+ return SZ_ERROR_MEM;
+
+
+3) initialize CLzmaEncProps properties;
+
+ LzmaEncProps_Init(&props);
+
+ Then you can change some properties in that structure.
+
+4) Send LZMA properties to LZMA Encoder
+
+ res = LzmaEnc_SetProps(enc, &props);
+
+5) Write encoded properties to header
+
+ Byte header[LZMA_PROPS_SIZE + 8];
+ size_t headerSize = LZMA_PROPS_SIZE;
+ UInt64 fileSize;
+ int i;
+
+ res = LzmaEnc_WriteProperties(enc, header, &headerSize);
+ fileSize = MyGetFileLength(inFile);
+ for (i = 0; i < 8; i++)
+ header[headerSize++] = (Byte)(fileSize >> (8 * i));
+ MyWriteFileAndCheck(outFile, header, headerSize)
+
+6) Call encoding function:
+ res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
+ NULL, &g_Alloc, &g_Alloc);
+
+7) Destroy LZMA Encoder Object
+ LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
+
+
+If callback function return some error code, LzmaEnc_Encode also returns that code
+or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS.
+
+
+Single-call RAM->RAM Compression
+--------------------------------
+
+Single-call RAM->RAM Compression is similar to Compression with callbacks,
+but you provide pointers to buffers instead of pointers to stream callbacks:
+
+HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+
+
+
+Defines
+-------
+
+_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
+
+_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
+ some structures will be doubled in that case.
+
+_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit.
+
+_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type.
+
+
+_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder.
+
+
+C++ LZMA Encoder/Decoder
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it,
+you can study basics of COM/OLE.
+C++ LZMA code is just wrapper over ANSI-C code.
+
+
+C++ Notes
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
+you must check that you correctly work with "new" operator.
+7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
+So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
+operator new(size_t size)
+{
+ void *p = ::malloc(size);
+ if (p == 0)
+ throw CNewException();
+ return p;
+}
+If you use MSCV that throws exception for "new" operator, you can compile without
+"NewHandler.cpp". So standard exception will be used. Actually some code of
+7-Zip catches any exception in internal code and converts it to HRESULT code.
+So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/src/libs/7zip/win/DOC/readme.txt b/src/libs/7zip/win/DOC/readme.txt
new file mode 100644
index 000000000..aad462642
--- /dev/null
+++ b/src/libs/7zip/win/DOC/readme.txt
@@ -0,0 +1,181 @@
+7-Zip 9.20 Sources
+------------------
+
+7-Zip is a file archiver for Windows.
+
+7-Zip Copyright (C) 1999-2010 Igor Pavlov.
+
+
+License Info
+------------
+
+7-Zip is free software distributed under the GNU LGPL
+(except for unRar code).
+read License.txt for more infomation about license.
+
+Notes about unRAR license:
+
+Please check main restriction from unRar license:
+
+ 2. The unRAR sources may be used in any software to handle RAR
+ archives without limitations free of charge, but cannot be used
+ to re-create the RAR compression algorithm, which is proprietary.
+ Distribution of modified unRAR sources in separate form or as a
+ part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+In brief it means:
+1) You can compile and use compiled files under GNU LGPL rules, since
+ unRAR license almost has no restrictions for compiled files.
+ You can link these compiled files to LGPL programs.
+2) You can fix bugs in source code and use compiled fixed version.
+3) You can not use unRAR sources to re-create the RAR compression algorithm.
+
+
+LZMA SDK
+--------
+
+Also this package contains files from LZMA SDK
+you can download LZMA SDK from this page:
+http://www.7-zip.org/sdk.html
+read about addtional licenses for LZMA SDK in file
+DOC/lzma.txt
+
+
+How to compile
+--------------
+To compile sources you need Visual C++ 6.0.
+For compiling some files you also need
+new Platform SDK from Microsoft' Site:
+http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm
+or
+http://www.microsoft.com/msdownload/platformsdk/sdkupdate/XPSP2FULLInstall.htm
+or
+http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
+
+If you use MSVC6, specify SDK directories at top of directories lists:
+Tools / Options / Directories
+ - Include files
+ - Library files
+
+
+To compile 7-Zip for AMD64 and IA64 you need:
+ Windows Server 2003 SP1 Platform SDK from microsoft.com
+
+Also you need Microsoft Macro Assembler:
+ - ml.exe for x86
+ - ml64.exe for AMD64
+You can use ml.exe from Windows SDK for Windows Vista or some other version.
+
+
+Compiling under Unix/Linux
+--------------------------
+Check this site for Posix/Linux version:
+http://sourceforge.net/projects/p7zip/
+
+
+Notes:
+------
+7-Zip consists of COM modules (DLL files).
+But 7-Zip doesn't use standard COM interfaces for creating objects.
+Look at
+7zip\UI\Client7z folder for example of using DLL files of 7-Zip.
+Some DLL files can use other DLL files from 7-Zip.
+If you don't like it, you must use standalone version of DLL.
+To compile standalone version of DLL you must include all used parts
+to project and define some defs.
+For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll
+that works with 7z format. So you can use such DLL in your project
+without additional DLL files.
+
+
+Description of 7-Zip sources package
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+DOC Documentation
+---
+ 7zFormat.txt - 7z format description
+ copying.txt - GNU LGPL license
+ unRarLicense.txt - License for unRAR part of source code
+ history.txt - Sources history
+ Methods.txt - Compression method IDs
+ readme.txt - Readme file
+ lzma.txt - LZMA SDK description
+ 7zip.nsi - installer script for NSIS
+
+
+C - Source code in C
+CPP - Source code in CPP
+
+Common Common modules
+Windows Win32 wrappers
+
+7zip
+-------
+ Common Common modules for 7-zip
+
+ Archive 7-Zip Archive Format Plugins
+ --------
+ Common
+ 7z
+ Arj
+ BZip2
+ Cab
+ Cpio
+ GZip
+ Rar
+ Rpm
+ Split
+ Tar
+ Zip
+
+ Bundle Modules that are bundles of other modules
+ ------
+ Alone 7za.exe: Standalone version of 7z
+ Alone7z 7zr.exe: Standalone version of 7z that supports only 7z/LZMA/BCJ/BCJ2
+ SFXCon 7zCon.sfx: Console 7z SFX module
+ SFXWin 7z.sfx: Windows 7z SFX module
+ SFXSetup 7zS.sfx: Windows 7z SFX module for Installers
+ Format7z 7za.dll: .7z support
+ Format7zExtract 7zxa.dll: .7z support, extracting only
+ Format7zR 7zr.dll: .7z support, LZMA/BCJ* only
+ Format7zExtractR 7zxr.dll: .7z support, LZMA/BCJ* only, extracting only
+ Format7zF 7z.dll: all formats
+
+ UI
+ --
+ Agent Intermediary modules for FAR plugin and Explorer plugin
+ Console 7z.exe Console version
+ Explorer Explorer plugin
+ Resource Resources
+ Far FAR plugin
+ Client7z Test application for 7za.dll
+
+ Compress
+ --------
+ BZip2 BZip2 compressor
+ Branch Branch converter
+ ByteSwap Byte Swap converter
+ Copy Copy coder
+ Deflate
+ Implode
+ Arj
+ LZMA
+ PPMd Dmitry Shkarin's PPMdH with small changes.
+ LZ Lempel - Ziv
+
+ Crypto Crypto modules
+ ------
+ 7zAES Cipher for 7z
+ AES AES Cipher
+ Rar20 Cipher for Rar 2.0
+ RarAES Cipher for Rar 3.0
+ Zip Cipher for Zip
+
+ FileManager File Manager
+
+
+---
+Igor Pavlov
+http://www.7-zip.org
diff --git a/src/libs/7zip/win/DOC/unRarLicense.txt b/src/libs/7zip/win/DOC/unRarLicense.txt
new file mode 100644
index 000000000..5f78b728d
--- /dev/null
+++ b/src/libs/7zip/win/DOC/unRarLicense.txt
@@ -0,0 +1,41 @@
+ ****** ***** ****** unRAR - free utility for RAR archives
+ ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ****** ******* ****** License for use and distribution of
+ ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ** ** ** ** ** ** FREE portable version
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ The source code of unRAR utility is freeware. This means:
+
+ 1. All copyrights to RAR and the utility unRAR are exclusively
+ owned by the author - Alexander Roshal.
+
+ 2. The unRAR sources may be used in any software to handle RAR
+ archives without limitations free of charge, but cannot be used
+ to re-create the RAR compression algorithm, which is proprietary.
+ Distribution of modified unRAR sources in separate form or as a
+ part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+ 3. The unRAR utility may be freely distributed. No person or company
+ may charge a fee for the distribution of unRAR without written
+ permission from the copyright holder.
+
+ 4. THE RAR ARCHIVER AND THE UNRAR UTILITY ARE DISTRIBUTED "AS IS".
+ NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
+ YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
+ DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
+ OR MISUSING THIS SOFTWARE.
+
+ 5. Installing and using the unRAR utility signifies acceptance of
+ these terms and conditions of the license.
+
+ 6. If you don't agree with terms of the license you must remove
+ unRAR files from your storage devices and cease to use the
+ utility.
+
+ Thank you for your interest in RAR and unRAR.
+
+
+ Alexander L. Roshal \ No newline at end of file
diff --git a/src/libs/7zip/win/installer_framework_changes.txt b/src/libs/7zip/win/installer_framework_changes.txt
new file mode 100644
index 000000000..2701503f9
--- /dev/null
+++ b/src/libs/7zip/win/installer_framework_changes.txt
@@ -0,0 +1,519 @@
+There are deleted files and very small changes to get the integration process of new versions very simple.
+--diff-filter=M means "modified" and
+--diff-filter=D means "deleted" files
+
+=== output of: git diff --diff-filter=M ===
+
+diff --git a/C/AesOpt.c b/C/AesOpt.c
+index 60cfd86..c0bd8bc 100644
+--- a/C/AesOpt.c
++++ b/C/AesOpt.c
+@@ -5,7 +5,7 @@
+
+ #ifdef MY_CPU_X86_OR_AMD64
+ #if _MSC_VER >= 1500
+-#define USE_INTEL_AES
++//#define USE_INTEL_AES
+ #endif
+ #endif
+
+diff --git a/CPP/7zip/Common/RegisterArc.h b/CPP/7zip/Common/RegisterArc.h
+index bc2a034..9b8cbd3 100644
+--- a/CPP/7zip/Common/RegisterArc.h
++++ b/CPP/7zip/Common/RegisterArc.h
+@@ -27,6 +27,6 @@ void RegisterArc(const CArcInfo *arcInfo);
+
+ #define REGISTER_ARC(x) struct REGISTER_ARC_NAME(x) { \
+ REGISTER_ARC_NAME(x)() { RegisterArc(&g_ArcInfo); }}; \
+- static REGISTER_ARC_NAME(x) g_RegisterArc;
+-
++ static REGISTER_ARC_NAME(x) g_RegisterArc; \
++ void registerArc##x() { static REGISTER_ARC_NAME(x) g_RegisterArc; }
+ #endif
+diff --git a/CPP/7zip/Common/RegisterCodec.h b/CPP/7zip/Common/RegisterCodec.h
+index 786b4a4..d53c434 100644
+--- a/CPP/7zip/Common/RegisterCodec.h
++++ b/CPP/7zip/Common/RegisterCodec.h
+@@ -22,12 +22,13 @@ void RegisterCodec(const CCodecInfo *codecInfo);
+
+ #define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \
+ REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \
+- static REGISTER_CODEC_NAME(x) g_RegisterCodec;
++ static REGISTER_CODEC_NAME(x) g_RegisterCodec; \
++ void registerCodec##x() { static REGISTER_CODEC_NAME(x) g_RegisterCodecs; }
+
+ #define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x
+ #define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \
+ REGISTER_CODECS_NAME(x)() { for (int i = 0; i < sizeof(g_CodecsInfo) / sizeof(g_CodecsInfo[0]); i++) \
+ RegisterCodec(&g_CodecsInfo[i]); }}; \
+- static REGISTER_CODECS_NAME(x) g_RegisterCodecs;
+-
++ static REGISTER_CODECS_NAME(x) g_RegisterCodecs; \
++ void registerCodec##x() { static REGISTER_CODECS_NAME(x) g_RegisterCodecs; }
+ #endif
+diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h
+index eb3c52d..f483e39 100644
+--- a/CPP/Common/MyString.h
++++ b/CPP/Common/MyString.h
+@@ -7,6 +7,8 @@
+
+ #include "MyVector.h"
+
++#include <windows.h>
++
+ template <class T>
+ inline int MyStringLen(const T *s)
+ {
+
+=== output of: git diff --diff-filter=D --name-only ===
+Asm/arm/7zCrcOpt.asm
+Asm/x86/7zAsm.asm
+Asm/x86/7zCrcOpt.asm
+Asm/x86/AesOpt.asm
+C/Util/7z/7z.dsp
+C/Util/7z/7z.dsw
+C/Util/7z/7zMain.c
+C/Util/7z/makefile
+C/Util/7z/makefile.gcc
+C/Util/Lzma/LzmaUtil.c
+C/Util/Lzma/LzmaUtil.dsp
+C/Util/Lzma/LzmaUtil.dsw
+C/Util/Lzma/makefile
+C/Util/Lzma/makefile.gcc
+C/Util/LzmaLib/LzmaLib.def
+C/Util/LzmaLib/LzmaLib.dsp
+C/Util/LzmaLib/LzmaLib.dsw
+C/Util/LzmaLib/LzmaLibExports.c
+C/Util/LzmaLib/makefile
+C/Util/LzmaLib/resource.rc
+C/Util/SfxSetup/SfxSetup.c
+C/Util/SfxSetup/SfxSetup.dsp
+C/Util/SfxSetup/SfxSetup.dsw
+C/Util/SfxSetup/makefile
+C/Util/SfxSetup/makefile_con
+C/Util/SfxSetup/resource.rc
+C/Util/SfxSetup/setup.ico
+CPP/7zip/Aes.mak
+CPP/7zip/Archive/7z/7z.dsp
+CPP/7zip/Archive/7z/7z.dsw
+CPP/7zip/Archive/7z/makefile
+CPP/7zip/Archive/7z/resource.rc
+CPP/7zip/Archive/Archive.def
+CPP/7zip/Archive/Archive2.def
+CPP/7zip/Archive/Icons/7z.ico
+CPP/7zip/Archive/Icons/arj.ico
+CPP/7zip/Archive/Icons/bz2.ico
+CPP/7zip/Archive/Icons/cab.ico
+CPP/7zip/Archive/Icons/cpio.ico
+CPP/7zip/Archive/Icons/deb.ico
+CPP/7zip/Archive/Icons/dmg.ico
+CPP/7zip/Archive/Icons/fat.ico
+CPP/7zip/Archive/Icons/gz.ico
+CPP/7zip/Archive/Icons/hfs.ico
+CPP/7zip/Archive/Icons/iso.ico
+CPP/7zip/Archive/Icons/lzh.ico
+CPP/7zip/Archive/Icons/lzma.ico
+CPP/7zip/Archive/Icons/ntfs.ico
+CPP/7zip/Archive/Icons/rar.ico
+CPP/7zip/Archive/Icons/rpm.ico
+CPP/7zip/Archive/Icons/split.ico
+CPP/7zip/Archive/Icons/squashfs.ico
+CPP/7zip/Archive/Icons/tar.ico
+CPP/7zip/Archive/Icons/vhd.ico
+CPP/7zip/Archive/Icons/wim.ico
+CPP/7zip/Archive/Icons/xar.ico
+CPP/7zip/Archive/Icons/xz.ico
+CPP/7zip/Archive/Icons/z.ico
+CPP/7zip/Archive/Icons/zip.ico
+CPP/7zip/Archive/makefile
+CPP/7zip/Asm.mak
+CPP/7zip/Bundles/Alone/Alone.dsp
+CPP/7zip/Bundles/Alone/Alone.dsw
+CPP/7zip/Bundles/Alone/StdAfx.cpp
+CPP/7zip/Bundles/Alone/StdAfx.h
+CPP/7zip/Bundles/Alone/afxres.h
+CPP/7zip/Bundles/Alone/makefile
+CPP/7zip/Bundles/Alone/resource.rc
+CPP/7zip/Bundles/Alone7z/StdAfx.cpp
+CPP/7zip/Bundles/Alone7z/StdAfx.h
+CPP/7zip/Bundles/Alone7z/makefile
+CPP/7zip/Bundles/Alone7z/resource.rc
+CPP/7zip/Bundles/Fm/FM.dsp
+CPP/7zip/Bundles/Fm/FM.dsw
+CPP/7zip/Bundles/Fm/StdAfx.cpp
+CPP/7zip/Bundles/Fm/StdAfx.h
+CPP/7zip/Bundles/Fm/makefile
+CPP/7zip/Bundles/Fm/resource.rc
+CPP/7zip/Bundles/Format7z/StdAfx.cpp
+CPP/7zip/Bundles/Format7z/StdAfx.h
+CPP/7zip/Bundles/Format7z/makefile
+CPP/7zip/Bundles/Format7z/resource.rc
+CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp
+CPP/7zip/Bundles/Format7zExtract/StdAfx.h
+CPP/7zip/Bundles/Format7zExtract/makefile
+CPP/7zip/Bundles/Format7zExtract/resource.rc
+CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp
+CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
+CPP/7zip/Bundles/Format7zExtractR/makefile
+CPP/7zip/Bundles/Format7zExtractR/resource.rc
+CPP/7zip/Bundles/Format7zF/Format7z.dsp
+CPP/7zip/Bundles/Format7zF/Format7z.dsw
+CPP/7zip/Bundles/Format7zF/StdAfx.cpp
+CPP/7zip/Bundles/Format7zF/StdAfx.h
+CPP/7zip/Bundles/Format7zF/makefile
+CPP/7zip/Bundles/Format7zF/resource.rc
+CPP/7zip/Bundles/Format7zR/StdAfx.cpp
+CPP/7zip/Bundles/Format7zR/StdAfx.h
+CPP/7zip/Bundles/Format7zR/makefile
+CPP/7zip/Bundles/Format7zR/resource.rc
+CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
+CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp
+CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw
+CPP/7zip/Bundles/LzmaCon/StdAfx.cpp
+CPP/7zip/Bundles/LzmaCon/StdAfx.h
+CPP/7zip/Bundles/LzmaCon/makefile
+CPP/7zip/Bundles/LzmaCon/makefile.gcc
+CPP/7zip/Bundles/SFXCon/7z.ico
+CPP/7zip/Bundles/SFXCon/Main.cpp
+CPP/7zip/Bundles/SFXCon/SFXCon.dsp
+CPP/7zip/Bundles/SFXCon/SFXCon.dsw
+CPP/7zip/Bundles/SFXCon/StdAfx.cpp
+CPP/7zip/Bundles/SFXCon/StdAfx.h
+CPP/7zip/Bundles/SFXCon/makefile
+CPP/7zip/Bundles/SFXCon/resource.rc
+CPP/7zip/Bundles/SFXSetup/ExtractCallback.cpp
+CPP/7zip/Bundles/SFXSetup/ExtractCallback.h
+CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp
+CPP/7zip/Bundles/SFXSetup/ExtractEngine.h
+CPP/7zip/Bundles/SFXSetup/Main.cpp
+CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
+CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw
+CPP/7zip/Bundles/SFXSetup/StdAfx.cpp
+CPP/7zip/Bundles/SFXSetup/StdAfx.h
+CPP/7zip/Bundles/SFXSetup/makefile
+CPP/7zip/Bundles/SFXSetup/resource.h
+CPP/7zip/Bundles/SFXSetup/resource.rc
+CPP/7zip/Bundles/SFXSetup/setup.ico
+CPP/7zip/Bundles/SFXWin/7z.ico
+CPP/7zip/Bundles/SFXWin/Main.cpp
+CPP/7zip/Bundles/SFXWin/SFXWin.dsp
+CPP/7zip/Bundles/SFXWin/SFXWin.dsw
+CPP/7zip/Bundles/SFXWin/StdAfx.cpp
+CPP/7zip/Bundles/SFXWin/StdAfx.h
+CPP/7zip/Bundles/SFXWin/makefile
+CPP/7zip/Bundles/SFXWin/resource.h
+CPP/7zip/Bundles/SFXWin/resource.rc
+CPP/7zip/Bundles/makefile
+CPP/7zip/Compress/Codec.def
+CPP/7zip/Compress/makefile
+CPP/7zip/Crc.mak
+CPP/7zip/Crypto/Codec.def
+CPP/7zip/GuiCommon.rc
+CPP/7zip/MyVersionInfo.rc
+CPP/7zip/SubBuild.mak
+CPP/7zip/UI/Agent/Agent.cpp
+CPP/7zip/UI/Agent/Agent.h
+CPP/7zip/UI/Agent/AgentOut.cpp
+CPP/7zip/UI/Agent/AgentProxy.cpp
+CPP/7zip/UI/Agent/AgentProxy.h
+CPP/7zip/UI/Agent/ArchiveFolder.cpp
+CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp
+CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
+CPP/7zip/UI/Agent/IFolderArchive.h
+CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp
+CPP/7zip/UI/Agent/UpdateCallbackAgent.h
+CPP/7zip/UI/Client7z/Client7z.cpp
+CPP/7zip/UI/Client7z/Client7z.dsp
+CPP/7zip/UI/Client7z/Client7z.dsw
+CPP/7zip/UI/Client7z/StdAfx.cpp
+CPP/7zip/UI/Client7z/StdAfx.h
+CPP/7zip/UI/Client7z/makefile
+CPP/7zip/UI/Console/Console.dsp
+CPP/7zip/UI/Console/Console.dsw
+CPP/7zip/UI/Console/makefile
+CPP/7zip/UI/Console/resource.rc
+CPP/7zip/UI/Explorer/7-zip.dll.manifest
+CPP/7zip/UI/Explorer/ContextMenu.cpp
+CPP/7zip/UI/Explorer/ContextMenu.h
+CPP/7zip/UI/Explorer/ContextMenuFlags.h
+CPP/7zip/UI/Explorer/DllExports.cpp
+CPP/7zip/UI/Explorer/Explorer.def
+CPP/7zip/UI/Explorer/Explorer.dsp
+CPP/7zip/UI/Explorer/Explorer.dsw
+CPP/7zip/UI/Explorer/MyMessages.cpp
+CPP/7zip/UI/Explorer/MyMessages.h
+CPP/7zip/UI/Explorer/OptionsDialog.cpp
+CPP/7zip/UI/Explorer/OptionsDialog.h
+CPP/7zip/UI/Explorer/RegistryContextMenu.cpp
+CPP/7zip/UI/Explorer/RegistryContextMenu.h
+CPP/7zip/UI/Explorer/StdAfx.cpp
+CPP/7zip/UI/Explorer/StdAfx.h
+CPP/7zip/UI/Explorer/makefile
+CPP/7zip/UI/Explorer/resource.h
+CPP/7zip/UI/Explorer/resource.rc
+CPP/7zip/UI/Explorer/resource2.rc
+CPP/7zip/UI/Far/ExtractEngine.cpp
+CPP/7zip/UI/Far/ExtractEngine.h
+CPP/7zip/UI/Far/Far.def
+CPP/7zip/UI/Far/Far.dsp
+CPP/7zip/UI/Far/Far.dsw
+CPP/7zip/UI/Far/FarPlugin.h
+CPP/7zip/UI/Far/FarUtils.cpp
+CPP/7zip/UI/Far/FarUtils.h
+CPP/7zip/UI/Far/Main.cpp
+CPP/7zip/UI/Far/Messages.h
+CPP/7zip/UI/Far/OverwriteDialog.cpp
+CPP/7zip/UI/Far/OverwriteDialog.h
+CPP/7zip/UI/Far/Plugin.cpp
+CPP/7zip/UI/Far/Plugin.h
+CPP/7zip/UI/Far/PluginCommon.cpp
+CPP/7zip/UI/Far/PluginDelete.cpp
+CPP/7zip/UI/Far/PluginRead.cpp
+CPP/7zip/UI/Far/PluginWrite.cpp
+CPP/7zip/UI/Far/ProgressBox.cpp
+CPP/7zip/UI/Far/ProgressBox.h
+CPP/7zip/UI/Far/StdAfx.cpp
+CPP/7zip/UI/Far/StdAfx.h
+CPP/7zip/UI/Far/UpdateCallback100.cpp
+CPP/7zip/UI/Far/UpdateCallback100.h
+CPP/7zip/UI/Far/makefile
+CPP/7zip/UI/Far/resource.rc
+CPP/7zip/UI/FileManager/7zFM.exe.manifest
+CPP/7zip/UI/FileManager/7zipLogo.ico
+CPP/7zip/UI/FileManager/AboutDialog.cpp
+CPP/7zip/UI/FileManager/AboutDialog.h
+CPP/7zip/UI/FileManager/AboutDialog.rc
+CPP/7zip/UI/FileManager/AboutDialogRes.h
+CPP/7zip/UI/FileManager/Add.bmp
+CPP/7zip/UI/FileManager/Add2.bmp
+CPP/7zip/UI/FileManager/App.cpp
+CPP/7zip/UI/FileManager/App.h
+CPP/7zip/UI/FileManager/AppState.h
+CPP/7zip/UI/FileManager/BrowseDialog.cpp
+CPP/7zip/UI/FileManager/BrowseDialog.h
+CPP/7zip/UI/FileManager/BrowseDialog.rc
+CPP/7zip/UI/FileManager/BrowseDialogRes.h
+CPP/7zip/UI/FileManager/ClassDefs.cpp
+CPP/7zip/UI/FileManager/ComboDialog.cpp
+CPP/7zip/UI/FileManager/ComboDialog.h
+CPP/7zip/UI/FileManager/ComboDialog.rc
+CPP/7zip/UI/FileManager/ComboDialogRes.h
+CPP/7zip/UI/FileManager/Copy.bmp
+CPP/7zip/UI/FileManager/Copy2.bmp
+CPP/7zip/UI/FileManager/CopyDialog.cpp
+CPP/7zip/UI/FileManager/CopyDialog.h
+CPP/7zip/UI/FileManager/CopyDialog.rc
+CPP/7zip/UI/FileManager/CopyDialogRes.h
+CPP/7zip/UI/FileManager/Delete.bmp
+CPP/7zip/UI/FileManager/Delete2.bmp
+CPP/7zip/UI/FileManager/DialogSize.h
+CPP/7zip/UI/FileManager/EditPage.cpp
+CPP/7zip/UI/FileManager/EditPage.h
+CPP/7zip/UI/FileManager/EditPage.rc
+CPP/7zip/UI/FileManager/EditPage2.rc
+CPP/7zip/UI/FileManager/EditPageRes.h
+CPP/7zip/UI/FileManager/EnumFormatEtc.cpp
+CPP/7zip/UI/FileManager/EnumFormatEtc.h
+CPP/7zip/UI/FileManager/Extract.bmp
+CPP/7zip/UI/FileManager/Extract2.bmp
+CPP/7zip/UI/FileManager/ExtractCallback.cpp
+CPP/7zip/UI/FileManager/ExtractCallback.h
+CPP/7zip/UI/FileManager/FM.cpp
+CPP/7zip/UI/FileManager/FM.dsp
+CPP/7zip/UI/FileManager/FM.dsw
+CPP/7zip/UI/FileManager/FM.ico
+CPP/7zip/UI/FileManager/FSDrives.cpp
+CPP/7zip/UI/FileManager/FSDrives.h
+CPP/7zip/UI/FileManager/FSFolder.cpp
+CPP/7zip/UI/FileManager/FSFolder.h
+CPP/7zip/UI/FileManager/FSFolderCopy.cpp
+CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp
+CPP/7zip/UI/FileManager/FileFolderPluginOpen.h
+CPP/7zip/UI/FileManager/FilePlugins.cpp
+CPP/7zip/UI/FileManager/FilePlugins.h
+CPP/7zip/UI/FileManager/FoldersPage.cpp
+CPP/7zip/UI/FileManager/FoldersPage.h
+CPP/7zip/UI/FileManager/FoldersPage.rc
+CPP/7zip/UI/FileManager/FoldersPage2.rc
+CPP/7zip/UI/FileManager/FoldersPageRes.h
+CPP/7zip/UI/FileManager/FormatUtils.cpp
+CPP/7zip/UI/FileManager/FormatUtils.h
+CPP/7zip/UI/FileManager/HelpUtils.cpp
+CPP/7zip/UI/FileManager/HelpUtils.h
+CPP/7zip/UI/FileManager/IFolder.h
+CPP/7zip/UI/FileManager/Info.bmp
+CPP/7zip/UI/FileManager/Info2.bmp
+CPP/7zip/UI/FileManager/LangPage.cpp
+CPP/7zip/UI/FileManager/LangPage.h
+CPP/7zip/UI/FileManager/LangPage.rc
+CPP/7zip/UI/FileManager/LangPageRes.h
+CPP/7zip/UI/FileManager/LangUtils.cpp
+CPP/7zip/UI/FileManager/LangUtils.h
+CPP/7zip/UI/FileManager/ListViewDialog.cpp
+CPP/7zip/UI/FileManager/ListViewDialog.h
+CPP/7zip/UI/FileManager/ListViewDialog.rc
+CPP/7zip/UI/FileManager/ListViewDialogRes.h
+CPP/7zip/UI/FileManager/MenuPage.cpp
+CPP/7zip/UI/FileManager/MenuPage.h
+CPP/7zip/UI/FileManager/MenuPage.rc
+CPP/7zip/UI/FileManager/MenuPage2.rc
+CPP/7zip/UI/FileManager/MenuPageRes.h
+CPP/7zip/UI/FileManager/MessagesDialog.cpp
+CPP/7zip/UI/FileManager/MessagesDialog.h
+CPP/7zip/UI/FileManager/MessagesDialog.rc
+CPP/7zip/UI/FileManager/MessagesDialogRes.h
+CPP/7zip/UI/FileManager/Move.bmp
+CPP/7zip/UI/FileManager/Move2.bmp
+CPP/7zip/UI/FileManager/MyCom2.h
+CPP/7zip/UI/FileManager/MyLoadMenu.cpp
+CPP/7zip/UI/FileManager/MyLoadMenu.h
+CPP/7zip/UI/FileManager/NetFolder.cpp
+CPP/7zip/UI/FileManager/NetFolder.h
+CPP/7zip/UI/FileManager/OpenCallback.cpp
+CPP/7zip/UI/FileManager/OpenCallback.h
+CPP/7zip/UI/FileManager/OptionsDialog.cpp
+CPP/7zip/UI/FileManager/OverwriteDialog.cpp
+CPP/7zip/UI/FileManager/OverwriteDialog.h
+CPP/7zip/UI/FileManager/OverwriteDialog.rc
+CPP/7zip/UI/FileManager/OverwriteDialogRes.h
+CPP/7zip/UI/FileManager/Panel.cpp
+CPP/7zip/UI/FileManager/Panel.h
+CPP/7zip/UI/FileManager/PanelCopy.cpp
+CPP/7zip/UI/FileManager/PanelCrc.cpp
+CPP/7zip/UI/FileManager/PanelDrag.cpp
+CPP/7zip/UI/FileManager/PanelFolderChange.cpp
+CPP/7zip/UI/FileManager/PanelItemOpen.cpp
+CPP/7zip/UI/FileManager/PanelItems.cpp
+CPP/7zip/UI/FileManager/PanelKey.cpp
+CPP/7zip/UI/FileManager/PanelListNotify.cpp
+CPP/7zip/UI/FileManager/PanelMenu.cpp
+CPP/7zip/UI/FileManager/PanelOperations.cpp
+CPP/7zip/UI/FileManager/PanelSelect.cpp
+CPP/7zip/UI/FileManager/PanelSort.cpp
+CPP/7zip/UI/FileManager/PanelSplitFile.cpp
+CPP/7zip/UI/FileManager/PasswordDialog.cpp
+CPP/7zip/UI/FileManager/PasswordDialog.h
+CPP/7zip/UI/FileManager/PasswordDialog.rc
+CPP/7zip/UI/FileManager/PasswordDialogRes.h
+CPP/7zip/UI/FileManager/PluginInterface.h
+CPP/7zip/UI/FileManager/PluginLoader.h
+CPP/7zip/UI/FileManager/PluginsPage.cpp
+CPP/7zip/UI/FileManager/PluginsPage.h
+CPP/7zip/UI/FileManager/PluginsPage.rc
+CPP/7zip/UI/FileManager/PluginsPageRes.h
+CPP/7zip/UI/FileManager/ProgramLocation.cpp
+CPP/7zip/UI/FileManager/ProgramLocation.h
+CPP/7zip/UI/FileManager/ProgressDialog.cpp
+CPP/7zip/UI/FileManager/ProgressDialog.h
+CPP/7zip/UI/FileManager/ProgressDialog.rc
+CPP/7zip/UI/FileManager/ProgressDialog2.cpp
+CPP/7zip/UI/FileManager/ProgressDialog2.h
+CPP/7zip/UI/FileManager/ProgressDialog2.rc
+CPP/7zip/UI/FileManager/ProgressDialog2Res.h
+CPP/7zip/UI/FileManager/ProgressDialog2a.rc
+CPP/7zip/UI/FileManager/ProgressDialogRes.h
+CPP/7zip/UI/FileManager/PropertyName.cpp
+CPP/7zip/UI/FileManager/PropertyName.h
+CPP/7zip/UI/FileManager/PropertyName.rc
+CPP/7zip/UI/FileManager/PropertyNameRes.h
+CPP/7zip/UI/FileManager/RegistryAssociations.cpp
+CPP/7zip/UI/FileManager/RegistryAssociations.h
+CPP/7zip/UI/FileManager/RegistryPlugins.cpp
+CPP/7zip/UI/FileManager/RegistryPlugins.h
+CPP/7zip/UI/FileManager/RegistryUtils.cpp
+CPP/7zip/UI/FileManager/RegistryUtils.h
+CPP/7zip/UI/FileManager/RootFolder.cpp
+CPP/7zip/UI/FileManager/RootFolder.h
+CPP/7zip/UI/FileManager/SettingsPage.cpp
+CPP/7zip/UI/FileManager/SettingsPage.h
+CPP/7zip/UI/FileManager/SettingsPage.rc
+CPP/7zip/UI/FileManager/SettingsPage2.rc
+CPP/7zip/UI/FileManager/SettingsPageRes.h
+CPP/7zip/UI/FileManager/SplitDialog.cpp
+CPP/7zip/UI/FileManager/SplitDialog.h
+CPP/7zip/UI/FileManager/SplitDialog.rc
+CPP/7zip/UI/FileManager/SplitDialogRes.h
+CPP/7zip/UI/FileManager/SplitUtils.cpp
+CPP/7zip/UI/FileManager/SplitUtils.h
+CPP/7zip/UI/FileManager/StdAfx.cpp
+CPP/7zip/UI/FileManager/StdAfx.h
+CPP/7zip/UI/FileManager/StringUtils.cpp
+CPP/7zip/UI/FileManager/StringUtils.h
+CPP/7zip/UI/FileManager/SysIconUtils.cpp
+CPP/7zip/UI/FileManager/SysIconUtils.h
+CPP/7zip/UI/FileManager/SystemPage.cpp
+CPP/7zip/UI/FileManager/SystemPage.h
+CPP/7zip/UI/FileManager/SystemPage.rc
+CPP/7zip/UI/FileManager/SystemPageRes.h
+CPP/7zip/UI/FileManager/Test.bmp
+CPP/7zip/UI/FileManager/Test2.bmp
+CPP/7zip/UI/FileManager/TextPairs.cpp
+CPP/7zip/UI/FileManager/TextPairs.h
+CPP/7zip/UI/FileManager/UpdateCallback100.cpp
+CPP/7zip/UI/FileManager/UpdateCallback100.h
+CPP/7zip/UI/FileManager/ViewSettings.cpp
+CPP/7zip/UI/FileManager/ViewSettings.h
+CPP/7zip/UI/FileManager/makefile
+CPP/7zip/UI/FileManager/resource.h
+CPP/7zip/UI/FileManager/resource.rc
+CPP/7zip/UI/FileManager/resourceGui.h
+CPP/7zip/UI/FileManager/resourceGui.rc
+CPP/7zip/UI/GUI/7zG.exe.manifest
+CPP/7zip/UI/GUI/BenchmarkDialog.cpp
+CPP/7zip/UI/GUI/BenchmarkDialog.h
+CPP/7zip/UI/GUI/BenchmarkDialog.rc
+CPP/7zip/UI/GUI/BenchmarkDialogRes.h
+CPP/7zip/UI/GUI/CompressDialog.cpp
+CPP/7zip/UI/GUI/CompressDialog.h
+CPP/7zip/UI/GUI/CompressDialog.rc
+CPP/7zip/UI/GUI/CompressDialogRes.h
+CPP/7zip/UI/GUI/Extract.rc
+CPP/7zip/UI/GUI/ExtractDialog.cpp
+CPP/7zip/UI/GUI/ExtractDialog.h
+CPP/7zip/UI/GUI/ExtractDialog.rc
+CPP/7zip/UI/GUI/ExtractDialogRes.h
+CPP/7zip/UI/GUI/ExtractGUI.cpp
+CPP/7zip/UI/GUI/ExtractGUI.h
+CPP/7zip/UI/GUI/ExtractRes.h
+CPP/7zip/UI/GUI/FM.ico
+CPP/7zip/UI/GUI/GUI.cpp
+CPP/7zip/UI/GUI/GUI.dsp
+CPP/7zip/UI/GUI/GUI.dsw
+CPP/7zip/UI/GUI/StdAfx.cpp
+CPP/7zip/UI/GUI/StdAfx.h
+CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp
+CPP/7zip/UI/GUI/UpdateCallbackGUI.h
+CPP/7zip/UI/GUI/UpdateGUI.cpp
+CPP/7zip/UI/GUI/UpdateGUI.h
+CPP/7zip/UI/GUI/makefile
+CPP/7zip/UI/GUI/resource.rc
+CPP/7zip/UI/GUI/resource2.h
+CPP/7zip/UI/GUI/resource2.rc
+CPP/7zip/UI/makefile
+CPP/7zip/makefile
+CPP/Build.mak
+CPP/Windows/Control/ComboBox.cpp
+CPP/Windows/Control/ComboBox.h
+CPP/Windows/Control/CommandBar.h
+CPP/Windows/Control/Dialog.cpp
+CPP/Windows/Control/Dialog.h
+CPP/Windows/Control/Edit.h
+CPP/Windows/Control/ImageList.cpp
+CPP/Windows/Control/ImageList.h
+CPP/Windows/Control/ListView.cpp
+CPP/Windows/Control/ListView.h
+CPP/Windows/Control/ProgressBar.h
+CPP/Windows/Control/PropertyPage.cpp
+CPP/Windows/Control/PropertyPage.h
+CPP/Windows/Control/ReBar.h
+CPP/Windows/Control/Static.h
+CPP/Windows/Control/StatusBar.h
+CPP/Windows/Control/StdAfx.h
+CPP/Windows/Control/ToolBar.h
+CPP/Windows/Control/Trackbar.h
+CPP/Windows/Control/Window2.cpp
+CPP/Windows/Control/Window2.h
+DOC/7zip.hhp
+DOC/7zip.inf
+DOC/7zip.nsi
+DOC/7zip.wxs
diff --git a/src/libs/7zip/win/win.pri b/src/libs/7zip/win/win.pri
new file mode 100644
index 000000000..a02ae151b
--- /dev/null
+++ b/src/libs/7zip/win/win.pri
@@ -0,0 +1,272 @@
+isEmpty(7ZIP_BASE): 7ZIP_BASE = $$(7ZIP_BASE)
+isEmpty(7ZIP_BASE): error(Please call qmake with 7ZIP_BASE=<path to nokia-sdk source directory> or add this line before you include that file in your pro file)
+
+7ZIP_BASE=$$7ZIP_BASE/win
+
+CONFIG += no_batch # this is needed because we have a same named *.c and *.cpp file -> 7in
+
+DEFINES += WIN_LONG_PATH _UNICODE _CRT_SECURE_NO_WARNINGS
+
+INCLUDEPATH += $$7ZIP_BASE/CPP
+
+#$(CONSOLE_OBJS): ../../UI/Console/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/BenchCon.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/ConsoleClose.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/List.cpp
+#SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/Main.cpp
+#SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/MainAr.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/PercentPrinter.cpp
+#SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/StdAfx.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Console/UserInputUtils.cpp
+
+#$(COMMON_OBJS): ../../../Common/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/CommandLineParser.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/CRC.cpp
+#SOURCES += $$7ZIP_BASE/CPP/Common/C_FileIO.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/IntToString.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/ListFileUtils.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/MyString.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/MyVector.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/NewHandler.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/StdInStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/StdOutStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/StringConvert.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/StringToInt.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/UTFConvert.cpp
+SOURCES += $$7ZIP_BASE/CPP/Common/Wildcard.cpp
+
+#$(WIN_OBJS): ../../../Windows/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/DLL.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/Error.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/FileDir.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/FileFind.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/FileIO.cpp
+#SOURCES += $$7ZIP_BASE/CPP/Windows/FileMapping.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/FileName.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/MemoryLock.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/PropVariant.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/PropVariantConversions.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/Registry.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/Synchronization.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/System.cpp
+SOURCES += $$7ZIP_BASE/CPP/Windows/Time.cpp
+
+#$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/CreateCoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/CWrappers.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/FilePathAutoRename.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/FileStreams.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/FilterCoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/InBuffer.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/InOutTempBuffer.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/LimitedStreams.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/LockedStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/MemBlocks.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/MethodId.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/MethodProps.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/OffsetStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/OutBuffer.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/OutMemStream.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/ProgressUtils.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/ProgressMt.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/StreamBinder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/StreamObjects.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/StreamUtils.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Common/VirtThread.cpp
+
+#$(UI_COMMON_OBJS): ../../UI/Common/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+#SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveName.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/Bench.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/DefaultName.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/EnumDirItems.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/Extract.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ExtractingFilePath.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/LoadCodecs.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/OpenArchive.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/PropIDUtils.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/SetProperties.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/SortUtils.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/TempFiles.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/Update.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateAction.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateCallback.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/UpdatePair.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/UpdateProduce.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/WorkDir.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/UI/Common/ZipRegistry.cpp
+
+#$(AR_OBJS): ../../Archive/$(*B).cpp
+#SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/ArchiveExports.cpp
+#SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/DllExports2.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Bz2Handler.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/DeflateProps.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/GzHandler.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/LzmaHandler.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/SplitHandler.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/XzHandler.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/ZHandler.cpp #added to support more then 7z
+
+#$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/CoderMixer2MT.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/CrossThreadProgress.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/DummyOutStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/FindSignature.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/HandlerOut.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/ItemNameUtils.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/MultiStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Common/ParseProperties.cpp
+
+#$(7Z_OBJS): ../../Archive/7z/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zCompressionMode.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zDecode.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zEncode.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zExtract.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderInStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zFolderOutStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandler.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHandlerOut.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zHeader.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zIn.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zOut.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zProperties.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zRegister.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zSpecStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/7zUpdate.cpp
+#SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/7z/StdAfx.cpp
+
+#$(CAB_OBJS): ../../Archive/Cab/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Cab/CabHandler.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Cab/CabHeader.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Cab/CabIn.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Cab/CabRegister.cpp
+
+#$(TAR_OBJS): ../../Archive/Tar/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Tar/TarHandler.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Tar/TarHeader.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Tar/TarIn.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Tar/TarOut.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Tar/TarRegister.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Tar/TarUpdate.cpp
+
+#$(ZIP_OBJS): ../../Archive/Zip/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipHandler.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipHeader.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipIn.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipItem.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipOut.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipUpdate.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Archive/Zip/ZipRegister.cpp
+
+#$(COMPRESS_OBJS): ../../Compress/$(*B).cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Bcj2Coder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Bcj2Register.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BcjCoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BcjRegister.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BitlDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BranchCoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BranchMisc.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BranchRegister.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/ByteSwap.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BZip2Encoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BZip2Decoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BZip2Crc.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/BZip2Register.cpp #added to support more then 7z
+#SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/CodecExports.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/CopyCoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/CopyRegister.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/DeltaFilter.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/DeflateDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/DeflateEncoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Deflate64Register.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/DeflateRegister.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/ImplodeDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Decoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Encoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Lzma2Register.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/LzmaDecoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/LzmaEncoder.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/LzmaRegister.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/LzOutWindow.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/Lzx86Converter.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/LzxDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/PpmdEncoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/PpmdDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/PpmdRegister.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/PpmdZip.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/QuantumDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/ShrinkDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/ZlibDecoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/ZlibEncoder.cpp #added to support more then 7z
+SOURCES += $$7ZIP_BASE/CPP/7zip/Compress/ZDecoder.cpp #added to support more then 7z
+
+#Crypto is not needed for 7z only
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/7zAes.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/7zAesRegister.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/HmacSha1.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/MyAes.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/RandGen.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/Sha1.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/WzAes.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/ZipCrypto.cpp
+SOURCES += $$7ZIP_BASE/CPP/7zip/Crypto/ZipStrong.cpp
+
+#$(C_OBJS): ../../../../C/$(*B).c
+#SOURCES += $$7ZIP_BASE/C/7zAlloc.c
+#SOURCES += $$7ZIP_BASE/C/7zBuf.c
+#SOURCES += $$7ZIP_BASE/C/7zBuf2.c
+SOURCES += $$7ZIP_BASE/C/7zCrc.c
+SOURCES += $$7ZIP_BASE/C/7zCrcOpt.c
+#SOURCES += $$7ZIP_BASE/C/7zDec.c
+#SOURCES += $$7ZIP_BASE/C/7zFile.c
+#SOURCES += $$7ZIP_BASE/C/7zIn.c
+SOURCES += $$7ZIP_BASE/C/7zStream.c
+SOURCES += $$7ZIP_BASE/C/Aes.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/AesOpt.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/Alloc.c
+#SOURCES += $$7ZIP_BASE/C/Bcj2.c
+SOURCES += $$7ZIP_BASE/C/Bra.c
+SOURCES += $$7ZIP_BASE/C/Bra86.c
+SOURCES += $$7ZIP_BASE/C/BraIA64.c
+SOURCES += $$7ZIP_BASE/C/BwtSort.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/CpuArch.c
+SOURCES += $$7ZIP_BASE/C/HuffEnc.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/Delta.c
+SOURCES += $$7ZIP_BASE/C/LzFind.c
+SOURCES += $$7ZIP_BASE/C/LzFindMt.c
+SOURCES += $$7ZIP_BASE/C/Lzma2Dec.c
+SOURCES += $$7ZIP_BASE/C/Lzma2Enc.c
+#SOURCES += $$7ZIP_BASE/C/Lzma86Dec.c
+#SOURCES += $$7ZIP_BASE/C/Lzma86Enc.c
+SOURCES += $$7ZIP_BASE/C/LzmaDec.c
+SOURCES += $$7ZIP_BASE/C/LzmaEnc.c
+#SOURCES += $$7ZIP_BASE/C/LzmaLib.c
+SOURCES += $$7ZIP_BASE/C/MtCoder.c
+SOURCES += $$7ZIP_BASE/C/Ppmd7.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/Ppmd7Dec.c
+SOURCES += $$7ZIP_BASE/C/Ppmd7Enc.c
+SOURCES += $$7ZIP_BASE/C/Ppmd8.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/Ppmd8Dec.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/Ppmd8Enc.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/Sha256.c
+SOURCES += $$7ZIP_BASE/C/Sort.c #added to support more then 7z
+SOURCES += $$7ZIP_BASE/C/Threads.c
+SOURCES += $$7ZIP_BASE/C/Xz.c
+SOURCES += $$7ZIP_BASE/C/XzCrc64.c
+SOURCES += $$7ZIP_BASE/C/XzDec.c
+SOURCES += $$7ZIP_BASE/C/XzEnc.c
+SOURCES += $$7ZIP_BASE/C/XzIn.c