summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/win/CPP
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/win/CPP
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/win/CPP')
-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
566 files changed, 98674 insertions, 0 deletions
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 *strea